From d11d904c81a202c7bfb5b18f4ee248eb2fc9174f Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Fri, 4 Apr 2025 10:47:07 -0500 Subject: [PATCH 0001/2760] hw/ipmi: Move vmsd registration to device class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's the right way to do it now, and it handles multiple instances properly. I need multiple instances for some testing I'm doing so this is the right thing to do. Tested by doing: (qemu) migrate -d exec:cat>filen.mig before and after the fix, then: scripts/analyze-migration.py -d desc -f file1.mig >file1.json scripts/analyze-migration.py -d desc -f file2.mig >file2.json diff file1.json file2.json with no differences. Signed-off-by: Corey Minyard Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Fabiano Rosas --- hw/ipmi/ipmi_bmc_extern.c | 3 +-- hw/ipmi/ipmi_bmc_sim.c | 3 +-- hw/ipmi/isa_ipmi_bt.c | 3 +-- hw/ipmi/isa_ipmi_kcs.c | 12 +++++------- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index d015500254..3e9f8c5a50 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -497,8 +497,6 @@ static void ipmi_bmc_extern_realize(DeviceState *dev, Error **errp) qemu_chr_fe_set_handlers(&ibe->chr, can_receive, receive, chr_event, NULL, ibe, NULL, true); - - vmstate_register(NULL, 0, &vmstate_ipmi_bmc_extern, ibe); } static void ipmi_bmc_extern_init(Object *obj) @@ -528,6 +526,7 @@ static void ipmi_bmc_extern_class_init(ObjectClass *oc, void *data) bk->handle_reset = ipmi_bmc_extern_handle_reset; dc->hotpluggable = false; dc->realize = ipmi_bmc_extern_realize; + dc->vmsd = &vmstate_ipmi_bmc_extern; device_class_set_props(dc, ipmi_bmc_extern_properties); } diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 6157ac7120..bc0ddc52a9 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -2187,8 +2187,6 @@ static void ipmi_sim_realize(DeviceState *dev, Error **errp) register_cmds(ibs); ibs->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, ipmi_timeout, ibs); - - vmstate_register(NULL, 0, &vmstate_ipmi_sim, ibs); } static const Property ipmi_sim_properties[] = { @@ -2212,6 +2210,7 @@ static void ipmi_sim_class_init(ObjectClass *oc, void *data) dc->hotpluggable = false; dc->realize = ipmi_sim_realize; + dc->vmsd = &vmstate_ipmi_sim; device_class_set_props(dc, ipmi_sim_properties); bk->handle_command = ipmi_sim_handle_command; } diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index a1b66d5ee8..474a792c9a 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -117,8 +117,6 @@ static void isa_ipmi_bt_realize(DeviceState *dev, Error **errp) qdev_set_legacy_instance_id(dev, iib->bt.io_base, iib->bt.io_length); isa_register_ioport(isadev, &iib->bt.io, iib->bt.io_base); - - vmstate_register(NULL, 0, &vmstate_ISAIPMIBTDevice, dev); } static void isa_ipmi_bt_init(Object *obj) @@ -147,6 +145,7 @@ static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data) AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); dc->realize = isa_ipmi_bt_realize; + dc->vmsd = &vmstate_ISAIPMIBTDevice; device_class_set_props(dc, ipmi_isa_properties); iic->get_backend_data = isa_ipmi_bt_get_backend_data; diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index d9ebdd5371..94bbe45d35 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -72,6 +72,10 @@ static bool vmstate_kcs_before_version2(void *opaque, int version) return version <= 1; } +/* + * Version 1 had an incorrect name, it clashed with the BT IPMI + * device, so receive it, but transmit a different version. + */ static const VMStateDescription vmstate_ISAIPMIKCSDevice = { .name = TYPE_IPMI_INTERFACE, .version_id = 2, @@ -119,13 +123,6 @@ static void ipmi_isa_realize(DeviceState *dev, Error **errp) qdev_set_legacy_instance_id(dev, iik->kcs.io_base, iik->kcs.io_length); isa_register_ioport(isadev, &iik->kcs.io, iik->kcs.io_base); - - /* - * Version 1 had an incorrect name, it clashed with the BT - * IPMI device, so receive it, but transmit a different - * version. - */ - vmstate_register(NULL, 0, &vmstate_ISAIPMIKCSDevice, iik); } static void isa_ipmi_kcs_init(Object *obj) @@ -154,6 +151,7 @@ static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(oc); dc->realize = ipmi_isa_realize; + dc->vmsd = &vmstate_ISAIPMIKCSDevice; device_class_set_props(dc, ipmi_isa_properties); iic->get_backend_data = isa_ipmi_kcs_get_backend_data; From 3e0a763136aa715c536497008d9fa2c0d64c3909 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 2 Apr 2025 00:01:48 +1000 Subject: [PATCH 0002/2760] ipmi/pci-ipmi-bt: Rename copy-paste variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IPMI drivers use p/k suffix in variable names depending on bt or kcs. The pci bt driver must have come from the kcs driver because it's still using k suffixes in some cases. Rename. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Nicholas Piggin Message-ID: <20250401140153.685523-2-npiggin@gmail.com> Signed-off-by: Corey Minyard --- hw/ipmi/pci_ipmi_bt.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c index afeea6f303..a3b742d22c 100644 --- a/hw/ipmi/pci_ipmi_bt.c +++ b/hw/ipmi/pci_ipmi_bt.c @@ -38,49 +38,49 @@ struct PCIIPMIBTDevice { uint32_t uuid; }; -static void pci_ipmi_raise_irq(IPMIBT *ik) +static void pci_ipmi_raise_irq(IPMIBT *ib) { - PCIIPMIBTDevice *pik = ik->opaque; + PCIIPMIBTDevice *pib = ib->opaque; - pci_set_irq(&pik->dev, true); + pci_set_irq(&pib->dev, true); } -static void pci_ipmi_lower_irq(IPMIBT *ik) +static void pci_ipmi_lower_irq(IPMIBT *ib) { - PCIIPMIBTDevice *pik = ik->opaque; + PCIIPMIBTDevice *pib = ib->opaque; - pci_set_irq(&pik->dev, false); + pci_set_irq(&pib->dev, false); } static void pci_ipmi_bt_realize(PCIDevice *pd, Error **errp) { Error *err = NULL; - PCIIPMIBTDevice *pik = PCI_IPMI_BT(pd); + PCIIPMIBTDevice *pib = PCI_IPMI_BT(pd); IPMIInterface *ii = IPMI_INTERFACE(pd); IPMIInterfaceClass *iic = IPMI_INTERFACE_GET_CLASS(ii); - if (!pik->bt.bmc) { + if (!pib->bt.bmc) { error_setg(errp, "IPMI device requires a bmc attribute to be set"); return; } - pik->uuid = ipmi_next_uuid(); + pib->uuid = ipmi_next_uuid(); - pik->bt.bmc->intf = ii; - pik->bt.opaque = pik; + pib->bt.bmc->intf = ii; + pib->bt.opaque = pib; pci_config_set_prog_interface(pd->config, 0x02); /* BT */ pci_config_set_interrupt_pin(pd->config, 0x01); - pik->bt.use_irq = 1; - pik->bt.raise_irq = pci_ipmi_raise_irq; - pik->bt.lower_irq = pci_ipmi_lower_irq; + pib->bt.use_irq = 1; + pib->bt.raise_irq = pci_ipmi_raise_irq; + pib->bt.lower_irq = pci_ipmi_lower_irq; iic->init(ii, 8, &err); if (err) { error_propagate(errp, err); return; } - pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pik->bt.io); + pci_register_bar(pd, 0, PCI_BASE_ADDRESS_SPACE_IO, &pib->bt.io); } const VMStateDescription vmstate_PCIIPMIBTDevice = { @@ -96,16 +96,16 @@ const VMStateDescription vmstate_PCIIPMIBTDevice = { static void pci_ipmi_bt_instance_init(Object *obj) { - PCIIPMIBTDevice *pik = PCI_IPMI_BT(obj); + PCIIPMIBTDevice *pib = PCI_IPMI_BT(obj); - ipmi_bmc_find_and_link(obj, (Object **) &pik->bt.bmc); + ipmi_bmc_find_and_link(obj, (Object **) &pib->bt.bmc); } static void *pci_ipmi_bt_get_backend_data(IPMIInterface *ii) { - PCIIPMIBTDevice *pik = PCI_IPMI_BT(ii); + PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii); - return &pik->bt; + return &pib->bt; } static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data) From 7376d10b50fb5faa8324092c3f70195d713e34ac Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 2 Apr 2025 00:01:49 +1000 Subject: [PATCH 0003/2760] ipmi: add fwinfo to pci ipmi devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This requires some adjustments to callers to avoid possible behaviour changes for PCI devices. Signed-off-by: Nicholas Piggin Message-ID: <20250401140153.685523-3-npiggin@gmail.com> Reviewed-by: Philippe Mathieu-Daudé [Rename pci_ipmi_bt_get_fwinfo to pci_ipmi_kcs_get_fwinfo in the pci_ipmi_kcs.c file.] Signed-off-by: Corey Minyard --- hw/acpi/ipmi.c | 3 ++- hw/ipmi/isa_ipmi_bt.c | 1 + hw/ipmi/isa_ipmi_kcs.c | 1 + hw/ipmi/pci_ipmi_bt.c | 12 ++++++++++++ hw/ipmi/pci_ipmi_kcs.c | 11 +++++++++++ hw/smbios/smbios_type_38.c | 7 ++++++- include/hw/ipmi/ipmi.h | 5 +++++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/hw/acpi/ipmi.c b/hw/acpi/ipmi.c index a20e57d465..39f8f2f6d6 100644 --- a/hw/acpi/ipmi.c +++ b/hw/acpi/ipmi.c @@ -55,7 +55,8 @@ static Aml *aml_ipmi_crs(IPMIFwInfo *info) abort(); } - if (info->interrupt_number) { + /* Should PCI interrupts also be appended? */ + if (info->irq_source == IPMI_ISA_IRQ && info->interrupt_number) { aml_append(crs, aml_irq_no_flags(info->interrupt_number)); } diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index 474a792c9a..76585e786e 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -49,6 +49,7 @@ static void isa_ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) ISAIPMIBTDevice *iib = ISA_IPMI_BT(ii); ipmi_bt_get_fwinfo(&iib->bt, info); + info->irq_source = IPMI_ISA_IRQ; info->interrupt_number = iib->isairq; info->i2c_slave_address = iib->bt.bmc->slave_addr; info->uuid = iib->uuid; diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 94bbe45d35..ba3ae208b2 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -49,6 +49,7 @@ static void isa_ipmi_kcs_get_fwinfo(IPMIInterface *ii, IPMIFwInfo *info) ISAIPMIKCSDevice *iik = ISA_IPMI_KCS(ii); ipmi_kcs_get_fwinfo(&iik->kcs, info); + info->irq_source = IPMI_ISA_IRQ; info->interrupt_number = iik->isairq; info->uuid = iik->uuid; } diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c index a3b742d22c..7ba8b3ab96 100644 --- a/hw/ipmi/pci_ipmi_bt.c +++ b/hw/ipmi/pci_ipmi_bt.c @@ -38,6 +38,17 @@ struct PCIIPMIBTDevice { uint32_t uuid; }; +static void pci_ipmi_bt_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) +{ + PCIIPMIBTDevice *pib = PCI_IPMI_BT(ii); + + ipmi_bt_get_fwinfo(&pib->bt, info); + info->irq_source = IPMI_PCI_IRQ; + info->interrupt_number = pci_intx(&pib->dev); + info->i2c_slave_address = pib->bt.bmc->slave_addr; + info->uuid = pib->uuid; +} + static void pci_ipmi_raise_irq(IPMIBT *ib) { PCIIPMIBTDevice *pib = ib->opaque; @@ -125,6 +136,7 @@ static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data) iic->get_backend_data = pci_ipmi_bt_get_backend_data; ipmi_bt_class_init(iic); + iic->get_fwinfo = pci_ipmi_bt_get_fwinfo; } static const TypeInfo pci_ipmi_bt_info = { diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c index 05ba97ec58..0aa35143e9 100644 --- a/hw/ipmi/pci_ipmi_kcs.c +++ b/hw/ipmi/pci_ipmi_kcs.c @@ -38,6 +38,16 @@ struct PCIIPMIKCSDevice { uint32_t uuid; }; +static void pci_ipmi_kcs_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) +{ + PCIIPMIKCSDevice *pik = PCI_IPMI_KCS(ii); + + ipmi_kcs_get_fwinfo(&pik->kcs, info); + info->irq_source = IPMI_PCI_IRQ; + info->interrupt_number = pci_intx(&pik->dev); + info->uuid = pik->uuid; +} + static void pci_ipmi_raise_irq(IPMIKCS *ik) { PCIIPMIKCSDevice *pik = ik->opaque; @@ -125,6 +135,7 @@ static void pci_ipmi_kcs_class_init(ObjectClass *oc, void *data) iic->get_backend_data = pci_ipmi_kcs_get_backend_data; ipmi_kcs_class_init(iic); + iic->get_fwinfo = pci_ipmi_kcs_get_fwinfo; } static const TypeInfo pci_ipmi_kcs_info = { diff --git a/hw/smbios/smbios_type_38.c b/hw/smbios/smbios_type_38.c index 168b886647..e9b856fcd9 100644 --- a/hw/smbios/smbios_type_38.c +++ b/hw/smbios/smbios_type_38.c @@ -72,7 +72,12 @@ static void smbios_build_one_type_38(IPMIFwInfo *info) " SMBIOS, ignoring this entry.", info->register_spacing); return; } - t->interrupt_number = info->interrupt_number; + if (info->irq_source == IPMI_ISA_IRQ) { + t->interrupt_number = info->interrupt_number; + } else { + /* TODO: How to handle PCI? */ + t->interrupt_number = 0; + } SMBIOS_BUILD_TABLE_POST; } diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h index 77a7213ed9..c8ef04856e 100644 --- a/include/hw/ipmi/ipmi.h +++ b/include/hw/ipmi/ipmi.h @@ -90,6 +90,11 @@ typedef struct IPMIFwInfo { } memspace; int interrupt_number; + enum { + IPMI_NO_IRQ = 0, + IPMI_ISA_IRQ, + IPMI_PCI_IRQ, + } irq_source; enum { IPMI_LEVEL_IRQ, IPMI_EDGE_IRQ From 7f9e7af40a1721e5adb95761754bc12af0f3d2f1 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 2 Apr 2025 00:01:50 +1000 Subject: [PATCH 0004/2760] ipmi/bmc-sim: Add 'Get Channel Info' command Linux issues this command when booting a powernv machine. Signed-off-by: Nicholas Piggin Message-ID: <20250401140153.685523-4-npiggin@gmail.com> Signed-off-by: Corey Minyard --- hw/ipmi/ipmi_bmc_sim.c | 68 ++++++++++++++++++++++++++++++++++++++++-- hw/ipmi/ipmi_bt.c | 2 ++ hw/ipmi/ipmi_kcs.c | 1 + include/hw/ipmi/ipmi.h | 10 +++++++ 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index bc0ddc52a9..03e58d283e 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -70,6 +70,7 @@ #define IPMI_CMD_GET_MSG 0x33 #define IPMI_CMD_SEND_MSG 0x34 #define IPMI_CMD_READ_EVT_MSG_BUF 0x35 +#define IPMI_CMD_GET_CHANNEL_INFO 0x42 #define IPMI_NETFN_STORAGE 0x0a @@ -1020,8 +1021,8 @@ static void send_msg(IPMIBmcSim *ibs, uint8_t *buf; uint8_t netfn, rqLun, rsLun, rqSeq; - if (cmd[2] != 0) { - /* We only handle channel 0 with no options */ + if (cmd[2] != IPMI_CHANNEL_IPMB) { + /* We only handle channel 0h (IPMB) with no options */ rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); return; } @@ -1219,6 +1220,68 @@ static void get_watchdog_timer(IPMIBmcSim *ibs, } } +static void get_channel_info(IPMIBmcSim *ibs, + uint8_t *cmd, unsigned int cmd_len, + RspBuffer *rsp) +{ + IPMIInterface *s = ibs->parent.intf; + IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); + IPMIFwInfo info = {}; + uint8_t ch = cmd[2] & 0x0f; + + /* Only define channel 0h (IPMB) and Fh (system interface) */ + + if (ch == 0x0e) { /* "This channel" */ + ch = IPMI_CHANNEL_SYSTEM; + } + rsp_buffer_push(rsp, ch); + + if (ch != IPMI_CHANNEL_IPMB && ch != IPMI_CHANNEL_SYSTEM) { + /* Not a supported channel */ + rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); + return; + } + + if (k->get_fwinfo) { + k->get_fwinfo(s, &info); + } + + if (ch == IPMI_CHANNEL_IPMB) { + rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_IPMB); + rsp_buffer_push(rsp, IPMI_CHANNEL_PROTOCOL_IPMB); + } else { /* IPMI_CHANNEL_SYSTEM */ + rsp_buffer_push(rsp, IPMI_CHANNEL_MEDIUM_SYSTEM); + rsp_buffer_push(rsp, info.ipmi_channel_protocol); + } + + rsp_buffer_push(rsp, 0x00); /* Session-less */ + + /* IPMI Enterprise Number for Vendor ID */ + rsp_buffer_push(rsp, 0xf2); + rsp_buffer_push(rsp, 0x1b); + rsp_buffer_push(rsp, 0x00); + + if (ch == IPMI_CHANNEL_SYSTEM) { + uint8_t irq; + + if (info.irq_source == IPMI_ISA_IRQ) { + irq = info.interrupt_number; + } else if (info.irq_source == IPMI_PCI_IRQ) { + irq = 0x10 + info.interrupt_number; + } else { + irq = 0xff; /* no interrupt / unspecified */ + } + + /* Both interrupts use the same irq number */ + rsp_buffer_push(rsp, irq); + rsp_buffer_push(rsp, irq); + } else { + /* Reserved */ + rsp_buffer_push(rsp, 0x00); + rsp_buffer_push(rsp, 0x00); + } +} + static void get_sdr_rep_info(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, RspBuffer *rsp) @@ -2015,6 +2078,7 @@ static const IPMICmdHandler app_cmds[] = { [IPMI_CMD_RESET_WATCHDOG_TIMER] = { reset_watchdog_timer }, [IPMI_CMD_SET_WATCHDOG_TIMER] = { set_watchdog_timer, 8 }, [IPMI_CMD_GET_WATCHDOG_TIMER] = { get_watchdog_timer }, + [IPMI_CMD_GET_CHANNEL_INFO] = { get_channel_info, 3 }, }; static const IPMINetfn app_netfn = { .cmd_nums = ARRAY_SIZE(app_cmds), diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c index 583fc64730..28cf6ab218 100644 --- a/hw/ipmi/ipmi_bt.c +++ b/hw/ipmi/ipmi_bt.c @@ -419,6 +419,8 @@ void ipmi_bt_get_fwinfo(struct IPMIBT *ib, IPMIFwInfo *info) info->interface_type = IPMI_SMBIOS_BT; info->ipmi_spec_major_revision = 2; info->ipmi_spec_minor_revision = 0; + /* BT System Interface Format, IPMI v1.5 */ + info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_BT_15; info->base_address = ib->io_base; info->register_length = ib->io_length; info->register_spacing = 1; diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c index c15977cab4..578dd7cef3 100644 --- a/hw/ipmi/ipmi_kcs.c +++ b/hw/ipmi/ipmi_kcs.c @@ -405,6 +405,7 @@ void ipmi_kcs_get_fwinfo(IPMIKCS *ik, IPMIFwInfo *info) info->interface_type = IPMI_SMBIOS_KCS; info->ipmi_spec_major_revision = 2; info->ipmi_spec_minor_revision = 0; + info->ipmi_channel_protocol = IPMI_CHANNEL_PROTOCOL_KCS; info->base_address = ik->io_base; info->i2c_slave_address = ik->bmc->slave_addr; info->register_length = ik->io_length; diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h index c8ef04856e..802a2febb0 100644 --- a/include/hw/ipmi/ipmi.h +++ b/include/hw/ipmi/ipmi.h @@ -41,6 +41,15 @@ enum ipmi_op { IPMI_SEND_NMI }; +/* Channel properties */ +#define IPMI_CHANNEL_IPMB 0x00 +#define IPMI_CHANNEL_SYSTEM 0x0f +#define IPMI_CHANNEL_MEDIUM_IPMB 0x01 +#define IPMI_CHANNEL_MEDIUM_SYSTEM 0x0c +#define IPMI_CHANNEL_PROTOCOL_IPMB 0x01 +#define IPMI_CHANNEL_PROTOCOL_KCS 0x05 +#define IPMI_CHANNEL_PROTOCOL_BT_15 0x08 + #define IPMI_CC_INVALID_CMD 0xc1 #define IPMI_CC_COMMAND_INVALID_FOR_LUN 0xc2 #define IPMI_CC_TIMEOUT 0xc3 @@ -76,6 +85,7 @@ typedef struct IPMIFwInfo { int interface_type; uint8_t ipmi_spec_major_revision; uint8_t ipmi_spec_minor_revision; + uint8_t ipmi_channel_protocol; uint8_t i2c_slave_address; uint32_t uuid; From d9494ef96c859515aa9df450fb61e833da7cb7c7 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 2 Apr 2025 00:01:51 +1000 Subject: [PATCH 0005/2760] ipmi/bmc-sim: implement watchdog dont log flag If the dont-log flag is set in the 'timer use' field for the 'set watchdog' command, a watchdog timeout will not get logged as a timer use expiration. Signed-off-by: Nicholas Piggin Message-ID: <20250401140153.685523-5-npiggin@gmail.com> Signed-off-by: Corey Minyard --- hw/ipmi/ipmi_bmc_sim.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 03e58d283e..4ed66e1ee0 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -514,7 +514,8 @@ static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, unsigned int bit, unsigned int val, - uint8_t evd1, uint8_t evd2, uint8_t evd3) + uint8_t evd1, uint8_t evd2, uint8_t evd3, + bool do_log) { IPMISensor *sens; uint16_t mask; @@ -534,7 +535,7 @@ static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, return; /* Already asserted */ } sens->assert_states |= mask & sens->assert_suppt; - if (sens->assert_enable & mask & sens->assert_states) { + if (do_log && (sens->assert_enable & mask & sens->assert_states)) { /* Send an event on assert */ gen_event(ibs, sensor, 0, evd1, evd2, evd3); } @@ -544,7 +545,7 @@ static void sensor_set_discrete_bit(IPMIBmcSim *ibs, unsigned int sensor, return; /* Already deasserted */ } sens->deassert_states |= mask & sens->deassert_suppt; - if (sens->deassert_enable & mask & sens->deassert_states) { + if (do_log && (sens->deassert_enable & mask & sens->deassert_states)) { /* Send an event on deassert */ gen_event(ibs, sensor, 1, evd1, evd2, evd3); } @@ -700,6 +701,7 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) { IPMIInterface *s = ibs->parent.intf; IPMIInterfaceClass *k = IPMI_INTERFACE_GET_CLASS(s); + bool do_log = !IPMI_BMC_WATCHDOG_GET_DONT_LOG(ibs); if (!ibs->watchdog_running) { goto out; @@ -711,14 +713,16 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; k->do_hw_op(s, IPMI_SEND_NMI, 0); sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, - 0xc8, (2 << 4) | 0xf, 0xff); + 0xc8, (2 << 4) | 0xf, 0xff, + do_log); break; case IPMI_BMC_WATCHDOG_PRE_MSG_INT: ibs->msg_flags |= IPMI_BMC_MSG_FLAG_WATCHDOG_TIMEOUT_MASK; k->set_atn(s, 1, attn_irq_enabled(ibs)); sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 8, 1, - 0xc8, (3 << 4) | 0xf, 0xff); + 0xc8, (3 << 4) | 0xf, 0xff, + do_log); break; default: @@ -738,24 +742,28 @@ static void ipmi_sim_handle_timeout(IPMIBmcSim *ibs) switch (IPMI_BMC_WATCHDOG_GET_ACTION(ibs)) { case IPMI_BMC_WATCHDOG_ACTION_NONE: sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 0, 1, - 0xc0, ibs->watchdog_use & 0xf, 0xff); + 0xc0, ibs->watchdog_use & 0xf, 0xff, + do_log); break; case IPMI_BMC_WATCHDOG_ACTION_RESET: sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 1, 1, - 0xc1, ibs->watchdog_use & 0xf, 0xff); + 0xc1, ibs->watchdog_use & 0xf, 0xff, + do_log); k->do_hw_op(s, IPMI_RESET_CHASSIS, 0); break; case IPMI_BMC_WATCHDOG_ACTION_POWER_DOWN: sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, - 0xc2, ibs->watchdog_use & 0xf, 0xff); + 0xc2, ibs->watchdog_use & 0xf, 0xff, + do_log); k->do_hw_op(s, IPMI_POWEROFF_CHASSIS, 0); break; case IPMI_BMC_WATCHDOG_ACTION_POWER_CYCLE: sensor_set_discrete_bit(ibs, IPMI_WATCHDOG_SENSOR, 2, 1, - 0xc3, ibs->watchdog_use & 0xf, 0xff); + 0xc3, ibs->watchdog_use & 0xf, 0xff, + do_log); k->do_hw_op(s, IPMI_POWERCYCLE_CHASSIS, 0); break; } From dacb3e70ef73d1c9a2d0d4cfd65031deff49f742 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 2 Apr 2025 00:01:52 +1000 Subject: [PATCH 0006/2760] ipmi/bmc-sim: add error handling for 'Set BMC Global Enables' command Mask out unsupported bits and return failure if attempting to set any. This is not required by the IPMI spec, but it does require that system software not change bits it isn't aware of. Signed-off-by: Nicholas Piggin Message-ID: <20250401140153.685523-6-npiggin@gmail.com> Signed-off-by: Corey Minyard --- hw/ipmi/ipmi_bmc_sim.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 4ed66e1ee0..1c60a71831 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -235,6 +235,7 @@ struct IPMIBmcSim { #define IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE_SET(s) \ (IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE & (s)->msg_flags) +#define IPMI_BMC_GLOBAL_ENABLES_SUPPORTED 0x0f #define IPMI_BMC_RCV_MSG_QUEUE_INT_BIT 0 #define IPMI_BMC_EVBUF_FULL_INT_BIT 1 #define IPMI_BMC_EVENT_MSG_BUF_BIT 2 @@ -934,7 +935,14 @@ static void set_bmc_global_enables(IPMIBmcSim *ibs, uint8_t *cmd, unsigned int cmd_len, RspBuffer *rsp) { - set_global_enables(ibs, cmd[2]); + uint8_t val = cmd[2]; + + if (val & ~IPMI_BMC_GLOBAL_ENABLES_SUPPORTED) { + rsp_buffer_set_error(rsp, IPMI_CC_INVALID_DATA_FIELD); + return; + } + + set_global_enables(ibs, val); } static void get_bmc_global_enables(IPMIBmcSim *ibs, From 08b462dd9970a88d7f0e7c61ca48502463b0b78d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Apr 2025 17:42:52 +0200 Subject: [PATCH 0007/2760] scsi: add conversion from ENODEV to sense This is mostly for completeness; I noticed it because ENODEV is used internally within scsi-disk.c, but when scsi_sense_from_errno(ENODEV) is called the resulting sense is never used and instead scsi_sense_from_host_status() is called later by scsi_req_complete_failed(). Signed-off-by: Paolo Bonzini --- scsi/utils.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scsi/utils.c b/scsi/utils.c index 357b036671..545956f4f9 100644 --- a/scsi/utils.c +++ b/scsi/utils.c @@ -587,20 +587,27 @@ int scsi_sense_from_errno(int errno_value, SCSISense *sense) return GOOD; case EDOM: return TASK_SET_FULL; +#if ENODEV != ENOMEDIUM + case ENODEV: + /* + * Some of the BSDs have ENODEV and ENOMEDIUM as synonyms. For + * everyone else, give a more severe sense code for ENODEV. + */ +#endif #ifdef CONFIG_LINUX /* These errno mapping are specific to Linux. For more information: * - scsi_check_sense and scsi_decide_disposition in drivers/scsi/scsi_error.c * - scsi_result_to_blk_status in drivers/scsi/scsi_lib.c * - blk_errors[] in block/blk-core.c */ + case EREMOTEIO: + *sense = SENSE_CODE(TARGET_FAILURE); + return CHECK_CONDITION; case EBADE: return RESERVATION_CONFLICT; case ENODATA: *sense = SENSE_CODE(READ_ERROR); return CHECK_CONDITION; - case EREMOTEIO: - *sense = SENSE_CODE(TARGET_FAILURE); - return CHECK_CONDITION; #endif case ENOMEDIUM: *sense = SENSE_CODE(NO_MEDIUM); From 280712b78781c43511d6286d40f9a518a4de25ff Mon Sep 17 00:00:00 2001 From: Ewan Hai Date: Mon, 14 Apr 2025 03:53:42 -0400 Subject: [PATCH 0008/2760] target/i386: Fix model number of Zhaoxin YongFeng vCPU template The model number was mistakenly set to 0x0b (11) in commit ff04bc1ac4. The correct value is 0x5b. This mistake occurred because the extended model bits in cpuid[eax=0x1].eax were overlooked, and only the base model was used. Using the wrong model number can affect guest behavior. One known issue is that vPMU (which relies on the model number) may fail to operate correctly. This patch corrects the model field by introducing a new vCPU version. Fixes: ff04bc1ac4 ("target/i386: Introduce Zhaoxin Yongfeng CPU model") Signed-off-by: Ewan Hai Link: https://lore.kernel.org/r/20250414075342.411626-1-ewanhai-oc@zhaoxin.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1b64ceaaba..3fb1ec62da 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5621,6 +5621,18 @@ static const X86CPUDefinition builtin_x86_defs[] = { .features[FEAT_VMX_VMFUNC] = MSR_VMX_VMFUNC_EPT_SWITCHING, .xlevel = 0x80000008, .model_id = "Zhaoxin YongFeng Processor", + .versions = (X86CPUVersionDefinition[]) { + { .version = 1 }, + { + .version = 2, + .note = "with the correct model number", + .props = (PropValue[]) { + { "model", "0x5b" }, + { /* end of list */ } + } + }, + { /* end of list */ } + } }, }; From f6b5f71f04529d3f56b35f91badac9f5e7e225ca Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Thu, 27 Mar 2025 19:24:16 +0100 Subject: [PATCH 0009/2760] target/i386: Reset parked vCPUs together with the online ones Commit 3f2a05b31ee9 ("target/i386: Reset TSCs of parked vCPUs too on VM reset") introduced a way to reset TSCs of parked vCPUs during VM reset to prevent them getting desynchronized with the online vCPUs and therefore causing the KVM PV clock to lose PVCLOCK_TSC_STABLE_BIT. The way this was done was by registering a parked vCPU-specific QEMU reset callback via qemu_register_reset(). However, it turns out that on particularly device-rich VMs QEMU reset callbacks can take a long time to execute (which isn't surprising, considering that they involve resetting all of VM devices). In particular, their total runtime can exceed the 1-second TSC synchronization window introduced in KVM commit 5d3cb0f6a8e3 ("KVM: Improve TSC offset matching"). Since the TSCs of online vCPUs are only reset from "synchronize_post_reset" AccelOps handler (which runs after all qemu_register_reset() handlers) this essentially makes that fix ineffective on these VMs. The easiest way to guarantee that these parked vCPUs are reset at the same time as the online ones (regardless how long it takes for VM devices to reset) is to piggyback on post-reset vCPU synchronization handler for one of online vCPUs - as there is no generic post-reset AccelOps handler that isn't per-vCPU. The first online vCPU was selected for that since it is easily available under "first_cpu" define. This does not create an ordering issue since the order of vCPU TSC resets does not matter. Fixes: 3f2a05b31ee9 ("target/i386: Reset TSCs of parked vCPUs too on VM reset") Signed-off-by: Maciej S. Szmigiero Link: https://lore.kernel.org/r/e8b85a5915f79aa177ca49eccf0e9b534470c1cd.1743099810.git.maciej.szmigiero@oracle.com Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f89568bfa3..951e8214e0 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -437,9 +437,8 @@ int kvm_unpark_vcpu(KVMState *s, unsigned long vcpu_id) return kvm_fd; } -static void kvm_reset_parked_vcpus(void *param) +static void kvm_reset_parked_vcpus(KVMState *s) { - KVMState *s = param; struct KVMParkedVcpu *cpu; QLIST_FOREACH(cpu, &s->kvm_parked_vcpus, node) { @@ -2738,7 +2737,6 @@ static int kvm_init(MachineState *ms) } qemu_register_reset(kvm_unpoison_all, NULL); - qemu_register_reset(kvm_reset_parked_vcpus, s); if (s->kernel_irqchip_allowed) { kvm_irqchip_create(s); @@ -2908,6 +2906,10 @@ static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg void kvm_cpu_synchronize_post_reset(CPUState *cpu) { run_on_cpu(cpu, do_kvm_cpu_synchronize_post_reset, RUN_ON_CPU_NULL); + + if (cpu == first_cpu) { + kvm_reset_parked_vcpus(kvm_state); + } } static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) From 94a159f3dc737d00749cc930adaec112abe07b3c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 3 Apr 2025 21:39:54 +0200 Subject: [PATCH 0010/2760] target/i386/hvf: fix lflags_to_rflags MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clear the flags before adding in the ones computed from lflags. Cc: Wei Liu Cc: qemu-stable@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_flags.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index 03d6de5efc..fedc70a1b8 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -293,6 +293,7 @@ void set_SF(CPUX86State *env, bool val) void lflags_to_rflags(CPUX86State *env) { + env->eflags &= ~(CC_C|CC_P|CC_A|CC_Z|CC_S|CC_O); env->eflags |= get_CF(env) ? CC_C : 0; env->eflags |= get_PF(env) ? CC_P : 0; env->eflags |= get_AF(env) ? CC_A : 0; From bd65810538bfa4baef4f9e2fe40166d008a2a64c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 17 Feb 2025 10:21:02 +0100 Subject: [PATCH 0011/2760] target/i386: special case ADC/SBB x,0 and SBB x,x Avoid the three-operand CC_OP_ADD and CC_OP_ADC in these relatively common cases. Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 71 +++++++++++++++++++++++++++++++++---- target/i386/tcg/translate.c | 20 +++++++++++ 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 0fa1664a24..f477a2da99 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1170,11 +1170,28 @@ static void gen_AAS(DisasContext *s, X86DecodedInsn *decode) assume_cc_op(s, CC_OP_EFLAGS); } +static void gen_ADD(DisasContext *s, X86DecodedInsn *decode); static void gen_ADC(DisasContext *s, X86DecodedInsn *decode) { MemOp ot = decode->op[1].ot; - TCGv c_in = tcg_temp_new(); + TCGv c_in; + /* + * Try to avoid CC_OP_ADC by transforming as follows: + * CC_ADC: src1 = dst + c_in, src2 = 0, src3 = c_in + * CC_ADD: src1 = dst + c_in, src2 = c_in (no src3) + * + * In general src2 vs. src3 matters when computing AF and OF, but not here: + * - AF is bit 4 of dst^src1^src2, which is bit 4 of dst^src1 in both cases + * - OF is a function of the two MSBs, and in both cases they are zero for src2 + */ + if (decode->e.op2 == X86_TYPE_I && decode->immediate == 0) { + gen_compute_eflags_c(s, s->T1); + gen_ADD(s, decode); + return; + } + + c_in = tcg_temp_new(); gen_compute_eflags_c(s, c_in); if (s->prefix & PREFIX_LOCK) { tcg_gen_add_tl(s->T0, c_in, s->T1); @@ -3830,22 +3847,64 @@ static void gen_SARX(DisasContext *s, X86DecodedInsn *decode) tcg_gen_sar_tl(s->T0, s->T0, s->T1); } +static void gen_SUB(DisasContext *s, X86DecodedInsn *decode); static void gen_SBB(DisasContext *s, X86DecodedInsn *decode) { MemOp ot = decode->op[0].ot; - TCGv c_in = tcg_temp_new(); + TCGv c_in; + /* + * Try to avoid CC_OP_SBB by transforming as follows: + * CC_SBB: src1 = dst + c_in, src2 = 0, src3 = c_in + * CC_SUB: src1 = dst + c_in, src2 = c_in (no src3) + * + * In general src2 vs. src3 matters when computing AF and OF, but not here: + * - AF is bit 4 of dst^src1^src2, which is bit 4 of dst^src1 in both cases + * - OF is a function of the two MSBs, and in both cases they are zero for src2 + */ + if (decode->e.op2 == X86_TYPE_I && decode->immediate == 0) { + gen_compute_eflags_c(s, s->T1); + gen_SUB(s, decode); + return; + } + + c_in = tcg_temp_new(); gen_compute_eflags_c(s, c_in); + + /* + * Here the change is as follows: + * CC_SBB: src1 = T0, src2 = T0, src3 = c_in + * CC_SUB: src1 = 0, src2 = c_in (no src3) + * + * The difference also does not matter: + * - AF is bit 4 of dst^src1^src2, but bit 4 of src1^src2 is zero in both cases + * therefore AF comes straight from dst (in fact it is c_in) + * - for OF, src1 and src2 have the same sign in both cases, meaning there + * can be no overflow + */ + if (decode->e.op2 != X86_TYPE_I && !decode->op[0].has_ea && decode->op[0].n == decode->op[2].n) { + if (s->cc_op == CC_OP_DYNAMIC) { + tcg_gen_neg_tl(s->T0, c_in); + } else { + /* + * Do not negate c_in because it will often be dead and only the + * instruction generated by negsetcond will survive. + */ + gen_neg_setcc(s, JCC_B << 1, s->T0); + } + tcg_gen_movi_tl(s->cc_srcT, 0); + decode->cc_src = c_in; + decode->cc_dst = s->T0; + decode->cc_op = CC_OP_SUBB + ot; + return; + } + if (s->prefix & PREFIX_LOCK) { tcg_gen_add_tl(s->T0, s->T1, c_in); tcg_gen_neg_tl(s->T0, s->T0); tcg_gen_atomic_add_fetch_tl(s->T0, s->A0, s->T0, s->mem_index, ot | MO_LE); } else { - /* - * TODO: SBB reg, reg could use gen_prepare_eflags_c followed by - * negsetcond, and CC_OP_SUBB as the cc_op. - */ tcg_gen_sub_tl(s->T0, s->T0, s->T1); tcg_gen_sub_tl(s->T0, s->T0, c_in); } diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a8935f487a..aee3342898 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1183,6 +1183,26 @@ static CCPrepare gen_prepare_cc(DisasContext *s, int b, TCGv reg) return cc; } +static void gen_neg_setcc(DisasContext *s, int b, TCGv reg) +{ + CCPrepare cc = gen_prepare_cc(s, b, reg); + + if (cc.no_setcond) { + if (cc.cond == TCG_COND_EQ) { + tcg_gen_addi_tl(reg, cc.reg, -1); + } else { + tcg_gen_neg_tl(reg, cc.reg); + } + return; + } + + if (cc.use_reg2) { + tcg_gen_negsetcond_tl(cc.cond, reg, cc.reg, cc.reg2); + } else { + tcg_gen_negsetcondi_tl(cc.cond, reg, cc.reg, cc.imm); + } +} + static void gen_setcc(DisasContext *s, int b, TCGv reg) { CCPrepare cc = gen_prepare_cc(s, b, reg); From ec6019f2308b5d27b4ee33497b06174e9f58b100 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Feb 2025 18:45:06 +0100 Subject: [PATCH 0012/2760] target/i386: tcg: remove tmp0 and tmp4 from SHLD/SHRD Apply some of the simplifications used for RCL and RCR. tmp4 is not used anywhere else, so remove it. Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 6 ++--- target/i386/tcg/translate.c | 51 +++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index f477a2da99..a41afb7fe4 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -4015,8 +4015,7 @@ static void gen_SHLD(DisasContext *s, X86DecodedInsn *decode) } decode->cc_dst = s->T0; - decode->cc_src = s->tmp0; - gen_shiftd_rm_T1(s, ot, false, count); + decode->cc_src = gen_shiftd_rm_T1(s, ot, false, count); if (can_be_zero) { gen_shift_dynamic_flags(s, decode, count, CC_OP_SHLB + ot); } else { @@ -4068,8 +4067,7 @@ static void gen_SHRD(DisasContext *s, X86DecodedInsn *decode) } decode->cc_dst = s->T0; - decode->cc_src = s->tmp0; - gen_shiftd_rm_T1(s, ot, true, count); + decode->cc_src = gen_shiftd_rm_T1(s, ot, true, count); if (can_be_zero) { gen_shift_dynamic_flags(s, decode, count, CC_OP_SARB + ot); } else { diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index aee3342898..5529327680 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -135,7 +135,6 @@ typedef struct DisasContext { /* TCG local register indexes (only used inside old micro ops) */ TCGv tmp0; - TCGv tmp4; TCGv_i32 tmp2_i32; TCGv_i32 tmp3_i32; TCGv_i64 tmp1_i64; @@ -1580,10 +1579,13 @@ static bool check_cpl0(DisasContext *s) } /* XXX: add faster immediate case */ -static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, +static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot, bool is_right, TCGv count) { target_ulong mask = (ot == MO_64 ? 63 : 31); + TCGv cc_src = tcg_temp_new(); + TCGv tmp = tcg_temp_new(); + TCGv hishift; switch (ot) { case MO_16: @@ -1591,9 +1593,9 @@ static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, This means "shrdw C, B, A" shifts A:B:A >> C. Build the B:A portion by constructing it as a 32-bit value. */ if (is_right) { - tcg_gen_deposit_tl(s->tmp0, s->T0, s->T1, 16, 16); + tcg_gen_deposit_tl(tmp, s->T0, s->T1, 16, 16); tcg_gen_mov_tl(s->T1, s->T0); - tcg_gen_mov_tl(s->T0, s->tmp0); + tcg_gen_mov_tl(s->T0, tmp); } else { tcg_gen_deposit_tl(s->T1, s->T0, s->T1, 16, 16); } @@ -1604,47 +1606,53 @@ static void gen_shiftd_rm_T1(DisasContext *s, MemOp ot, case MO_32: #ifdef TARGET_X86_64 /* Concatenate the two 32-bit values and use a 64-bit shift. */ - tcg_gen_subi_tl(s->tmp0, count, 1); + tcg_gen_subi_tl(tmp, count, 1); if (is_right) { tcg_gen_concat_tl_i64(s->T0, s->T0, s->T1); - tcg_gen_shr_i64(s->tmp0, s->T0, s->tmp0); + tcg_gen_shr_i64(cc_src, s->T0, tmp); tcg_gen_shr_i64(s->T0, s->T0, count); } else { tcg_gen_concat_tl_i64(s->T0, s->T1, s->T0); - tcg_gen_shl_i64(s->tmp0, s->T0, s->tmp0); + tcg_gen_shl_i64(cc_src, s->T0, tmp); tcg_gen_shl_i64(s->T0, s->T0, count); - tcg_gen_shri_i64(s->tmp0, s->tmp0, 32); + tcg_gen_shri_i64(cc_src, cc_src, 32); tcg_gen_shri_i64(s->T0, s->T0, 32); } break; #endif default: - tcg_gen_subi_tl(s->tmp0, count, 1); + hishift = tcg_temp_new(); + tcg_gen_subi_tl(tmp, count, 1); if (is_right) { - tcg_gen_shr_tl(s->tmp0, s->T0, s->tmp0); + tcg_gen_shr_tl(cc_src, s->T0, tmp); - tcg_gen_subfi_tl(s->tmp4, mask + 1, count); + /* mask + 1 - count = mask - tmp = mask ^ tmp */ + tcg_gen_xori_tl(hishift, tmp, mask); tcg_gen_shr_tl(s->T0, s->T0, count); - tcg_gen_shl_tl(s->T1, s->T1, s->tmp4); + tcg_gen_shl_tl(s->T1, s->T1, hishift); } else { - tcg_gen_shl_tl(s->tmp0, s->T0, s->tmp0); + tcg_gen_shl_tl(cc_src, s->T0, tmp); + if (ot == MO_16) { /* Only needed if count > 16, for Intel behaviour. */ - tcg_gen_subfi_tl(s->tmp4, 33, count); - tcg_gen_shr_tl(s->tmp4, s->T1, s->tmp4); - tcg_gen_or_tl(s->tmp0, s->tmp0, s->tmp4); + tcg_gen_subfi_tl(tmp, 33, count); + tcg_gen_shr_tl(tmp, s->T1, tmp); + tcg_gen_or_tl(cc_src, cc_src, tmp); } - tcg_gen_subfi_tl(s->tmp4, mask + 1, count); + /* mask + 1 - count = mask - tmp = mask ^ tmp */ + tcg_gen_xori_tl(hishift, tmp, mask); tcg_gen_shl_tl(s->T0, s->T0, count); - tcg_gen_shr_tl(s->T1, s->T1, s->tmp4); + tcg_gen_shr_tl(s->T1, s->T1, hishift); } - tcg_gen_movi_tl(s->tmp4, 0); - tcg_gen_movcond_tl(TCG_COND_EQ, s->T1, count, s->tmp4, - s->tmp4, s->T1); + tcg_gen_movcond_tl(TCG_COND_EQ, s->T1, + count, tcg_constant_tl(0), + tcg_constant_tl(0), s->T1); tcg_gen_or_tl(s->T0, s->T0, s->T1); break; } + + return cc_src; } #define X86_MAX_INSN_LENGTH 15 @@ -3768,7 +3776,6 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->tmp1_i64 = tcg_temp_new_i64(); dc->tmp2_i32 = tcg_temp_new_i32(); dc->tmp3_i32 = tcg_temp_new_i32(); - dc->tmp4 = tcg_temp_new(); dc->cc_srcT = tcg_temp_new(); } From a440975cc33b48316f26d4ba0f1714375ff47738 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Feb 2025 19:25:41 +0100 Subject: [PATCH 0013/2760] target/i386: tcg: remove subf from SHLD/SHRD expansion It is computing 33-count but 32-count had just been used, so just shift further by one. Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 5529327680..822dbb2e9a 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -1633,17 +1633,16 @@ static TCGv gen_shiftd_rm_T1(DisasContext *s, MemOp ot, } else { tcg_gen_shl_tl(cc_src, s->T0, tmp); - if (ot == MO_16) { - /* Only needed if count > 16, for Intel behaviour. */ - tcg_gen_subfi_tl(tmp, 33, count); - tcg_gen_shr_tl(tmp, s->T1, tmp); - tcg_gen_or_tl(cc_src, cc_src, tmp); - } - /* mask + 1 - count = mask - tmp = mask ^ tmp */ tcg_gen_xori_tl(hishift, tmp, mask); tcg_gen_shl_tl(s->T0, s->T0, count); tcg_gen_shr_tl(s->T1, s->T1, hishift); + + if (ot == MO_16) { + /* Only needed if count > 16, for Intel behaviour. */ + tcg_gen_shri_tl(tmp, s->T1, 1); + tcg_gen_or_tl(cc_src, cc_src, tmp); + } } tcg_gen_movcond_tl(TCG_COND_EQ, s->T1, count, tcg_constant_tl(0), From d387eb7fa989f3397d681111324f6a54c1b32484 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Feb 2025 19:30:20 +0100 Subject: [PATCH 0014/2760] target/i386: tcg: remove tmp0 Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 20 ++++++++++---------- target/i386/tcg/translate.c | 27 +++++++++++++++------------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index a41afb7fe4..bd24438230 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1710,22 +1710,22 @@ static void gen_CMPccXADD(DisasContext *s, X86DecodedInsn *decode) switch (jcc_op) { case JCC_O: /* (src1 ^ src2) & (src1 ^ dst). newv is only used here for a moment */ + cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(0); tcg_gen_xor_tl(newv, s->cc_srcT, s->T0); - tcg_gen_xor_tl(s->tmp0, s->cc_srcT, cmpv); - tcg_gen_and_tl(s->tmp0, s->tmp0, newv); - tcg_gen_sextract_tl(s->tmp0, s->tmp0, 0, 8 << ot); - cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0); + tcg_gen_xor_tl(cmp_lhs, s->cc_srcT, cmpv); + tcg_gen_and_tl(cmp_lhs, cmp_lhs, newv); + tcg_gen_sextract_tl(cmp_lhs, cmp_lhs, 0, 8 << ot); break; case JCC_P: - tcg_gen_ext8u_tl(s->tmp0, s->T0); - tcg_gen_ctpop_tl(s->tmp0, s->tmp0); - cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(1); + cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(1); + tcg_gen_ext8u_tl(cmp_lhs, s->T0); + tcg_gen_ctpop_tl(cmp_lhs, cmp_lhs); break; case JCC_S: - tcg_gen_sextract_tl(s->tmp0, s->T0, 0, 8 << ot); - cmp_lhs = s->tmp0, cmp_rhs = tcg_constant_tl(0); + cmp_lhs = tcg_temp_new(), cmp_rhs = tcg_constant_tl(0); + tcg_gen_sextract_tl(cmp_lhs, s->T0, 0, 8 << ot); break; default: @@ -1876,7 +1876,7 @@ static void gen_CMPXCHG8B(DisasContext *s, X86DecodedInsn *decode) s->mem_index, MO_TEUQ); } - /* Set tmp0 to match the required value of Z. */ + /* Compute the required value of Z. */ tcg_gen_setcond_i64(TCG_COND_EQ, cmp, old, cmp); Z = tcg_temp_new(); tcg_gen_trunc_i64_tl(Z, cmp); diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 822dbb2e9a..5d433f8522 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -134,7 +134,6 @@ typedef struct DisasContext { TCGv T1; /* TCG local register indexes (only used inside old micro ops) */ - TCGv tmp0; TCGv_i32 tmp2_i32; TCGv_i32 tmp3_i32; TCGv_i64 tmp1_i64; @@ -2175,14 +2174,17 @@ static void gen_enter(DisasContext *s, int esp_addend, int level) level &= 31; if (level != 0) { int i; + if (level > 1) { + TCGv fp = tcg_temp_new(); - /* Copy level-1 pointers from the previous frame. */ - for (i = 1; i < level; ++i) { - gen_lea_ss_ofs(s, s->A0, cpu_regs[R_EBP], -size * i); - gen_op_ld_v(s, d_ot, s->tmp0, s->A0); + /* Copy level-1 pointers from the previous frame. */ + for (i = 1; i < level; ++i) { + gen_lea_ss_ofs(s, s->A0, cpu_regs[R_EBP], -size * i); + gen_op_ld_v(s, d_ot, fp, s->A0); - gen_lea_ss_ofs(s, s->A0, s->T1, -size * i); - gen_op_st_v(s, d_ot, s->tmp0, s->A0); + gen_lea_ss_ofs(s, s->A0, s->T1, -size * i); + gen_op_st_v(s, d_ot, fp, s->A0); + } } /* Push the current FrameTemp as the last level. */ @@ -2405,10 +2407,11 @@ static void gen_ldy_env_A0(DisasContext *s, int offset, bool align) int mem_index = s->mem_index; TCGv_i128 t0 = tcg_temp_new_i128(); TCGv_i128 t1 = tcg_temp_new_i128(); + TCGv a0_hi = tcg_temp_new(); tcg_gen_qemu_ld_i128(t0, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0)); - tcg_gen_addi_tl(s->tmp0, s->A0, 16); - tcg_gen_qemu_ld_i128(t1, s->tmp0, mem_index, mop); + tcg_gen_addi_tl(a0_hi, s->A0, 16); + tcg_gen_qemu_ld_i128(t1, a0_hi, mem_index, mop); tcg_gen_st_i128(t0, tcg_env, offset + offsetof(YMMReg, YMM_X(0))); tcg_gen_st_i128(t1, tcg_env, offset + offsetof(YMMReg, YMM_X(1))); @@ -2419,12 +2422,13 @@ static void gen_sty_env_A0(DisasContext *s, int offset, bool align) MemOp mop = MO_128 | MO_LE | MO_ATOM_IFALIGN_PAIR; int mem_index = s->mem_index; TCGv_i128 t = tcg_temp_new_i128(); + TCGv a0_hi = tcg_temp_new(); tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(0))); tcg_gen_qemu_st_i128(t, s->A0, mem_index, mop | (align ? MO_ALIGN_32 : 0)); - tcg_gen_addi_tl(s->tmp0, s->A0, 16); + tcg_gen_addi_tl(a0_hi, s->A0, 16); tcg_gen_ld_i128(t, tcg_env, offset + offsetof(YMMReg, YMM_X(1))); - tcg_gen_qemu_st_i128(t, s->tmp0, mem_index, mop); + tcg_gen_qemu_st_i128(t, a0_hi, mem_index, mop); } #include "emit.c.inc" @@ -3771,7 +3775,6 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->T1 = tcg_temp_new(); dc->A0 = tcg_temp_new(); - dc->tmp0 = tcg_temp_new(); dc->tmp1_i64 = tcg_temp_new_i64(); dc->tmp2_i32 = tcg_temp_new_i32(); dc->tmp3_i32 = tcg_temp_new_i32(); From 9a688e70bdb2f23112afeddefd91bd45674d4db9 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Feb 2025 18:51:34 +0100 Subject: [PATCH 0015/2760] target/i386: tcg: remove some more uses of temporaries Remove all uses of 32-bit temporaries in emit.c.inc. Remove uses in translate.c outside the large multiplexed generator functions. tmp3_i32 is not used anymore and can go away. Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 83 +++++++++++++++++++++++-------------- target/i386/tcg/translate.c | 43 +++++++++++-------- 2 files changed, 77 insertions(+), 49 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index bd24438230..4e09e96fc1 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1916,9 +1916,10 @@ static void gen_CPUID(DisasContext *s, X86DecodedInsn *decode) static void gen_CRC32(DisasContext *s, X86DecodedInsn *decode) { MemOp ot = decode->op[2].ot; + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_crc32(s->T0, s->tmp2_i32, s->T1, tcg_constant_i32(8 << ot)); + tcg_gen_trunc_tl_i32(tmp, s->T0); + gen_helper_crc32(s->T0, tmp, s->T1, tcg_constant_i32(8 << ot)); } static void gen_CVTPI2Px(DisasContext *s, X86DecodedInsn *decode) @@ -2376,8 +2377,10 @@ static void gen_LAR(DisasContext *s, X86DecodedInsn *decode) static void gen_LDMXCSR(DisasContext *s, X86DecodedInsn *decode) { - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - gen_helper_ldmxcsr(tcg_env, s->tmp2_i32); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(tmp, s->T0); + gen_helper_ldmxcsr(tcg_env, tmp); } static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg) @@ -2590,11 +2593,13 @@ static void gen_MOVDQ(DisasContext *s, X86DecodedInsn *decode) static void gen_MOVMSK(DisasContext *s, X86DecodedInsn *decode) { typeof(gen_helper_movmskps_ymm) *ps, *pd, *fn; + TCGv_i32 tmp = tcg_temp_new_i32(); + ps = s->vex_l ? gen_helper_movmskps_ymm : gen_helper_movmskps_xmm; pd = s->vex_l ? gen_helper_movmskpd_ymm : gen_helper_movmskpd_xmm; fn = s->prefix & PREFIX_DATA ? pd : ps; - fn(s->tmp2_i32, tcg_env, OP_PTR2); - tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); + fn(tmp, tcg_env, OP_PTR2); + tcg_gen_extu_i32_tl(s->T0, tmp); } static void gen_MOVQ(DisasContext *s, X86DecodedInsn *decode) @@ -2691,13 +2696,17 @@ static void gen_MULX(DisasContext *s, X86DecodedInsn *decode) switch (ot) { case MO_32: #ifdef TARGET_X86_64 - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T1); - tcg_gen_mulu2_i32(s->tmp2_i32, s->tmp3_i32, - s->tmp2_i32, s->tmp3_i32); - tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], s->tmp2_i32); - tcg_gen_extu_i32_tl(s->T0, s->tmp3_i32); - break; + { + TCGv_i32 t0 = tcg_temp_new_i32(); + TCGv_i32 t1 = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(t0, s->T0); + tcg_gen_trunc_tl_i32(t1, s->T1); + tcg_gen_mulu2_i32(t0, t1, t0, t1); + tcg_gen_extu_i32_tl(cpu_regs[s->vex_v], t0); + tcg_gen_extu_i32_tl(s->T0, t1); + break; + } case MO_64: #endif @@ -3741,10 +3750,14 @@ static void gen_RORX(DisasContext *s, X86DecodedInsn *decode) switch (ot) { case MO_32: #ifdef TARGET_X86_64 - tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0); - tcg_gen_rotri_i32(s->tmp2_i32, s->tmp2_i32, b); - tcg_gen_extu_i32_tl(s->T0, s->tmp2_i32); - break; + { + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(tmp, s->T0); + tcg_gen_rotri_i32(tmp, tmp, b); + tcg_gen_extu_i32_tl(s->T0, tmp); + break; + } case MO_64: #endif @@ -4334,7 +4347,7 @@ static void gen_VCVTSI2Sx(DisasContext *s, X86DecodedInsn *decode) } return; } - in = s->tmp2_i32; + in = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(in, s->T1); #else in = s->T1; @@ -4364,7 +4377,7 @@ static inline void gen_VCVTtSx2SI(DisasContext *s, X86DecodedInsn *decode, return; } - out = s->tmp2_i32; + out = tcg_temp_new_i32(); #else out = s->T0; #endif @@ -4416,7 +4429,7 @@ static void gen_VEXTRACTPS(DisasContext *s, X86DecodedInsn *decode) gen_pextr(s, decode, MO_32); } -static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode) +static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode, TCGv_i32 tmp) { int val = decode->immediate; int dest_word = (val >> 4) & 3; @@ -4433,7 +4446,7 @@ static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode) } if (new_mask != (val & 15)) { - tcg_gen_st_i32(s->tmp2_i32, tcg_env, + tcg_gen_st_i32(tmp, tcg_env, vector_elem_offset(&decode->op[0], MO_32, dest_word)); } @@ -4452,15 +4465,19 @@ static void gen_vinsertps(DisasContext *s, X86DecodedInsn *decode) static void gen_VINSERTPS_r(DisasContext *s, X86DecodedInsn *decode) { int val = decode->immediate; - tcg_gen_ld_i32(s->tmp2_i32, tcg_env, + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_ld_i32(tmp, tcg_env, vector_elem_offset(&decode->op[2], MO_32, (val >> 6) & 3)); - gen_vinsertps(s, decode); + gen_vinsertps(s, decode, tmp); } static void gen_VINSERTPS_m(DisasContext *s, X86DecodedInsn *decode) { - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); - gen_vinsertps(s, decode); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_qemu_ld_i32(tmp, s->A0, s->mem_index, MO_LEUL); + gen_vinsertps(s, decode, tmp); } static void gen_VINSERTx128(DisasContext *s, X86DecodedInsn *decode) @@ -4581,25 +4598,29 @@ static void gen_VMOVSD_ld(DisasContext *s, X86DecodedInsn *decode) static void gen_VMOVSS(DisasContext *s, X86DecodedInsn *decode) { int vec_len = vector_len(s, decode); + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_ld_i32(tmp, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); tcg_gen_gvec_mov(MO_64, decode->op[0].offset, decode->op[1].offset, vec_len, vec_len); - tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_st_i32(tmp, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); } static void gen_VMOVSS_ld(DisasContext *s, X86DecodedInsn *decode) { int vec_len = vector_len(s, decode); + TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_qemu_ld_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); + tcg_gen_qemu_ld_i32(tmp, s->A0, s->mem_index, MO_LEUL); tcg_gen_gvec_dup_imm(MO_64, decode->op[0].offset, vec_len, vec_len, 0); - tcg_gen_st_i32(s->tmp2_i32, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_st_i32(tmp, OP_PTR0, offsetof(ZMMReg, ZMM_L(0))); } static void gen_VMOVSS_st(DisasContext *s, X86DecodedInsn *decode) { - tcg_gen_ld_i32(s->tmp2_i32, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); - tcg_gen_qemu_st_i32(s->tmp2_i32, s->A0, s->mem_index, MO_LEUL); + TCGv_i32 tmp = tcg_temp_new_i32(); + + tcg_gen_ld_i32(tmp, OP_PTR2, offsetof(ZMMReg, ZMM_L(0))); + tcg_gen_qemu_st_i32(tmp, s->A0, s->mem_index, MO_LEUL); } static void gen_VPMASKMOV_st(DisasContext *s, X86DecodedInsn *decode) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 5d433f8522..abe210cc4e 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -135,7 +135,6 @@ typedef struct DisasContext { /* TCG local register indexes (only used inside old micro ops) */ TCGv_i32 tmp2_i32; - TCGv_i32 tmp3_i32; TCGv_i64 tmp1_i64; sigjmp_buf jmpbuf; @@ -1318,30 +1317,35 @@ static void gen_bpt_io(DisasContext *s, TCGv_i32 t_port, int ot) static void gen_ins(DisasContext *s, MemOp ot, TCGv dshift) { + TCGv_i32 port = tcg_temp_new_i32(); + gen_string_movl_A0_EDI(s); /* Note: we must do this dummy write first to be restartable in case of page fault. */ tcg_gen_movi_tl(s->T0, 0); gen_op_st_v(s, ot, s->T0, s->A0); - tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); - tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff); - gen_helper_in_func(ot, s->T0, s->tmp2_i32); + tcg_gen_trunc_tl_i32(port, cpu_regs[R_EDX]); + tcg_gen_andi_i32(port, port, 0xffff); + gen_helper_in_func(ot, s->T0, port); gen_op_st_v(s, ot, s->T0, s->A0); gen_op_add_reg(s, s->aflag, R_EDI, dshift); - gen_bpt_io(s, s->tmp2_i32, ot); + gen_bpt_io(s, port, ot); } static void gen_outs(DisasContext *s, MemOp ot, TCGv dshift) { + TCGv_i32 port = tcg_temp_new_i32(); + TCGv_i32 value = tcg_temp_new_i32(); + gen_string_movl_A0_ESI(s); gen_op_ld_v(s, ot, s->T0, s->A0); - tcg_gen_trunc_tl_i32(s->tmp2_i32, cpu_regs[R_EDX]); - tcg_gen_andi_i32(s->tmp2_i32, s->tmp2_i32, 0xffff); - tcg_gen_trunc_tl_i32(s->tmp3_i32, s->T0); - gen_helper_out_func(ot, s->tmp2_i32, s->tmp3_i32); + tcg_gen_trunc_tl_i32(port, cpu_regs[R_EDX]); + tcg_gen_andi_i32(port, port, 0xffff); + tcg_gen_trunc_tl_i32(value, s->T0); + gen_helper_out_func(ot, port, value); gen_op_add_reg(s, s->aflag, R_ESI, dshift); - gen_bpt_io(s, s->tmp2_i32, ot); + gen_bpt_io(s, port, ot); } #define REP_MAX 65535 @@ -1869,14 +1873,16 @@ static void gen_bndck(DisasContext *s, X86DecodedInsn *decode, TCGCond cond, TCGv_i64 bndv) { TCGv ea = gen_lea_modrm_1(s, decode->mem, false); + TCGv_i32 t32 = tcg_temp_new_i32(); + TCGv_i64 t64 = tcg_temp_new_i64(); - tcg_gen_extu_tl_i64(s->tmp1_i64, ea); + tcg_gen_extu_tl_i64(t64, ea); if (!CODE64(s)) { - tcg_gen_ext32u_i64(s->tmp1_i64, s->tmp1_i64); + tcg_gen_ext32u_i64(t64, t64); } - tcg_gen_setcond_i64(cond, s->tmp1_i64, s->tmp1_i64, bndv); - tcg_gen_extrl_i64_i32(s->tmp2_i32, s->tmp1_i64); - gen_helper_bndck(tcg_env, s->tmp2_i32); + tcg_gen_setcond_i64(cond, t64, t64, bndv); + tcg_gen_extrl_i64_i32(t32, t64); + gen_helper_bndck(tcg_env, t32); } /* generate modrm load of memory or register. */ @@ -2021,8 +2027,10 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg) static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src) { if (PE(s) && !VM86(s)) { - tcg_gen_trunc_tl_i32(s->tmp2_i32, src); - gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), s->tmp2_i32); + TCGv_i32 sel = tcg_temp_new_i32(); + + tcg_gen_trunc_tl_i32(sel, src); + gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel); /* abort translation because the addseg value may change or because ss32 may change. For R_SS, translation must always stop as a special handling must be done to disable hardware @@ -3777,7 +3785,6 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu) dc->tmp1_i64 = tcg_temp_new_i64(); dc->tmp2_i32 = tcg_temp_new_i32(); - dc->tmp3_i32 = tcg_temp_new_i32(); dc->cc_srcT = tcg_temp_new(); } From 3fec86e95cd44ac7db639686ef1dda143af59aea Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 3 Apr 2025 14:06:37 +0200 Subject: [PATCH 0016/2760] target/i386: tcg: simplify computation of AF after INC/DEC No difference in generated code, but the XOR-based formula is easily understood on its own. This will make more sense once ADD/SUB stop using dst^src1^src2 to compute AF. Signed-off-by: Paolo Bonzini --- target/i386/tcg/cc_helper_template.h.inc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/i386/tcg/cc_helper_template.h.inc b/target/i386/tcg/cc_helper_template.h.inc index 9aff16b880..b821e5bca3 100644 --- a/target/i386/tcg/cc_helper_template.h.inc +++ b/target/i386/tcg/cc_helper_template.h.inc @@ -175,13 +175,10 @@ static uint32_t glue(compute_all_logic, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) static uint32_t glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { uint32_t cf, pf, af, zf, sf, of; - DATA_TYPE src2; cf = src1; - src1 = dst - 1; - src2 = 1; pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & CC_A; + af = (dst ^ (dst - 1)) & CC_A; /* bits 0..3 are all clear */ zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; of = (dst == SIGN_MASK) * CC_O; @@ -191,13 +188,10 @@ static uint32_t glue(compute_all_inc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) static uint32_t glue(compute_all_dec, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) { uint32_t cf, pf, af, zf, sf, of; - DATA_TYPE src2; cf = src1; - src1 = dst + 1; - src2 = 1; pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & CC_A; + af = (dst ^ (dst + 1)) & CC_A; /* bits 0..3 are all set */ zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; of = (dst == SIGN_MASK - 1) * CC_O; From 767149d3d078356073a32238b313cee9d02db5d8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 20 Mar 2025 14:55:42 +0100 Subject: [PATCH 0017/2760] target/i386: emulate: microoptimize and explain ADD_COUT_VEC/SUB_COUT_VEC The logic is the same, but the majority(NOT a, b, c) is brought out to a separate macro and implemented without NOT operations. Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_flags.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index fedc70a1b8..60ab4f01a2 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -45,14 +45,30 @@ #define LF_MASK_CF (0x01 << LF_BIT_CF) #define LF_MASK_PO (0x01 << LF_BIT_PO) +/* majority(NOT a, b, c) = (a ^ b) ? b : c */ +#define MAJ_INV1(a, b, c) ((((a) ^ (b)) & ((b) ^ (c))) ^ (c)) + +/* + * ADD_COUT_VEC(x, y) = majority((x + y) ^ x ^ y, x, y) + * + * If two corresponding bits in x and y are the same, that's the carry + * independent of the value (x+y)^x^y. Hence x^y can be replaced with + * 1 in (x+y)^x^y, resulting in majority(NOT (x+y), x, y) + */ #define ADD_COUT_VEC(op1, op2, result) \ - (((op1) & (op2)) | (((op1) | (op2)) & (~(result)))) + MAJ_INV1(result, op1, op2) +/* + * SUB_COUT_VEC(x, y) = NOT majority(x, NOT y, (x - y) ^ x ^ NOT y) + * = majority(NOT x, y, (x - y) ^ x ^ y) + * + * Note that the carry out is actually a borrow, i.e. it is inverted. + * If two corresponding bits in x and y are different, the value of the + * bit in (x-y)^x^y likewise does not matter. Hence, x^y can be replaced + * with 0 in (x-y)^x^y, resulting in majority(NOT x, y, x-y) + */ #define SUB_COUT_VEC(op1, op2, result) \ - (((~(op1)) & (op2)) | (((~(op1)) ^ (op2)) & (result))) - -#define GET_ADD_OVERFLOW(op1, op2, result, mask) \ - ((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) + MAJ_INV1(op1, op2, result) /* ******************* */ /* OSZAPC */ From 5dcdbd071253e249a76c7771bcf78eca3763a131 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 3 Apr 2025 18:20:06 +0200 Subject: [PATCH 0018/2760] target/i386: tcg: use cout to commonize add/adc/sub/sbb cases Use the carry-out vector as the basis to compute AF, CF and OF. The cost is pretty much the same, because the carry-out is just four boolean operations, and the code is much smaller because add/adc/sub/sbb now share most of it. A similar algorithm to what is used in target/i386/emulate can also be used for APX, in order to build the result of CCMP/CTEST with a new CC_OP_*. CCMP needs to place into the flags from either a subtraction or a constant value; CTEST likewise place into the flags either an AND or a constant value. The new CC_OP for CCMP and CTEST would store for a successful predcate: - in DST and SRC2, the result of the operation; - in SRC, a carry-out vector for CCMP or zero for CTEST; If the default flag value is used, DST/SRC/SRC2 can be filled with constants: - in DST the negated ZF; - in SRC's top 2 bits, a value that results in the desired OF and CF; - in SRC2 a suitable value (any of 0/1/~0/~1) that can be used instead of DST to compute the desired SF and PF. Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 25 ++++++++ target/i386/hvf/x86_flags.c | 25 -------- target/i386/tcg/cc_helper_template.h.inc | 80 ++++++++---------------- 3 files changed, 52 insertions(+), 78 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 76f24446a5..7a8d695bdb 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2843,4 +2843,29 @@ static inline bool ctl_has_irq(CPUX86State *env) # define TARGET_VSYSCALL_PAGE (UINT64_C(-10) << 20) #endif +/* majority(NOT a, b, c) = (a ^ b) ? b : c */ +#define MAJ_INV1(a, b, c) ((((a) ^ (b)) & ((b) ^ (c))) ^ (c)) + +/* + * ADD_COUT_VEC(x, y) = majority((x + y) ^ x ^ y, x, y) + * + * If two corresponding bits in x and y are the same, that's the carry + * independent of the value (x+y)^x^y. Hence x^y can be replaced with + * 1 in (x+y)^x^y, resulting in majority(NOT (x+y), x, y) + */ +#define ADD_COUT_VEC(op1, op2, result) \ + MAJ_INV1(result, op1, op2) + +/* + * SUB_COUT_VEC(x, y) = NOT majority(x, NOT y, (x - y) ^ x ^ NOT y) + * = majority(NOT x, y, (x - y) ^ x ^ y) + * + * Note that the carry out is actually a borrow, i.e. it is inverted. + * If two corresponding bits in x and y are different, the value of the + * bit in (x-y)^x^y likewise does not matter. Hence, x^y can be replaced + * with 0 in (x-y)^x^y, resulting in majority(NOT x, y, x-y) + */ +#define SUB_COUT_VEC(op1, op2, result) \ + MAJ_INV1(op1, op2, result) + #endif /* I386_CPU_H */ diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index 60ab4f01a2..0c75e0419c 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -45,31 +45,6 @@ #define LF_MASK_CF (0x01 << LF_BIT_CF) #define LF_MASK_PO (0x01 << LF_BIT_PO) -/* majority(NOT a, b, c) = (a ^ b) ? b : c */ -#define MAJ_INV1(a, b, c) ((((a) ^ (b)) & ((b) ^ (c))) ^ (c)) - -/* - * ADD_COUT_VEC(x, y) = majority((x + y) ^ x ^ y, x, y) - * - * If two corresponding bits in x and y are the same, that's the carry - * independent of the value (x+y)^x^y. Hence x^y can be replaced with - * 1 in (x+y)^x^y, resulting in majority(NOT (x+y), x, y) - */ -#define ADD_COUT_VEC(op1, op2, result) \ - MAJ_INV1(result, op1, op2) - -/* - * SUB_COUT_VEC(x, y) = NOT majority(x, NOT y, (x - y) ^ x ^ NOT y) - * = majority(NOT x, y, (x - y) ^ x ^ y) - * - * Note that the carry out is actually a borrow, i.e. it is inverted. - * If two corresponding bits in x and y are different, the value of the - * bit in (x-y)^x^y likewise does not matter. Hence, x^y can be replaced - * with 0 in (x-y)^x^y, resulting in majority(NOT x, y, x-y) - */ -#define SUB_COUT_VEC(op1, op2, result) \ - MAJ_INV1(op1, op2, result) - /* ******************* */ /* OSZAPC */ /* ******************* */ diff --git a/target/i386/tcg/cc_helper_template.h.inc b/target/i386/tcg/cc_helper_template.h.inc index b821e5bca3..d8fd976ca1 100644 --- a/target/i386/tcg/cc_helper_template.h.inc +++ b/target/i386/tcg/cc_helper_template.h.inc @@ -44,18 +44,32 @@ /* dynamic flags computation */ -static uint32_t glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +static uint32_t glue(compute_all_cout, SUFFIX)(DATA_TYPE dst, DATA_TYPE carries) { - uint32_t cf, pf, af, zf, sf, of; - DATA_TYPE src2 = dst - src1; + uint32_t af_cf, pf, zf, sf, of; - cf = dst < src1; + /* PF, ZF, SF computed from result. */ pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & CC_A; zf = (dst == 0) * CC_Z; sf = lshift(dst, 8 - DATA_BITS) & CC_S; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; - return cf + pf + af + zf + sf + of; + + /* + * AF, CF, OF computed from carry out vector. To compute AF and CF, rotate it + * left by one so cout(DATA_BITS - 1) is in bit 0 and cout(3) in bit 4. + * + * To compute OF, place the highest two carry bits into OF and the bit + * immediately to the right of it; then, adding CC_O / 2 XORs them. + */ + af_cf = ((carries << 1) | (carries >> (DATA_BITS - 1))) & (CC_A | CC_C); + of = (lshift(carries, 12 - DATA_BITS) + CC_O / 2) & CC_O; + return pf + zf + sf + af_cf + of; +} + +static uint32_t glue(compute_all_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) +{ + DATA_TYPE src2 = dst - src1; + DATA_TYPE carries = ADD_COUT_VEC(src1, src2, dst); + return glue(compute_all_cout, SUFFIX)(dst, carries); } static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) @@ -66,25 +80,9 @@ static int glue(compute_c_add, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) static uint32_t glue(compute_all_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, DATA_TYPE src3) { - uint32_t cf, pf, af, zf, sf, of; - -#ifdef WIDER_TYPE - WIDER_TYPE src13 = (WIDER_TYPE) src1 + (WIDER_TYPE) src3; - DATA_TYPE src2 = dst - src13; - - cf = dst < src13; -#else DATA_TYPE src2 = dst - src1 - src3; - - cf = (src3 ? dst <= src1 : dst < src1); -#endif - - pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & 0x10; - zf = (dst == 0) << 6; - sf = lshift(dst, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2 ^ -1) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; - return cf + pf + af + zf + sf + of; + DATA_TYPE carries = ADD_COUT_VEC(src1, src2, dst); + return glue(compute_all_cout, SUFFIX)(dst, carries); } static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, @@ -101,16 +99,9 @@ static int glue(compute_c_adc, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1, static uint32_t glue(compute_all_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) { - uint32_t cf, pf, af, zf, sf, of; DATA_TYPE src1 = dst + src2; - - cf = src1 < src2; - pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & CC_A; - zf = (dst == 0) * CC_Z; - sf = lshift(dst, 8 - DATA_BITS) & CC_S; - of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; - return cf + pf + af + zf + sf + of; + DATA_TYPE carries = SUB_COUT_VEC(src1, src2, dst); + return glue(compute_all_cout, SUFFIX)(dst, carries); } static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) @@ -123,25 +114,9 @@ static int glue(compute_c_sub, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2) static uint32_t glue(compute_all_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, DATA_TYPE src3) { - uint32_t cf, pf, af, zf, sf, of; - -#ifdef WIDER_TYPE - WIDER_TYPE src23 = (WIDER_TYPE) src2 + (WIDER_TYPE) src3; - DATA_TYPE src1 = dst + src23; - - cf = src1 < src23; -#else DATA_TYPE src1 = dst + src2 + src3; - - cf = (src3 ? src1 <= src2 : src1 < src2); -#endif - - pf = compute_pf(dst); - af = (dst ^ src1 ^ src2) & 0x10; - zf = (dst == 0) << 6; - sf = lshift(dst, 8 - DATA_BITS) & 0x80; - of = lshift((src1 ^ src2) & (src1 ^ dst), 12 - DATA_BITS) & CC_O; - return cf + pf + af + zf + sf + of; + DATA_TYPE carries = SUB_COUT_VEC(src1, src2, dst); + return glue(compute_all_cout, SUFFIX)(dst, carries); } static int glue(compute_c_sbb, SUFFIX)(DATA_TYPE dst, DATA_TYPE src2, @@ -286,6 +261,5 @@ static int glue(compute_c_blsi, SUFFIX)(DATA_TYPE dst, DATA_TYPE src1) #undef DATA_BITS #undef SIGN_MASK #undef DATA_TYPE -#undef DATA_MASK #undef SUFFIX #undef WIDER_TYPE From 26a44d9d2d4296701ceebc1085ab28171a1e7e3b Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:12 -0800 Subject: [PATCH 0019/2760] target/i386/hvf: introduce x86_emul_ops This will be used to remove HVF specific code from the instruction emulator. For now we only introduce two hooks for x86_decode.c. More hooks will be added when the code is refactored. The emulator initialization function now takes in a pointer to the ops structure. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-2-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 20 +++++++++++++++++++- target/i386/hvf/x86_emu.c | 5 ++++- target/i386/hvf/x86_emu.h | 10 +++++++++- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 9ba0e04ac7..03456ffbc7 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -229,6 +229,24 @@ hv_return_t hvf_arch_vm_create(MachineState *ms, uint32_t pa_range) return hv_vm_create(HV_VM_DEFAULT); } +static void hvf_read_segment_descriptor(CPUState *s, struct x86_segment_descriptor *desc, + X86Seg seg) +{ + struct vmx_segment vmx_segment; + vmx_read_segment_descriptor(s, &vmx_segment, seg); + vmx_segment_to_x86_descriptor(s, &vmx_segment, desc); +} + +static void hvf_read_mem(CPUState *cpu, void *data, target_ulong gva, int bytes) +{ + vmx_read_mem(cpu, data, gva, bytes); +} + +static const struct x86_emul_ops hvf_x86_emul_ops = { + .read_mem = hvf_read_mem, + .read_segment_descriptor = hvf_read_segment_descriptor, +}; + int hvf_arch_init_vcpu(CPUState *cpu) { X86CPU *x86cpu = X86_CPU(cpu); @@ -237,7 +255,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) int r; uint64_t reqCap; - init_emu(); + init_emu(&hvf_x86_emul_ops); init_decoder(); if (hvf_state->hvf_caps == NULL) { diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index ebba80a36b..c15b5a7ca8 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -1231,6 +1231,8 @@ static struct cmd_handler { static struct cmd_handler _cmd_handler[X86_DECODE_CMD_LAST]; +const struct x86_emul_ops *emul_ops; + static void init_cmd_handler(void) { int i; @@ -1253,7 +1255,8 @@ bool exec_instruction(CPUX86State *env, struct x86_decode *ins) return true; } -void init_emu(void) +void init_emu(const struct x86_emul_ops *o) { + emul_ops = o; init_cmd_handler(); } diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index bc0fc72c76..1422d06ea1 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -23,7 +23,15 @@ #include "x86_decode.h" #include "cpu.h" -void init_emu(void); +struct x86_emul_ops { + void (*read_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes); + void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc, + enum X86Seg seg); +}; + +extern const struct x86_emul_ops *emul_ops; + +void init_emu(const struct x86_emul_ops *ops); bool exec_instruction(CPUX86State *env, struct x86_decode *ins); void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_code); From 0860abbe849e7345fee28c08fa200f7cc315f175 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:13 -0800 Subject: [PATCH 0020/2760] target/i386/hvf: remove HVF specific calls from x86_decode.c Use the newly defined emul_ops. This allows the module to be reused by other accelerator in the future. No functional change intended. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-3-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_decode.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 5fea2dd3cc..728e159638 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -21,6 +21,7 @@ #include "panic.h" #include "x86_decode.h" #include "vmx.h" +#include "x86_emu.h" #include "x86_mmu.h" #include "x86_descr.h" @@ -74,7 +75,7 @@ static inline uint64_t decode_bytes(CPUX86State *env, struct x86_decode *decode, break; } target_ulong va = linear_rip(env_cpu(env), env->eip) + decode->len; - vmx_read_mem(env_cpu(env), &val, va, size); + emul_ops->read_mem(env_cpu(env), &val, va, size); decode->len += size; return val; @@ -1893,16 +1894,6 @@ static void decode_prefix(CPUX86State *env, struct x86_decode *decode) } } -static struct x86_segment_descriptor get_cs_descriptor(CPUState *s) -{ - struct vmx_segment vmx_cs; - x86_segment_descriptor cs; - vmx_read_segment_descriptor(s, &vmx_cs, R_CS); - vmx_segment_to_x86_descriptor(s, &vmx_cs, &cs); - - return cs; -} - void set_addressing_size(CPUX86State *env, struct x86_decode *decode) { decode->addressing_size = -1; @@ -1914,7 +1905,8 @@ void set_addressing_size(CPUX86State *env, struct x86_decode *decode) } } else if (!x86_is_long_mode(env_cpu(env))) { /* protected */ - x86_segment_descriptor cs = get_cs_descriptor(env_cpu(env)); + x86_segment_descriptor cs; + emul_ops->read_segment_descriptor(env_cpu(env), &cs, R_CS); /* check db */ if (cs.db) { if (decode->addr_size_override) { @@ -1950,7 +1942,8 @@ void set_operand_size(CPUX86State *env, struct x86_decode *decode) } } else if (!x86_is_long_mode(env_cpu(env))) { /* protected */ - x86_segment_descriptor cs = get_cs_descriptor(env_cpu(env)); + x86_segment_descriptor cs; + emul_ops->read_segment_descriptor(env_cpu(env), &cs, R_CS); /* check db */ if (cs.db) { if (decode->op_size_override) { From 444bae08bbdae175b14cc96a11af8640eb262963 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:14 -0800 Subject: [PATCH 0021/2760] target/i386/hvf: provide and use handle_io in emul_ops This drops the calls to hvf_handle_io from x86_emu.c. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-4-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 1 + target/i386/hvf/x86_emu.c | 29 +++++++++++++++-------------- target/i386/hvf/x86_emu.h | 2 ++ 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 03456ffbc7..7da03f9c08 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -245,6 +245,7 @@ static void hvf_read_mem(CPUState *cpu, void *data, target_ulong gva, int bytes) static const struct x86_emul_ops hvf_x86_emul_ops = { .read_mem = hvf_read_mem, .read_segment_descriptor = hvf_read_segment_descriptor, + .handle_io = hvf_handle_io, }; int hvf_arch_init_vcpu(CPUState *cpu) diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index c15b5a7ca8..7b01ccde5d 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -396,18 +396,18 @@ static void exec_out(CPUX86State *env, struct x86_decode *decode) { switch (decode->opcode[0]) { case 0xe6: - hvf_handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1); + emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 1, 1, 1); break; case 0xe7: - hvf_handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1, - decode->operand_size, 1); + emul_ops->handle_io(env_cpu(env), decode->op[0].val, &RAX(env), 1, + decode->operand_size, 1); break; case 0xee: - hvf_handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1); + emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 1, 1, 1); break; case 0xef: - hvf_handle_io(env_cpu(env), DX(env), &RAX(env), 1, - decode->operand_size, 1); + emul_ops->handle_io(env_cpu(env), DX(env), &RAX(env), 1, + decode->operand_size, 1); break; default: VM_PANIC("Bad out opcode\n"); @@ -421,10 +421,10 @@ static void exec_in(CPUX86State *env, struct x86_decode *decode) target_ulong val = 0; switch (decode->opcode[0]) { case 0xe4: - hvf_handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1); + emul_ops->handle_io(env_cpu(env), decode->op[0].val, &AL(env), 0, 1, 1); break; case 0xe5: - hvf_handle_io(env_cpu(env), decode->op[0].val, &val, 0, + emul_ops->handle_io(env_cpu(env), decode->op[0].val, &val, 0, decode->operand_size, 1); if (decode->operand_size == 2) { AX(env) = val; @@ -433,10 +433,11 @@ static void exec_in(CPUX86State *env, struct x86_decode *decode) } break; case 0xec: - hvf_handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1); + emul_ops->handle_io(env_cpu(env), DX(env), &AL(env), 0, 1, 1); break; case 0xed: - hvf_handle_io(env_cpu(env), DX(env), &val, 0, decode->operand_size, 1); + emul_ops->handle_io(env_cpu(env), DX(env), &val, 0, + decode->operand_size, 1); if (decode->operand_size == 2) { AX(env) = val; } else { @@ -486,8 +487,8 @@ static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); - hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 0, - decode->operand_size, 1); + emul_ops->handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 0, + decode->operand_size, 1); vmx_write_mem(env_cpu(env), addr, env->hvf_mmio_buf, decode->operand_size); @@ -511,8 +512,8 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, addr, decode->operand_size); - hvf_handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 1, - decode->operand_size, 1); + emul_ops->handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 1, + decode->operand_size, 1); string_increment_reg(env, R_ESI, decode); } diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index 1422d06ea1..40cc786694 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -27,6 +27,8 @@ struct x86_emul_ops { void (*read_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes); void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc, enum X86Seg seg); + void (*handle_io)(CPUState *cpu, uint16_t port, void *data, int direction, + int size, int count); }; extern const struct x86_emul_ops *emul_ops; From e9c40026b641da21c96c877153cbe08706b2aac9 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:15 -0800 Subject: [PATCH 0022/2760] target/i386: rename hvf_mmio_buf to emu_mmio_buf We want to refactor HVF's instruction emulator to a common component. Renaming hvf_mmio_buf removes the association between HVF and the instruction emulator. The definition of the field is still guarded by CONFIG_HVF for now, since it is the only user. No functional change. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-5-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 2 +- target/i386/hvf/hvf.c | 4 ++-- target/i386/hvf/x86_emu.c | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7a8d695bdb..3c5c39ce3d 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2109,7 +2109,7 @@ typedef struct CPUArchState { #endif #if defined(CONFIG_HVF) HVFX86LazyFlags hvf_lflags; - void *hvf_mmio_buf; + void *emu_mmio_buf; #endif uint64_t mcg_cap; diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 7da03f9c08..1cecb76595 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -168,7 +168,7 @@ void hvf_arch_vcpu_destroy(CPUState *cpu) X86CPU *x86_cpu = X86_CPU(cpu); CPUX86State *env = &x86_cpu->env; - g_free(env->hvf_mmio_buf); + g_free(env->emu_mmio_buf); } static void init_tsc_freq(CPUX86State *env) @@ -262,7 +262,7 @@ int hvf_arch_init_vcpu(CPUState *cpu) if (hvf_state->hvf_caps == NULL) { hvf_state->hvf_caps = g_new0(struct hvf_vcpu_caps, 1); } - env->hvf_mmio_buf = g_new(char, 4096); + env->emu_mmio_buf = g_new(char, 4096); if (x86cpu->vmware_cpuid_freq) { init_tsc_freq(env); diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 7b01ccde5d..e59a73e00d 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -184,8 +184,8 @@ void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int siz uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) { - vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, ptr, bytes); - return env->hvf_mmio_buf; + vmx_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); + return env->emu_mmio_buf; } @@ -487,9 +487,9 @@ static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) target_ulong addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); - emul_ops->handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 0, + emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0, decode->operand_size, 1); - vmx_write_mem(env_cpu(env), addr, env->hvf_mmio_buf, + vmx_write_mem(env_cpu(env), addr, env->emu_mmio_buf, decode->operand_size); string_increment_reg(env, R_EDI, decode); @@ -510,9 +510,9 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); - vmx_read_mem(env_cpu(env), env->hvf_mmio_buf, addr, + vmx_read_mem(env_cpu(env), env->emu_mmio_buf, addr, decode->operand_size); - emul_ops->handle_io(env_cpu(env), DX(env), env->hvf_mmio_buf, 1, + emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 1, decode->operand_size, 1); string_increment_reg(env, R_ESI, decode); From ae3c6134ecb4c7d3ba1c6bae3ff5b5dd6cf05d56 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:16 -0800 Subject: [PATCH 0023/2760] target/i386/hvf: use emul_ops->read_mem in x86_emu.c No functional change. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-6-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_emu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index e59a73e00d..7b816b5a1d 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -184,7 +184,7 @@ void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int siz uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) { - vmx_read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); + emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, ptr, bytes); return env->emu_mmio_buf; } @@ -510,8 +510,8 @@ static void exec_outs_single(CPUX86State *env, struct x86_decode *decode) { target_ulong addr = decode_linear_addr(env, decode, RSI(env), R_DS); - vmx_read_mem(env_cpu(env), env->emu_mmio_buf, addr, - decode->operand_size); + emul_ops->read_mem(env_cpu(env), env->emu_mmio_buf, addr, + decode->operand_size); emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 1, decode->operand_size, 1); @@ -620,7 +620,7 @@ static void exec_scas_single(CPUX86State *env, struct x86_decode *decode) addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); decode->op[1].type = X86_VAR_IMMEDIATE; - vmx_read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size); + emul_ops->read_mem(env_cpu(env), &decode->op[1].val, addr, decode->operand_size); EXEC_2OP_FLAGS_CMD(env, decode, -, SET_FLAGS_OSZAPC_SUB, false); string_increment_reg(env, R_EDI, decode); @@ -645,7 +645,7 @@ static void exec_lods_single(CPUX86State *env, struct x86_decode *decode) target_ulong val = 0; addr = decode_linear_addr(env, decode, RSI(env), R_DS); - vmx_read_mem(env_cpu(env), &val, addr, decode->operand_size); + emul_ops->read_mem(env_cpu(env), &val, addr, decode->operand_size); write_reg(env, R_EAX, val, decode->operand_size); string_increment_reg(env, R_ESI, decode); From 63d8bc669302ec22bd394c45380848a2d5947943 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:17 -0800 Subject: [PATCH 0024/2760] target/i386/hvf: provide and use write_mem in emul_ops Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-7-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 6 ++++++ target/i386/hvf/x86_emu.c | 8 ++++---- target/i386/hvf/x86_emu.h | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 1cecb76595..e4f48a79fb 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -242,8 +242,14 @@ static void hvf_read_mem(CPUState *cpu, void *data, target_ulong gva, int bytes) vmx_read_mem(cpu, data, gva, bytes); } +static void hvf_write_mem(CPUState *cpu, void *data, target_ulong gva, int bytes) +{ + vmx_write_mem(cpu, gva, data, bytes); +} + static const struct x86_emul_ops hvf_x86_emul_ops = { .read_mem = hvf_read_mem, + .write_mem = hvf_write_mem, .read_segment_descriptor = hvf_read_segment_descriptor, .handle_io = hvf_handle_io, }; diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 7b816b5a1d..3ff41c35d8 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -179,7 +179,7 @@ void write_val_ext(CPUX86State *env, target_ulong ptr, target_ulong val, int siz write_val_to_reg(ptr, val, size); return; } - vmx_write_mem(env_cpu(env), ptr, &val, size); + emul_ops->write_mem(env_cpu(env), &val, ptr, size); } uint8_t *read_mmio(CPUX86State *env, target_ulong ptr, int bytes) @@ -489,8 +489,8 @@ static void exec_ins_single(CPUX86State *env, struct x86_decode *decode) emul_ops->handle_io(env_cpu(env), DX(env), env->emu_mmio_buf, 0, decode->operand_size, 1); - vmx_write_mem(env_cpu(env), addr, env->emu_mmio_buf, - decode->operand_size); + emul_ops->write_mem(env_cpu(env), env->emu_mmio_buf, addr, + decode->operand_size); string_increment_reg(env, R_EDI, decode); } @@ -596,7 +596,7 @@ static void exec_stos_single(CPUX86State *env, struct x86_decode *decode) addr = linear_addr_size(env_cpu(env), RDI(env), decode->addressing_size, R_ES); val = read_reg(env, R_EAX, decode->operand_size); - vmx_write_mem(env_cpu(env), addr, &val, decode->operand_size); + emul_ops->write_mem(env_cpu(env), &val, addr, decode->operand_size); string_increment_reg(env, R_EDI, decode); } diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index 40cc786694..107c1f1ac8 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -25,6 +25,7 @@ struct x86_emul_ops { void (*read_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes); + void (*write_mem)(CPUState *cpu, void *data, target_ulong addr, int bytes); void (*read_segment_descriptor)(CPUState *cpu, struct x86_segment_descriptor *desc, enum X86Seg seg); void (*handle_io)(CPUState *cpu, uint16_t port, void *data, int direction, From 585678640c778ee35a86638eacb22372bda70ee1 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:18 -0800 Subject: [PATCH 0025/2760] target/i386/hvf: provide and use simulate_{wrmsr, rdmsr} in emul_ops Change the first argument's type to be CPUState to match other hooks. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-8-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf-i386.h | 4 ++-- target/i386/hvf/hvf.c | 18 ++++++++++-------- target/i386/hvf/x86_emu.c | 4 ++-- target/i386/hvf/x86_emu.h | 2 ++ 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/target/i386/hvf/hvf-i386.h b/target/i386/hvf/hvf-i386.h index 044ad236ae..8c42ae6b01 100644 --- a/target/i386/hvf/hvf-i386.h +++ b/target/i386/hvf/hvf-i386.h @@ -19,8 +19,8 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, int reg); void hvf_handle_io(CPUState *, uint16_t, void *, int, int, int); -void hvf_simulate_rdmsr(CPUX86State *env); -void hvf_simulate_wrmsr(CPUX86State *env); +void hvf_simulate_rdmsr(CPUState *cpu); +void hvf_simulate_wrmsr(CPUState *cpu); /* Host specific functions */ int hvf_inject_interrupt(CPUArchState *env, int vector); diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index e4f48a79fb..8c31d2e0cf 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -252,6 +252,8 @@ static const struct x86_emul_ops hvf_x86_emul_ops = { .write_mem = hvf_write_mem, .read_segment_descriptor = hvf_read_segment_descriptor, .handle_io = hvf_handle_io, + .simulate_rdmsr = hvf_simulate_rdmsr, + .simulate_wrmsr = hvf_simulate_wrmsr, }; int hvf_arch_init_vcpu(CPUState *cpu) @@ -506,10 +508,10 @@ void hvf_store_regs(CPUState *cs) macvm_set_rip(cs, env->eip); } -void hvf_simulate_rdmsr(CPUX86State *env) +void hvf_simulate_rdmsr(CPUState *cs) { - X86CPU *cpu = env_archcpu(env); - CPUState *cs = env_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; uint32_t msr = ECX(env); uint64_t val = 0; @@ -611,10 +613,10 @@ void hvf_simulate_rdmsr(CPUX86State *env) RDX(env) = (uint32_t)(val >> 32); } -void hvf_simulate_wrmsr(CPUX86State *env) +void hvf_simulate_wrmsr(CPUState *cs) { - X86CPU *cpu = env_archcpu(env); - CPUState *cs = env_cpu(env); + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; uint32_t msr = ECX(env); uint64_t data = ((uint64_t)EDX(env) << 32) | EAX(env); @@ -900,9 +902,9 @@ int hvf_vcpu_exec(CPUState *cpu) { hvf_load_regs(cpu); if (exit_reason == EXIT_REASON_RDMSR) { - hvf_simulate_rdmsr(env); + hvf_simulate_rdmsr(cpu); } else { - hvf_simulate_wrmsr(env); + hvf_simulate_wrmsr(cpu); } env->eip += ins_len; hvf_store_regs(cpu); diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index 3ff41c35d8..aec7a8a3fa 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -672,13 +672,13 @@ void x86_emul_raise_exception(CPUX86State *env, int exception_index, int error_c static void exec_rdmsr(CPUX86State *env, struct x86_decode *decode) { - hvf_simulate_rdmsr(env); + emul_ops->simulate_rdmsr(env_cpu(env)); env->eip += decode->len; } static void exec_wrmsr(CPUX86State *env, struct x86_decode *decode) { - hvf_simulate_wrmsr(env); + emul_ops->simulate_wrmsr(env_cpu(env)); env->eip += decode->len; } diff --git a/target/i386/hvf/x86_emu.h b/target/i386/hvf/x86_emu.h index 107c1f1ac8..555b567e2c 100644 --- a/target/i386/hvf/x86_emu.h +++ b/target/i386/hvf/x86_emu.h @@ -30,6 +30,8 @@ struct x86_emul_ops { enum X86Seg seg); void (*handle_io)(CPUState *cpu, uint16_t port, void *data, int direction, int size, int count); + void (*simulate_rdmsr)(CPUState *cs); + void (*simulate_wrmsr)(CPUState *cs); }; extern const struct x86_emul_ops *emul_ops; From 7517ee9ec23801d4b6c4e5acbc0ad1bfa06c755a Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:19 -0800 Subject: [PATCH 0026/2760] target/i386: rename lazy flags field and its type The same structure and code can be used by other accelerators. Drop the hvf prefix in the type and field name. No functional change. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-9-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 6 ++-- target/i386/hvf/x86_flags.c | 56 ++++++++++++++++++------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 3c5c39ce3d..119efc6c60 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1811,10 +1811,10 @@ typedef struct CPUCaches { CPUCacheInfo *l3_cache; } CPUCaches; -typedef struct HVFX86LazyFlags { +typedef struct X86LazyFlags { target_ulong result; target_ulong auxbits; -} HVFX86LazyFlags; +} X86LazyFlags; typedef struct CPUArchState { /* standard registers */ @@ -2108,7 +2108,7 @@ typedef struct CPUArchState { QemuMutex xen_timers_lock; #endif #if defined(CONFIG_HVF) - HVFX86LazyFlags hvf_lflags; + X86LazyFlags lflags; void *emu_mmio_buf; #endif diff --git a/target/i386/hvf/x86_flags.c b/target/i386/hvf/x86_flags.c index 0c75e0419c..84e27364a0 100644 --- a/target/i386/hvf/x86_flags.c +++ b/target/i386/hvf/x86_flags.c @@ -53,7 +53,7 @@ #define SET_FLAGS_OSZAPC_SIZE(size, lf_carries, lf_result) { \ target_ulong temp = ((lf_carries) & (LF_MASK_AF)) | \ (((lf_carries) >> (size - 2)) << LF_BIT_PO); \ - env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \ + env->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ if ((size) == 32) { \ temp = ((lf_carries) & ~(LF_MASK_PDB | LF_MASK_SD)); \ } else if ((size) == 16) { \ @@ -63,7 +63,7 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_lflags.auxbits = (target_ulong)(uint32_t)temp; \ + env->lflags.auxbits = (target_ulong)(uint32_t)temp; \ } /* carries, result */ @@ -90,10 +90,10 @@ } else { \ VM_PANIC("unimplemented"); \ } \ - env->hvf_lflags.result = (target_ulong)(int##size##_t)(lf_result); \ - target_ulong delta_c = (env->hvf_lflags.auxbits ^ temp) & LF_MASK_CF; \ + env->lflags.result = (target_ulong)(int##size##_t)(lf_result); \ + target_ulong delta_c = (env->lflags.auxbits ^ temp) & LF_MASK_CF; \ delta_c ^= (delta_c >> 1); \ - env->hvf_lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \ + env->lflags.auxbits = (target_ulong)(uint32_t)(temp ^ delta_c); \ } /* carries, result */ @@ -107,8 +107,8 @@ void SET_FLAGS_OxxxxC(CPUX86State *env, uint32_t new_of, uint32_t new_cf) { uint32_t temp_po = new_of ^ new_cf; - env->hvf_lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF); - env->hvf_lflags.auxbits |= (temp_po << LF_BIT_PO) | (new_cf << LF_BIT_CF); + env->lflags.auxbits &= ~(LF_MASK_PO | LF_MASK_CF); + env->lflags.auxbits |= (temp_po << LF_BIT_PO) | (new_cf << LF_BIT_CF); } void SET_FLAGS_OSZAPC_SUB32(CPUX86State *env, uint32_t v1, uint32_t v2, @@ -204,27 +204,27 @@ void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, bool get_PF(CPUX86State *env) { - uint32_t temp = (255 & env->hvf_lflags.result); - temp = temp ^ (255 & (env->hvf_lflags.auxbits >> LF_BIT_PDB)); + uint32_t temp = (255 & env->lflags.result); + temp = temp ^ (255 & (env->lflags.auxbits >> LF_BIT_PDB)); temp = (temp ^ (temp >> 4)) & 0x0F; return (0x9669U >> temp) & 1; } void set_PF(CPUX86State *env, bool val) { - uint32_t temp = (255 & env->hvf_lflags.result) ^ (!val); - env->hvf_lflags.auxbits &= ~(LF_MASK_PDB); - env->hvf_lflags.auxbits |= (temp << LF_BIT_PDB); + uint32_t temp = (255 & env->lflags.result) ^ (!val); + env->lflags.auxbits &= ~(LF_MASK_PDB); + env->lflags.auxbits |= (temp << LF_BIT_PDB); } bool get_OF(CPUX86State *env) { - return ((env->hvf_lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; + return ((env->lflags.auxbits + (1U << LF_BIT_PO)) >> LF_BIT_CF) & 1; } bool get_CF(CPUX86State *env) { - return (env->hvf_lflags.auxbits >> LF_BIT_CF) & 1; + return (env->lflags.auxbits >> LF_BIT_CF) & 1; } void set_OF(CPUX86State *env, bool val) @@ -241,45 +241,45 @@ void set_CF(CPUX86State *env, bool val) bool get_AF(CPUX86State *env) { - return (env->hvf_lflags.auxbits >> LF_BIT_AF) & 1; + return (env->lflags.auxbits >> LF_BIT_AF) & 1; } void set_AF(CPUX86State *env, bool val) { - env->hvf_lflags.auxbits &= ~(LF_MASK_AF); - env->hvf_lflags.auxbits |= val << LF_BIT_AF; + env->lflags.auxbits &= ~(LF_MASK_AF); + env->lflags.auxbits |= val << LF_BIT_AF; } bool get_ZF(CPUX86State *env) { - return !env->hvf_lflags.result; + return !env->lflags.result; } void set_ZF(CPUX86State *env, bool val) { if (val) { - env->hvf_lflags.auxbits ^= - (((env->hvf_lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD); + env->lflags.auxbits ^= + (((env->lflags.result >> LF_SIGN_BIT) & 1) << LF_BIT_SD); /* merge the parity bits into the Parity Delta Byte */ - uint32_t temp_pdb = (255 & env->hvf_lflags.result); - env->hvf_lflags.auxbits ^= (temp_pdb << LF_BIT_PDB); + uint32_t temp_pdb = (255 & env->lflags.result); + env->lflags.auxbits ^= (temp_pdb << LF_BIT_PDB); /* now zero the .result value */ - env->hvf_lflags.result = 0; + env->lflags.result = 0; } else { - env->hvf_lflags.result |= (1 << 8); + env->lflags.result |= (1 << 8); } } bool get_SF(CPUX86State *env) { - return ((env->hvf_lflags.result >> LF_SIGN_BIT) ^ - (env->hvf_lflags.auxbits >> LF_BIT_SD)) & 1; + return ((env->lflags.result >> LF_SIGN_BIT) ^ + (env->lflags.auxbits >> LF_BIT_SD)) & 1; } void set_SF(CPUX86State *env, bool val) { bool temp_sf = get_SF(env); - env->hvf_lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; + env->lflags.auxbits ^= (temp_sf ^ val) << LF_BIT_SD; } void lflags_to_rflags(CPUX86State *env) @@ -295,7 +295,7 @@ void lflags_to_rflags(CPUX86State *env) void rflags_to_lflags(CPUX86State *env) { - env->hvf_lflags.auxbits = env->hvf_lflags.result = 0; + env->lflags.auxbits = env->lflags.result = 0; set_OF(env, env->eflags & CC_O); set_SF(env, env->eflags & CC_S); set_ZF(env, env->eflags & CC_Z); From 3667f0bb58427edadc4a049080141d395b48fc29 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:20 -0800 Subject: [PATCH 0027/2760] target/i386/hvf: drop unused headers Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-10-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_decode.c | 3 --- target/i386/hvf/x86_emu.c | 4 ---- 2 files changed, 7 deletions(-) diff --git a/target/i386/hvf/x86_decode.c b/target/i386/hvf/x86_decode.c index 728e159638..ddd7b60bcf 100644 --- a/target/i386/hvf/x86_decode.c +++ b/target/i386/hvf/x86_decode.c @@ -20,10 +20,7 @@ #include "panic.h" #include "x86_decode.h" -#include "vmx.h" #include "x86_emu.h" -#include "x86_mmu.h" -#include "x86_descr.h" #define OPCODE_ESCAPE 0xf diff --git a/target/i386/hvf/x86_emu.c b/target/i386/hvf/x86_emu.c index aec7a8a3fa..26a4876aac 100644 --- a/target/i386/hvf/x86_emu.c +++ b/target/i386/hvf/x86_emu.c @@ -40,11 +40,7 @@ #include "x86_decode.h" #include "x86.h" #include "x86_emu.h" -#include "x86_mmu.h" #include "x86_flags.h" -#include "vmcs.h" -#include "vmx.h" -#include "hvf-i386.h" #define EXEC_2OP_FLAGS_CMD(env, decode, cmd, FLAGS_FUNC, save_res) \ { \ From fb8ebedd2a9d2c2c098464dee4ec7bd1c8c463a1 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:21 -0800 Subject: [PATCH 0028/2760] target/i386/hvf: rename some include guards These headers will be moved out to its own component. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-11-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86.h | 4 ++-- target/i386/hvf/x86_decode.h | 4 ++-- target/i386/hvf/x86_flags.h | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/target/i386/hvf/x86.h b/target/i386/hvf/x86.h index 063cd0b83e..73edccfba0 100644 --- a/target/i386/hvf/x86.h +++ b/target/i386/hvf/x86.h @@ -16,8 +16,8 @@ * License along with this program; if not, see . */ -#ifndef HVF_X86_H -#define HVF_X86_H +#ifndef X86_EMU_DEFS_H +#define X86_EMU_DEFS_H typedef struct x86_register { union { diff --git a/target/i386/hvf/x86_decode.h b/target/i386/hvf/x86_decode.h index a2d7a2a27b..930d965164 100644 --- a/target/i386/hvf/x86_decode.h +++ b/target/i386/hvf/x86_decode.h @@ -15,8 +15,8 @@ * License along with this program; if not, see . */ -#ifndef HVF_X86_DECODE_H -#define HVF_X86_DECODE_H +#ifndef X86_EMU_DECODE_H +#define X86_EMU_DECODE_H #include "cpu.h" #include "x86.h" diff --git a/target/i386/hvf/x86_flags.h b/target/i386/hvf/x86_flags.h index 75c2a7feab..6c175007b5 100644 --- a/target/i386/hvf/x86_flags.h +++ b/target/i386/hvf/x86_flags.h @@ -21,8 +21,8 @@ * x86 eflags functions */ -#ifndef X86_FLAGS_H -#define X86_FLAGS_H +#ifndef X86_EMU_FLAGS_H +#define X86_EMU_FLAGS_H #include "cpu.h" void lflags_to_rflags(CPUX86State *env); @@ -78,4 +78,4 @@ void SET_FLAGS_OSZAPC_LOGIC16(CPUX86State *env, uint16_t v1, uint16_t v2, void SET_FLAGS_OSZAPC_LOGIC8(CPUX86State *env, uint8_t v1, uint8_t v2, uint8_t diff); -#endif /* X86_FLAGS_H */ +#endif /* X86_EMU_FLAGS_H */ From 5ffd2705f797ffe59165f3f29ad1065f648d6add Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:22 -0800 Subject: [PATCH 0029/2760] target/i386: add a directory for x86 instruction emulator Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-12-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/emulate/meson.build | 0 target/i386/meson.build | 1 + 2 files changed, 1 insertion(+) create mode 100644 target/i386/emulate/meson.build diff --git a/target/i386/emulate/meson.build b/target/i386/emulate/meson.build new file mode 100644 index 0000000000..e69de29bb2 diff --git a/target/i386/meson.build b/target/i386/meson.build index 2e9c472f49..c1aacea613 100644 --- a/target/i386/meson.build +++ b/target/i386/meson.build @@ -31,6 +31,7 @@ subdir('whpx') subdir('nvmm') subdir('hvf') subdir('tcg') +subdir('emulate') target_arch += {'i386': i386_ss} target_system_arch += {'i386': i386_system_ss} From 2d4f09523fd48bdb42a163e3b53a420c799217f3 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:23 -0800 Subject: [PATCH 0030/2760] target/i386/emulate: add a panic.h The macros will be used by the instruction emulator. The code is the same as the one under hvf. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-13-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/emulate/panic.h | 45 +++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 target/i386/emulate/panic.h diff --git a/target/i386/emulate/panic.h b/target/i386/emulate/panic.h new file mode 100644 index 0000000000..71c24874ba --- /dev/null +++ b/target/i386/emulate/panic.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 Veertu Inc, + * Copyright (C) 2017 Google Inc, + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, see . + */ +#ifndef X86_EMU_PANIC_H +#define X86_EMU_PANIC_H + +#define VM_PANIC(x) {\ + printf("%s\n", x); \ + abort(); \ +} + +#define VM_PANIC_ON(x) {\ + if (x) { \ + printf("%s\n", #x); \ + abort(); \ + } \ +} + +#define VM_PANIC_EX(...) {\ + printf(__VA_ARGS__); \ + abort(); \ +} + +#define VM_PANIC_ON_EX(x, ...) {\ + if (x) { \ + printf(__VA_ARGS__); \ + abort(); \ + } \ +} + +#endif From 27458df871097d7fc14b19d9e01c35d29737b9b3 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:24 -0800 Subject: [PATCH 0031/2760] target/i386: move x86 instruction emulator out of hvf Move x86_decode, x86_emu, x86_flags and some headers to the new location. Fix up all the inclusion sites in hvf. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-14-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/emulate/meson.build | 5 +++++ target/i386/{hvf => emulate}/x86.h | 0 target/i386/{hvf => emulate}/x86_decode.c | 0 target/i386/{hvf => emulate}/x86_decode.h | 0 target/i386/{hvf => emulate}/x86_emu.c | 0 target/i386/{hvf => emulate}/x86_emu.h | 0 target/i386/{hvf => emulate}/x86_flags.c | 0 target/i386/{hvf => emulate}/x86_flags.h | 0 target/i386/hvf/hvf.c | 8 ++++---- target/i386/hvf/meson.build | 3 --- target/i386/hvf/vmx.h | 2 +- target/i386/hvf/x86.c | 4 ++-- target/i386/hvf/x86_cpuid.c | 2 +- target/i386/hvf/x86_descr.h | 2 +- target/i386/hvf/x86_mmu.c | 2 +- target/i386/hvf/x86_task.c | 6 +++--- target/i386/hvf/x86hvf.c | 2 +- 17 files changed, 19 insertions(+), 17 deletions(-) rename target/i386/{hvf => emulate}/x86.h (100%) rename target/i386/{hvf => emulate}/x86_decode.c (100%) rename target/i386/{hvf => emulate}/x86_decode.h (100%) rename target/i386/{hvf => emulate}/x86_emu.c (100%) rename target/i386/{hvf => emulate}/x86_emu.h (100%) rename target/i386/{hvf => emulate}/x86_flags.c (100%) rename target/i386/{hvf => emulate}/x86_flags.h (100%) diff --git a/target/i386/emulate/meson.build b/target/i386/emulate/meson.build index e69de29bb2..4edd4f462f 100644 --- a/target/i386/emulate/meson.build +++ b/target/i386/emulate/meson.build @@ -0,0 +1,5 @@ +i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files( + 'x86_decode.c', + 'x86_emu.c', + 'x86_flags.c', +)) diff --git a/target/i386/hvf/x86.h b/target/i386/emulate/x86.h similarity index 100% rename from target/i386/hvf/x86.h rename to target/i386/emulate/x86.h diff --git a/target/i386/hvf/x86_decode.c b/target/i386/emulate/x86_decode.c similarity index 100% rename from target/i386/hvf/x86_decode.c rename to target/i386/emulate/x86_decode.c diff --git a/target/i386/hvf/x86_decode.h b/target/i386/emulate/x86_decode.h similarity index 100% rename from target/i386/hvf/x86_decode.h rename to target/i386/emulate/x86_decode.h diff --git a/target/i386/hvf/x86_emu.c b/target/i386/emulate/x86_emu.c similarity index 100% rename from target/i386/hvf/x86_emu.c rename to target/i386/emulate/x86_emu.c diff --git a/target/i386/hvf/x86_emu.h b/target/i386/emulate/x86_emu.h similarity index 100% rename from target/i386/hvf/x86_emu.h rename to target/i386/emulate/x86_emu.h diff --git a/target/i386/hvf/x86_flags.c b/target/i386/emulate/x86_flags.c similarity index 100% rename from target/i386/hvf/x86_flags.c rename to target/i386/emulate/x86_flags.c diff --git a/target/i386/hvf/x86_flags.h b/target/i386/emulate/x86_flags.h similarity index 100% rename from target/i386/hvf/x86_flags.h rename to target/i386/emulate/x86_flags.h diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 8c31d2e0cf..23ebf2550a 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -59,12 +59,12 @@ #include "hvf-i386.h" #include "vmcs.h" #include "vmx.h" -#include "x86.h" +#include "emulate/x86.h" #include "x86_descr.h" -#include "x86_flags.h" +#include "emulate/x86_flags.h" #include "x86_mmu.h" -#include "x86_decode.h" -#include "x86_emu.h" +#include "emulate/x86_decode.h" +#include "emulate/x86_emu.h" #include "x86_task.h" #include "x86hvf.h" diff --git a/target/i386/hvf/meson.build b/target/i386/hvf/meson.build index 05c3c8cf18..519d190f0e 100644 --- a/target/i386/hvf/meson.build +++ b/target/i386/hvf/meson.build @@ -2,10 +2,7 @@ i386_system_ss.add(when: [hvf, 'CONFIG_HVF'], if_true: files( 'hvf.c', 'x86.c', 'x86_cpuid.c', - 'x86_decode.c', 'x86_descr.c', - 'x86_emu.c', - 'x86_flags.c', 'x86_mmu.c', 'x86_task.c', 'x86hvf.c', diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 80ce26279b..3c56afc9d3 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -29,7 +29,7 @@ #include #include "vmcs.h" #include "cpu.h" -#include "x86.h" +#include "emulate/x86.h" #include "system/hvf.h" #include "system/hvf_int.h" diff --git a/target/i386/hvf/x86.c b/target/i386/hvf/x86.c index a0ede13886..5c75ec9a00 100644 --- a/target/i386/hvf/x86.c +++ b/target/i386/hvf/x86.c @@ -19,8 +19,8 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "x86_decode.h" -#include "x86_emu.h" +#include "emulate/x86_decode.h" +#include "emulate/x86_emu.h" #include "vmcs.h" #include "vmx.h" #include "x86_mmu.h" diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index ae836f65cc..fa131b18c6 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -24,7 +24,7 @@ #include "qemu/cpuid.h" #include "host/cpuinfo.h" #include "cpu.h" -#include "x86.h" +#include "emulate/x86.h" #include "vmx.h" #include "system/hvf.h" #include "hvf-i386.h" diff --git a/target/i386/hvf/x86_descr.h b/target/i386/hvf/x86_descr.h index ce5de98349..24af4946cd 100644 --- a/target/i386/hvf/x86_descr.h +++ b/target/i386/hvf/x86_descr.h @@ -19,7 +19,7 @@ #ifndef HVF_X86_DESCR_H #define HVF_X86_DESCR_H -#include "x86.h" +#include "emulate/x86.h" typedef struct vmx_segment { uint16_t sel; diff --git a/target/i386/hvf/x86_mmu.c b/target/i386/hvf/x86_mmu.c index 579d0c3a4c..afc5c17d5d 100644 --- a/target/i386/hvf/x86_mmu.c +++ b/target/i386/hvf/x86_mmu.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "panic.h" #include "cpu.h" -#include "x86.h" +#include "emulate/x86.h" #include "x86_mmu.h" #include "vmcs.h" #include "vmx.h" diff --git a/target/i386/hvf/x86_task.c b/target/i386/hvf/x86_task.c index 161217991f..bdf8b51ae6 100644 --- a/target/i386/hvf/x86_task.c +++ b/target/i386/hvf/x86_task.c @@ -14,11 +14,11 @@ #include "hvf-i386.h" #include "vmcs.h" #include "vmx.h" -#include "x86.h" +#include "emulate/x86.h" #include "x86_descr.h" #include "x86_mmu.h" -#include "x86_decode.h" -#include "x86_emu.h" +#include "emulate/x86_decode.h" +#include "emulate/x86_emu.h" #include "x86_task.h" #include "x86hvf.h" diff --git a/target/i386/hvf/x86hvf.c b/target/i386/hvf/x86hvf.c index 531a340b37..2057314892 100644 --- a/target/i386/hvf/x86hvf.c +++ b/target/i386/hvf/x86hvf.c @@ -24,7 +24,7 @@ #include "vmcs.h" #include "cpu.h" #include "x86_descr.h" -#include "x86_decode.h" +#include "emulate/x86_decode.h" #include "system/hw_accel.h" #include "hw/i386/apic_internal.h" From 6aa0d0391c56e411d43bbf9f9c6acd1fea6f55c4 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 7 Mar 2025 11:55:25 -0800 Subject: [PATCH 0032/2760] MAINTAINERS: add an entry for the x86 instruction emulator Add myself as a reviewer. Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/1741377325-28175-15-git-send-email-liuwe@linux.microsoft.com Signed-off-by: Paolo Bonzini --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d54b5578f8..67228401f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -534,6 +534,14 @@ S: Supported F: target/i386/whpx/ F: include/system/whpx.h +X86 Instruction Emulator +M: Cameron Esfahani +M: Roman Bolshakov +R: Phil Dennis-Jordan +R: Wei Liu +S: Maintained +F: target/i386/emulate/ + Guest CPU Cores (Xen) --------------------- X86 Xen CPUs From c901905ea6703a2feb5867537a8559dc129447f7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 3 Apr 2025 21:45:36 +0200 Subject: [PATCH 0033/2760] target/i386/emulate: remove flags_mask The field is written but never read. Cc: Wei Liu Reviewed-by: Richard Henderson Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_decode.c | 864 +++++++++++++++---------------- target/i386/emulate/x86_decode.h | 2 - 2 files changed, 424 insertions(+), 442 deletions(-) diff --git a/target/i386/emulate/x86_decode.c b/target/i386/emulate/x86_decode.c index ddd7b60bcf..7fee219687 100644 --- a/target/i386/emulate/x86_decode.c +++ b/target/i386/emulate/x86_decode.c @@ -429,7 +429,6 @@ struct decode_tbl { void (*decode_op4)(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op4); void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); - uint32_t flags_mask; }; struct decode_x87_tbl { @@ -445,7 +444,6 @@ struct decode_x87_tbl { void (*decode_op2)(CPUX86State *env, struct x86_decode *decode, struct x86_decode_op *op2); void (*decode_postfix)(CPUX86State *env, struct x86_decode *decode); - uint32_t flags_mask; }; struct decode_tbl invl_inst = {0x0, 0, 0, false, NULL, NULL, NULL, NULL, @@ -470,7 +468,6 @@ static void decode_x87_ins(CPUX86State *env, struct x86_decode *decode) if (decoder->operand_size) { decode->operand_size = decoder->operand_size; } - decode->flags_mask = decoder->flags_mask; decode->fpop_stack = decoder->pop; decode->frev = decoder->rev; @@ -503,9 +500,6 @@ static void decode_ffgroup(CPUX86State *env, struct x86_decode *decode) X86_DECODE_CMD_INVL }; decode->cmd = group[decode->modrm.reg]; - if (decode->modrm.reg > 2) { - decode->flags_mask = 0; - } } static void decode_sldtgroup(CPUX86State *env, struct x86_decode *decode) @@ -693,733 +687,724 @@ static void decode_db_4(CPUX86State *env, struct x86_decode *decode) } -#define RFLAGS_MASK_NONE 0 -#define RFLAGS_MASK_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C) -#define RFLAGS_MASK_LAHF (CC_S | CC_Z | CC_A | CC_P | CC_C) -#define RFLAGS_MASK_CF (CC_C) -#define RFLAGS_MASK_IF (IF_MASK) -#define RFLAGS_MASK_TF (TF_MASK) -#define RFLAGS_MASK_DF (DF_MASK) -#define RFLAGS_MASK_ZF (CC_Z) - struct decode_tbl _1op_inst[] = { {0x0, X86_DECODE_CMD_ADD, 1, true, decode_modrm_rm, decode_modrm_reg, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0x1, X86_DECODE_CMD_ADD, 0, true, decode_modrm_rm, decode_modrm_reg, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0x2, X86_DECODE_CMD_ADD, 1, true, decode_modrm_reg, decode_modrm_rm, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0x3, X86_DECODE_CMD_ADD, 0, true, decode_modrm_reg, decode_modrm_rm, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0x4, X86_DECODE_CMD_ADD, 1, false, decode_rax, decode_imm8, NULL, NULL, - NULL, RFLAGS_MASK_OSZAPC}, + NULL}, {0x5, X86_DECODE_CMD_ADD, 0, false, decode_rax, decode_imm, NULL, NULL, - NULL, RFLAGS_MASK_OSZAPC}, + NULL}, {0x6, X86_DECODE_CMD_PUSH_SEG, 0, false, false, NULL, NULL, NULL, - decode_pushseg, RFLAGS_MASK_NONE}, + decode_pushseg}, {0x7, X86_DECODE_CMD_POP_SEG, 0, false, false, NULL, NULL, NULL, - decode_popseg, RFLAGS_MASK_NONE}, + decode_popseg}, {0x8, X86_DECODE_CMD_OR, 1, true, decode_modrm_rm, decode_modrm_reg, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0x9, X86_DECODE_CMD_OR, 0, true, decode_modrm_rm, decode_modrm_reg, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0xa, X86_DECODE_CMD_OR, 1, true, decode_modrm_reg, decode_modrm_rm, NULL, - NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL}, {0xb, X86_DECODE_CMD_OR, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xc, X86_DECODE_CMD_OR, 1, false, decode_rax, decode_imm8, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xd, X86_DECODE_CMD_OR, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xe, X86_DECODE_CMD_PUSH_SEG, 0, false, false, - NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_pushseg}, {0xf, X86_DECODE_CMD_POP_SEG, 0, false, false, - NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_popseg}, {0x10, X86_DECODE_CMD_ADC, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x11, X86_DECODE_CMD_ADC, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x12, X86_DECODE_CMD_ADC, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x13, X86_DECODE_CMD_ADC, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x14, X86_DECODE_CMD_ADC, 1, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x15, X86_DECODE_CMD_ADC, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x16, X86_DECODE_CMD_PUSH_SEG, 0, false, false, - NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_pushseg}, {0x17, X86_DECODE_CMD_POP_SEG, 0, false, false, - NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_popseg}, {0x18, X86_DECODE_CMD_SBB, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x19, X86_DECODE_CMD_SBB, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x1a, X86_DECODE_CMD_SBB, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x1b, X86_DECODE_CMD_SBB, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x1c, X86_DECODE_CMD_SBB, 1, false, decode_rax, decode_imm8, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x1d, X86_DECODE_CMD_SBB, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x1e, X86_DECODE_CMD_PUSH_SEG, 0, false, false, - NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_pushseg}, {0x1f, X86_DECODE_CMD_POP_SEG, 0, false, false, - NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_popseg}, {0x20, X86_DECODE_CMD_AND, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x21, X86_DECODE_CMD_AND, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x22, X86_DECODE_CMD_AND, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x23, X86_DECODE_CMD_AND, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x24, X86_DECODE_CMD_AND, 1, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x25, X86_DECODE_CMD_AND, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x28, X86_DECODE_CMD_SUB, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x29, X86_DECODE_CMD_SUB, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x2a, X86_DECODE_CMD_SUB, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x2b, X86_DECODE_CMD_SUB, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x2c, X86_DECODE_CMD_SUB, 1, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x2d, X86_DECODE_CMD_SUB, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x2f, X86_DECODE_CMD_DAS, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, NULL}, {0x30, X86_DECODE_CMD_XOR, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x31, X86_DECODE_CMD_XOR, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x32, X86_DECODE_CMD_XOR, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x33, X86_DECODE_CMD_XOR, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x34, X86_DECODE_CMD_XOR, 1, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x35, X86_DECODE_CMD_XOR, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x38, X86_DECODE_CMD_CMP, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x39, X86_DECODE_CMD_CMP, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x3a, X86_DECODE_CMD_CMP, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x3b, X86_DECODE_CMD_CMP, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x3c, X86_DECODE_CMD_CMP, 1, false, decode_rax, decode_imm8, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x3d, X86_DECODE_CMD_CMP, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x3f, X86_DECODE_CMD_AAS, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, NULL}, {0x40, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x41, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x42, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x43, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x44, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x45, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x46, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x47, X86_DECODE_CMD_INC, 0, false, - NULL, NULL, NULL, NULL, decode_incgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_incgroup}, {0x48, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x49, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4a, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4b, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4c, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4d, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4e, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x4f, X86_DECODE_CMD_DEC, 0, false, - NULL, NULL, NULL, NULL, decode_decgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_decgroup}, {0x50, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x51, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x52, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x53, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x54, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x55, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x56, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x57, X86_DECODE_CMD_PUSH, 0, false, - NULL, NULL, NULL, NULL, decode_pushgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_pushgroup}, {0x58, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x59, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5a, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5b, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5c, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5d, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5e, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x5f, X86_DECODE_CMD_POP, 0, false, - NULL, NULL, NULL, NULL, decode_popgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_popgroup}, {0x60, X86_DECODE_CMD_PUSHA, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x61, X86_DECODE_CMD_POPA, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x68, X86_DECODE_CMD_PUSH, 0, false, decode_imm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x6a, X86_DECODE_CMD_PUSH, 0, false, decode_imm8_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x69, X86_DECODE_CMD_IMUL_3, 0, true, decode_modrm_reg, - decode_modrm_rm, decode_imm, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_modrm_rm, decode_imm, NULL, NULL}, {0x6b, X86_DECODE_CMD_IMUL_3, 0, true, decode_modrm_reg, decode_modrm_rm, - decode_imm8_signed, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_imm8_signed, NULL, NULL}, {0x6c, X86_DECODE_CMD_INS, 1, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x6d, X86_DECODE_CMD_INS, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x6e, X86_DECODE_CMD_OUTS, 1, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x6f, X86_DECODE_CMD_OUTS, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x70, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x71, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x72, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x73, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x74, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x75, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x76, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x77, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x78, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x79, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7a, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7b, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7c, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7d, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7e, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x7f, X86_DECODE_CMD_JXX, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x80, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, - NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_addgroup}, {0x81, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm, - NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_addgroup}, {0x82, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, - NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_addgroup}, {0x83, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8_signed, - NULL, NULL, decode_addgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_addgroup}, {0x84, X86_DECODE_CMD_TST, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x85, X86_DECODE_CMD_TST, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0x86, X86_DECODE_CMD_XCHG, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x87, X86_DECODE_CMD_XCHG, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x88, X86_DECODE_CMD_MOV, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x89, X86_DECODE_CMD_MOV, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x8a, X86_DECODE_CMD_MOV, 1, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x8b, X86_DECODE_CMD_MOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x8c, X86_DECODE_CMD_MOV_FROM_SEG, 0, true, decode_modrm_rm, - decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_reg, NULL, NULL, NULL}, {0x8d, X86_DECODE_CMD_LEA, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x8e, X86_DECODE_CMD_MOV_TO_SEG, 0, true, decode_modrm_reg, - decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_rm, NULL, NULL, NULL}, {0x8f, X86_DECODE_CMD_POP, 0, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x90, X86_DECODE_CMD_NOP, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x91, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x92, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x93, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x94, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x95, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x96, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x97, X86_DECODE_CMD_XCHG, 0, false, NULL, decode_rax, - NULL, NULL, decode_xchgroup, RFLAGS_MASK_NONE}, + NULL, NULL, decode_xchgroup}, {0x98, X86_DECODE_CMD_CBW, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x99, X86_DECODE_CMD_CWD, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x9a, X86_DECODE_CMD_CALL_FAR, 0, false, NULL, - NULL, NULL, NULL, decode_farjmp, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_farjmp}, {0x9c, X86_DECODE_CMD_PUSHF, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, /*{0x9d, X86_DECODE_CMD_POPF, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_POPF},*/ + NULL, NULL, NULL},*/ {0x9e, X86_DECODE_CMD_SAHF, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x9f, X86_DECODE_CMD_LAHF, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_LAHF}, + NULL, NULL, NULL}, {0xa0, X86_DECODE_CMD_MOV, 1, false, decode_rax, fetch_moffs, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa1, X86_DECODE_CMD_MOV, 0, false, decode_rax, fetch_moffs, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa2, X86_DECODE_CMD_MOV, 1, false, fetch_moffs, decode_rax, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa3, X86_DECODE_CMD_MOV, 0, false, fetch_moffs, decode_rax, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa4, X86_DECODE_CMD_MOVS, 1, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa5, X86_DECODE_CMD_MOVS, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa6, X86_DECODE_CMD_CMPS, 1, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xa7, X86_DECODE_CMD_CMPS, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xaa, X86_DECODE_CMD_STOS, 1, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xab, X86_DECODE_CMD_STOS, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xac, X86_DECODE_CMD_LODS, 1, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xad, X86_DECODE_CMD_LODS, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xae, X86_DECODE_CMD_SCAS, 1, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xaf, X86_DECODE_CMD_SCAS, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xa8, X86_DECODE_CMD_TST, 1, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xa9, X86_DECODE_CMD_TST, 0, false, decode_rax, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xb0, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb1, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb2, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb3, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb4, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb5, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb6, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb7, X86_DECODE_CMD_MOV, 1, false, NULL, - NULL, NULL, NULL, decode_movgroup8, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup8}, {0xb8, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xb9, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xba, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xbb, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xbc, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xbd, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xbe, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xbf, X86_DECODE_CMD_MOV, 0, false, NULL, - NULL, NULL, NULL, decode_movgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_movgroup}, {0xc0, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm8, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xc1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xc2, X86_DECODE_RET_NEAR, 0, false, decode_imm16, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xc3, X86_DECODE_RET_NEAR, 0, false, NULL, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xc4, X86_DECODE_CMD_LES, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xc5, X86_DECODE_CMD_LDS, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xc6, X86_DECODE_CMD_MOV, 1, true, decode_modrm_rm, decode_imm8, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xc7, X86_DECODE_CMD_MOV, 0, true, decode_modrm_rm, decode_imm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xc8, X86_DECODE_CMD_ENTER, 0, false, decode_imm16, decode_imm8, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xc9, X86_DECODE_CMD_LEAVE, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xca, X86_DECODE_RET_FAR, 0, false, decode_imm16, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xcb, X86_DECODE_RET_FAR, 0, false, decode_imm_0, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xcd, X86_DECODE_CMD_INT, 0, false, decode_imm8, NULL, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, /*{0xcf, X86_DECODE_CMD_IRET, 0, false, NULL, NULL, - NULL, NULL, NULL, RFLAGS_MASK_IRET},*/ + NULL, NULL, NULL},*/ {0xd0, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_imm_1, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xd1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm_1, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xd2, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, decode_rcx, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xd3, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_rcx, - NULL, NULL, decode_rotgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_rotgroup}, {0xd4, X86_DECODE_CMD_AAM, 0, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL}, {0xd5, X86_DECODE_CMD_AAD, 0, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL}, {0xd7, X86_DECODE_CMD_XLAT, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xd8, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xd9, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xda, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xdb, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xdc, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xdd, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xde, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xdf, X86_DECODE_CMD_INVL, 0, true, NULL, - NULL, NULL, NULL, decode_x87_ins, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_x87_ins}, {0xe0, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe1, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe2, X86_DECODE_CMD_LOOP, 0, false, decode_imm8_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe3, X86_DECODE_CMD_JCXZ, 1, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0xe4, X86_DECODE_CMD_IN, 1, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe5, X86_DECODE_CMD_IN, 0, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe6, X86_DECODE_CMD_OUT, 1, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe7, X86_DECODE_CMD_OUT, 0, false, decode_imm8, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe8, X86_DECODE_CMD_CALL_NEAR, 0, false, decode_imm_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xe9, X86_DECODE_CMD_JMP_NEAR, 0, false, decode_imm_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xea, X86_DECODE_CMD_JMP_FAR, 0, false, - NULL, NULL, NULL, NULL, decode_farjmp, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_farjmp}, {0xeb, X86_DECODE_CMD_JMP_NEAR, 1, false, decode_imm8_signed, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xec, X86_DECODE_CMD_IN, 1, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xed, X86_DECODE_CMD_IN, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xee, X86_DECODE_CMD_OUT, 1, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xef, X86_DECODE_CMD_OUT, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xf4, X86_DECODE_CMD_HLT, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xf5, X86_DECODE_CMD_CMC, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + NULL, NULL, NULL, NULL, NULL}, {0xf6, X86_DECODE_CMD_INVL, 1, true, - NULL, NULL, NULL, NULL, decode_f7group, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_f7group}, {0xf7, X86_DECODE_CMD_INVL, 0, true, - NULL, NULL, NULL, NULL, decode_f7group, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, NULL, decode_f7group}, {0xf8, X86_DECODE_CMD_CLC, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + NULL, NULL, NULL, NULL, NULL}, {0xf9, X86_DECODE_CMD_STC, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_CF}, + NULL, NULL, NULL, NULL, NULL}, {0xfa, X86_DECODE_CMD_CLI, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_IF}, + NULL, NULL, NULL, NULL, NULL}, {0xfb, X86_DECODE_CMD_STI, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_IF}, + NULL, NULL, NULL, NULL, NULL}, {0xfc, X86_DECODE_CMD_CLD, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_DF}, + NULL, NULL, NULL, NULL, NULL}, {0xfd, X86_DECODE_CMD_STD, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_DF}, + NULL, NULL, NULL, NULL, NULL}, {0xfe, X86_DECODE_CMD_INVL, 1, true, decode_modrm_rm, - NULL, NULL, NULL, decode_incgroup2, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, decode_incgroup2}, {0xff, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, - NULL, NULL, NULL, decode_ffgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL, decode_ffgroup}, }; struct decode_tbl _2op_inst[] = { {0x0, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, - NULL, NULL, NULL, decode_sldtgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_sldtgroup}, {0x1, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, - NULL, NULL, NULL, decode_lidtgroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_lidtgroup}, {0x6, X86_DECODE_CMD_CLTS, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_TF}, + NULL, NULL, NULL, NULL, NULL}, {0x9, X86_DECODE_CMD_WBINVD, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x18, X86_DECODE_CMD_PREFETCH, 0, true, - NULL, NULL, NULL, NULL, decode_x87_general, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_x87_general}, {0x1f, X86_DECODE_CMD_NOP, 0, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x20, X86_DECODE_CMD_MOV_FROM_CR, 0, true, decode_modrm_rm, - decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_reg, NULL, NULL, NULL}, {0x21, X86_DECODE_CMD_MOV_FROM_DR, 0, true, decode_modrm_rm, - decode_modrm_reg, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_reg, NULL, NULL, NULL}, {0x22, X86_DECODE_CMD_MOV_TO_CR, 0, true, decode_modrm_reg, - decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_rm, NULL, NULL, NULL}, {0x23, X86_DECODE_CMD_MOV_TO_DR, 0, true, decode_modrm_reg, - decode_modrm_rm, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + decode_modrm_rm, NULL, NULL, NULL}, {0x30, X86_DECODE_CMD_WRMSR, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x31, X86_DECODE_CMD_RDTSC, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x32, X86_DECODE_CMD_RDMSR, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0x40, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x41, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x42, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x43, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x44, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x45, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x46, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x47, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x48, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x49, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4a, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4b, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4c, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4d, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4e, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x4f, X86_DECODE_CMD_CMOV, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0x77, X86_DECODE_CMD_EMMS, 0, false, - NULL, NULL, NULL, NULL, decode_x87_general, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_x87_general}, {0x82, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x83, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x84, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x85, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x86, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x87, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x88, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x89, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8a, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8b, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8c, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8d, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8e, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x8f, X86_DECODE_CMD_JXX, 0, false, - NULL, NULL, NULL, NULL, decode_jxx, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_jxx}, {0x90, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x91, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x92, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x93, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x94, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x95, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x96, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x97, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x98, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x99, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9a, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9b, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9c, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9d, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9e, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0x9f, X86_DECODE_CMD_SETXX, 1, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL}, {0xb0, X86_DECODE_CMD_CMPXCHG, 1, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xb1, X86_DECODE_CMD_CMPXCHG, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xb6, X86_DECODE_CMD_MOVZX, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xb7, X86_DECODE_CMD_MOVZX, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xb8, X86_DECODE_CMD_POPCNT, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xbe, X86_DECODE_CMD_MOVSX, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xbf, X86_DECODE_CMD_MOVSX, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xa0, X86_DECODE_CMD_PUSH_SEG, 0, false, false, - NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_pushseg}, {0xa1, X86_DECODE_CMD_POP_SEG, 0, false, false, - NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_popseg}, {0xa2, X86_DECODE_CMD_CPUID, 0, false, - NULL, NULL, NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, NULL}, {0xa3, X86_DECODE_CMD_BT, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_CF}, + NULL, NULL, NULL}, {0xa4, X86_DECODE_CMD_SHLD, 0, true, decode_modrm_rm, decode_modrm_reg, - decode_imm8, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_imm8, NULL, NULL}, {0xa5, X86_DECODE_CMD_SHLD, 0, true, decode_modrm_rm, decode_modrm_reg, - decode_rcx, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_rcx, NULL, NULL}, {0xa8, X86_DECODE_CMD_PUSH_SEG, 0, false, false, - NULL, NULL, NULL, decode_pushseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_pushseg}, {0xa9, X86_DECODE_CMD_POP_SEG, 0, false, false, - NULL, NULL, NULL, decode_popseg, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_popseg}, {0xab, X86_DECODE_CMD_BTS, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_CF}, + NULL, NULL, NULL}, {0xac, X86_DECODE_CMD_SHRD, 0, true, decode_modrm_rm, decode_modrm_reg, - decode_imm8, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_imm8, NULL, NULL}, {0xad, X86_DECODE_CMD_SHRD, 0, true, decode_modrm_rm, decode_modrm_reg, - decode_rcx, NULL, NULL, RFLAGS_MASK_OSZAPC}, + decode_rcx, NULL, NULL}, {0xae, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, - NULL, NULL, NULL, decode_aegroup, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, decode_aegroup}, {0xaf, X86_DECODE_CMD_IMUL_2, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xb2, X86_DECODE_CMD_LSS, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_NONE}, + NULL, NULL, NULL}, {0xb3, X86_DECODE_CMD_BTR, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xba, X86_DECODE_CMD_INVL, 0, true, decode_modrm_rm, decode_imm8, - NULL, NULL, decode_btgroup, RFLAGS_MASK_OSZAPC}, + NULL, NULL, decode_btgroup}, {0xbb, X86_DECODE_CMD_BTC, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xbc, X86_DECODE_CMD_BSF, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xbd, X86_DECODE_CMD_BSR, 0, true, decode_modrm_reg, decode_modrm_rm, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xc1, X86_DECODE_CMD_XADD, 0, true, decode_modrm_rm, decode_modrm_reg, - NULL, NULL, NULL, RFLAGS_MASK_OSZAPC}, + NULL, NULL, NULL}, {0xc7, X86_DECODE_CMD_CMPXCHG8B, 0, true, decode_modrm_rm, - NULL, NULL, NULL, NULL, RFLAGS_MASK_ZF}, + NULL, NULL, NULL, NULL}, {0xc8, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xc9, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xca, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xcb, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xcc, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xcd, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xce, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, {0xcf, X86_DECODE_CMD_BSWAP, 0, false, - NULL, NULL, NULL, NULL, decode_bswap, RFLAGS_MASK_NONE}, + NULL, NULL, NULL, NULL, decode_bswap}, }; struct decode_x87_tbl invl_inst_x87 = {0x0, 0, 0, 0, 0, false, false, NULL, @@ -1427,207 +1412,207 @@ struct decode_x87_tbl invl_inst_x87 = {0x0, 0, 0, 0, 0, false, false, NULL, struct decode_x87_tbl _x87_inst[] = { {0xd8, 0, 3, X86_DECODE_CMD_FADD, 10, false, false, - decode_x87_modrm_st0, decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_decode_x87_modrm_st0, NULL}, {0xd8, 0, 0, X86_DECODE_CMD_FADD, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd8, 1, 3, X86_DECODE_CMD_FMUL, 10, false, false, decode_x87_modrm_st0, - decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_decode_x87_modrm_st0, NULL}, {0xd8, 1, 0, X86_DECODE_CMD_FMUL, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd8, 4, 3, X86_DECODE_CMD_FSUB, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xd8, 4, 0, X86_DECODE_CMD_FSUB, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd8, 5, 3, X86_DECODE_CMD_FSUB, 10, true, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xd8, 5, 0, X86_DECODE_CMD_FSUB, 4, true, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd8, 6, 3, X86_DECODE_CMD_FDIV, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xd8, 6, 0, X86_DECODE_CMD_FDIV, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd8, 7, 3, X86_DECODE_CMD_FDIV, 10, true, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xd8, 7, 0, X86_DECODE_CMD_FDIV, 4, true, false, decode_x87_modrm_st0, - decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL}, {0xd9, 0, 3, X86_DECODE_CMD_FLD, 10, false, false, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xd9, 0, 0, X86_DECODE_CMD_FLD, 4, false, false, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xd9, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xd9, 1, 0, X86_DECODE_CMD_INVL, 10, false, false, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xd9, 2, 3, X86_DECODE_CMD_INVL, 10, false, false, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xd9, 2, 0, X86_DECODE_CMD_FST, 4, false, false, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xd9, 3, 3, X86_DECODE_CMD_INVL, 10, false, false, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xd9, 3, 0, X86_DECODE_CMD_FST, 4, false, true, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xd9, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, - decode_x87_modrm_st0, NULL, decode_d9_4, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, decode_d9_4}, {0xd9, 4, 0, X86_DECODE_CMD_INVL, 4, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xd9, 5, 3, X86_DECODE_CMD_FLDxx, 10, false, false, NULL, NULL, NULL, RFLAGS_MASK_NONE}, {0xd9, 5, 0, X86_DECODE_CMD_FLDCW, 2, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xd9, 7, 3, X86_DECODE_CMD_FNSTCW, 2, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xd9, 7, 0, X86_DECODE_CMD_FNSTCW, 2, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xda, 0, 3, X86_DECODE_CMD_FCMOV, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xda, 0, 0, X86_DECODE_CMD_FADD, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xda, 1, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, - decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_decode_x87_modrm_st0, NULL}, {0xda, 1, 0, X86_DECODE_CMD_FMUL, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xda, 2, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xda, 3, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xda, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, RFLAGS_MASK_NONE}, {0xda, 4, 0, X86_DECODE_CMD_FSUB, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xda, 5, 3, X86_DECODE_CMD_FUCOM, 10, false, true, decode_x87_modrm_st0, - decode_decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_decode_x87_modrm_st0, NULL}, {0xda, 5, 0, X86_DECODE_CMD_FSUB, 4, true, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xda, 6, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, RFLAGS_MASK_NONE}, {0xda, 6, 0, X86_DECODE_CMD_FDIV, 4, false, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xda, 7, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, RFLAGS_MASK_NONE}, {0xda, 7, 0, X86_DECODE_CMD_FDIV, 4, true, false, decode_x87_modrm_st0, - decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL}, {0xdb, 0, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, - decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL}, {0xdb, 0, 0, X86_DECODE_CMD_FLD, 4, false, false, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdb, 1, 3, X86_DECODE_CMD_FCMOV, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdb, 2, 3, X86_DECODE_CMD_FCMOV, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdb, 2, 0, X86_DECODE_CMD_FST, 4, false, false, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdb, 3, 3, X86_DECODE_CMD_FCMOV, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdb, 3, 0, X86_DECODE_CMD_FST, 4, false, true, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdb, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, - decode_db_4, RFLAGS_MASK_NONE}, + decode_db_4}, {0xdb, 4, 0, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, RFLAGS_MASK_NONE}, {0xdb, 5, 3, X86_DECODE_CMD_FUCOMI, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdb, 5, 0, X86_DECODE_CMD_FLD, 10, false, false, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xdb, 7, 0, X86_DECODE_CMD_FST, 10, false, true, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xdc, 0, 3, X86_DECODE_CMD_FADD, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 0, 0, X86_DECODE_CMD_FADD, 8, false, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdc, 1, 3, X86_DECODE_CMD_FMUL, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 1, 0, X86_DECODE_CMD_FMUL, 8, false, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdc, 4, 3, X86_DECODE_CMD_FSUB, 10, true, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 4, 0, X86_DECODE_CMD_FSUB, 8, false, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdc, 5, 3, X86_DECODE_CMD_FSUB, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 5, 0, X86_DECODE_CMD_FSUB, 8, true, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdc, 6, 3, X86_DECODE_CMD_FDIV, 10, true, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 6, 0, X86_DECODE_CMD_FDIV, 8, false, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdc, 7, 3, X86_DECODE_CMD_FDIV, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdc, 7, 0, X86_DECODE_CMD_FDIV, 8, true, false, - decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_floatp, NULL}, {0xdd, 0, 0, X86_DECODE_CMD_FLD, 8, false, false, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xdd, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdd, 2, 3, X86_DECODE_CMD_FST, 10, false, false, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xdd, 2, 0, X86_DECODE_CMD_FST, 8, false, false, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xdd, 3, 3, X86_DECODE_CMD_FST, 10, false, true, - decode_x87_modrm_st0, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, NULL, NULL}, {0xdd, 3, 0, X86_DECODE_CMD_FST, 8, false, true, - decode_x87_modrm_floatp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_floatp, NULL, NULL}, {0xdd, 4, 3, X86_DECODE_CMD_FUCOM, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdd, 4, 0, X86_DECODE_CMD_FRSTOR, 8, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xdd, 5, 3, X86_DECODE_CMD_FUCOM, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdd, 7, 0, X86_DECODE_CMD_FNSTSW, 0, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xdd, 7, 3, X86_DECODE_CMD_FNSTSW, 0, false, false, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xde, 0, 3, X86_DECODE_CMD_FADD, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 0, 0, X86_DECODE_CMD_FADD, 2, false, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xde, 1, 3, X86_DECODE_CMD_FMUL, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 1, 0, X86_DECODE_CMD_FMUL, 2, false, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xde, 4, 3, X86_DECODE_CMD_FSUB, 10, true, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 4, 0, X86_DECODE_CMD_FSUB, 2, false, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xde, 5, 3, X86_DECODE_CMD_FSUB, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 5, 0, X86_DECODE_CMD_FSUB, 2, true, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xde, 6, 3, X86_DECODE_CMD_FDIV, 10, true, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 6, 0, X86_DECODE_CMD_FDIV, 2, false, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xde, 7, 3, X86_DECODE_CMD_FDIV, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xde, 7, 0, X86_DECODE_CMD_FDIV, 2, true, false, - decode_x87_modrm_st0, decode_x87_modrm_intp, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xdf, 0, 0, X86_DECODE_CMD_FLD, 2, false, false, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdf, 1, 3, X86_DECODE_CMD_FXCH, 10, false, false, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdf, 2, 3, X86_DECODE_CMD_FST, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdf, 2, 0, X86_DECODE_CMD_FST, 2, false, false, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdf, 3, 3, X86_DECODE_CMD_FST, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdf, 3, 0, X86_DECODE_CMD_FST, 2, false, true, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdf, 4, 3, X86_DECODE_CMD_FNSTSW, 2, false, true, - decode_x87_modrm_bytep, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_bytep, NULL, NULL}, {0xdf, 5, 3, X86_DECODE_CMD_FUCOMI, 10, false, true, - decode_x87_modrm_st0, decode_x87_modrm_st0, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdf, 5, 0, X86_DECODE_CMD_FLD, 8, false, false, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, {0xdf, 7, 0, X86_DECODE_CMD_FST, 8, false, true, - decode_x87_modrm_intp, NULL, NULL, RFLAGS_MASK_NONE}, + decode_x87_modrm_intp, NULL, NULL}, }; void calc_modrm_operand16(CPUX86State *env, struct x86_decode *decode, @@ -2045,7 +2030,6 @@ static inline void decode_opcode_general(CPUX86State *env, if (inst_decoder->operand_size) { decode->operand_size = inst_decoder->operand_size; } - decode->flags_mask = inst_decoder->flags_mask; if (inst_decoder->is_modrm) { decode_modrm(env, decode); diff --git a/target/i386/emulate/x86_decode.h b/target/i386/emulate/x86_decode.h index 930d965164..87cc728598 100644 --- a/target/i386/emulate/x86_decode.h +++ b/target/i386/emulate/x86_decode.h @@ -295,8 +295,6 @@ typedef struct x86_decode { struct x86_modrm modrm; struct x86_decode_op op[4]; bool is_fpu; - uint32_t flags_mask; - } x86_decode; uint64_t sign(uint64_t val, int size); From ae39acef49e29169f90cd3a799d6cd0b50bc65d2 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Thu, 10 Apr 2025 15:56:19 +0800 Subject: [PATCH 0034/2760] i386/cpu: Consolidate the helper to get Host's vendor Extend host_cpu_vendor_fms() to help more cases to get Host's vendor information. Cc: Dongli Zhang Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250410075619.145792-1-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- target/i386/host-cpu.c | 10 ++++++---- target/i386/kvm/vmsr_energy.c | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index 3e4e85e729..072731a4dd 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -109,9 +109,13 @@ void host_cpu_vendor_fms(char *vendor, int *family, int *model, int *stepping) { uint32_t eax, ebx, ecx, edx; - host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); + host_cpuid(0x0, 0, NULL, &ebx, &ecx, &edx); x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + if (!family && !model && !stepping) { + return; + } + host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); if (family) { *family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); @@ -129,11 +133,9 @@ void host_cpu_instance_init(X86CPU *cpu) X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu); if (xcc->model) { - uint32_t ebx = 0, ecx = 0, edx = 0; char vendor[CPUID_VENDOR_SZ + 1]; - host_cpuid(0, 0, NULL, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(vendor, ebx, edx, ecx); + host_cpu_vendor_fms(vendor, NULL, NULL, NULL); object_property_set_str(OBJECT(cpu), "vendor", vendor, &error_abort); } } diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c index 31508d4e77..f499ec6e8b 100644 --- a/target/i386/kvm/vmsr_energy.c +++ b/target/i386/kvm/vmsr_energy.c @@ -29,10 +29,9 @@ char *vmsr_compute_default_paths(void) bool is_host_cpu_intel(void) { - int family, model, stepping; char vendor[CPUID_VENDOR_SZ + 1]; - host_cpu_vendor_fms(vendor, &family, &model, &stepping); + host_cpu_vendor_fms(vendor, NULL, NULL, NULL); return g_str_equal(vendor, CPUID_VENDOR_INTEL); } From 1da8f3a3c53b604edfe0d55e475102640490549e Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Tue, 22 Apr 2025 15:09:23 -0400 Subject: [PATCH 0035/2760] Open 10.1 development tree Signed-off-by: Stefan Hajnoczi --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a13e7b9c87..54e6ccf854 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -10.0.0 +10.0.50 From 6b661b7ed7cd02c54a78426d5eb7dd8543b030ed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 23 Mar 2025 10:16:23 -0700 Subject: [PATCH 0036/2760] target/avr: Improve decode of LDS, STS The comment about not being able to define a field with zero bits is out of date since 94597b6146f3 ("decodetree: Allow !function with no input bits"). This fixes the missing load of imm in the disassembler. Cc: qemu-stable@nongnu.org Fixes: 9d8caa67a24 ("target/avr: Add support for disassembling via option '-d in_asm'") Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/insn.decode | 7 ++----- target/avr/translate.c | 2 -- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/target/avr/insn.decode b/target/avr/insn.decode index 482c23ad0c..cc302249db 100644 --- a/target/avr/insn.decode +++ b/target/avr/insn.decode @@ -118,11 +118,8 @@ BRBC 1111 01 ....... ... @op_bit_imm @io_rd_imm .... . .. ..... .... &rd_imm rd=%rd imm=%io_imm @ldst_d .. . . .. . rd:5 . ... &rd_imm imm=%ldst_d_imm -# The 16-bit immediate is completely in the next word. -# Fields cannot be defined with no bits, so we cannot play -# the same trick and append to a zero-bit value. -# Defer reading the immediate until trans_{LDS,STS}. -@ldst_s .... ... rd:5 .... imm=0 +%ldst_imm !function=next_word +@ldst_s .... ... rd:5 .... imm=%ldst_imm MOV 0010 11 . ..... .... @op_rd_rr MOVW 0000 0001 .... .... &rd_rr rd=%rd_d rr=%rr_d diff --git a/target/avr/translate.c b/target/avr/translate.c index 4ab71d8138..e7f8ced9b3 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -1578,7 +1578,6 @@ static bool trans_LDS(DisasContext *ctx, arg_LDS *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; - a->imm = next_word(ctx); tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ tcg_gen_shli_tl(addr, addr, 16); @@ -1783,7 +1782,6 @@ static bool trans_STS(DisasContext *ctx, arg_STS *a) TCGv Rd = cpu_r[a->rd]; TCGv addr = tcg_temp_new_i32(); TCGv H = cpu_rampD; - a->imm = next_word(ctx); tcg_gen_mov_tl(addr, H); /* addr = H:M:L */ tcg_gen_shli_tl(addr, addr, 16); From 29bcd5a46a9de61587f490d92c5a5500b2684f22 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Mar 2025 14:31:26 -0700 Subject: [PATCH 0037/2760] target/avr: Remove OFFSET_CPU_REGISTERS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This define isn't really used. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/cpu.h | 2 -- target/avr/helper.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 06f5ae4d1b..84a8f5cc8c 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -60,8 +60,6 @@ #define OFFSET_CODE 0x00000000 /* CPU registers, IO registers, and SRAM */ #define OFFSET_DATA 0x00800000 -/* CPU registers specifically, these are mapped at the start of data */ -#define OFFSET_CPU_REGISTERS OFFSET_DATA /* * IO registers, including status register, stack pointer, and memory * mapped peripherals, mapped just after CPU registers diff --git a/target/avr/helper.c b/target/avr/helper.c index 3412312ad5..e5bf16c6b7 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -340,8 +340,7 @@ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) env->fullacc = false; /* Following logic assumes this: */ - assert(OFFSET_CPU_REGISTERS == OFFSET_DATA); - assert(OFFSET_IO_REGISTERS == OFFSET_CPU_REGISTERS + + assert(OFFSET_IO_REGISTERS == OFFSET_DATA + NUMBER_OF_CPU_REGISTERS); if (addr < NUMBER_OF_CPU_REGISTERS) { From a2860ff908da0d71ce25adcb02388fe26b467390 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 08:58:56 -0700 Subject: [PATCH 0038/2760] target/avr: Add defines for i/o port registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/cpu.h | 10 ++++++++++ target/avr/helper.c | 36 ++++++++++++++++++------------------ 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 84a8f5cc8c..1a5a5b8e3e 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -47,6 +47,16 @@ /* Number of IO registers accessible by ld/st/in/out */ #define NUMBER_OF_IO_REGISTERS 64 +/* CPU registers mapped into i/o ports 0x38-0x3f. */ +#define REG_38_RAMPD 0 +#define REG_38_RAMPX 1 +#define REG_38_RAMPY 2 +#define REG_38_RAMPZ 3 +#define REG_38_EIDN 4 +#define REG_38_SPL 5 +#define REG_38_SPH 6 +#define REG_38_SREG 7 + /* * Offsets of AVR memory regions in host memory space. * diff --git a/target/avr/helper.c b/target/avr/helper.c index e5bf16c6b7..f8ada8b106 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -216,29 +216,29 @@ target_ulong helper_inb(CPUAVRState *env, uint32_t port) { target_ulong data = 0; - switch (port) { - case 0x38: /* RAMPD */ + switch (port - 0x38) { + case REG_38_RAMPD: data = 0xff & (env->rampD >> 16); break; - case 0x39: /* RAMPX */ + case REG_38_RAMPX: data = 0xff & (env->rampX >> 16); break; - case 0x3a: /* RAMPY */ + case REG_38_RAMPY: data = 0xff & (env->rampY >> 16); break; - case 0x3b: /* RAMPZ */ + case REG_38_RAMPZ: data = 0xff & (env->rampZ >> 16); break; - case 0x3c: /* EIND */ + case REG_38_EIDN: data = 0xff & (env->eind >> 16); break; - case 0x3d: /* SPL */ + case REG_38_SPL: data = env->sp & 0x00ff; break; - case 0x3e: /* SPH */ + case REG_38_SPH: data = env->sp >> 8; break; - case 0x3f: /* SREG */ + case REG_38_SREG: data = cpu_get_sreg(env); break; default: @@ -265,39 +265,39 @@ void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) { data &= 0x000000ff; - switch (port) { - case 0x38: /* RAMPD */ + switch (port - 0x38) { + case REG_38_RAMPD: if (avr_feature(env, AVR_FEATURE_RAMPD)) { env->rampD = (data & 0xff) << 16; } break; - case 0x39: /* RAMPX */ + case REG_38_RAMPX: if (avr_feature(env, AVR_FEATURE_RAMPX)) { env->rampX = (data & 0xff) << 16; } break; - case 0x3a: /* RAMPY */ + case REG_38_RAMPY: if (avr_feature(env, AVR_FEATURE_RAMPY)) { env->rampY = (data & 0xff) << 16; } break; - case 0x3b: /* RAMPZ */ + case REG_38_RAMPZ: if (avr_feature(env, AVR_FEATURE_RAMPZ)) { env->rampZ = (data & 0xff) << 16; } break; - case 0x3c: /* EIDN */ + case REG_38_EIDN: env->eind = (data & 0xff) << 16; break; - case 0x3d: /* SPL */ + case REG_38_SPL: env->sp = (env->sp & 0xff00) | (data); break; - case 0x3e: /* SPH */ + case REG_38_SPH: if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { env->sp = (env->sp & 0x00ff) | (data << 8); } break; - case 0x3f: /* SREG */ + case REG_38_SREG: cpu_set_sreg(env, data); break; default: From 204a7bd85686601e7c60d1d23502540a8d9661bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Mar 2025 17:14:27 -0700 Subject: [PATCH 0039/2760] target/avr: Move cpu register accesses into system memory Integrate the i/o 0x00-0x1f and 0x38-0x3f loopbacks into the cpu registers with normal address space accesses. We no longer need to trap accesses to the first page within avr_cpu_tlb_fill but can wait until a write occurs. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/cpu.c | 16 +++ target/avr/cpu.h | 7 ++ target/avr/helper.c | 223 +++++++++++++++++------------------------ target/avr/helper.h | 3 - target/avr/translate.c | 42 ++++---- 5 files changed, 138 insertions(+), 153 deletions(-) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 834c7082aa..0b14b36c17 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -23,6 +23,7 @@ #include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "exec/translation-block.h" +#include "exec/address-spaces.h" #include "cpu.h" #include "disas/dis-asm.h" #include "tcg/debug-assert.h" @@ -110,6 +111,8 @@ static void avr_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) static void avr_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); + CPUAVRState *env = cpu_env(cs); + AVRCPU *cpu = env_archcpu(env); AVRCPUClass *mcc = AVR_CPU_GET_CLASS(dev); Error *local_err = NULL; @@ -122,6 +125,19 @@ static void avr_cpu_realizefn(DeviceState *dev, Error **errp) cpu_reset(cs); mcc->parent_realize(dev, errp); + + /* + * Two blocks in the low data space loop back into cpu registers. + */ + memory_region_init_io(&cpu->cpu_reg1, OBJECT(cpu), &avr_cpu_reg1, env, + "avr-cpu-reg1", 32); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA, &cpu->cpu_reg1); + + memory_region_init_io(&cpu->cpu_reg2, OBJECT(cpu), &avr_cpu_reg2, env, + "avr-cpu-reg2", 8); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + 0x58, &cpu->cpu_reg2); } static void avr_cpu_set_int(void *opaque, int irq, int level) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 1a5a5b8e3e..6f68060ab0 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -23,6 +23,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/memory.h" #ifdef CONFIG_USER_ONLY #error "AVR 8-bit does not support user mode" @@ -152,6 +153,9 @@ struct ArchCPU { CPUAVRState env; + MemoryRegion cpu_reg1; + MemoryRegion cpu_reg2; + /* Initial value of stack pointer */ uint32_t init_sp; }; @@ -252,6 +256,9 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); +extern const MemoryRegionOps avr_cpu_reg1; +extern const MemoryRegionOps avr_cpu_reg2; + #include "exec/cpu-all.h" #endif /* QEMU_AVR_CPU_H */ diff --git a/target/avr/helper.c b/target/avr/helper.c index f8ada8b106..d0e86f5614 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -108,7 +108,7 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr) { - int prot, page_size = TARGET_PAGE_SIZE; + int prot; uint32_t paddr; address &= TARGET_PAGE_MASK; @@ -133,23 +133,9 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, /* Access to memory. */ paddr = OFFSET_DATA + address; prot = PAGE_READ | PAGE_WRITE; - if (address < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* - * Access to CPU registers, exit and rebuilt this TB to use - * full access in case it touches specially handled registers - * like SREG or SP. For probing, set page_size = 1, in order - * to force tlb_fill to be called for the next access. - */ - if (probe) { - page_size = 1; - } else { - cpu_env(cs)->fullacc = 1; - cpu_loop_exit_restore(cs, retaddr); - } - } } - tlb_set_page(cs, address, paddr, prot, mmu_idx, page_size); + tlb_set_page(cs, address, paddr, prot, mmu_idx, TARGET_PAGE_SIZE); return true; } @@ -203,134 +189,78 @@ void helper_wdr(CPUAVRState *env) } /* - * This function implements IN instruction - * - * It does the following - * a. if an IO register belongs to CPU, its value is read and returned - * b. otherwise io address is translated to mem address and physical memory - * is read. - * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation - * + * The first 32 bytes of the data space are mapped to the cpu regs. + * We cannot write these from normal store operations because TCG + * does not expect global temps to be modified -- a global may be + * live in a host cpu register across the store. We can however + * read these, as TCG does make sure the global temps are saved + * in case the load operation traps. */ -target_ulong helper_inb(CPUAVRState *env, uint32_t port) + +static uint64_t avr_cpu_reg1_read(void *opaque, hwaddr addr, unsigned size) { - target_ulong data = 0; + CPUAVRState *env = opaque; - switch (port - 0x38) { - case REG_38_RAMPD: - data = 0xff & (env->rampD >> 16); - break; - case REG_38_RAMPX: - data = 0xff & (env->rampX >> 16); - break; - case REG_38_RAMPY: - data = 0xff & (env->rampY >> 16); - break; - case REG_38_RAMPZ: - data = 0xff & (env->rampZ >> 16); - break; - case REG_38_EIDN: - data = 0xff & (env->eind >> 16); - break; - case REG_38_SPL: - data = env->sp & 0x00ff; - break; - case REG_38_SPH: - data = env->sp >> 8; - break; - case REG_38_SREG: - data = cpu_get_sreg(env); - break; - default: - /* not a special register, pass to normal memory access */ - data = address_space_ldub(&address_space_memory, - OFFSET_IO_REGISTERS + port, - MEMTXATTRS_UNSPECIFIED, NULL); - } - - return data; + assert(addr < 32); + return env->r[addr]; } /* - * This function implements OUT instruction - * - * It does the following - * a. if an IO register belongs to CPU, its value is written into the register - * b. otherwise io address is translated to mem address and physical memory - * is written. - * c. it caches the value for sake of SBI, SBIC, SBIS & CBI implementation - * + * The range 0x38-0x3f of the i/o space is mapped to cpu regs. + * As above, we cannot write these from normal store operations. */ -void helper_outb(CPUAVRState *env, uint32_t port, uint32_t data) -{ - data &= 0x000000ff; - switch (port - 0x38) { +static uint64_t avr_cpu_reg2_read(void *opaque, hwaddr addr, unsigned size) +{ + CPUAVRState *env = opaque; + + switch (addr) { case REG_38_RAMPD: - if (avr_feature(env, AVR_FEATURE_RAMPD)) { - env->rampD = (data & 0xff) << 16; - } - break; + return 0xff & (env->rampD >> 16); case REG_38_RAMPX: - if (avr_feature(env, AVR_FEATURE_RAMPX)) { - env->rampX = (data & 0xff) << 16; - } - break; + return 0xff & (env->rampX >> 16); case REG_38_RAMPY: - if (avr_feature(env, AVR_FEATURE_RAMPY)) { - env->rampY = (data & 0xff) << 16; - } - break; + return 0xff & (env->rampY >> 16); case REG_38_RAMPZ: - if (avr_feature(env, AVR_FEATURE_RAMPZ)) { - env->rampZ = (data & 0xff) << 16; - } - break; + return 0xff & (env->rampZ >> 16); case REG_38_EIDN: - env->eind = (data & 0xff) << 16; - break; + return 0xff & (env->eind >> 16); case REG_38_SPL: - env->sp = (env->sp & 0xff00) | (data); - break; + return env->sp & 0x00ff; case REG_38_SPH: - if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { - env->sp = (env->sp & 0x00ff) | (data << 8); - } - break; + return 0xff & (env->sp >> 8); case REG_38_SREG: - cpu_set_sreg(env, data); - break; - default: - /* not a special register, pass to normal memory access */ - address_space_stb(&address_space_memory, OFFSET_IO_REGISTERS + port, - data, MEMTXATTRS_UNSPECIFIED, NULL); + return cpu_get_sreg(env); } + g_assert_not_reached(); } -/* - * this function implements LD instruction when there is a possibility to read - * from a CPU register - */ -target_ulong helper_fullrd(CPUAVRState *env, uint32_t addr) +static void avr_cpu_trap_write(void *opaque, hwaddr addr, + uint64_t data64, unsigned size) { - uint8_t data; + CPUAVRState *env = opaque; + CPUState *cs = env_cpu(env); - env->fullacc = false; - - if (addr < NUMBER_OF_CPU_REGISTERS) { - /* CPU registers */ - data = env->r[addr]; - } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* IO registers */ - data = helper_inb(env, addr - NUMBER_OF_CPU_REGISTERS); - } else { - /* memory */ - data = address_space_ldub(&address_space_memory, OFFSET_DATA + addr, - MEMTXATTRS_UNSPECIFIED, NULL); - } - return data; + env->fullacc = true; + cpu_loop_exit_restore(cs, cs->mem_io_pc); } +const MemoryRegionOps avr_cpu_reg1 = { + .read = avr_cpu_reg1_read, + .write = avr_cpu_trap_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 1, +}; + +const MemoryRegionOps avr_cpu_reg2 = { + .read = avr_cpu_reg2_read, + .write = avr_cpu_trap_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid.min_access_size = 1, + .valid.max_access_size = 1, +}; + /* * this function implements ST instruction when there is a possibility to write * into a CPU register @@ -339,19 +269,50 @@ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) { env->fullacc = false; - /* Following logic assumes this: */ - assert(OFFSET_IO_REGISTERS == OFFSET_DATA + - NUMBER_OF_CPU_REGISTERS); - - if (addr < NUMBER_OF_CPU_REGISTERS) { + switch (addr) { + case 0 ... 31: /* CPU registers */ env->r[addr] = data; - } else if (addr < NUMBER_OF_CPU_REGISTERS + NUMBER_OF_IO_REGISTERS) { - /* IO registers */ - helper_outb(env, addr - NUMBER_OF_CPU_REGISTERS, data); - } else { - /* memory */ + break; + + case REG_38_RAMPD + 0x38 + NUMBER_OF_CPU_REGISTERS: + if (avr_feature(env, AVR_FEATURE_RAMPD)) { + env->rampD = data << 16; + } + break; + case REG_38_RAMPX + 0x38 + NUMBER_OF_CPU_REGISTERS: + if (avr_feature(env, AVR_FEATURE_RAMPX)) { + env->rampX = data << 16; + } + break; + case REG_38_RAMPY + 0x38 + NUMBER_OF_CPU_REGISTERS: + if (avr_feature(env, AVR_FEATURE_RAMPY)) { + env->rampY = data << 16; + } + break; + case REG_38_RAMPZ + 0x38 + NUMBER_OF_CPU_REGISTERS: + if (avr_feature(env, AVR_FEATURE_RAMPZ)) { + env->rampZ = data << 16; + } + break; + case REG_38_EIDN + 0x38 + NUMBER_OF_CPU_REGISTERS: + env->eind = data << 16; + break; + case REG_38_SPL + 0x38 + NUMBER_OF_CPU_REGISTERS: + env->sp = (env->sp & 0xff00) | data; + break; + case REG_38_SPH + 0x38 + NUMBER_OF_CPU_REGISTERS: + if (avr_feature(env, AVR_FEATURE_2_BYTE_SP)) { + env->sp = (env->sp & 0x00ff) | (data << 8); + } + break; + case REG_38_SREG + 0x38 + NUMBER_OF_CPU_REGISTERS: + cpu_set_sreg(env, data); + break; + + default: address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, MEMTXATTRS_UNSPECIFIED, NULL); + break; } } diff --git a/target/avr/helper.h b/target/avr/helper.h index 4d02e648fa..e8d13e925f 100644 --- a/target/avr/helper.h +++ b/target/avr/helper.h @@ -23,7 +23,4 @@ DEF_HELPER_1(debug, noreturn, env) DEF_HELPER_1(break, noreturn, env) DEF_HELPER_1(sleep, noreturn, env) DEF_HELPER_1(unsupported, noreturn, env) -DEF_HELPER_3(outb, void, env, i32, i32) -DEF_HELPER_2(inb, tl, env, i32) DEF_HELPER_3(fullwr, void, env, i32, i32) -DEF_HELPER_2(fullrd, tl, env, i32) diff --git a/target/avr/translate.c b/target/avr/translate.c index e7f8ced9b3..0490936cd5 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -194,6 +194,9 @@ static bool avr_have_feature(DisasContext *ctx, int feature) static bool decode_insn(DisasContext *ctx, uint16_t insn); #include "decode-insn.c.inc" +static void gen_inb(DisasContext *ctx, TCGv data, int port); +static void gen_outb(DisasContext *ctx, TCGv data, int port); + /* * Arithmetic Instructions */ @@ -1293,9 +1296,8 @@ static bool trans_SBRS(DisasContext *ctx, arg_SBRS *a) static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_EQ; ctx->skip_var0 = data; @@ -1311,9 +1313,8 @@ static bool trans_SBIC(DisasContext *ctx, arg_SBIC *a) static bool trans_SBIS(DisasContext *ctx, arg_SBIS *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, 1 << a->bit); ctx->skip_cond = TCG_COND_NE; ctx->skip_var0 = data; @@ -1502,11 +1503,18 @@ static void gen_data_store(DisasContext *ctx, TCGv data, TCGv addr) static void gen_data_load(DisasContext *ctx, TCGv data, TCGv addr) { - if (ctx->base.tb->flags & TB_FLAGS_FULL_ACCESS) { - gen_helper_fullrd(data, tcg_env, addr); - } else { - tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB); - } + tcg_gen_qemu_ld_tl(data, addr, MMU_DATA_IDX, MO_UB); +} + +static void gen_inb(DisasContext *ctx, TCGv data, int port) +{ + gen_data_load(ctx, data, tcg_constant_i32(port + NUMBER_OF_CPU_REGISTERS)); +} + +static void gen_outb(DisasContext *ctx, TCGv data, int port) +{ + gen_helper_fullwr(tcg_env, data, + tcg_constant_i32(port + NUMBER_OF_CPU_REGISTERS)); } /* @@ -2126,9 +2134,8 @@ static bool trans_SPMX(DisasContext *ctx, arg_SPMX *a) static bool trans_IN(DisasContext *ctx, arg_IN *a) { TCGv Rd = cpu_r[a->rd]; - TCGv port = tcg_constant_i32(a->imm); - gen_helper_inb(Rd, tcg_env, port); + gen_inb(ctx, Rd, a->imm); return true; } @@ -2139,9 +2146,8 @@ static bool trans_IN(DisasContext *ctx, arg_IN *a) static bool trans_OUT(DisasContext *ctx, arg_OUT *a) { TCGv Rd = cpu_r[a->rd]; - TCGv port = tcg_constant_i32(a->imm); - gen_helper_outb(tcg_env, port, Rd); + gen_outb(ctx, Rd, a->imm); return true; } @@ -2407,11 +2413,10 @@ static bool trans_SWAP(DisasContext *ctx, arg_SWAP *a) static bool trans_SBI(DisasContext *ctx, arg_SBI *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_ori_tl(data, data, 1 << a->bit); - gen_helper_outb(tcg_env, port, data); + gen_outb(ctx, data, a->reg); return true; } @@ -2422,11 +2427,10 @@ static bool trans_SBI(DisasContext *ctx, arg_SBI *a) static bool trans_CBI(DisasContext *ctx, arg_CBI *a) { TCGv data = tcg_temp_new_i32(); - TCGv port = tcg_constant_i32(a->reg); - gen_helper_inb(data, tcg_env, port); + gen_inb(ctx, data, a->reg); tcg_gen_andi_tl(data, data, ~(1 << a->bit)); - gen_helper_outb(tcg_env, port, data); + gen_outb(ctx, data, a->reg); return true; } From ba675861ea6f1f8b3eeee4a2d64b47204b883ab1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 08:37:49 -0700 Subject: [PATCH 0040/2760] target/avr: Remove NUMBER_OF_IO_REGISTERS This define is no longer used. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/cpu.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 6f68060ab0..9862705c6a 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -45,8 +45,6 @@ /* Number of CPU registers */ #define NUMBER_OF_CPU_REGISTERS 32 -/* Number of IO registers accessible by ld/st/in/out */ -#define NUMBER_OF_IO_REGISTERS 64 /* CPU registers mapped into i/o ports 0x38-0x3f. */ #define REG_38_RAMPD 0 From c0f830cb6a756add847f9cd9d62d50397a1284c1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 21 Mar 2025 18:19:28 -0700 Subject: [PATCH 0041/2760] target/avr: Use cpu_stb_mmuidx_ra in helper_fullwr Avoid direct use of address_space_memory. Make use of the softmmu cache of the i/o page. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/helper.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target/avr/helper.c b/target/avr/helper.c index d0e86f5614..7d6954ec26 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -23,10 +23,10 @@ #include "qemu/error-report.h" #include "cpu.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/getpc.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" #include "exec/helper-proto.h" bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) @@ -67,6 +67,11 @@ bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) return false; } +static void do_stb(CPUAVRState *env, uint32_t addr, uint8_t data, uintptr_t ra) +{ + cpu_stb_mmuidx_ra(env, addr, data, MMU_DATA_IDX, ra); +} + void avr_cpu_do_interrupt(CPUState *cs) { CPUAVRState *env = cpu_env(cs); @@ -311,8 +316,7 @@ void helper_fullwr(CPUAVRState *env, uint32_t data, uint32_t addr) break; default: - address_space_stb(&address_space_memory, OFFSET_DATA + addr, data, - MEMTXATTRS_UNSPECIFIED, NULL); + do_stb(env, addr, data, GETPC()); break; } } From 95d4f72d6a667c71adae8a3c8093efe32043d9b4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Mar 2025 20:10:28 -0700 Subject: [PATCH 0042/2760] target/avr: Use do_stb in avr_cpu_do_interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/avr/helper.c b/target/avr/helper.c index 7d6954ec26..f23fa3e8ba 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -88,14 +88,14 @@ void avr_cpu_do_interrupt(CPUState *cs) } if (avr_feature(env, AVR_FEATURE_3_BYTE_PC)) { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); - cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); - cpu_stb_data(env, env->sp--, (ret & 0xff0000) >> 16); + do_stb(env, env->sp--, ret, 0); + do_stb(env, env->sp--, ret >> 8, 0); + do_stb(env, env->sp--, ret >> 16, 0); } else if (avr_feature(env, AVR_FEATURE_2_BYTE_PC)) { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); - cpu_stb_data(env, env->sp--, (ret & 0x00ff00) >> 8); + do_stb(env, env->sp--, ret, 0); + do_stb(env, env->sp--, ret >> 8, 0); } else { - cpu_stb_data(env, env->sp--, (ret & 0x0000ff)); + do_stb(env, env->sp--, ret, 0); } env->pc_w = base + vector * size; From 9f99072fc08e1044700404ae0a5f13a30a0a2a60 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 15:26:28 -0700 Subject: [PATCH 0043/2760] hw/avr: Prepare for TARGET_PAGE_SIZE > 256 If i/o does not cover the entire first page, allocate a portion of ram as an i/o device, so that the entire first page is i/o. While memory_region_init_ram_device_ptr is happy to allocate the RAMBlock, it does not register the ram for migration. Do this by hand. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- hw/avr/atmega.c | 39 ++++++++++++++++++++++++++++++++------- hw/avr/atmega.h | 1 + 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index f6844bf118..11fab184de 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -19,6 +19,7 @@ #include "hw/sysbus.h" #include "qom/object.h" #include "hw/misc/unimp.h" +#include "migration/vmstate.h" #include "atmega.h" enum AtmegaPeripheral { @@ -224,8 +225,6 @@ static void atmega_realize(DeviceState *dev, Error **errp) char *devname; size_t i; - assert(mc->io_size <= 0x200); - if (!s->xtal_freq_hz) { error_setg(errp, "\"xtal-frequency-hz\" property must be provided."); return; @@ -240,11 +239,37 @@ static void atmega_realize(DeviceState *dev, Error **errp) qdev_realize(DEVICE(&s->cpu), NULL, &error_abort); cpudev = DEVICE(&s->cpu); - /* SRAM */ - memory_region_init_ram(&s->sram, OBJECT(dev), "sram", mc->sram_size, - &error_abort); - memory_region_add_subregion(get_system_memory(), - OFFSET_DATA + mc->io_size, &s->sram); + /* + * SRAM + * + * Softmmu is not able mix i/o and ram on the same page. + * Therefore in all cases, the first page exclusively contains i/o. + * + * If the MCU's i/o region matches the page size, then we can simply + * allocate all ram starting at the second page. Otherwise, we must + * allocate some ram as i/o to complete the first page. + */ + assert(mc->io_size == 0x100 || mc->io_size == 0x200); + if (mc->io_size >= TARGET_PAGE_SIZE) { + memory_region_init_ram(&s->sram, OBJECT(dev), "sram", mc->sram_size, + &error_abort); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + mc->io_size, &s->sram); + } else { + int sram_io_size = TARGET_PAGE_SIZE - mc->io_size; + void *sram_io_mem = g_malloc0(sram_io_size); + + memory_region_init_ram_device_ptr(&s->sram_io, OBJECT(dev), "sram-as-io", + sram_io_size, sram_io_mem); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + mc->io_size, &s->sram_io); + vmstate_register_ram(&s->sram_io, dev); + + memory_region_init_ram(&s->sram, OBJECT(dev), "sram", + mc->sram_size - sram_io_size, &error_abort); + memory_region_add_subregion(get_system_memory(), + OFFSET_DATA + TARGET_PAGE_SIZE, &s->sram); + } /* Flash */ memory_region_init_rom(&s->flash, OBJECT(dev), diff --git a/hw/avr/atmega.h b/hw/avr/atmega.h index a99ee15c7e..9ac4678231 100644 --- a/hw/avr/atmega.h +++ b/hw/avr/atmega.h @@ -41,6 +41,7 @@ struct AtmegaMcuState { MemoryRegion flash; MemoryRegion eeprom; MemoryRegion sram; + MemoryRegion sram_io; DeviceState *io; AVRMaskState pwr[POWER_MAX]; AVRUsartState usart[USART_MAX]; From eba24b60a72115e21e850977b3019aaf037c66c9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 15:32:50 -0700 Subject: [PATCH 0044/2760] target/avr: Increase TARGET_PAGE_BITS to 10 Now that we can handle the MCU allocating only a portion of the first page to i/o, increase the page size. Choose 10 as larger than the i/o on every MCU, just so that this path is tested. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/avr/cpu-param.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h index 81f3f49ee1..f5248ce9e7 100644 --- a/target/avr/cpu-param.h +++ b/target/avr/cpu-param.h @@ -21,13 +21,7 @@ #ifndef AVR_CPU_PARAM_H #define AVR_CPU_PARAM_H -/* - * TARGET_PAGE_BITS cannot be more than 8 bits because - * 1. all IO registers occupy [0x0000 .. 0x00ff] address range, and they - * should be implemented as a device and not memory - * 2. SRAM starts at the address 0x0100 - */ -#define TARGET_PAGE_BITS 8 +#define TARGET_PAGE_BITS 10 #define TARGET_PHYS_ADDR_SPACE_BITS 24 #define TARGET_VIRT_ADDR_SPACE_BITS 24 From 2de267c330381d44862a29efd9025d64c9c0e9b4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jan 2025 08:38:12 +0100 Subject: [PATCH 0045/2760] hw/s390x/s390-virtio-ccw: Remove the deprecated 2.9 machine type The s390-ccw-virtio-2.9 machine is older than 6 years, so according to our machine support policy, it can be removed now. Message-ID: <20250115073819.15452-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- hw/s390x/s390-virtio-ccw.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 75b32182eb..72de2bd8dc 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -1270,30 +1270,6 @@ static void ccw_machine_2_10_class_options(MachineClass *mc) } DEFINE_CCW_MACHINE(2, 10); -static void ccw_machine_2_9_instance_options(MachineState *machine) -{ - ccw_machine_2_10_instance_options(machine); - s390_cpudef_featoff_greater(12, 1, S390_FEAT_ESOP); - s390_cpudef_featoff_greater(12, 1, S390_FEAT_SIDE_EFFECT_ACCESS_ESOP2); - s390_cpudef_featoff_greater(12, 1, S390_FEAT_ZPCI); - s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_INT_SUPPRESSION); - s390_cpudef_featoff_greater(12, 1, S390_FEAT_ADAPTER_EVENT_NOTIFICATION); - css_migration_enabled = false; -} - -static void ccw_machine_2_9_class_options(MachineClass *mc) -{ - static GlobalProperty compat[] = { - { TYPE_S390_STATTRIB, "migration-enabled", "off", }, - { TYPE_S390_FLIC_COMMON, "migration-enabled", "off", }, - }; - - ccw_machine_2_10_class_options(mc); - compat_props_add(mc->compat_props, hw_compat_2_9, hw_compat_2_9_len); - compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); -} -DEFINE_CCW_MACHINE(2, 9); - #endif static void ccw_machine_register_types(void) From 2abe33895868c3846cd5d50a7207ca22cc98f741 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jan 2025 08:38:13 +0100 Subject: [PATCH 0046/2760] hw/s390x/css: Remove the obsolete "css_migration_enabled" variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the s390-ccw-virtio-2.9 machine type has been removed, we don't need the "css_migration_enabled" variable anymore and can remove the related code. Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250115073819.15452-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- hw/s390x/css.c | 31 +------------------------------ include/hw/s390x/css.h | 6 ------ 2 files changed, 1 insertion(+), 36 deletions(-) diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 738800c98d..17afcbb2cd 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -23,8 +23,6 @@ #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/s390-ccw.h" -bool css_migration_enabled = true; - typedef struct CrwContainer { CRW crw; QTAILQ_ENTRY(CrwContainer) sibling; @@ -180,16 +178,10 @@ static const VMStateDescription vmstate_orb = { } }; -static bool vmstate_schdev_orb_needed(void *opaque) -{ - return css_migration_enabled; -} - static const VMStateDescription vmstate_schdev_orb = { .name = "s390_subch_dev/orb", .version_id = 1, .minimum_version_id = 1, - .needed = vmstate_schdev_orb_needed, .fields = (const VMStateField[]) { VMSTATE_STRUCT(orb, SubchDev, 1, vmstate_orb, ORB), VMSTATE_END_OF_LIST() @@ -390,33 +382,12 @@ static int subch_dev_post_load(void *opaque, int version_id) css_subch_assign(s->cssid, s->ssid, s->schid, s->devno, s); } - if (css_migration_enabled) { - /* No compat voodoo to do ;) */ - return 0; - } - /* - * Hack alert. If we don't migrate the channel subsystem status - * we still need to find out if the guest enabled mss/mcss-e. - * If the subchannel is enabled, it certainly was able to access it, - * so adjust the max_ssid/max_cssid values for relevant ssid/cssid - * values. This is not watertight, but better than nothing. - */ - if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) { - if (s->ssid) { - channel_subsys.max_ssid = MAX_SSID; - } - if (s->cssid != channel_subsys.default_cssid) { - channel_subsys.max_cssid = MAX_CSSID; - } - } return 0; } void css_register_vmstate(void) { - if (css_migration_enabled) { - vmstate_register(NULL, 0, &vmstate_css, &channel_subsys); - } + vmstate_register(NULL, 0, &vmstate_css, &channel_subsys); } IndAddr *get_indicator(hwaddr ind_addr, int len) diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index cd97e2b707..dbf919bdd2 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -333,10 +333,4 @@ static inline int ccw_dstream_read_buf(CcwDataStream *cds, void *buff, int len) #define ccw_dstream_read(cds, v) ccw_dstream_read_buf((cds), &(v), sizeof(v)) #define ccw_dstream_write(cds, v) ccw_dstream_write_buf((cds), &(v), sizeof(v)) -/** - * true if (vmstate based) migration of the channel subsystem - * is enabled, false if it is disabled. - */ -extern bool css_migration_enabled; - #endif From d6305b6e613fa23882b9b7b58f6b0aec0eeef015 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jan 2025 08:38:14 +0100 Subject: [PATCH 0047/2760] hw/s390x/s390-stattrib: Remove the old migration_enabled flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the machine types that set the migration_enabled flag to false are gone, we can remove it and the related code. Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250115073819.15452-4-thuth@redhat.com> Signed-off-by: Thomas Huth --- hw/s390x/s390-stattrib-kvm.c | 2 +- hw/s390x/s390-stattrib.c | 7 +------ include/hw/s390x/storage-attributes.h | 1 - 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c index 2a8e31718b..d0ff04364d 100644 --- a/hw/s390x/s390-stattrib-kvm.c +++ b/hw/s390x/s390-stattrib-kvm.c @@ -185,7 +185,7 @@ static long long kvm_s390_stattrib_get_dirtycount(S390StAttribState *sa) static int kvm_s390_stattrib_get_active(S390StAttribState *sa) { - return kvm_s390_cmma_active() && sa->migration_enabled; + return kvm_s390_cmma_active(); } static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index be07c28c6e..35bf697ef0 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -304,7 +304,7 @@ static int qemu_s390_set_migrationmode_stub(S390StAttribState *sa, bool value, static int qemu_s390_get_active(S390StAttribState *sa) { - return sa->migration_enabled; + return true; } static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) @@ -360,10 +360,6 @@ static void s390_stattrib_realize(DeviceState *dev, Error **errp) &savevm_s390_stattrib_handlers, dev); } -static const Property s390_stattrib_props[] = { - DEFINE_PROP_BOOL("migration-enabled", S390StAttribState, migration_enabled, true), -}; - static void s390_stattrib_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -371,7 +367,6 @@ static void s390_stattrib_class_init(ObjectClass *oc, void *data) dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->realize = s390_stattrib_realize; - device_class_set_props(dc, s390_stattrib_props); } static void s390_stattrib_instance_init(Object *obj) diff --git a/include/hw/s390x/storage-attributes.h b/include/hw/s390x/storage-attributes.h index 8921a04d51..b5c6d8fa55 100644 --- a/include/hw/s390x/storage-attributes.h +++ b/include/hw/s390x/storage-attributes.h @@ -25,7 +25,6 @@ OBJECT_DECLARE_TYPE(S390StAttribState, S390StAttribClass, S390_STATTRIB) struct S390StAttribState { DeviceState parent_obj; uint64_t migration_cur_gfn; - bool migration_enabled; }; From 7c3b69feb07acbd70cbf3ce6cbd5ccbefedf5e58 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 15 Jan 2025 08:38:15 +0100 Subject: [PATCH 0048/2760] hw/intc/s390_flic: Remove the obsolete migration_enabled flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the machine types that set the migration_enabled flag to false are gone, we can remove it and the related code. Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250115073819.15452-5-thuth@redhat.com> Signed-off-by: Thomas Huth --- hw/intc/s390_flic.c | 14 -------------- include/hw/s390x/s390_flic.h | 1 - 2 files changed, 15 deletions(-) diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index c20f4c1075..4fae023197 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -470,11 +470,6 @@ static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) fsc->inject_crw_mchk = qemu_s390_inject_crw_mchk; } -static const Property s390_flic_common_properties[] = { - DEFINE_PROP_BOOL("migration-enabled", S390FLICState, - migration_enabled, true), -}; - static void s390_flic_common_realize(DeviceState *dev, Error **errp) { S390FLICState *fs = S390_FLIC_COMMON(dev); @@ -486,7 +481,6 @@ static void s390_flic_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); - device_class_set_props(dc, s390_flic_common_properties); dc->realize = s390_flic_common_realize; } @@ -515,18 +509,10 @@ static void qemu_s390_flic_register_types(void) type_init(qemu_s390_flic_register_types) -static bool adapter_info_so_needed(void *opaque) -{ - S390FLICState *fs = s390_get_flic(); - - return fs->migration_enabled; -} - const VMStateDescription vmstate_adapter_info_so = { .name = "s390_adapter_info/summary_offset", .version_id = 1, .minimum_version_id = 1, - .needed = adapter_info_so_needed, .fields = (const VMStateField[]) { VMSTATE_UINT32(summary_offset, AdapterInfo), VMSTATE_END_OF_LIST() diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h index 85016d5ccc..91edaaca40 100644 --- a/include/hw/s390x/s390_flic.h +++ b/include/hw/s390x/s390_flic.h @@ -42,7 +42,6 @@ OBJECT_DECLARE_TYPE(S390FLICState, S390FLICStateClass, struct S390FLICState { SysBusDevice parent_obj; bool ais_supported; - bool migration_enabled; }; From 4b91f6d16d4e50cf0f19d74f318d0ba61f90cc64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Mar 2025 16:14:11 +0100 Subject: [PATCH 0049/2760] hw/s390x/skeys: Declare QOM types using DEFINE_TYPES() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When multiple QOM types are registered in the same file, it is simpler to use the the DEFINE_TYPES() macro. In particular because type array declared with such macro are easier to review. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Eric Farman Reviewed-by: Thomas Huth Message-ID: <20250310151414.11550-2-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/s390x/s390-skeys.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 811d892122..d50e71b927 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -316,14 +316,6 @@ static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; } -static const TypeInfo qemu_s390_skeys_info = { - .name = TYPE_QEMU_S390_SKEYS, - .parent = TYPE_S390_SKEYS, - .instance_size = sizeof(QEMUS390SKeysState), - .class_init = qemu_s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), -}; - static void s390_storage_keys_save(QEMUFile *f, void *opaque) { S390SKeysState *ss = S390_SKEYS(opaque); @@ -481,19 +473,22 @@ static void s390_skeys_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static const TypeInfo s390_skeys_info = { - .name = TYPE_S390_SKEYS, - .parent = TYPE_DEVICE, - .instance_size = sizeof(S390SKeysState), - .class_init = s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), - .abstract = true, +static const TypeInfo s390_skeys_types[] = { + { + .name = TYPE_S390_SKEYS, + .parent = TYPE_DEVICE, + .instance_size = sizeof(S390SKeysState), + .class_init = s390_skeys_class_init, + .class_size = sizeof(S390SKeysClass), + .abstract = true, + }, + { + .name = TYPE_QEMU_S390_SKEYS, + .parent = TYPE_S390_SKEYS, + .instance_size = sizeof(QEMUS390SKeysState), + .class_init = qemu_s390_skeys_class_init, + .class_size = sizeof(S390SKeysClass), + }, }; -static void qemu_s390_skeys_register_types(void) -{ - type_register_static(&s390_skeys_info); - type_register_static(&qemu_s390_skeys_info); -} - -type_init(qemu_s390_skeys_register_types) +DEFINE_TYPES(s390_skeys_types) From 3f979fe13e405d5721f3b43b5669a462f4816569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Mar 2025 16:14:12 +0100 Subject: [PATCH 0050/2760] hw/s390x/skeys: Introduce TYPE_DUMP_SKEYS_INTERFACE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The storage keys are part of the machine memory. Introduce the TYPE_DUMP_SKEYS_INTERFACE type, allowing machine using storage keys to dump them when a DumpSKeysInterface::qmp_dump_skeys() callback is provided. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Eric Farman Reviewed-by: Thomas Huth Message-ID: <20250310151414.11550-3-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/s390x/s390-skeys.c | 5 +++++ include/hw/s390x/storage-keys.h | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index d50e71b927..0d3d4f74b4 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -474,6 +474,11 @@ static void s390_skeys_class_init(ObjectClass *oc, void *data) } static const TypeInfo s390_skeys_types[] = { + { + .name = TYPE_DUMP_SKEYS_INTERFACE, + .parent = TYPE_INTERFACE, + .class_size = sizeof(DumpSKeysInterface), + }, { .name = TYPE_S390_SKEYS, .parent = TYPE_DEVICE, diff --git a/include/hw/s390x/storage-keys.h b/include/hw/s390x/storage-keys.h index 408d2815d4..fb766d4631 100644 --- a/include/hw/s390x/storage-keys.h +++ b/include/hw/s390x/storage-keys.h @@ -125,4 +125,19 @@ S390SKeysState *s390_get_skeys_device(void); void hmp_dump_skeys(Monitor *mon, const QDict *qdict); void hmp_info_skeys(Monitor *mon, const QDict *qdict); +#define TYPE_DUMP_SKEYS_INTERFACE "dump-skeys-interface" + +typedef struct DumpSKeysInterface DumpSKeysInterface; +DECLARE_CLASS_CHECKERS(DumpSKeysInterface, DUMP_SKEYS_INTERFACE, + TYPE_DUMP_SKEYS_INTERFACE) + +struct DumpSKeysInterface { + InterfaceClass parent_class; + + /** + * @qmp_dump_skeys: Callback to dump guest's storage keys to @filename. + */ + void (*qmp_dump_skeys)(const char *filename, Error **errp); +}; + #endif /* S390_STORAGE_KEYS_H */ From 1b759bb0cdd6ee5c83bdf8ff3c6897071c5a3a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Mar 2025 16:14:13 +0100 Subject: [PATCH 0051/2760] hw/s390x/ccw: Have CCW machine implement a qmp_dump_skeys() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation to make @dump-skeys command generic, extract s390_qmp_dump_skeys() out of qmp_dump_skeys(). Register it as CCW qmp_dump_skeys() callback. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Eric Farman Message-ID: <20250310151414.11550-4-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/s390x/s390-skeys.c | 7 ++++++- hw/s390x/s390-virtio-ccw.c | 3 +++ include/hw/s390x/storage-keys.h | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 0d3d4f74b4..fd1123b0f3 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -142,7 +142,7 @@ void hmp_dump_skeys(Monitor *mon, const QDict *qdict) } } -void qmp_dump_skeys(const char *filename, Error **errp) +void s390_qmp_dump_skeys(const char *filename, Error **errp) { S390SKeysState *ss = s390_get_skeys_device(); S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); @@ -219,6 +219,11 @@ out: fclose(f); } +void qmp_dump_skeys(const char *filename, Error **errp) +{ + s390_qmp_dump_skeys(filename, errp); +} + static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss) { QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 72de2bd8dc..910dab0831 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -810,6 +810,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) NMIClass *nc = NMI_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); S390CcwMachineClass *s390mc = S390_CCW_MACHINE_CLASS(mc); + DumpSKeysInterface *dsi = DUMP_SKEYS_INTERFACE_CLASS(oc); s390mc->hpage_1m_allowed = true; s390mc->max_threads = 1; @@ -835,6 +836,7 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) nc->nmi_monitor_handler = s390_nmi; mc->default_ram_id = "s390.ram"; mc->default_nic = "virtio-net-ccw"; + dsi->qmp_dump_skeys = s390_qmp_dump_skeys; object_class_property_add_bool(oc, "aes-key-wrap", machine_get_aes_key_wrap, @@ -876,6 +878,7 @@ static const TypeInfo ccw_machine_info = { .interfaces = (InterfaceInfo[]) { { TYPE_NMI }, { TYPE_HOTPLUG_HANDLER}, + { TYPE_DUMP_SKEYS_INTERFACE}, { } }, }; diff --git a/include/hw/s390x/storage-keys.h b/include/hw/s390x/storage-keys.h index fb766d4631..ac303001f5 100644 --- a/include/hw/s390x/storage-keys.h +++ b/include/hw/s390x/storage-keys.h @@ -122,6 +122,7 @@ int s390_skeys_set(S390SKeysState *ks, uint64_t start_gfn, S390SKeysState *s390_get_skeys_device(void); +void s390_qmp_dump_skeys(const char *filename, Error **errp); void hmp_dump_skeys(Monitor *mon, const QDict *qdict); void hmp_info_skeys(Monitor *mon, const QDict *qdict); From 76720b6e85b5a6c61044e2110195068c1106fe4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Mar 2025 16:14:14 +0100 Subject: [PATCH 0052/2760] qapi/machine: Make @dump-skeys command generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce misc-target.json by one target specific command. Error message is returned for machines not implementing TYPE_DUMP_SKEYS_INTERFACE: $ qemu-system-aarch64 -M virt -S -qmp stdio {"QMP": {"version": {"qemu": {"micro": 50, "major": 9}}, "capabilities": ["oob"]}} { "execute": "qmp_capabilities" } {"return": {}} { "execute": "dump-skeys", "arguments": { "filename": "/tmp/foo" } } {"error": {"class": "GenericError", "desc": "Storage keys information not available for this architecture"}} Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Message-ID: <20250310151414.11550-5-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/core/machine-qmp-cmds.c | 14 ++++++++++++++ hw/s390x/s390-skeys.c | 6 +----- qapi/machine.json | 18 ++++++++++++++++++ qapi/misc-target.json | 19 ------------------- 4 files changed, 33 insertions(+), 24 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 3130c5cd45..fd8b4e0b44 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -25,6 +25,7 @@ #include "system/numa.h" #include "system/runstate.h" #include "system/system.h" +#include "hw/s390x/storage-keys.h" /* * fast means: we NEVER interrupt vCPU threads to retrieve @@ -406,3 +407,16 @@ GuidInfo *qmp_query_vm_generation_id(Error **errp) info->guid = qemu_uuid_unparse_strdup(&vms->guid); return info; } + +void qmp_dump_skeys(const char *filename, Error **errp) +{ + ObjectClass *mc = object_get_class(qdev_get_machine()); + ObjectClass *oc = object_class_dynamic_cast(mc, TYPE_DUMP_SKEYS_INTERFACE); + + if (!oc) { + error_setg(errp, "Storage keys information not available" + " for this architecture"); + return; + } + DUMP_SKEYS_INTERFACE_CLASS(oc)->qmp_dump_skeys(filename, errp); +} diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index fd1123b0f3..067ea03726 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -15,6 +15,7 @@ #include "hw/qdev-properties.h" #include "hw/s390x/storage-keys.h" #include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc-target.h" #include "qobject/qdict.h" #include "qemu/error-report.h" @@ -219,11 +220,6 @@ out: fclose(f); } -void qmp_dump_skeys(const char *filename, Error **errp) -{ - s390_qmp_dump_skeys(filename, errp); -} - static bool qemu_s390_skeys_are_enabled(S390SKeysState *ss) { QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(ss); diff --git a/qapi/machine.json b/qapi/machine.json index a6b8795b09..a9ff807631 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1898,3 +1898,21 @@ { 'command': 'x-query-interrupt-controllers', 'returns': 'HumanReadableText', 'features': [ 'unstable' ]} + +## +# @dump-skeys: +# +# Dump the storage keys for an s390x guest +# +# @filename: the path to the file to dump to +# +# Since: 2.5 +# +# .. qmp-example:: +# +# -> { "execute": "dump-skeys", +# "arguments": { "filename": "/tmp/skeys" } } +# <- { "return": {} } +## +{ 'command': 'dump-skeys', + 'data': { 'filename': 'str' } } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 8d70bd24d8..42e4a7417d 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -274,25 +274,6 @@ 'returns': 'SevAttestationReport', 'if': 'TARGET_I386' } -## -# @dump-skeys: -# -# Dump guest's storage keys -# -# @filename: the path to the file to dump to -# -# Since: 2.5 -# -# .. qmp-example:: -# -# -> { "execute": "dump-skeys", -# "arguments": { "filename": "/tmp/skeys" } } -# <- { "return": {} } -## -{ 'command': 'dump-skeys', - 'data': { 'filename': 'str' }, - 'if': 'TARGET_S390X' } - ## # @GICCapability: # From 4a00039c4666fb3f5b24dca8f3212fe049e0f92e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 14 Apr 2025 11:45:43 +0200 Subject: [PATCH 0053/2760] hw: add compat machines for 10.1 Add 10.1 machine types for arm/i440fx/m68k/q35/s390x/spapr. Signed-off-by: Cornelia Huck Reviewed-by: Zhao Liu Reviewed-by: Thomas Huth Acked-by: Michael S. Tsirkin Message-ID: <20250414094543.221241-1-cohuck@redhat.com> Signed-off-by: Thomas Huth --- hw/arm/virt.c | 11 +++++++++-- hw/core/machine.c | 3 +++ hw/i386/pc.c | 3 +++ hw/i386/pc_piix.c | 13 +++++++++++-- hw/i386/pc_q35.c | 13 +++++++++++-- hw/m68k/virt.c | 11 +++++++++-- hw/ppc/spapr.c | 17 ++++++++++++++--- hw/s390x/s390-virtio-ccw.c | 14 +++++++++++++- include/hw/boards.h | 3 +++ include/hw/i386/pc.h | 3 +++ 10 files changed, 79 insertions(+), 12 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index a96452f17a..3e72adaa91 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3408,10 +3408,17 @@ static void machvirt_machine_init(void) } type_init(machvirt_machine_init); -static void virt_machine_10_0_options(MachineClass *mc) +static void virt_machine_10_1_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(10, 0) +DEFINE_VIRT_MACHINE_AS_LATEST(10, 1) + +static void virt_machine_10_0_options(MachineClass *mc) +{ + virt_machine_10_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); +} +DEFINE_VIRT_MACHINE(10, 0) static void virt_machine_9_2_options(MachineClass *mc) { diff --git a/hw/core/machine.c b/hw/core/machine.c index 63c6ef93d2..abfcedd4a5 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -37,6 +37,9 @@ #include "hw/virtio/virtio-iommu.h" #include "audio/audio.h" +GlobalProperty hw_compat_10_0[] = {}; +const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0); + GlobalProperty hw_compat_9_2[] = { {"arm-cpu", "backcompat-pauth-default-use-qarma5", "true"}, { "virtio-balloon-pci", "vectors", "0" }, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 01d0581f62..1b5d55e96d 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -79,6 +79,9 @@ { "qemu64-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, },\ { "athlon-" TYPE_X86_CPU, "model-id", "QEMU Virtual CPU version " v, }, +GlobalProperty pc_compat_10_0[] = {}; +const size_t pc_compat_10_0_len = G_N_ELEMENTS(pc_compat_10_0); + GlobalProperty pc_compat_9_2[] = {}; const size_t pc_compat_9_2_len = G_N_ELEMENTS(pc_compat_9_2); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 6c91e2d292..dbb59df64f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -479,12 +479,21 @@ static void pc_i440fx_machine_options(MachineClass *m) "Use a different south bridge than PIIX3"); } -static void pc_i440fx_machine_10_0_options(MachineClass *m) +static void pc_i440fx_machine_10_1_options(MachineClass *m) { pc_i440fx_machine_options(m); } -DEFINE_I440FX_MACHINE_AS_LATEST(10, 0); +DEFINE_I440FX_MACHINE_AS_LATEST(10, 1); + +static void pc_i440fx_machine_10_0_options(MachineClass *m) +{ + pc_i440fx_machine_10_1_options(m); + compat_props_add(m->compat_props, hw_compat_10_0, hw_compat_10_0_len); + compat_props_add(m->compat_props, pc_compat_10_0, pc_compat_10_0_len); +} + +DEFINE_I440FX_MACHINE(10, 0); static void pc_i440fx_machine_9_2_options(MachineClass *m) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index fd96d0345c..c538b3d05b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -361,12 +361,21 @@ static void pc_q35_machine_options(MachineClass *m) pc_q35_compat_defaults, pc_q35_compat_defaults_len); } -static void pc_q35_machine_10_0_options(MachineClass *m) +static void pc_q35_machine_10_1_options(MachineClass *m) { pc_q35_machine_options(m); } -DEFINE_Q35_MACHINE_AS_LATEST(10, 0); +DEFINE_Q35_MACHINE_AS_LATEST(10, 1); + +static void pc_q35_machine_10_0_options(MachineClass *m) +{ + pc_q35_machine_10_1_options(m); + compat_props_add(m->compat_props, hw_compat_10_0, hw_compat_10_0_len); + compat_props_add(m->compat_props, pc_compat_10_0, pc_compat_10_0_len); +} + +DEFINE_Q35_MACHINE(10, 0); static void pc_q35_machine_9_2_options(MachineClass *m) { diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index d967bdd743..295a614e16 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -366,10 +366,17 @@ type_init(virt_machine_register_types) #define DEFINE_VIRT_MACHINE(major, minor) \ DEFINE_VIRT_MACHINE_IMPL(false, major, minor) -static void virt_machine_10_0_options(MachineClass *mc) +static void virt_machine_10_1_options(MachineClass *mc) { } -DEFINE_VIRT_MACHINE_AS_LATEST(10, 0) +DEFINE_VIRT_MACHINE_AS_LATEST(10, 1) + +static void virt_machine_10_0_options(MachineClass *mc) +{ + virt_machine_10_1_options(mc); + compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); +} +DEFINE_VIRT_MACHINE(10, 0) static void virt_machine_9_2_options(MachineClass *mc) { diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index b0a0f8c689..6fef1d167a 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4767,14 +4767,25 @@ static void spapr_machine_latest_class_options(MachineClass *mc) DEFINE_SPAPR_MACHINE_IMPL(false, major, minor) /* - * pseries-10.0 + * pseries-10.1 */ -static void spapr_machine_10_0_class_options(MachineClass *mc) +static void spapr_machine_10_1_class_options(MachineClass *mc) { /* Defaults for the latest behaviour inherited from the base class */ } -DEFINE_SPAPR_MACHINE_AS_LATEST(10, 0); +DEFINE_SPAPR_MACHINE_AS_LATEST(10, 1); + +/* + * pseries-10.0 + */ +static void spapr_machine_10_0_class_options(MachineClass *mc) +{ + spapr_machine_10_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); +} + +DEFINE_SPAPR_MACHINE(10, 0); /* * pseries-9.2 diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 910dab0831..5af3c4f547 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -924,14 +924,26 @@ static const TypeInfo ccw_machine_info = { DEFINE_CCW_MACHINE_IMPL(false, major, minor) +static void ccw_machine_10_1_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_10_1_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE_AS_LATEST(10, 1); + static void ccw_machine_10_0_instance_options(MachineState *machine) { + ccw_machine_10_1_instance_options(machine); } static void ccw_machine_10_0_class_options(MachineClass *mc) { + ccw_machine_10_1_class_options(mc); + compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); } -DEFINE_CCW_MACHINE_AS_LATEST(10, 0); +DEFINE_CCW_MACHINE(10, 0); static void ccw_machine_9_2_instance_options(MachineState *machine) { diff --git a/include/hw/boards.h b/include/hw/boards.h index f22b2e7fc7..bfe8643a27 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -761,6 +761,9 @@ struct MachineState { } \ type_init(machine_initfn##_register_types) +extern GlobalProperty hw_compat_10_0[]; +extern const size_t hw_compat_10_0_len; + extern GlobalProperty hw_compat_9_2[]; extern const size_t hw_compat_9_2_len; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 103b54301f..8677dc8950 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -215,6 +215,9 @@ void pc_system_parse_ovmf_flash(uint8_t *flash_ptr, size_t flash_size); /* sgx.c */ void pc_machine_init_sgx_epc(PCMachineState *pcms); +extern GlobalProperty pc_compat_10_0[]; +extern const size_t pc_compat_10_0_len; + extern GlobalProperty pc_compat_9_2[]; extern const size_t pc_compat_9_2_len; From 4e3823c68cc5ce04756a8f11d1ec9c18172f0bd3 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 14 Apr 2025 11:37:32 +0200 Subject: [PATCH 0054/2760] tests/functional/test_vnc: skip test if no crypto backend available The test_change_password test will fail if no cryptographic backend is available (e.g. if QEMU was built on a system with no cryptographic library development packages installed); just skip the test in that case. Signed-off-by: Cornelia Huck Reviewed-by: Thomas Huth Message-ID: <20250414093732.220498-1-cohuck@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/test_vnc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/test_vnc.py b/tests/functional/test_vnc.py index 8c9953bdb0..d4e9dd0279 100755 --- a/tests/functional/test_vnc.py +++ b/tests/functional/test_vnc.py @@ -55,6 +55,8 @@ class Vnc(QemuSystemTest): except VMLaunchFailure as excp: if "-vnc: invalid option" in excp.output: self.skipTest("VNC support not available") + elif "Cipher backend does not support DES algorithm" in excp.output: + self.skipTest("No cryptographic backend available") else: self.log.info("unhandled launch failure: %s", excp.output) raise excp From 22baa5f340d4fe3e7f271d275367b806ef3da834 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:15 +0200 Subject: [PATCH 0055/2760] gitlab-ci: Remove the avocado tests from the CI pipelines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are going to move the remaining Avocado tests step by step into the functional test framework. Unfortunately, Avocado fails with an error if it cannot determine a test to run, so disable the tests here now to avoid failures in the Gitlab-CI during the next steps. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-2-thuth@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/buildtest-template.yml | 11 ---------- .gitlab-ci.d/buildtest.yml | 33 +++++++++++------------------ 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 39da7698b0..13fa4f4a4f 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -95,7 +95,6 @@ cache: key: "${CI_JOB_NAME}-cache" paths: - - ${CI_PROJECT_DIR}/avocado-cache - ${CI_PROJECT_DIR}/functional-cache policy: pull-push artifacts: @@ -109,16 +108,6 @@ reports: junit: build/tests/results/latest/results.xml before_script: - - mkdir -p ~/.config/avocado - - echo "[datadir.paths]" > ~/.config/avocado/avocado.conf - - echo "cache_dirs = ['${CI_PROJECT_DIR}/avocado-cache']" - >> ~/.config/avocado/avocado.conf - - echo -e '[job.output.testlogs]\nstatuses = ["FAIL", "INTERRUPT"]' - >> ~/.config/avocado/avocado.conf - - if [ -d ${CI_PROJECT_DIR}/avocado-cache ]; then - du -chs ${CI_PROJECT_DIR}/*-cache ; - fi - - export AVOCADO_ALLOW_UNTRUSTED_CODE=1 - export QEMU_TEST_ALLOW_UNTRUSTED_CODE=1 - export QEMU_TEST_CACHE_DIR=${CI_PROJECT_DIR}/functional-cache after_script: diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 00f4bfcd9f..431bc07d8f 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -29,8 +29,7 @@ functional-system-alpine: artifacts: true variables: IMAGE: alpine - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:avr arch:loongarch64 arch:mips64 arch:mipsel + MAKE_CHECK_ARGS: check-functional build-system-ubuntu: extends: @@ -60,8 +59,7 @@ functional-system-ubuntu: artifacts: true variables: IMAGE: ubuntu2204 - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:alpha arch:microblazeel arch:mips64el + MAKE_CHECK_ARGS: check-functional build-system-debian: extends: @@ -92,8 +90,7 @@ functional-system-debian: artifacts: true variables: IMAGE: debian - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:arm arch:i386 arch:riscv64 arch:sh4 arch:sparc arch:xtensa + MAKE_CHECK_ARGS: check-functional crash-test-debian: extends: .native_test_job_template @@ -155,9 +152,7 @@ functional-system-fedora: artifacts: true variables: IMAGE: fedora - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:microblaze arch:mips arch:xtensa arch:m68k - arch:riscv32 arch:ppc arch:sparc64 + MAKE_CHECK_ARGS: check-functional crash-test-fedora: extends: .native_test_job_template @@ -278,9 +273,7 @@ functional-system-centos: artifacts: true variables: IMAGE: centos9 - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:ppc64 arch:or1k arch:s390x arch:x86_64 arch:rx - arch:sh4 + MAKE_CHECK_ARGS: check-functional build-system-opensuse: extends: @@ -309,8 +302,7 @@ functional-system-opensuse: artifacts: true variables: IMAGE: opensuse-leap - MAKE_CHECK_ARGS: check-avocado check-functional - AVOCADO_TAGS: arch:s390x arch:x86_64 arch:aarch64 + MAKE_CHECK_ARGS: check-functional # # Flaky tests. We don't run these by default and they are allow fail @@ -338,10 +330,9 @@ functional-system-flaky: allow_failure: true variables: IMAGE: debian - MAKE_CHECK_ARGS: check-avocado check-functional + MAKE_CHECK_ARGS: check-functional QEMU_JOB_OPTIONAL: 1 QEMU_TEST_FLAKY_TESTS: 1 - AVOCADO_TAGS: flaky # This jobs explicitly disable TCG (--disable-tcg), KVM is detected by # the configure script. The container doesn't contain Xen headers so @@ -482,8 +473,8 @@ clang-user: # Since slirp callbacks are used in QEMU Timers, we cannot use libslirp with # CFI builds, and thus have to disable it here. # -# Split in three sets of build/check/avocado to limit the execution time of each -# job +# Split in three sets of build/check/functional to limit the execution time +# of each job build-cfi-aarch64: extends: - .native_build_job_template @@ -520,7 +511,7 @@ functional-cfi-aarch64: artifacts: true variables: IMAGE: fedora - MAKE_CHECK_ARGS: check-avocado check-functional + MAKE_CHECK_ARGS: check-functional build-cfi-ppc64-s390x: extends: @@ -558,7 +549,7 @@ functional-cfi-ppc64-s390x: artifacts: true variables: IMAGE: fedora - MAKE_CHECK_ARGS: check-avocado check-functional + MAKE_CHECK_ARGS: check-functional build-cfi-x86_64: extends: @@ -592,7 +583,7 @@ functional-cfi-x86_64: artifacts: true variables: IMAGE: fedora - MAKE_CHECK_ARGS: check-avocado check-functional + MAKE_CHECK_ARGS: check-functional tsan-build: extends: .native_build_job_template From bc65ae696104c15e52a5e26f225b689e2c2cdba6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:16 +0200 Subject: [PATCH 0056/2760] tests/functional: Move the check for the parameters from avocado to functional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_x86_64_pc in tests/avocado/boot_linux_console.py only checks whether the kernel parameters have correctly been passed to the kernel in the guest by looking for them in the console output of the guest. Let's move that to the functional test framework now, but instead of doing it in a separate test, let's do it for all tuxrun tests instead, so it is done automatically for all targets that have a tuxrun test. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-3-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/boot_linux_console.py | 34 ------------------------ tests/functional/qemu_test/tuxruntest.py | 9 ++++--- 2 files changed, 5 insertions(+), 38 deletions(-) diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py index c15f39ae1f..cbb1e2fb50 100644 --- a/tests/avocado/boot_linux_console.py +++ b/tests/avocado/boot_linux_console.py @@ -9,17 +9,9 @@ # later. See the COPYING file in the top-level directory. import os -import lzma -import gzip import shutil -from avocado import skip -from avocado import skipUnless -from avocado import skipUnless from avocado_qemu import QemuSystemTest -from avocado_qemu import exec_command -from avocado_qemu import exec_command_and_wait_for_pattern -from avocado_qemu import interrupt_interactive_console_until_pattern from avocado_qemu import wait_for_console_pattern from avocado.utils import process from avocado.utils import archive @@ -68,29 +60,3 @@ class LinuxKernelTest(QemuSystemTest): process.run("rpm2cpio %s | cpio -id %s" % (rpm, path), shell=True) os.chdir(cwd) return os.path.normpath(os.path.join(self.workdir, path)) - -class BootLinuxConsole(LinuxKernelTest): - """ - Boots a Linux kernel and checks that the console is operational and the - kernel command line is properly passed from QEMU to the kernel - """ - timeout = 90 - - def test_x86_64_pc(self): - """ - :avocado: tags=arch:x86_64 - :avocado: tags=machine:pc - """ - kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' - '/linux/releases/29/Everything/x86_64/os/images/pxeboot' - '/vmlinuz') - kernel_hash = '23bebd2680757891cf7adedb033532163a792495' - kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - - self.vm.set_console() - kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' - self.vm.add_args('-kernel', kernel_path, - '-append', kernel_command_line) - self.vm.launch() - console_pattern = 'Kernel command line: %s' % kernel_command_line - self.wait_for_console_pattern(console_pattern) diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index ad74156f9c..c2bd5baaae 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -77,12 +77,12 @@ class TuxRunBaselineTest(QemuSystemTest): blockdev = "driver=raw,file.driver=file," \ + f"file.filename={disk},node-name=hd0" - kcmd_line = self.KERNEL_COMMON_COMMAND_LINE - kcmd_line += f" root=/dev/{self.root}" - kcmd_line += f" console={self.console}" + self.kcmd_line = self.KERNEL_COMMON_COMMAND_LINE + self.kcmd_line += f" root=/dev/{self.root}" + self.kcmd_line += f" console={self.console}" self.vm.add_args('-kernel', kernel, - '-append', kcmd_line, + '-append', self.kcmd_line, '-blockdev', blockdev) # Sometimes we need extra devices attached @@ -103,6 +103,7 @@ class TuxRunBaselineTest(QemuSystemTest): wait to exit cleanly. """ ps1='root@tuxtest:~#' + self.wait_for_console_pattern(self.kcmd_line) self.wait_for_console_pattern('tuxtest login:') exec_command_and_wait_for_pattern(self, 'root', ps1) exec_command_and_wait_for_pattern(self, 'cat /proc/interrupts', ps1) From 951ededf12a89534195cf5c5210242a169a85656 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:17 +0200 Subject: [PATCH 0057/2760] tests/functional: Convert reverse_debugging tests to the functional framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests are using the gdb-related library functions from the Avocado framework which we don't have in the functional framework yet. So for the time being, keep those imports and skip the test if the Avocado framework is not installed on the host. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-4-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 +- tests/functional/meson.build | 4 + .../reverse_debugging.py | 114 +++--------------- .../functional/test_aarch64_reverse_debug.py | 38 ++++++ tests/functional/test_ppc64_reverse_debug.py | 41 +++++++ tests/functional/test_x86_64_reverse_debug.py | 36 ++++++ 6 files changed, 139 insertions(+), 96 deletions(-) rename tests/{avocado => functional}/reverse_debugging.py (66%) create mode 100755 tests/functional/test_aarch64_reverse_debug.py create mode 100755 tests/functional/test_ppc64_reverse_debug.py create mode 100755 tests/functional/test_x86_64_reverse_debug.py diff --git a/MAINTAINERS b/MAINTAINERS index d54b5578f8..af1d847f8e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3671,7 +3671,7 @@ F: docs/system/replay.rst F: stubs/replay.c F: tests/avocado/replay_kernel.py F: tests/avocado/replay_linux.py -F: tests/avocado/reverse_debugging.py +F: tests/functional/*reverse_debug*.py F: tests/functional/*replay*.py F: qapi/replay.json diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 0f8be30fe2..7b0f4ab0b1 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -13,6 +13,7 @@ endif test_timeouts = { 'aarch64_aspeed' : 600, 'aarch64_raspi4' : 480, + 'aarch64_reverse_debug' : 180, 'aarch64_rme_virt' : 1200, 'aarch64_rme_sbsaref' : 1200, 'aarch64_sbsaref_alpine' : 1200, @@ -78,6 +79,7 @@ tests_aarch64_system_thorough = [ 'aarch64_raspi3', 'aarch64_raspi4', 'aarch64_replay', + 'aarch64_reverse_debug', 'aarch64_rme_virt', 'aarch64_rme_sbsaref', 'aarch64_sbsaref', @@ -229,6 +231,7 @@ tests_ppc64_system_thorough = [ 'ppc64_powernv', 'ppc64_pseries', 'ppc64_replay', + 'ppc64_reverse_debug', 'ppc64_tuxrun', 'ppc64_mac99', ] @@ -311,6 +314,7 @@ tests_x86_64_system_thorough = [ 'x86_64_hotplug_cpu', 'x86_64_kvm_xen', 'x86_64_replay', + 'x86_64_reverse_debug', 'x86_64_tuxrun', ] diff --git a/tests/avocado/reverse_debugging.py b/tests/functional/reverse_debugging.py similarity index 66% rename from tests/avocado/reverse_debugging.py rename to tests/functional/reverse_debugging.py index f24287cd0a..f9a1d395f1 100644 --- a/tests/avocado/reverse_debugging.py +++ b/tests/functional/reverse_debugging.py @@ -1,5 +1,7 @@ # Reverse debugging test # +# SPDX-License-Identifier: GPL-2.0-or-later +# # Copyright (c) 2020 ISP RAS # # Author: @@ -10,14 +12,9 @@ import os import logging -from avocado import skipUnless -from avocado_qemu import BUILD_DIR -from avocado.utils import datadrainer -from avocado.utils import gdb -from avocado.utils import process -from avocado.utils.network.ports import find_free_port -from avocado.utils.path import find_command -from boot_linux_console import LinuxKernelTest +from qemu_test import LinuxKernelTest, get_qemu_img +from qemu_test.ports import Ports + class ReverseDebugging(LinuxKernelTest): """ @@ -36,8 +33,10 @@ class ReverseDebugging(LinuxKernelTest): endian_is_le = True def run_vm(self, record, shift, args, replay_path, image_path, port): + from avocado.utils import datadrainer + logger = logging.getLogger('replay') - vm = self.get_vm() + vm = self.get_vm(name='record' if record else 'replay') vm.set_console() if record: logger.info('recording the execution...') @@ -100,25 +99,25 @@ class ReverseDebugging(LinuxKernelTest): return vm.qmp('query-replay')['return']['icount'] def reverse_debugging(self, shift=7, args=None): + from avocado.utils import gdb + from avocado.utils import process + logger = logging.getLogger('replay') # create qcow2 for snapshots logger.info('creating qcow2 image for VM snapshots') image_path = os.path.join(self.workdir, 'disk.qcow2') - qemu_img = os.path.join(BUILD_DIR, 'qemu-img') - if not os.path.exists(qemu_img): - qemu_img = find_command('qemu-img', False) - if qemu_img is False: - self.cancel('Could not find "qemu-img", which is required to ' - 'create the temporary qcow2 image') + qemu_img = get_qemu_img(self) + if qemu_img is None: + self.skipTest('Could not find "qemu-img", which is required to ' + 'create the temporary qcow2 image') cmd = '%s create -f qcow2 %s 128M' % (qemu_img, image_path) process.run(cmd) replay_path = os.path.join(self.workdir, 'replay.bin') - port = find_free_port() # record the log - vm = self.run_vm(True, shift, args, replay_path, image_path, port) + vm = self.run_vm(True, shift, args, replay_path, image_path, -1) while self.vm_get_icount(vm) <= self.STEPS: pass last_icount = self.vm_get_icount(vm) @@ -127,7 +126,9 @@ class ReverseDebugging(LinuxKernelTest): logger.info("recorded log with %s+ steps" % last_icount) # replay and run debug commands - vm = self.run_vm(False, shift, args, replay_path, image_path, port) + with Ports() as ports: + port = ports.find_free_port() + vm = self.run_vm(False, shift, args, replay_path, image_path, port) logger.info('connecting to gdbstub') g = gdb.GDBRemote('127.0.0.1', port, False, False) g.connect() @@ -193,80 +194,3 @@ class ReverseDebugging(LinuxKernelTest): logger.info('exiting gdb and qemu') vm.shutdown() - -class ReverseDebugging_X86_64(ReverseDebugging): - """ - :avocado: tags=accel:tcg - """ - - REG_PC = 0x10 - REG_CS = 0x12 - def get_pc(self, g): - return self.get_reg_le(g, self.REG_PC) \ - + self.get_reg_le(g, self.REG_CS) * 0x10 - - # unidentified gitlab timeout problem - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_x86_64_pc(self): - """ - :avocado: tags=arch:x86_64 - :avocado: tags=machine:pc - """ - # start with BIOS only - self.reverse_debugging() - -class ReverseDebugging_AArch64(ReverseDebugging): - """ - :avocado: tags=accel:tcg - """ - - REG_PC = 32 - - # unidentified gitlab timeout problem - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_aarch64_virt(self): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - :avocado: tags=cpu:cortex-a53 - """ - kernel_url = ('https://archives.fedoraproject.org/pub/archive/fedora' - '/linux/releases/29/Everything/aarch64/os/images/pxeboot' - '/vmlinuz') - kernel_hash = '8c73e469fc6ea06a58dc83a628fc695b693b8493' - kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - - self.reverse_debugging( - args=('-kernel', kernel_path)) - -class ReverseDebugging_ppc64(ReverseDebugging): - """ - :avocado: tags=accel:tcg - """ - - REG_PC = 0x40 - - # unidentified gitlab timeout problem - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_ppc64_pseries(self): - """ - :avocado: tags=arch:ppc64 - :avocado: tags=machine:pseries - :avocado: tags=flaky - """ - # SLOF branches back to its entry point, which causes this test - # to take the 'hit a breakpoint again' path. That's not a problem, - # just slightly different than the other machines. - self.endian_is_le = False - self.reverse_debugging() - - # See https://gitlab.com/qemu-project/qemu/-/issues/1992 - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test_ppc64_powernv(self): - """ - :avocado: tags=arch:ppc64 - :avocado: tags=machine:powernv - :avocado: tags=flaky - """ - self.endian_is_le = False - self.reverse_debugging() diff --git a/tests/functional/test_aarch64_reverse_debug.py b/tests/functional/test_aarch64_reverse_debug.py new file mode 100755 index 0000000000..58d4532835 --- /dev/null +++ b/tests/functional/test_aarch64_reverse_debug.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test +# +# Copyright (c) 2020 ISP RAS +# +# Author: +# Pavel Dovgalyuk +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +from qemu_test import Asset, skipIfMissingImports, skipFlakyTest +from reverse_debugging import ReverseDebugging + + +@skipIfMissingImports('avocado.utils') +class ReverseDebugging_AArch64(ReverseDebugging): + + REG_PC = 32 + + KERNEL_ASSET = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), + '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7') + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2921") + def test_aarch64_virt(self): + self.set_machine('virt') + self.cpu = 'cortex-a53' + kernel_path = self.KERNEL_ASSET.fetch() + self.reverse_debugging(args=('-kernel', kernel_path)) + + +if __name__ == '__main__': + ReverseDebugging.main() diff --git a/tests/functional/test_ppc64_reverse_debug.py b/tests/functional/test_ppc64_reverse_debug.py new file mode 100755 index 0000000000..5931adef5a --- /dev/null +++ b/tests/functional/test_ppc64_reverse_debug.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test +# +# Copyright (c) 2020 ISP RAS +# +# Author: +# Pavel Dovgalyuk +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +from qemu_test import skipIfMissingImports, skipFlakyTest +from reverse_debugging import ReverseDebugging + + +@skipIfMissingImports('avocado.utils') +class ReverseDebugging_ppc64(ReverseDebugging): + + REG_PC = 0x40 + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") + def test_ppc64_pseries(self): + self.set_machine('pseries') + # SLOF branches back to its entry point, which causes this test + # to take the 'hit a breakpoint again' path. That's not a problem, + # just slightly different than the other machines. + self.endian_is_le = False + self.reverse_debugging() + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992") + def test_ppc64_powernv(self): + self.set_machine('powernv') + self.endian_is_le = False + self.reverse_debugging() + + +if __name__ == '__main__': + ReverseDebugging.main() diff --git a/tests/functional/test_x86_64_reverse_debug.py b/tests/functional/test_x86_64_reverse_debug.py new file mode 100755 index 0000000000..d713e91e14 --- /dev/null +++ b/tests/functional/test_x86_64_reverse_debug.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Reverse debugging test +# +# Copyright (c) 2020 ISP RAS +# +# Author: +# Pavel Dovgalyuk +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +from qemu_test import skipIfMissingImports, skipFlakyTest +from reverse_debugging import ReverseDebugging + + +@skipIfMissingImports('avocado.utils') +class ReverseDebugging_X86_64(ReverseDebugging): + + REG_PC = 0x10 + REG_CS = 0x12 + def get_pc(self, g): + return self.get_reg_le(g, self.REG_PC) \ + + self.get_reg_le(g, self.REG_CS) * 0x10 + + @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/2922") + def test_x86_64_pc(self): + self.set_machine('pc') + # start with BIOS only + self.reverse_debugging() + + +if __name__ == '__main__': + ReverseDebugging.main() From 0e756f404d73ddf7b5506e9109e2c074f30fb79e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:18 +0200 Subject: [PATCH 0058/2760] tests/functional: Convert the i386 replay avocado test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since this was the last test in tests/avocado/replay_kernel.py, we can remove that Avocado file now. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-5-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 - tests/avocado/replay_kernel.py | 110 --------------------------- tests/functional/meson.build | 1 + tests/functional/test_i386_replay.py | 28 +++++++ 4 files changed, 29 insertions(+), 111 deletions(-) delete mode 100644 tests/avocado/replay_kernel.py create mode 100755 tests/functional/test_i386_replay.py diff --git a/MAINTAINERS b/MAINTAINERS index af1d847f8e..42348df9d6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3669,7 +3669,6 @@ F: include/system/replay.h F: docs/devel/replay.rst F: docs/system/replay.rst F: stubs/replay.c -F: tests/avocado/replay_kernel.py F: tests/avocado/replay_linux.py F: tests/functional/*reverse_debug*.py F: tests/functional/*replay*.py diff --git a/tests/avocado/replay_kernel.py b/tests/avocado/replay_kernel.py deleted file mode 100644 index 3551532372..0000000000 --- a/tests/avocado/replay_kernel.py +++ /dev/null @@ -1,110 +0,0 @@ -# Record/replay test that boots a Linux kernel -# -# Copyright (c) 2020 ISP RAS -# -# Author: -# Pavel Dovgalyuk -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os -import lzma -import shutil -import logging -import time -import subprocess - -from avocado import skip -from avocado import skipUnless -from avocado import skipUnless -from avocado_qemu import wait_for_console_pattern -from avocado.utils import archive -from avocado.utils import process -from boot_linux_console import LinuxKernelTest - -class ReplayKernelBase(LinuxKernelTest): - """ - Boots a Linux kernel in record mode and checks that the console - is operational and the kernel command line is properly passed - from QEMU to the kernel. - Then replays the same scenario and verifies, that QEMU correctly - terminates. - """ - - timeout = 180 - KERNEL_COMMON_COMMAND_LINE = 'printk.time=1 panic=-1 ' - - 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() - vm.set_console() - if record: - logger.info('recording the execution...') - mode = 'record' - else: - logger.info('replaying the execution...') - mode = 'replay' - vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % - (shift, mode, replay_path), - '-kernel', kernel_path, - '-append', kernel_command_line, - '-net', 'none', - '-no-reboot') - if args: - vm.add_args(*args) - vm.launch() - self.wait_for_console_pattern(console_pattern, vm) - if record: - vm.shutdown() - logger.info('finished the recording with log size %s bytes' - % os.path.getsize(replay_path)) - self.run_replay_dump(replay_path) - logger.info('successfully tested replay-dump.py') - else: - vm.wait() - logger.info('successfully finished the replay') - elapsed = time.time() - start_time - logger.info('elapsed time %.2f sec' % elapsed) - return elapsed - - def run_replay_dump(self, replay_path): - try: - subprocess.check_call(["./scripts/replay-dump.py", - "-f", replay_path], - stdout=subprocess.DEVNULL) - except subprocess.CalledProcessError: - self.fail('replay-dump.py failed') - - def run_rr(self, kernel_path, kernel_command_line, console_pattern, - shift=7, args=None): - replay_path = os.path.join(self.workdir, 'replay.bin') - t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern, - True, shift, args, replay_path) - t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern, - False, shift, args, replay_path) - logger = logging.getLogger('replay') - logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) - -class ReplayKernelNormal(ReplayKernelBase): - - def test_i386_pc(self): - """ - :avocado: tags=arch:i386 - :avocado: tags=machine:pc - """ - kernel_url = ('https://storage.tuxboot.com/20230331/i386/bzImage') - kernel_hash = 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956' - kernel_path = self.fetch_asset(kernel_url, - asset_hash=kernel_hash, - algorithm = "sha256") - - kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' - console_pattern = 'VFS: Cannot open root device' - - self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 7b0f4ab0b1..4113b221de 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -151,6 +151,7 @@ tests_i386_system_quick = [ ] tests_i386_system_thorough = [ + 'i386_replay', 'i386_tuxrun', ] diff --git a/tests/functional/test_i386_replay.py b/tests/functional/test_i386_replay.py new file mode 100755 index 0000000000..7c4c2602da --- /dev/null +++ b/tests/functional/test_i386_replay.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# +# Replay test that boots a Linux kernel on a i386 machine +# and checks the console +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import Asset +from replay_kernel import ReplayKernelBase + + +class I386Replay(ReplayKernelBase): + + ASSET_KERNEL = Asset( + 'https://storage.tuxboot.com/20230331/i386/bzImage', + 'a3e5b32a354729e65910f5a1ffcda7c14a6c12a55e8213fb86e277f1b76ed956') + + def test_pc(self): + self.set_machine('pc') + kernel_url = () + kernel_path = self.ASSET_KERNEL.fetch() + kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' + console_pattern = 'VFS: Cannot open root device' + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) + + +if __name__ == '__main__': + ReplayKernelBase.main() From 574f71bc1f22640d45a90969805eaaacd38bf859 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:19 +0200 Subject: [PATCH 0059/2760] tests/avocado: Remove the LinuxKernelTest class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All tests that used this class have been converted to the functional framework, so we can remove the boot_linux_console.py file now. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-6-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/boot_linux_console.py | 62 ----------------------------- 1 file changed, 62 deletions(-) delete mode 100644 tests/avocado/boot_linux_console.py diff --git a/tests/avocado/boot_linux_console.py b/tests/avocado/boot_linux_console.py deleted file mode 100644 index cbb1e2fb50..0000000000 --- a/tests/avocado/boot_linux_console.py +++ /dev/null @@ -1,62 +0,0 @@ -# Functional test that boots a Linux kernel and checks the console -# -# Copyright (c) 2018 Red Hat, Inc. -# -# Author: -# Cleber Rosa -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os -import shutil - -from avocado_qemu import QemuSystemTest -from avocado_qemu import wait_for_console_pattern -from avocado.utils import process -from avocado.utils import archive - -class LinuxKernelTest(QemuSystemTest): - KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' - - def wait_for_console_pattern(self, success_message, vm=None): - wait_for_console_pattern(self, success_message, - failure_message='Kernel panic - not syncing', - vm=vm) - - def extract_from_deb(self, deb, path): - """ - Extracts a file from a deb package into the test workdir - - :param deb: path to the deb archive - :param path: path within the deb archive of the file to be extracted - :returns: path of the extracted file - """ - cwd = os.getcwd() - os.chdir(self.workdir) - file_path = process.run("ar t %s" % deb).stdout_text.split()[2] - process.run("ar x %s %s" % (deb, file_path)) - archive.extract(file_path, self.workdir) - os.chdir(cwd) - # Return complete path to extracted file. Because callers to - # extract_from_deb() specify 'path' with a leading slash, it is - # necessary to use os.path.relpath() as otherwise os.path.join() - # interprets it as an absolute path and drops the self.workdir part. - return os.path.normpath(os.path.join(self.workdir, - os.path.relpath(path, '/'))) - - def extract_from_rpm(self, rpm, path): - """ - Extracts a file from an RPM package into the test workdir. - - :param rpm: path to the rpm archive - :param path: path within the rpm archive of the file to be extracted - needs to be a relative path (starting with './') because - cpio(1), which is used to extract the file, expects that. - :returns: path of the extracted file - """ - cwd = os.getcwd() - os.chdir(self.workdir) - process.run("rpm2cpio %s | cpio -id %s" % (rpm, path), shell=True) - os.chdir(cwd) - return os.path.normpath(os.path.join(self.workdir, path)) From 42a87f0ce7aaf1923a610cabe4d65f7b1ce9a327 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:20 +0200 Subject: [PATCH 0060/2760] tests/functional: Convert the 32-bit big endian Wheezy mips test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test checks some entries in /proc and the output of some commands ... we put these checks into exportable functions now so that they can be reused more easily. Additionally the linux_ssh_mips_malta.py uses SSH to test the networking of the guest. Since we don't have a SSH module in the functional framework yet, let's use the check_http_download() function here instead. And while we're at it, also switch the NIC to e1000 now to get some more test coverage, since the "pcnet" device is already tested in the test test_mips_malta_cpio. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-7-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/linux_ssh_mips_malta.py | 8 -- tests/functional/meson.build | 2 +- tests/functional/test_mips_malta.py | 108 +++++++++++++++++++++++++- 3 files changed, 107 insertions(+), 11 deletions(-) diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py index d9bb525ad9..73d294ad5c 100644 --- a/tests/avocado/linux_ssh_mips_malta.py +++ b/tests/avocado/linux_ssh_mips_malta.py @@ -172,14 +172,6 @@ class LinuxSSH(QemuSystemTest, LinuxSSHMixIn): # Wait for VM to shut down gracefully self.vm.wait() - def test_mips_malta32eb_kernel3_2_0(self): - """ - :avocado: tags=arch:mips - :avocado: tags=endian:big - :avocado: tags=device:pcnet32 - """ - self.check_mips_malta('mips', 'be') - def test_mips_malta32el_kernel3_2_0(self): """ :avocado: tags=arch:mipsel diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 4113b221de..4dedfc7b9f 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -39,7 +39,7 @@ test_timeouts = { 'arm_tuxrun' : 240, 'arm_sx1' : 360, 'intel_iommu': 300, - 'mips_malta' : 120, + 'mips_malta' : 480, 'mipsel_replay' : 480, 'mips64el_replay' : 180, 'netdev_ethtool' : 180, diff --git a/tests/functional/test_mips_malta.py b/tests/functional/test_mips_malta.py index 9697c7d63f..89b9556f30 100755 --- a/tests/functional/test_mips_malta.py +++ b/tests/functional/test_mips_malta.py @@ -6,10 +6,93 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import LinuxKernelTest, Asset +import os + +from qemu_test import LinuxKernelTest, Asset, wait_for_console_pattern from qemu_test import exec_command_and_wait_for_pattern +def mips_run_common_commands(test, prompt='#'): + exec_command_and_wait_for_pattern(test, + 'uname -m', + 'mips') + exec_command_and_wait_for_pattern(test, + 'grep XT-PIC /proc/interrupts', + 'timer') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'grep XT-PIC /proc/interrupts', + 'serial') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'grep XT-PIC /proc/interrupts', + 'ata_piix') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'grep XT-PIC /proc/interrupts', + 'rtc') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'cat /proc/devices', + 'input') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'cat /proc/devices', + 'fb') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'cat /proc/ioports', + ' : serial') + wait_for_console_pattern(test, prompt) + exec_command_and_wait_for_pattern(test, + 'cat /proc/ioports', + ' : ata_piix') + wait_for_console_pattern(test, prompt) + +def mips_check_wheezy(test, kernel_path, image_path, kernel_command_line, + dl_file, hsum, nic='pcnet', cpuinfo='MIPS 24Kc'): + test.require_netdev('user') + test.require_device(nic) + test.set_machine('malta') + + port=8080 + test.vm.add_args('-kernel', kernel_path, + '-append', kernel_command_line, + '-drive', 'file=%s,snapshot=on' % image_path, + '-netdev', 'user,id=n1' + + ',tftp=' + os.path.basename(kernel_path) + + ',hostfwd=tcp:127.0.0.1:0-:%d' % port, + '-device', f'{nic},netdev=n1', + '-no-reboot') + test.vm.set_console() + test.vm.launch() + + wait_for_console_pattern(test, 'login: ', 'Oops') + exec_command_and_wait_for_pattern(test, 'root', 'Password:') + exec_command_and_wait_for_pattern(test, 'root', ':~# ') + mips_run_common_commands(test) + + exec_command_and_wait_for_pattern(test, 'cd /', '# ') + test.check_http_download(dl_file, hsum, port, + pythoncmd='python -m SimpleHTTPServer') + + exec_command_and_wait_for_pattern(test, 'cat /proc/cpuinfo', cpuinfo) + exec_command_and_wait_for_pattern(test, 'cat /proc/devices', 'usb') + exec_command_and_wait_for_pattern(test, 'cat /proc/ioports', + ' : piix4_smbus') + # lspci for the host bridge does not work on big endian targets: + # https://gitlab.com/qemu-project/qemu/-/issues/2826 + # exec_command_and_wait_for_pattern(test, 'lspci -d 11ab:4620', + # 'GT-64120') + exec_command_and_wait_for_pattern(test, + 'cat /sys/bus/i2c/devices/i2c-0/name', + 'SMBus PIIX4 adapter') + exec_command_and_wait_for_pattern(test, 'cat /proc/mtd', 'YAMON') + # Empty 'Board Config' (64KB) + exec_command_and_wait_for_pattern(test, 'md5sum /dev/mtd2ro', + '0dfbe8aa4c20b52e1b8bf3cb6cbdf193') + + class MaltaMachineConsole(LinuxKernelTest): ASSET_KERNEL_2_63_2 = Asset( @@ -70,7 +153,8 @@ class MaltaMachineConsole(LinuxKernelTest): exec_command_and_wait_for_pattern(self, 'cat /proc/cpuinfo', 'BogoMIPS') exec_command_and_wait_for_pattern(self, 'uname -a', - 'Debian') + '4.5.0-2-4kc-malta #1 Debian') + mips_run_common_commands(self) exec_command_and_wait_for_pattern(self, 'ip link set eth0 up', 'eth0: link up') @@ -89,6 +173,26 @@ class MaltaMachineConsole(LinuxKernelTest): # Wait for VM to shut down gracefully self.vm.wait() + ASSET_WHEEZY_KERNEL = Asset( + ('https://people.debian.org/~aurel32/qemu/mips/' + 'vmlinux-3.2.0-4-4kc-malta'), + '0377fcda31299213c10b8e5babe7260ef99188b3ae1aca6f56594abb71e7f67e') + + ASSET_WHEEZY_DISK = Asset( + ('https://people.debian.org/~aurel32/qemu/mips/' + 'debian_wheezy_mips_standard.qcow2'), + 'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2') + + def test_wheezy(self): + kernel_path = self.ASSET_WHEEZY_KERNEL.fetch() + image_path = self.ASSET_WHEEZY_DISK.fetch() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 root=/dev/sda1') + mips_check_wheezy(self, + kernel_path, image_path, kernel_command_line, nic='e1000', + dl_file='/boot/initrd.img-3.2.0-4-4kc-malta', + hsum='ff0c0369143d9bbb9a6e6bc79322a2be535619df639e84103237f406e87493dc') + if __name__ == '__main__': LinuxKernelTest.main() From 689a8b56a6f3d16458004006b604950295da87df Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:21 +0200 Subject: [PATCH 0061/2760] tests/functional: Convert the 32-bit little endian Wheezy mips test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse the test function from the big endian test to easily convert the 32-bit little endian Wheezy mips test. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-8-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/linux_ssh_mips_malta.py | 8 -------- tests/functional/meson.build | 1 + tests/functional/test_mipsel_malta.py | 22 ++++++++++++++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py index 73d294ad5c..c1300aec96 100644 --- a/tests/avocado/linux_ssh_mips_malta.py +++ b/tests/avocado/linux_ssh_mips_malta.py @@ -172,14 +172,6 @@ class LinuxSSH(QemuSystemTest, LinuxSSHMixIn): # Wait for VM to shut down gracefully self.vm.wait() - def test_mips_malta32el_kernel3_2_0(self): - """ - :avocado: tags=arch:mipsel - :avocado: tags=endian:little - :avocado: tags=device:pcnet32 - """ - self.check_mips_malta('mips', 'le') - def test_mips_malta64eb_kernel3_2_0(self): """ :avocado: tags=arch:mips64 diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 4dedfc7b9f..cba0abf292 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -40,6 +40,7 @@ test_timeouts = { 'arm_sx1' : 360, 'intel_iommu': 300, 'mips_malta' : 480, + 'mipsel_malta' : 420, 'mipsel_replay' : 480, 'mips64el_replay' : 180, 'netdev_ethtool' : 180, diff --git a/tests/functional/test_mipsel_malta.py b/tests/functional/test_mipsel_malta.py index fe9c3a172e..9ee2884da8 100755 --- a/tests/functional/test_mipsel_malta.py +++ b/tests/functional/test_mipsel_malta.py @@ -13,6 +13,8 @@ from qemu_test import QemuSystemTest, LinuxKernelTest, Asset from qemu_test import interrupt_interactive_console_until_pattern from qemu_test import wait_for_console_pattern +from test_mips_malta import mips_check_wheezy + class MaltaMachineConsole(LinuxKernelTest): @@ -57,6 +59,26 @@ class MaltaMachineConsole(LinuxKernelTest): def test_mips_malta32el_nanomips_64k_dbg(self): self.do_test_mips_malta32el_nanomips(self.ASSET_KERNEL_64K) + ASSET_WHEEZY_KERNEL = Asset( + ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'vmlinux-3.2.0-4-4kc-malta'), + 'dc8a3648305b0201ca7a5cd135fe2890067a65d93c38728022bb0e656ad2bf9a') + + ASSET_WHEEZY_DISK = Asset( + ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'debian_wheezy_mipsel_standard.qcow2'), + '454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914') + + def test_wheezy(self): + kernel_path = self.ASSET_WHEEZY_KERNEL.fetch() + image_path = self.ASSET_WHEEZY_DISK.fetch() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 root=/dev/sda1') + mips_check_wheezy(self, + kernel_path, image_path, kernel_command_line, + dl_file='/boot/initrd.img-3.2.0-4-4kc-malta', + hsum='9fc9f250ed56a74e35e704ddfd5a1c5a5625adefc5c9da91f649288d3ca000f0') + class MaltaMachineYAMON(QemuSystemTest): From 8e3461c3a6fc0b1bce4571e46e861db0b2bcf621 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:22 +0200 Subject: [PATCH 0062/2760] tests/functional: Convert the 64-bit little endian Wheezy mips test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse the test function from the 32-bit big endian test to easily convert the 64-bit little endian Wheezy mips test. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-9-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/linux_ssh_mips_malta.py | 8 -------- tests/functional/meson.build | 1 + tests/functional/test_mips64el_malta.py | 22 ++++++++++++++++++++++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py index c1300aec96..2fa5cf9a6c 100644 --- a/tests/avocado/linux_ssh_mips_malta.py +++ b/tests/avocado/linux_ssh_mips_malta.py @@ -179,11 +179,3 @@ class LinuxSSH(QemuSystemTest, LinuxSSHMixIn): :avocado: tags=device:pcnet32 """ self.check_mips_malta('mips64', 'be') - - def test_mips_malta64el_kernel3_2_0(self): - """ - :avocado: tags=arch:mips64el - :avocado: tags=endian:little - :avocado: tags=device:pcnet32 - """ - self.check_mips_malta('mips64', 'le') diff --git a/tests/functional/meson.build b/tests/functional/meson.build index cba0abf292..a4a317115b 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -42,6 +42,7 @@ test_timeouts = { 'mips_malta' : 480, 'mipsel_malta' : 420, 'mipsel_replay' : 480, + 'mips64el_malta' : 420, 'mips64el_replay' : 180, 'netdev_ethtool' : 180, 'ppc_40p' : 240, diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py index a8da15a26b..dd37212f9d 100755 --- a/tests/functional/test_mips64el_malta.py +++ b/tests/functional/test_mips64el_malta.py @@ -16,6 +16,8 @@ from qemu_test import LinuxKernelTest, Asset from qemu_test import exec_command_and_wait_for_pattern from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest +from test_mips_malta import mips_check_wheezy + class MaltaMachineConsole(LinuxKernelTest): @@ -90,6 +92,26 @@ class MaltaMachineConsole(LinuxKernelTest): # Wait for VM to shut down gracefully self.vm.wait() + ASSET_WHEEZY_KERNEL = Asset( + ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'vmlinux-3.2.0-4-5kc-malta'), + '5e8b725244c59745bb8b64f5d8f49f25fecfa549f3395fb6d19a3b9e5065b85b') + + ASSET_WHEEZY_DISK = Asset( + ('https://people.debian.org/~aurel32/qemu/mipsel/' + 'debian_wheezy_mipsel_standard.qcow2'), + '454f09ae39f7e6461c84727b927100d2c7813841f2a0a5dce328114887ecf914') + + def test_wheezy(self): + kernel_path = self.ASSET_WHEEZY_KERNEL.fetch() + image_path = self.ASSET_WHEEZY_DISK.fetch() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 root=/dev/sda1') + mips_check_wheezy(self, + kernel_path, image_path, kernel_command_line, cpuinfo='MIPS 20Kc', + dl_file='/boot/initrd.img-3.2.0-4-5kc-malta', + hsum='7579f8b56c1187c7c04d0dc3c0c56c7a6314c5ddd3a9bf8803ecc7cf8a3be9f8') + @skipIfMissingImports('numpy', 'cv2') class MaltaMachineFramebuffer(LinuxKernelTest): From f79592f427d7faabb25d533815d6c3dd4ab9726d Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:23 +0200 Subject: [PATCH 0063/2760] tests/functional: Convert the 64-bit big endian Wheezy mips test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse the test function from the 32-bit big endian test to easily convert the 64-bit big endian Wheezy mips test. Since this was the last test in tests/avocado/linux_ssh_mips_malta.py, we can remove this avocado file now, too. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-10-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 1 - tests/avocado/linux_ssh_mips_malta.py | 181 -------------------------- tests/functional/meson.build | 2 + tests/functional/test_mips64_malta.py | 35 +++++ 4 files changed, 37 insertions(+), 182 deletions(-) delete mode 100644 tests/avocado/linux_ssh_mips_malta.py create mode 100755 tests/functional/test_mips64_malta.py diff --git a/MAINTAINERS b/MAINTAINERS index 42348df9d6..72f6b208f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1355,7 +1355,6 @@ F: hw/acpi/piix4.c F: hw/mips/malta.c F: hw/pci-host/gt64120.c F: include/hw/southbridge/piix.h -F: tests/avocado/linux_ssh_mips_malta.py F: tests/functional/test_mips*_malta.py F: tests/functional/test_mips*_tuxrun.py diff --git a/tests/avocado/linux_ssh_mips_malta.py b/tests/avocado/linux_ssh_mips_malta.py deleted file mode 100644 index 2fa5cf9a6c..0000000000 --- a/tests/avocado/linux_ssh_mips_malta.py +++ /dev/null @@ -1,181 +0,0 @@ -# Functional test that boots a VM and run commands via a SSH session -# -# Copyright (c) Philippe Mathieu-Daudé -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os -import re -import base64 -import logging -import time - -from avocado import skipUnless -from avocado_qemu import LinuxSSHMixIn -from avocado_qemu import QemuSystemTest -from avocado_qemu import wait_for_console_pattern -from avocado.utils import process -from avocado.utils import archive -from avocado.utils import ssh - - -@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') -@skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available') -class LinuxSSH(QemuSystemTest, LinuxSSHMixIn): - """ - :avocado: tags=accel:tcg - """ - - timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg' - - KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' - VM_IP = '127.0.0.1' - - BASE_URL = 'https://people.debian.org/~aurel32/qemu/' - IMAGE_INFO = { - 'be': {'base_url': 'mips', - 'image_name': 'debian_wheezy_mips_standard.qcow2', - 'image_hash': '8987a63270df67345b2135a6b7a4885a35e392d5', - 'kernel_hash': { - 32: '592e384a4edc16dade52a6cd5c785c637bcbc9ad', - 64: 'db6eea7de35d36c77d8c165b6bcb222e16eb91db'} - }, - 'le': {'base_url': 'mipsel', - 'image_name': 'debian_wheezy_mipsel_standard.qcow2', - 'image_hash': '7866764d9de3ef536ffca24c9fb9f04ffdb45802', - 'kernel_hash': { - 32: 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a', - 64: '6a7f77245acf231415a0e8b725d91ed2f3487794'} - } - } - CPU_INFO = { - 32: {'cpu': 'MIPS 24Kc', 'kernel_release': '3.2.0-4-4kc-malta'}, - 64: {'cpu': 'MIPS 20Kc', 'kernel_release': '3.2.0-4-5kc-malta'} - } - - def get_url(self, endianess, path=''): - qkey = {'le': 'el', 'be': ''} - return '%s/mips%s/%s' % (self.BASE_URL, qkey[endianess], path) - - def get_image_info(self, endianess): - dinfo = self.IMAGE_INFO[endianess] - image_url = self.get_url(endianess, dinfo['image_name']) - image_hash = dinfo['image_hash'] - return (image_url, image_hash) - - def get_kernel_info(self, endianess, wordsize): - minfo = self.CPU_INFO[wordsize] - kernel_url = self.get_url(endianess, - 'vmlinux-%s' % minfo['kernel_release']) - kernel_hash = self.IMAGE_INFO[endianess]['kernel_hash'][wordsize] - return kernel_url, kernel_hash - - def ssh_disconnect_vm(self): - self.ssh_session.quit() - - def boot_debian_wheezy_image_and_ssh_login(self, endianess, kernel_path): - image_url, image_hash = self.get_image_info(endianess) - image_path = self.fetch_asset(image_url, asset_hash=image_hash) - - self.vm.set_console() - kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE - + 'console=ttyS0 root=/dev/sda1') - self.vm.add_args('-no-reboot', - '-kernel', kernel_path, - '-append', kernel_command_line, - '-drive', 'file=%s,snapshot=on' % image_path, - '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', - '-device', 'pcnet,netdev=vnet') - self.vm.launch() - - self.log.info('VM launched, waiting for sshd') - console_pattern = 'Starting OpenBSD Secure Shell server: sshd' - wait_for_console_pattern(self, console_pattern, 'Oops') - self.log.info('sshd ready') - - self.ssh_connect('root', 'root', False) - - def shutdown_via_ssh(self): - self.ssh_command('poweroff') - self.ssh_disconnect_vm() - wait_for_console_pattern(self, 'Power down', 'Oops') - - def run_common_commands(self, wordsize): - self.ssh_command_output_contains( - 'cat /proc/cpuinfo', - self.CPU_INFO[wordsize]['cpu']) - self.ssh_command_output_contains( - 'uname -m', - 'mips') - self.ssh_command_output_contains( - 'uname -r', - self.CPU_INFO[wordsize]['kernel_release']) - self.ssh_command_output_contains( - 'cat /proc/interrupts', - 'XT-PIC timer') - self.ssh_command_output_contains( - 'cat /proc/interrupts', - 'XT-PIC i8042') - self.ssh_command_output_contains( - 'cat /proc/interrupts', - 'XT-PIC serial') - self.ssh_command_output_contains( - 'cat /proc/interrupts', - 'XT-PIC ata_piix') - self.ssh_command_output_contains( - 'cat /proc/interrupts', - 'XT-PIC eth0') - self.ssh_command_output_contains( - 'cat /proc/devices', - 'input') - self.ssh_command_output_contains( - 'cat /proc/devices', - 'usb') - self.ssh_command_output_contains( - 'cat /proc/devices', - 'fb') - self.ssh_command_output_contains( - 'cat /proc/ioports', - ' : serial') - self.ssh_command_output_contains( - 'cat /proc/ioports', - ' : ata_piix') - self.ssh_command_output_contains( - 'cat /proc/ioports', - ' : piix4_smbus') - self.ssh_command_output_contains( - 'lspci -d 11ab:4620', - 'GT-64120') - self.ssh_command_output_contains( - 'cat /sys/bus/i2c/devices/i2c-0/name', - 'SMBus PIIX4 adapter') - self.ssh_command_output_contains( - 'cat /proc/mtd', - 'YAMON') - # Empty 'Board Config' (64KB) - self.ssh_command_output_contains( - 'md5sum /dev/mtd2ro', - '0dfbe8aa4c20b52e1b8bf3cb6cbdf193') - - def check_mips_malta(self, uname_m, endianess): - wordsize = 64 if '64' in uname_m else 32 - kernel_url, kernel_hash = self.get_kernel_info(endianess, wordsize) - kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) - self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path) - - stdout, _ = self.ssh_command('uname -a') - self.assertIn(True, [uname_m + " GNU/Linux" in line for line in stdout]) - - self.run_common_commands(wordsize) - self.shutdown_via_ssh() - # Wait for VM to shut down gracefully - self.vm.wait() - - def test_mips_malta64eb_kernel3_2_0(self): - """ - :avocado: tags=arch:mips64 - :avocado: tags=endian:big - :avocado: tags=device:pcnet32 - """ - self.check_mips_malta('mips64', 'be') diff --git a/tests/functional/meson.build b/tests/functional/meson.build index a4a317115b..985ac5c27f 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -42,6 +42,7 @@ test_timeouts = { 'mips_malta' : 480, 'mipsel_malta' : 420, 'mipsel_replay' : 480, + 'mips64_malta' : 240, 'mips64el_malta' : 420, 'mips64el_replay' : 180, 'netdev_ethtool' : 180, @@ -191,6 +192,7 @@ tests_mipsel_system_thorough = [ ] tests_mips64_system_thorough = [ + 'mips64_malta', 'mips64_tuxrun', ] diff --git a/tests/functional/test_mips64_malta.py b/tests/functional/test_mips64_malta.py new file mode 100755 index 0000000000..53c3e0c122 --- /dev/null +++ b/tests/functional/test_mips64_malta.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# +# Functional tests for the big-endian 64-bit MIPS Malta board +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import LinuxKernelTest, Asset +from test_mips_malta import mips_check_wheezy + + +class MaltaMachineConsole(LinuxKernelTest): + + ASSET_WHEEZY_KERNEL = Asset( + ('https://people.debian.org/~aurel32/qemu/mips/' + 'vmlinux-3.2.0-4-5kc-malta'), + '3e4ec154db080b3f1839f04dde83120654a33e5e1716863de576c47cb94f68f6') + + ASSET_WHEEZY_DISK = Asset( + ('https://people.debian.org/~aurel32/qemu/mips/' + 'debian_wheezy_mips_standard.qcow2'), + 'de03599285b8382ad309309a6c4869f6c6c42a5cfc983342bab9ec0dfa7849a2') + + def test_wheezy(self): + kernel_path = self.ASSET_WHEEZY_KERNEL.fetch() + image_path = self.ASSET_WHEEZY_DISK.fetch() + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + 'console=ttyS0 root=/dev/sda1') + mips_check_wheezy(self, + kernel_path, image_path, kernel_command_line, cpuinfo='MIPS 20Kc', + dl_file='/boot/initrd.img-3.2.0-4-5kc-malta', + hsum='d98b953bb4a41c0fc0fd8d19bbc691c08989ac52568c1d3054d92dfd890d3f06') + + +if __name__ == '__main__': + LinuxKernelTest.main() From e83aee9c6a0f169e8c5d9387f2429ec8f539dda9 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:24 +0200 Subject: [PATCH 0064/2760] tests/avocado: Remove the boot_linux.py tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests are based on the cloudinit functions from Avocado. The cloudinit is very, very slow compared to our other tests, so most of these Avocado tests have either been disabled by default with a decorator, or have been marked to only run with KVM. We won't include this sluggish cloudinit stuff in the functional framework, and we've already got plenty of other tests there that check pretty much the same things, so let's simply get rid of these old tests now. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-11-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/boot_linux.py | 132 ------------------------------------ 1 file changed, 132 deletions(-) delete mode 100644 tests/avocado/boot_linux.py diff --git a/tests/avocado/boot_linux.py b/tests/avocado/boot_linux.py deleted file mode 100644 index a029ef4ad1..0000000000 --- a/tests/avocado/boot_linux.py +++ /dev/null @@ -1,132 +0,0 @@ -# Functional test that boots a complete Linux system via a cloud image -# -# Copyright (c) 2018-2020 Red Hat, Inc. -# -# Author: -# Cleber Rosa -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os - -from avocado_qemu.linuxtest import LinuxTest -from avocado_qemu import BUILD_DIR - -from avocado import skipUnless - - -class BootLinuxX8664(LinuxTest): - """ - :avocado: tags=arch:x86_64 - """ - timeout = 480 - - def test_pc_i440fx_tcg(self): - """ - :avocado: tags=machine:pc - :avocado: tags=accel:tcg - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.launch_and_wait(set_up_ssh_connection=False) - - def test_pc_i440fx_kvm(self): - """ - :avocado: tags=machine:pc - :avocado: tags=accel:kvm - """ - self.require_accelerator("kvm") - self.vm.add_args("-accel", "kvm") - self.launch_and_wait(set_up_ssh_connection=False) - - def test_pc_q35_tcg(self): - """ - :avocado: tags=machine:q35 - :avocado: tags=accel:tcg - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.launch_and_wait(set_up_ssh_connection=False) - - def test_pc_q35_kvm(self): - """ - :avocado: tags=machine:q35 - :avocado: tags=accel:kvm - """ - self.require_accelerator("kvm") - self.vm.add_args("-accel", "kvm") - self.launch_and_wait(set_up_ssh_connection=False) - - -# For Aarch64 we only boot KVM tests in CI as booting the current -# Fedora OS in TCG tests is very heavyweight. There are lighter weight -# distros which we use in the machine_aarch64_virt.py tests. -class BootLinuxAarch64(LinuxTest): - """ - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - """ - timeout = 720 - - def test_virt_kvm(self): - """ - :avocado: tags=accel:kvm - :avocado: tags=cpu:host - """ - self.require_accelerator("kvm") - self.vm.add_args("-accel", "kvm") - self.vm.add_args("-machine", "virt,gic-version=host") - self.vm.add_args('-bios', - os.path.join(BUILD_DIR, 'pc-bios', - 'edk2-aarch64-code.fd')) - self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') - self.vm.add_args('-object', 'rng-random,id=rng0,filename=/dev/urandom') - self.launch_and_wait(set_up_ssh_connection=False) - - -# See the tux_baseline.py tests for almost the same coverage in a lot -# less time. -class BootLinuxPPC64(LinuxTest): - """ - :avocado: tags=arch:ppc64 - """ - - timeout = 360 - - @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited') - def test_pseries_tcg(self): - """ - :avocado: tags=machine:pseries - :avocado: tags=accel:tcg - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.launch_and_wait(set_up_ssh_connection=False) - - def test_pseries_kvm(self): - """ - :avocado: tags=machine:pseries - :avocado: tags=accel:kvm - """ - self.require_accelerator("kvm") - self.vm.add_args("-accel", "kvm") - self.vm.add_args("-machine", "cap-ccf-assist=off") - self.launch_and_wait(set_up_ssh_connection=False) - -class BootLinuxS390X(LinuxTest): - """ - :avocado: tags=arch:s390x - """ - - timeout = 240 - - @skipUnless(os.getenv('SPEED') == 'slow', 'runtime limited') - def test_s390_ccw_virtio_tcg(self): - """ - :avocado: tags=machine:s390-ccw-virtio - :avocado: tags=accel:tcg - """ - self.require_accelerator("tcg") - self.vm.add_args("-accel", "tcg") - self.launch_and_wait(set_up_ssh_connection=False) From 7fecdb0acd99fa838bb461c67164f6119ec1a3bb Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:25 +0200 Subject: [PATCH 0065/2760] tests/functional: Use the tuxrun kernel for the x86 replay test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we can do a full boot in record-replay mode and should get a similar test coverage compared to the old replay test from tests/avocado/replay_linux.py. Thus remove the x86 avocado replay_linux test now. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-12-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/avocado/replay_linux.py | 46 -------------------------- tests/functional/test_x86_64_replay.py | 43 ++++++++++++++++++------ 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py index 5916922435..6ba283d3bf 100644 --- a/tests/avocado/replay_linux.py +++ b/tests/avocado/replay_linux.py @@ -118,52 +118,6 @@ class ReplayLinux(LinuxTest): except subprocess.CalledProcessError: self.fail('replay-dump.py failed') -@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') -class ReplayLinuxX8664(ReplayLinux): - """ - :avocado: tags=arch:x86_64 - :avocado: tags=accel:tcg - """ - - chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' - - def test_pc_i440fx(self): - """ - :avocado: tags=machine:pc - """ - self.run_rr(shift=1) - - def test_pc_q35(self): - """ - :avocado: tags=machine:q35 - """ - self.run_rr(shift=3) - -@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') -class ReplayLinuxX8664Virtio(ReplayLinux): - """ - :avocado: tags=arch:x86_64 - :avocado: tags=virtio - :avocado: tags=accel:tcg - """ - - hdd = 'virtio-blk-pci' - cd = 'virtio-blk-pci' - bus = None - - chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' - - def test_pc_i440fx(self): - """ - :avocado: tags=machine:pc - """ - self.run_rr(shift=1) - - def test_pc_q35(self): - """ - :avocado: tags=machine:q35 - """ - self.run_rr(shift=3) @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') class ReplayLinuxAarch64(ReplayLinux): diff --git a/tests/functional/test_x86_64_replay.py b/tests/functional/test_x86_64_replay.py index 180f23a60c..27287d452d 100755 --- a/tests/functional/test_x86_64_replay.py +++ b/tests/functional/test_x86_64_replay.py @@ -5,30 +5,53 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, skipFlakyTest +from subprocess import check_call, DEVNULL + +from qemu_test import Asset, skipFlakyTest, get_qemu_img from replay_kernel import ReplayKernelBase class X86Replay(ReplayKernelBase): ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora/linux' - '/releases/29/Everything/x86_64/os/images/pxeboot/vmlinuz'), - '8f237d84712b1b411baf3af2aeaaee10b9aae8e345ec265b87ab3a39639eb143') + 'https://storage.tuxboot.com/buildroot/20241119/x86_64/bzImage', + 'f57bfc6553bcd6e0a54aab86095bf642b33b5571d14e3af1731b18c87ed5aef8') - def do_test_x86(self, machine): + ASSET_ROOTFS = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/x86_64/rootfs.ext4.zst', + '4b8b2a99117519c5290e1202cb36eb6c7aaba92b357b5160f5970cf5fb78a751') + + def do_test_x86(self, machine, blkdevice, devroot): + self.require_netdev('user') self.set_machine(machine) + self.cpu="Nehalem" kernel_path = self.ASSET_KERNEL.fetch() - kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0' - console_pattern = 'VFS: Cannot open root device' - self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5) + + raw_disk = self.uncompress(self.ASSET_ROOTFS) + disk = self.scratch_file('scratch.qcow2') + qemu_img = get_qemu_img(self) + check_call([qemu_img, 'create', '-f', 'qcow2', '-b', raw_disk, + '-F', 'raw', disk], stdout=DEVNULL, stderr=DEVNULL) + + args = ('-drive', 'file=%s,snapshot=on,id=hd0,if=none' % disk, + '-drive', 'driver=blkreplay,id=hd0-rr,if=none,image=hd0', + '-device', '%s,drive=hd0-rr' % blkdevice, + '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', + '-device', 'virtio-net,netdev=vnet', + '-object', 'filter-replay,id=replay,netdev=vnet') + + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + + f"console=ttyS0 root=/dev/{devroot}") + console_pattern = 'Welcome to TuxTest' + self.run_rr(kernel_path, kernel_command_line, console_pattern, shift=5, + args=args) @skipFlakyTest('https://gitlab.com/qemu-project/qemu/-/issues/2094') def test_pc(self): - self.do_test_x86('pc') + self.do_test_x86('pc', 'virtio-blk', 'vda') def test_q35(self): - self.do_test_x86('q35') + self.do_test_x86('q35', 'ide-hd', 'sda') if __name__ == '__main__': From a820caf8444c963faf69228e4a0a0d4673c24ab5 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:26 +0200 Subject: [PATCH 0066/2760] tests/functional: Use the tuxrun kernel for the aarch64 replay test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way we can do a full boot in record-replay mode and should get a similar test coverage compared to the old replay test from tests/avocado/replay_linux.py. Since the aarch64 test was the last avocado test in the tests/avocado/replay_linux.py file, we can remove this file now completely. Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth Message-ID: <20250414113031.151105-13-thuth@redhat.com> --- MAINTAINERS | 1 - tests/avocado/replay_linux.py | 160 ------------------------ tests/functional/test_aarch64_replay.py | 37 ++++-- 3 files changed, 29 insertions(+), 169 deletions(-) delete mode 100644 tests/avocado/replay_linux.py diff --git a/MAINTAINERS b/MAINTAINERS index 72f6b208f5..e29910cbd7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3668,7 +3668,6 @@ F: include/system/replay.h F: docs/devel/replay.rst F: docs/system/replay.rst F: stubs/replay.c -F: tests/avocado/replay_linux.py F: tests/functional/*reverse_debug*.py F: tests/functional/*replay*.py F: qapi/replay.json diff --git a/tests/avocado/replay_linux.py b/tests/avocado/replay_linux.py deleted file mode 100644 index 6ba283d3bf..0000000000 --- a/tests/avocado/replay_linux.py +++ /dev/null @@ -1,160 +0,0 @@ -# Record/replay test that boots a complete Linux system via a cloud image -# -# Copyright (c) 2020 ISP RAS -# -# Author: -# Pavel Dovgalyuk -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os -import logging -import time - -from avocado import skipUnless -from avocado_qemu import BUILD_DIR -from avocado.utils import cloudinit -from avocado.utils import network -from avocado.utils import vmimage -from avocado.utils import datadrainer -from avocado.utils.path import find_command -from avocado_qemu.linuxtest import LinuxTest - -class ReplayLinux(LinuxTest): - """ - Boots a Linux system, checking for a successful initialization - """ - - timeout = 1800 - chksum = None - hdd = 'ide-hd' - cd = 'ide-cd' - bus = 'ide' - - def setUp(self): - # LinuxTest does many replay-incompatible things, but includes - # useful methods. Do not setup LinuxTest here and just - # call some functions. - super(LinuxTest, self).setUp() - self._set_distro() - self.boot_path = self.download_boot() - self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0), - self.name) - ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys() - self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey) - - def vm_add_disk(self, vm, path, id, device): - bus_string = '' - if self.bus: - bus_string = ',bus=%s.%d' % (self.bus, id,) - vm.add_args('-drive', 'file=%s,snapshot=on,id=disk%s,if=none' % (path, id)) - vm.add_args('-drive', - 'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id)) - vm.add_args('-device', - '%s,drive=disk%s-rr%s' % (device, id, bus_string)) - - def vm_add_cdrom(self, vm, path, id, device): - vm.add_args('-drive', 'file=%s,id=disk%s,if=none,media=cdrom' % (path, id)) - - def launch_and_wait(self, record, args, shift): - self.require_netdev('user') - vm = self.get_vm() - vm.add_args('-smp', '1') - vm.add_args('-m', '1024') - vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', - '-device', 'virtio-net,netdev=vnet') - vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet') - if args: - vm.add_args(*args) - self.vm_add_disk(vm, self.boot_path, 0, self.hdd) - self.vm_add_cdrom(vm, self.cloudinit_path, 1, self.cd) - logger = logging.getLogger('replay') - if record: - logger.info('recording the execution...') - mode = 'record' - else: - logger.info('replaying the execution...') - mode = 'replay' - replay_path = os.path.join(self.workdir, 'replay.bin') - vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % - (shift, mode, replay_path)) - - start_time = time.time() - - vm.set_console() - vm.launch() - console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(), - logger=self.log.getChild('console'), - stop_check=(lambda : not vm.is_running())) - console_drainer.start() - if record: - while not self.phone_server.instance_phoned_back: - self.phone_server.handle_request() - vm.shutdown() - logger.info('finished the recording with log size %s bytes' - % os.path.getsize(replay_path)) - self.run_replay_dump(replay_path) - logger.info('successfully tested replay-dump.py') - else: - vm.event_wait('SHUTDOWN', self.timeout) - vm.wait() - logger.info('successfully finished the replay') - elapsed = time.time() - start_time - logger.info('elapsed time %.2f sec' % elapsed) - return elapsed - - def run_rr(self, args=None, shift=7): - t1 = self.launch_and_wait(True, args, shift) - t2 = self.launch_and_wait(False, args, shift) - logger = logging.getLogger('replay') - logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) - - def run_replay_dump(self, replay_path): - try: - subprocess.check_call(["./scripts/replay-dump.py", - "-f", replay_path], - stdout=subprocess.DEVNULL) - except subprocess.CalledProcessError: - self.fail('replay-dump.py failed') - - -@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') -class ReplayLinuxAarch64(ReplayLinux): - """ - :avocado: tags=accel:tcg - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - :avocado: tags=cpu:max - """ - - chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49' - - hdd = 'virtio-blk-device' - cd = 'virtio-blk-device' - bus = None - - def get_common_args(self): - return ('-bios', - os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'), - "-cpu", "max,lpa2=off", - '-device', 'virtio-rng-pci,rng=rng0', - '-object', 'rng-builtin,id=rng0') - - def test_virt_gicv2(self): - """ - :avocado: tags=machine:gic-version=2 - """ - - self.run_rr(shift=3, - args=(*self.get_common_args(), - "-machine", "virt,gic-version=2")) - - def test_virt_gicv3(self): - """ - :avocado: tags=machine:gic-version=3 - """ - - self.run_rr(shift=3, - args=(*self.get_common_args(), - "-machine", "virt,gic-version=3")) diff --git a/tests/functional/test_aarch64_replay.py b/tests/functional/test_aarch64_replay.py index bd6609d914..db12e76603 100755 --- a/tests/functional/test_aarch64_replay.py +++ b/tests/functional/test_aarch64_replay.py @@ -5,25 +5,46 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, skipIfOperatingSystem +from subprocess import check_call, DEVNULL + +from qemu_test import Asset, skipIfOperatingSystem, get_qemu_img from replay_kernel import ReplayKernelBase class Aarch64Replay(ReplayKernelBase): ASSET_KERNEL = Asset( - ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' - 'releases/29/Everything/aarch64/os/images/pxeboot/vmlinuz'), - '7e1430b81c26bdd0da025eeb8fbd77b5dc961da4364af26e771bd39f379cbbf7') + 'https://storage.tuxboot.com/buildroot/20241119/arm64/Image', + 'b74743c5e89e1cea0f73368d24ae0ae85c5204ff84be3b5e9610417417d2f235') + + ASSET_ROOTFS = Asset( + 'https://storage.tuxboot.com/buildroot/20241119/arm64/rootfs.ext4.zst', + 'a1acaaae2068df4648d04ff75f532aaa8c5edcd6b936122b6f0db4848a07b465') def test_aarch64_virt(self): + self.require_netdev('user') self.set_machine('virt') - self.cpu = 'cortex-a53' + self.cpu = 'cortex-a57' kernel_path = self.ASSET_KERNEL.fetch() + + raw_disk = self.uncompress(self.ASSET_ROOTFS) + disk = self.scratch_file('scratch.qcow2') + qemu_img = get_qemu_img(self) + check_call([qemu_img, 'create', '-f', 'qcow2', '-b', raw_disk, + '-F', 'raw', disk], stdout=DEVNULL, stderr=DEVNULL) + + args = ('-drive', 'file=%s,snapshot=on,id=hd0,if=none' % disk, + '-drive', 'driver=blkreplay,id=hd0-rr,if=none,image=hd0', + '-device', 'virtio-blk-device,drive=hd0-rr', + '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', + '-device', 'virtio-net,netdev=vnet', + '-object', 'filter-replay,id=replay,netdev=vnet') + kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + - 'console=ttyAMA0') - console_pattern = 'VFS: Cannot open root device' - self.run_rr(kernel_path, kernel_command_line, console_pattern) + 'console=ttyAMA0 root=/dev/vda') + console_pattern = 'Welcome to TuxTest' + self.run_rr(kernel_path, kernel_command_line, console_pattern, + args=args) if __name__ == '__main__': From 5c2bae2155b162f7355ca759881c5fdaaf7bc209 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:27 +0200 Subject: [PATCH 0067/2760] tests/functional: Convert the SMMU test to the functional framework This test was using cloudinit and a "dnf install" command in the guest to exercise the NIC with SMMU enabled. Since we don't have the cloudinit stuff in the functional framework and we should not rely on having access to external networks (once our ASSETs have been cached), we rather boot into the initrd first, manually mount the root disk and then use the check_http_download() function from the functional framework here instead for testing whether the network works as expected. Unfortunately, there seems to be a small race when using the files from Fedora 33: To enter the initrd shell, we have to send a "return" once. But it does not seem to work if we send it too early. Using a sleep(0.2) makes it work reliably for me, but to make it even more unlikely to trigger this situation, let's better limit the Fedora 33 tests to only run with KVM. Finally, while we're at it, we also add some lines for testing writes to the hard disk, as we already do it in the test_intel_iommu test. Reviewed-by: Eric Auger Tested-by: Eric Auger Message-ID: <20250414113031.151105-14-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 2 +- tests/avocado/smmu.py | 139 ----------------- tests/functional/meson.build | 2 + tests/functional/test_aarch64_smmu.py | 205 ++++++++++++++++++++++++++ 4 files changed, 208 insertions(+), 140 deletions(-) delete mode 100644 tests/avocado/smmu.py create mode 100755 tests/functional/test_aarch64_smmu.py diff --git a/MAINTAINERS b/MAINTAINERS index e29910cbd7..07f77c048e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -211,7 +211,7 @@ L: qemu-arm@nongnu.org S: Maintained F: hw/arm/smmu* F: include/hw/arm/smmu* -F: tests/avocado/smmu.py +F: tests/functional/test_aarch64_smmu.py AVR TCG CPUs M: Michael Rolnik diff --git a/tests/avocado/smmu.py b/tests/avocado/smmu.py deleted file mode 100644 index 83fd79e922..0000000000 --- a/tests/avocado/smmu.py +++ /dev/null @@ -1,139 +0,0 @@ -# SMMUv3 Functional tests -# -# Copyright (c) 2021 Red Hat, Inc. -# -# Author: -# Eric Auger -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. -import os - -from avocado import skipUnless -from avocado_qemu import BUILD_DIR -from avocado_qemu.linuxtest import LinuxTest - -@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') -class SMMU(LinuxTest): - """ - :avocado: tags=accel:kvm - :avocado: tags=cpu:host - :avocado: tags=arch:aarch64 - :avocado: tags=machine:virt - :avocado: tags=distro:fedora - :avocado: tags=smmu - :avocado: tags=flaky - """ - - IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on' - kernel_path = None - initrd_path = None - kernel_params = None - - def set_up_boot(self): - path = self.download_boot() - self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' + - 'drive=drv0,id=virtio-disk0,bootindex=1,' - 'werror=stop,rerror=stop' + self.IOMMU_ADDON) - self.vm.add_args('-drive', - 'file=%s,if=none,cache=writethrough,id=drv0' % path) - - def setUp(self): - super(SMMU, self).setUp(None, 'virtio-net-pci' + self.IOMMU_ADDON) - - def common_vm_setup(self, custom_kernel=False): - self.require_accelerator("kvm") - self.vm.add_args("-accel", "kvm") - self.vm.add_args("-cpu", "host") - self.vm.add_args("-machine", "iommu=smmuv3") - self.vm.add_args("-d", "guest_errors") - self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', - 'edk2-aarch64-code.fd')) - self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') - self.vm.add_args('-object', - 'rng-random,id=rng0,filename=/dev/urandom') - - if custom_kernel is False: - return - - kernel_url = self.distro.pxeboot_url + 'vmlinuz' - initrd_url = self.distro.pxeboot_url + 'initrd.img' - self.kernel_path = self.fetch_asset(kernel_url) - self.initrd_path = self.fetch_asset(initrd_url) - - def run_and_check(self): - if self.kernel_path: - self.vm.add_args('-kernel', self.kernel_path, - '-append', self.kernel_params, - '-initrd', self.initrd_path) - self.launch_and_wait() - self.ssh_command('cat /proc/cmdline') - self.ssh_command('dnf -y install numactl-devel') - - - # 5.3 kernel without RIL # - - def test_smmu_noril(self): - """ - :avocado: tags=smmu_noril - :avocado: tags=smmu_noril_tests - :avocado: tags=distro_version:31 - """ - self.common_vm_setup() - self.run_and_check() - - def test_smmu_noril_passthrough(self): - """ - :avocado: tags=smmu_noril_passthrough - :avocado: tags=smmu_noril_tests - :avocado: tags=distro_version:31 - """ - self.common_vm_setup(True) - self.kernel_params = (self.distro.default_kernel_params + - ' iommu.passthrough=on') - self.run_and_check() - - def test_smmu_noril_nostrict(self): - """ - :avocado: tags=smmu_noril_nostrict - :avocado: tags=smmu_noril_tests - :avocado: tags=distro_version:31 - """ - self.common_vm_setup(True) - self.kernel_params = (self.distro.default_kernel_params + - ' iommu.strict=0') - self.run_and_check() - - # 5.8 kernel featuring range invalidation - # >= v5.7 kernel - - def test_smmu_ril(self): - """ - :avocado: tags=smmu_ril - :avocado: tags=smmu_ril_tests - :avocado: tags=distro_version:33 - """ - self.common_vm_setup() - self.run_and_check() - - def test_smmu_ril_passthrough(self): - """ - :avocado: tags=smmu_ril_passthrough - :avocado: tags=smmu_ril_tests - :avocado: tags=distro_version:33 - """ - self.common_vm_setup(True) - self.kernel_params = (self.distro.default_kernel_params + - ' iommu.passthrough=on') - self.run_and_check() - - def test_smmu_ril_nostrict(self): - """ - :avocado: tags=smmu_ril_nostrict - :avocado: tags=smmu_ril_tests - :avocado: tags=distro_version:33 - """ - self.common_vm_setup(True) - self.kernel_params = (self.distro.default_kernel_params + - ' iommu.strict=0') - self.run_and_check() diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 985ac5c27f..b317ad42c5 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -18,6 +18,7 @@ test_timeouts = { 'aarch64_rme_sbsaref' : 1200, 'aarch64_sbsaref_alpine' : 1200, 'aarch64_sbsaref_freebsd' : 720, + 'aarch64_smmu' : 720, 'aarch64_tuxrun' : 240, 'aarch64_virt' : 360, 'aarch64_virt_gpu' : 480, @@ -88,6 +89,7 @@ tests_aarch64_system_thorough = [ 'aarch64_sbsaref', 'aarch64_sbsaref_alpine', 'aarch64_sbsaref_freebsd', + 'aarch64_smmu', 'aarch64_tcg_plugins', 'aarch64_tuxrun', 'aarch64_virt', diff --git a/tests/functional/test_aarch64_smmu.py b/tests/functional/test_aarch64_smmu.py new file mode 100755 index 0000000000..c65d0f2817 --- /dev/null +++ b/tests/functional/test_aarch64_smmu.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python3 +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# SMMUv3 Functional tests +# +# Copyright (c) 2021 Red Hat, Inc. +# +# Author: +# Eric Auger +# +# This work is licensed under the terms of the GNU GPL, version 2 or +# later. See the COPYING file in the top-level directory. + +import os +import time + +from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern +from qemu_test import BUILD_DIR +from qemu.utils import kvm_available + + +class SMMU(LinuxKernelTest): + + default_kernel_params = ('earlyprintk=pl011,0x9000000 no_timer_check ' + 'printk.time=1 rd_NO_PLYMOUTH net.ifnames=0 ' + 'console=ttyAMA0 rd.rescue') + IOMMU_ADDON = ',iommu_platform=on,disable-modern=off,disable-legacy=on' + kernel_path = None + initrd_path = None + kernel_params = None + + GUEST_PORT = 8080 + + def set_up_boot(self, path): + self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' + + 'drive=drv0,id=virtio-disk0,bootindex=1,' + 'werror=stop,rerror=stop' + self.IOMMU_ADDON) + self.vm.add_args('-drive', + f'file={path},if=none,cache=writethrough,id=drv0,snapshot=on') + + self.vm.add_args('-netdev', + 'user,id=n1,hostfwd=tcp:127.0.0.1:0-:%d' % + self.GUEST_PORT) + self.vm.add_args('-device', 'virtio-net,netdev=n1' + self.IOMMU_ADDON) + + def common_vm_setup(self, kernel, initrd, disk): + self.require_accelerator("kvm") + self.require_netdev('user') + self.set_machine("virt") + self.vm.add_args('-m', '1G') + self.vm.add_args("-accel", "kvm") + self.vm.add_args("-cpu", "host") + self.vm.add_args("-machine", "iommu=smmuv3") + self.vm.add_args("-d", "guest_errors") + self.vm.add_args('-bios', os.path.join(BUILD_DIR, 'pc-bios', + 'edk2-aarch64-code.fd')) + self.vm.add_args('-device', 'virtio-rng-pci,rng=rng0') + self.vm.add_args('-object', + 'rng-random,id=rng0,filename=/dev/urandom') + + self.kernel_path = kernel.fetch() + self.initrd_path = initrd.fetch() + self.set_up_boot(disk.fetch()) + + def run_and_check(self, filename, hashsum): + self.vm.add_args('-initrd', self.initrd_path) + self.vm.add_args('-append', self.kernel_params) + self.launch_kernel(self.kernel_path, initrd=self.initrd_path, + wait_for='attach it to a bug report.') + prompt = '# ' + # Fedora 33 requires 'return' to be pressed to enter the shell. + # There seems to be a small race between detecting the previous ':' + # and sending the newline, so we need to add a small delay here. + self.wait_for_console_pattern(':') + time.sleep(0.2) + exec_command_and_wait_for_pattern(self, '\n', prompt) + exec_command_and_wait_for_pattern(self, 'cat /proc/cmdline', + self.kernel_params) + + # Checking for SMMU enablement: + self.log.info("Checking whether SMMU has been enabled...") + exec_command_and_wait_for_pattern(self, 'dmesg | grep smmu', + 'arm-smmu-v3') + self.wait_for_console_pattern(prompt) + exec_command_and_wait_for_pattern(self, + 'find /sys/kernel/iommu_groups/ -type l', + 'devices/0000:00:') + self.wait_for_console_pattern(prompt) + + # Copy a file (checked later), umount afterwards to drop disk cache: + self.log.info("Checking hard disk...") + exec_command_and_wait_for_pattern(self, + "while ! (dmesg -c | grep vda:) ; do sleep 1 ; done", + "vda2") + exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot', + 'mounted filesystem') + exec_command_and_wait_for_pattern(self, 'cp /bin/vi /sysroot/root/vi', + prompt) + exec_command_and_wait_for_pattern(self, 'umount /sysroot', prompt) + # Switch from initrd to the cloud image filesystem: + exec_command_and_wait_for_pattern(self, 'mount /dev/vda2 /sysroot', + prompt) + exec_command_and_wait_for_pattern(self, + ('for d in dev proc sys run ; do ' + 'mount -o bind /$d /sysroot/$d ; done'), prompt) + exec_command_and_wait_for_pattern(self, 'chroot /sysroot', prompt) + # Check files on the hard disk: + exec_command_and_wait_for_pattern(self, + ('if diff -q /root/vi /usr/bin/vi ; then echo "file" "ok" ; ' + 'else echo "files differ"; fi'), 'file ok') + self.wait_for_console_pattern(prompt) + exec_command_and_wait_for_pattern(self, f'sha256sum {filename}', + hashsum) + + # Check virtio-net via HTTP: + exec_command_and_wait_for_pattern(self, 'dhclient eth0', prompt) + self.check_http_download(filename, hashsum, self.GUEST_PORT) + + + # 5.3 kernel without RIL # + + ASSET_KERNEL_F31 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/31/Server/aarch64/os/images/pxeboot/vmlinuz'), + '3ae07fcafbfc8e4abeb693035a74fe10698faae15e9ccd48882a9167800c1527') + + ASSET_INITRD_F31 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/31/Server/aarch64/os/images/pxeboot/initrd.img'), + '9f3146b28bc531c689f3c5f114cb74e4bd7bd548e0ba19fa77921d8bd256755a') + + ASSET_DISK_F31 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' + '/31/Cloud/aarch64/images/Fedora-Cloud-Base-31-1.9.aarch64.qcow2'), + '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49') + + F31_FILENAME = '/boot/initramfs-5.3.7-301.fc31.aarch64.img' + F31_HSUM = '1a4beec6607d94df73d9dd1b4985c9c23dd0fdcf4e6ca1351d477f190df7bef9' + + def test_smmu_noril(self): + self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, + self.ASSET_DISK_F31) + self.kernel_params = self.default_kernel_params + self.run_and_check(self.F31_FILENAME, self.F31_HSUM) + + def test_smmu_noril_passthrough(self): + self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, + self.ASSET_DISK_F31) + self.kernel_params = (self.default_kernel_params + + ' iommu.passthrough=on') + self.run_and_check(self.F31_FILENAME, self.F31_HSUM) + + def test_smmu_noril_nostrict(self): + self.common_vm_setup(self.ASSET_KERNEL_F31, self.ASSET_INITRD_F31, + self.ASSET_DISK_F31) + self.kernel_params = (self.default_kernel_params + + ' iommu.strict=0') + self.run_and_check(self.F31_FILENAME, self.F31_HSUM) + + + # 5.8 kernel featuring range invalidation + # >= v5.7 kernel + + ASSET_KERNEL_F33 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/33/Server/aarch64/os/images/pxeboot/vmlinuz'), + 'd8b1e6f7241f339d8e7609c456cf0461ffa4583ed07e0b55c7d1d8a0c154aa89') + + ASSET_INITRD_F33 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/' + 'releases/33/Server/aarch64/os/images/pxeboot/initrd.img'), + '92513f55295c2c16a777f7b6c35ccd70a438e9e1e40b6ba39e0e60900615b3df') + + ASSET_DISK_F33 = Asset( + ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' + '/33/Cloud/aarch64/images/Fedora-Cloud-Base-33-1.2.aarch64.qcow2'), + 'e7f75cdfd523fe5ac2ca9eeece68edc1a81f386a17f969c1d1c7c87031008a6b') + + F33_FILENAME = '/boot/initramfs-5.8.15-301.fc33.aarch64.img' + F33_HSUM = '079cfad0caa82e84c8ca1fb0897a4999dd769f262216099f518619e807a550d9' + + def test_smmu_ril(self): + self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, + self.ASSET_DISK_F33) + self.kernel_params = self.default_kernel_params + self.run_and_check(self.F33_FILENAME, self.F33_HSUM) + + def test_smmu_ril_passthrough(self): + self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, + self.ASSET_DISK_F33) + self.kernel_params = (self.default_kernel_params + + ' iommu.passthrough=on') + self.run_and_check(self.F33_FILENAME, self.F33_HSUM) + + def test_smmu_ril_nostrict(self): + self.common_vm_setup(self.ASSET_KERNEL_F33, self.ASSET_INITRD_F33, + self.ASSET_DISK_F33) + self.kernel_params = (self.default_kernel_params + + ' iommu.strict=0') + self.run_and_check(self.F33_FILENAME, self.F33_HSUM) + + +if __name__ == '__main__': + LinuxKernelTest.main() From f8c54844175922d77faa8b586f451e379d53a191 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:28 +0200 Subject: [PATCH 0068/2760] gitlab-ci: Update QEMU_JOB_AVOCADO and QEMU_CI_AVOCADO_TESTING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we don't run the Avocado jobs in the CI anymore, rename these variables to QEMU_JOB_FUNCTIONAL and QEMU_CI_FUNCTIONAL. Also, there was a mismatch between the documentation and the implementation of QEMU_CI_AVOCADO_TESTING: While the documentation said that you had to "Set this variable to have the tests using the Avocado framework run automatically", you indeed needed to set it to make the pipelines appear in your dashboard - but they were never run automatically in forks and had to be triggered manually. Let's improve this now: No need to hide these pipelines from the users by default anymore (the functional tests should be stable enough nowadays), and rather allow the users to run the pipelines auto- matically with this switch now instead, as was documented. Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-15-thuth@redhat.com> Signed-off-by: Thomas Huth --- .gitlab-ci.d/base.yml | 8 ++------ .gitlab-ci.d/buildtest-template.yml | 2 +- docs/devel/testing/ci-jobs.rst.inc | 19 +++++++++---------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.gitlab-ci.d/base.yml b/.gitlab-ci.d/base.yml index 25b88aaa06..60a24a9d14 100644 --- a/.gitlab-ci.d/base.yml +++ b/.gitlab-ci.d/base.yml @@ -69,10 +69,6 @@ variables: - if: '$QEMU_CI != "1" && $QEMU_CI != "2" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: never - # Avocado jobs don't run in forks unless $QEMU_CI_AVOCADO_TESTING is set - - if: '$QEMU_JOB_AVOCADO && $QEMU_CI_AVOCADO_TESTING != "1" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' - when: never - ############################################################# # Stage 2: fine tune execution of jobs in specific scenarios @@ -101,8 +97,8 @@ variables: when: manual allow_failure: true - # Avocado jobs can be manually start in forks if $QEMU_CI_AVOCADO_TESTING is unset - - if: '$QEMU_JOB_AVOCADO && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' + # Functional jobs can be manually started in forks + - if: '$QEMU_JOB_FUNCTIONAL && $QEMU_CI_FUNCTIONAL != "1" && $CI_PROJECT_NAMESPACE != $QEMU_CI_UPSTREAM' when: manual allow_failure: true diff --git a/.gitlab-ci.d/buildtest-template.yml b/.gitlab-ci.d/buildtest-template.yml index 13fa4f4a4f..d4f145fdb5 100644 --- a/.gitlab-ci.d/buildtest-template.yml +++ b/.gitlab-ci.d/buildtest-template.yml @@ -114,4 +114,4 @@ - cd build - du -chs ${CI_PROJECT_DIR}/*-cache variables: - QEMU_JOB_AVOCADO: 1 + QEMU_JOB_FUNCTIONAL: 1 diff --git a/docs/devel/testing/ci-jobs.rst.inc b/docs/devel/testing/ci-jobs.rst.inc index 3756bbe355..f1c541cc25 100644 --- a/docs/devel/testing/ci-jobs.rst.inc +++ b/docs/devel/testing/ci-jobs.rst.inc @@ -126,10 +126,10 @@ QEMU_JOB_PUBLISH The job is for publishing content after a branch has been merged into the upstream default branch. -QEMU_JOB_AVOCADO -~~~~~~~~~~~~~~~~ +QEMU_JOB_FUNCTIONAL +~~~~~~~~~~~~~~~~~~~ -The job runs the Avocado integration test suite +The job runs the functional test suite Contributor controlled runtime variables ---------------------------------------- @@ -149,13 +149,12 @@ the jobs to be manually started from the UI Set this variable to 2 to create the pipelines and run all the jobs immediately, as was the historical behaviour -QEMU_CI_AVOCADO_TESTING -~~~~~~~~~~~~~~~~~~~~~~~ -By default, tests using the Avocado framework are not run automatically in -the pipelines (because multiple artifacts have to be downloaded, and if -these artifacts are not already cached, downloading them make the jobs -reach the timeout limit). Set this variable to have the tests using the -Avocado framework run automatically. +QEMU_CI_FUNCTIONAL +~~~~~~~~~~~~~~~~~~ +By default, tests using the functional framework are not run automatically +in the pipelines (because multiple artifacts have to be downloaded, which +might cause a lot of network traffic). Set this variable to have the tests +using the functional framework run automatically. Other misc variables -------------------- From 5748e464150911127d07c0b7adeea474fd905149 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 14 Mar 2025 09:59:57 +0100 Subject: [PATCH 0069/2760] docs/devel/testing: Dissolve the ci-definitions.rst.inc file This file was meant for defining the vocabulary for our testing efforts, but it did not age well: First, the definitions are not only about the CI part, but also about testing in general, so most of the information should rather reside in main.rst instead. Second, some vocabulary has never been really adopted by the QEMU project, for example we never really use the word "system testing" since "system" rather means the system emulator binaries in the QEMU project (and we also don't do any testing with other components like libvirt and virt-managers here). It also defines that the qtests are the "functional" tests in QEMU, which is not really up to date anymore after the "tests/functional" framework has been introduced a couple of months ago (FWIW, the qtests could rather be seen as a mix between unit testing and functional testing). To solve this problem, move the useful parts of this file into main.rst and directly into ci.rst, and drop the ones (like "system testing") that we don't really need anymore. Message-ID: <20250314085959.1585568-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- docs/devel/testing/ci-definitions.rst.inc | 121 ---------------------- docs/devel/testing/ci.rst | 28 ++++- docs/devel/testing/main.rst | 65 ++++++++++-- 3 files changed, 81 insertions(+), 133 deletions(-) delete mode 100644 docs/devel/testing/ci-definitions.rst.inc diff --git a/docs/devel/testing/ci-definitions.rst.inc b/docs/devel/testing/ci-definitions.rst.inc deleted file mode 100644 index 6d5c6fd9f2..0000000000 --- a/docs/devel/testing/ci-definitions.rst.inc +++ /dev/null @@ -1,121 +0,0 @@ -Definition of terms -=================== - -This section defines the terms used in this document and correlates them with -what is currently used on QEMU. - -Automated tests ---------------- - -An automated test is written on a test framework using its generic test -functions/classes. The test framework can run the tests and report their -success or failure [1]_. - -An automated test has essentially three parts: - -1. The test initialization of the parameters, where the expected parameters, - like inputs and expected results, are set up; -2. The call to the code that should be tested; -3. An assertion, comparing the result from the previous call with the expected - result set during the initialization of the parameters. If the result - matches the expected result, the test has been successful; otherwise, it has - failed. - -Unit testing ------------- - -A unit test is responsible for exercising individual software components as a -unit, like interfaces, data structures, and functionality, uncovering errors -within the boundaries of a component. The verification effort is in the -smallest software unit and focuses on the internal processing logic and data -structures. A test case of unit tests should be designed to uncover errors due -to erroneous computations, incorrect comparisons, or improper control flow [2]_. - -On QEMU, unit testing is represented by the 'check-unit' target from 'make'. - -Functional testing ------------------- - -A functional test focuses on the functional requirement of the software. -Deriving sets of input conditions, the functional tests should fully exercise -all the functional requirements for a program. Functional testing is -complementary to other testing techniques, attempting to find errors like -incorrect or missing functions, interface errors, behavior errors, and -initialization and termination errors [3]_. - -On QEMU, functional testing is represented by the 'check-qtest' target from -'make'. - -System testing --------------- - -System tests ensure all application elements mesh properly while the overall -functionality and performance are achieved [4]_. Some or all system components -are integrated to create a complete system to be tested as a whole. System -testing ensures that components are compatible, interact correctly, and -transfer the right data at the right time across their interfaces. As system -testing focuses on interactions, use case-based testing is a practical approach -to system testing [5]_. Note that, in some cases, system testing may require -interaction with third-party software, like operating system images, databases, -networks, and so on. - -On QEMU, system testing is represented by the 'check-avocado' target from -'make'. - -Flaky tests ------------ - -A flaky test is defined as a test that exhibits both a passing and a failing -result with the same code on different runs. Some usual reasons for an -intermittent/flaky test are async wait, concurrency, and test order dependency -[6]_. - -Gating ------- - -A gate restricts the move of code from one stage to another on a -test/deployment pipeline. The step move is granted with approval. The approval -can be a manual intervention or a set of tests succeeding [7]_. - -On QEMU, the gating process happens during the pull request. The approval is -done by the project leader running its own set of tests. The pull request gets -merged when the tests succeed. - -Continuous Integration (CI) ---------------------------- - -Continuous integration (CI) requires the builds of the entire application and -the execution of a comprehensive set of automated tests every time there is a -need to commit any set of changes [8]_. The automated tests can be composed of -the unit, functional, system, and other tests. - -Keynotes about continuous integration (CI) [9]_: - -1. System tests may depend on external software (operating system images, - firmware, database, network). -2. It may take a long time to build and test. It may be impractical to build - the system being developed several times per day. -3. If the development platform is different from the target platform, it may - not be possible to run system tests in the developer’s private workspace. - There may be differences in hardware, operating system, or installed - software. Therefore, more time is required for testing the system. - -References ----------- - -.. [1] Sommerville, Ian (2016). Software Engineering. p. 233. -.. [2] Pressman, Roger S. & Maxim, Bruce R. (2020). Software Engineering, - A Practitioner’s Approach. p. 48, 376, 378, 381. -.. [3] Pressman, Roger S. & Maxim, Bruce R. (2020). Software Engineering, - A Practitioner’s Approach. p. 388. -.. [4] Pressman, Roger S. & Maxim, Bruce R. (2020). Software Engineering, - A Practitioner’s Approach. Software Engineering, p. 377. -.. [5] Sommerville, Ian (2016). Software Engineering. p. 59, 232, 240. -.. [6] Luo, Qingzhou, et al. An empirical analysis of flaky tests. - Proceedings of the 22nd ACM SIGSOFT International Symposium on - Foundations of Software Engineering. 2014. -.. [7] Humble, Jez & Farley, David (2010). Continuous Delivery: - Reliable Software Releases Through Build, Test, and Deployment, p. 122. -.. [8] Humble, Jez & Farley, David (2010). Continuous Delivery: - Reliable Software Releases Through Build, Test, and Deployment, p. 55. -.. [9] Sommerville, Ian (2016). Software Engineering. p. 743. diff --git a/docs/devel/testing/ci.rst b/docs/devel/testing/ci.rst index ed88a2010b..e21d39db57 100644 --- a/docs/devel/testing/ci.rst +++ b/docs/devel/testing/ci.rst @@ -1,14 +1,34 @@ .. _ci: -== -CI -== +Continuous Integration (CI) +=========================== + +Continuous integration (CI) requires the builds of the entire application and +the execution of a comprehensive set of automated tests every time there is a +need to commit any set of changes [1]_. The automated tests are composed +of unit, functional and other tests. Most of QEMU's CI is run on GitLab's infrastructure although a number of other CI services are used for specialised purposes. The most up to date information about them and their status can be found on the `project wiki testing page `_. -.. include:: ci-definitions.rst.inc +These tests are also used as gating tests before merging pull requests. +A gating test restricts the move of code from one stage to another on a +test/deployment pipeline. The step move is granted with approval. The approval +can be a manual intervention or a set of tests succeeding [2]_. + +On QEMU, the gating process happens during the pull request. The approval is +done by the project leader running its own set of tests. The pull request gets +merged when the tests succeed. + .. include:: ci-jobs.rst.inc .. include:: ci-runners.rst.inc + +References +---------- + +.. [1] Humble, Jez & Farley, David (2010). Continuous Delivery: + Reliable Software Releases Through Build, Test, and Deployment, p. 55. +.. [2] Humble, Jez & Farley, David (2010). Continuous Delivery: + Reliable Software Releases Through Build, Test, and Deployment, p. 122. diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst index 9869bcf034..e56da22edf 100644 --- a/docs/devel/testing/main.rst +++ b/docs/devel/testing/main.rst @@ -5,19 +5,32 @@ Testing in QEMU QEMU's testing infrastructure is fairly complex as it covers everything from unit testing and exercising specific sub-systems all -the way to full blown acceptance tests. To get an overview of the +the way to full blown functional tests. To get an overview of the tests you can run ``make check-help`` from either the source or build tree. -Most (but not all) tests are also integrated into the meson build -system so can be run directly from the build tree, for example: - -.. code:: +Most (but not all) tests are also integrated as an automated test into +the meson build system so can be run directly from the build tree, +for example:: [./pyvenv/bin/]meson test --suite qemu:softfloat will run just the softfloat tests. +An automated test is written with one of the test frameworks using its +generic test functions/classes. The test framework can run the tests and +report their success or failure [1]_. + +An automated test has essentially three parts: + +1. The test initialization of the parameters, where the expected parameters, + like inputs and expected results, are set up; +2. The call to the code that should be tested; +3. An assertion, comparing the result from the previous call with the expected + result set during the initialization of the parameters. If the result + matches the expected result, the test has been successful; otherwise, it has + failed. + The rest of this document will cover the details for specific test groups. @@ -44,9 +57,17 @@ cannot find them. Unit tests ~~~~~~~~~~ -Unit tests, which can be invoked with ``make check-unit``, are simple C tests -that typically link to individual QEMU object files and exercise them by -calling exported functions. +A unit test is responsible for exercising individual software components as a +unit, like interfaces, data structures, and functionality, uncovering errors +within the boundaries of a component. The verification effort is in the +smallest software unit and focuses on the internal processing logic and data +structures. A test case of unit tests should be designed to uncover errors +due to erroneous computations, incorrect comparisons, or improper control +flow [2]_. + +In QEMU, unit tests can be invoked with ``make check-unit``. They are +simple C tests that typically link to individual QEMU object files and +exercise them by calling exported functions. If you are writing new code in QEMU, consider adding a unit test, especially for utility modules that are relatively stateless or have few dependencies. To @@ -885,6 +906,10 @@ changing the ``-c`` option. Functional tests using Python ----------------------------- +A functional test focuses on the functional requirement of the software, +attempting to find errors like incorrect functions, interface errors, +behavior errors, and initialization and termination errors [3]_. + The ``tests/functional`` directory hosts functional tests written in Python. You can run the functional tests simply by executing: @@ -1023,3 +1048,27 @@ coverage-html`` which will create Further analysis can be conducted by running the ``gcov`` command directly on the various .gcda output files. Please read the ``gcov`` documentation for more information. + +Flaky tests +----------- + +A flaky test is defined as a test that exhibits both a passing and a failing +result with the same code on different runs. Some usual reasons for an +intermittent/flaky test are async wait, concurrency, and test order dependency +[4]_. + +In QEMU, tests that are identified to be flaky are normally disabled by +default. Set the QEMU_TEST_FLAKY_TESTS environment variable before running +the tests to enable them. + +References +---------- + +.. [1] Sommerville, Ian (2016). Software Engineering. p. 233. +.. [2] Pressman, Roger S. & Maxim, Bruce R. (2020). Software Engineering, + A Practitioner’s Approach. p. 48, 376, 378, 381. +.. [3] Pressman, Roger S. & Maxim, Bruce R. (2020). Software Engineering, + A Practitioner’s Approach. p. 388. +.. [4] Luo, Qingzhou, et al. An empirical analysis of flaky tests. + Proceedings of the 22nd ACM SIGSOFT International Symposium on + Foundations of Software Engineering. 2014. From 52e9ed6d3ac44424e098333772077a41bb88c4db Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 13:30:29 +0200 Subject: [PATCH 0070/2760] Remove the remainders of the Avocado tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all Avocado tests have been converted to or been replaced by other functional tests, we can delete the remainders of the Avocado tests from the QEMU source tree. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Message-ID: <20250414113031.151105-16-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 8 +- configure | 2 +- docs/about/build-platforms.rst | 10 +- docs/devel/build-system.rst | 11 +- docs/devel/codebase.rst | 5 - docs/devel/testing/avocado.rst | 581 ------------------------ docs/devel/testing/functional.rst | 3 - docs/devel/testing/index.rst | 1 - docs/devel/testing/main.rst | 15 - pythondeps.toml | 8 +- tests/Makefile.include | 60 +-- tests/avocado/README.rst | 10 - tests/avocado/avocado_qemu/__init__.py | 424 ----------------- tests/avocado/avocado_qemu/linuxtest.py | 253 ----------- 14 files changed, 16 insertions(+), 1375 deletions(-) delete mode 100644 docs/devel/testing/avocado.rst delete mode 100644 tests/avocado/README.rst delete mode 100644 tests/avocado/avocado_qemu/__init__.py delete mode 100644 tests/avocado/avocado_qemu/linuxtest.py diff --git a/MAINTAINERS b/MAINTAINERS index 07f77c048e..5fd757c5dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2073,7 +2073,7 @@ S: Supported F: hw/acpi/viot.c F: hw/acpi/viot.h -ACPI/AVOCADO/BIOSBITS +ACPI/FUNCTIONAL/BIOSBITS M: Ani Sinha M: Michael S. Tsirkin S: Supported @@ -4246,12 +4246,6 @@ R: Philippe Mathieu-Daudé S: Maintained F: tests/tcg/Makefile.target -Integration Testing with the Avocado framework -W: https://trello.com/b/6Qi1pxVn/avocado-qemu -R: Cleber Rosa -S: Odd Fixes -F: tests/avocado/ - GitLab custom runner (Works On Arm Sponsored) M: Alex Bennée M: Philippe Mathieu-Daudé diff --git a/configure b/configure index 02f1dd2311..000309cf61 100755 --- a/configure +++ b/configure @@ -1685,7 +1685,7 @@ LINKS="$LINKS pc-bios/optionrom/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS pc-bios/vof/Makefile" LINKS="$LINKS .gdbinit scripts" # scripts needed by relative path in .gdbinit -LINKS="$LINKS tests/avocado tests/data" +LINKS="$LINKS tests/data" LINKS="$LINKS tests/qemu-iotests/check tests/qemu-iotests/Makefile" LINKS="$LINKS python" for f in $LINKS ; do diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 1552b1a704..52521552c8 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -123,11 +123,11 @@ Rust build dependencies to build QEMU. Optional build dependencies - Build components whose absence does not affect the ability to build - QEMU may not be available in distros, or may be too old for QEMU's - requirements. Many of these, such as the Avocado testing framework - or various linters, are written in Python and therefore can also - be installed using ``pip``. Cross compilers are another example + Build components whose absence does not affect the ability to build QEMU + may not be available in distros, or may be too old for our requirements. + Many of these, such as additional modules for the functional testing + framework or various linters, are written in Python and therefore can + also be installed using ``pip``. Cross compilers are another example of optional build-time dependency; in this case it is possible to download them from repositories such as EPEL, to use container-based cross compilation using ``docker`` or ``podman``, or to use pre-built diff --git a/docs/devel/build-system.rst b/docs/devel/build-system.rst index a759982f45..258cfad3fe 100644 --- a/docs/devel/build-system.rst +++ b/docs/devel/build-system.rst @@ -134,7 +134,7 @@ in how the build process runs Python code. At this stage, ``configure`` also queries the chosen Python interpreter about QEMU's build dependencies. Note that the build process does *not* -look for ``meson``, ``sphinx-build`` or ``avocado`` binaries in the PATH; +look for ``meson`` or ``sphinx-build`` binaries in the PATH; likewise, there are no options such as ``--meson`` or ``--sphinx-build``. This avoids a potential mismatch, where Meson and Sphinx binaries on the PATH might operate in a different Python environment than the one chosen @@ -151,7 +151,7 @@ virtual environment with ``pip``, either from wheels in ``python/wheels`` or by downloading the package with PyPI. Downloading can be disabled with ``--disable-download``; and anyway, it only happens when a ``configure`` option (currently, only ``--enable-docs``) is explicitly enabled but -the dependencies are not present\ [#pip]_. +the dependencies are not present. .. [#distlib] The scripts are created based on the package's metadata, specifically the ``console_script`` entry points. This is the @@ -164,10 +164,6 @@ the dependencies are not present\ [#pip]_. because the Python Packaging Authority provides a package ``distlib.scripts`` to perform this task. -.. [#pip] ``pip`` might also be used when running ``make check-avocado`` - if downloading is enabled, to ensure that Avocado is - available. - The required versions of the packages are stored in a configuration file ``pythondeps.toml``. The format is custom to QEMU, but it is documented at the top of the file itself and it should be easy to understand. The @@ -497,8 +493,7 @@ number of dynamically created files listed later. ``pyvenv/bin``, and calling ``pip`` to install dependencies. ``tests/Makefile.include`` - Rules for external test harnesses. These include the TCG tests - and the Avocado-based integration tests. + Rules for external test harnesses like the TCG tests. ``tests/docker/Makefile.include`` Rules for Docker tests. Like ``tests/Makefile.include``, this file is diff --git a/docs/devel/codebase.rst b/docs/devel/codebase.rst index ef98578296..40273e7d31 100644 --- a/docs/devel/codebase.rst +++ b/docs/devel/codebase.rst @@ -175,11 +175,6 @@ yet, so sometimes the source code is all you have. * `tests `_: QEMU `test ` suite - - `avocado `_: - Functional tests booting full VM using `Avocado framework `. - Those tests will be transformed and moved into - `tests/functional `_ - in the future. - `data `_: Data for various tests. - `decode `_: diff --git a/docs/devel/testing/avocado.rst b/docs/devel/testing/avocado.rst deleted file mode 100644 index eda76fe2db..0000000000 --- a/docs/devel/testing/avocado.rst +++ /dev/null @@ -1,581 +0,0 @@ -.. _checkavocado-ref: - - -Integration testing with Avocado -================================ - -The ``tests/avocado`` directory hosts integration tests. They're usually -higher level tests, and may interact with external resources and with -various guest operating systems. - -These tests are written using the Avocado Testing Framework (which must be -installed separately) in conjunction with a the ``avocado_qemu.QemuSystemTest`` -class, implemented at ``tests/avocado/avocado_qemu``. - -Tests based on ``avocado_qemu.QemuSystemTest`` can easily: - - * Customize the command line arguments given to the convenience - ``self.vm`` attribute (a QEMUMachine instance) - - * Interact with the QEMU monitor, send QMP commands and check - their results - - * Interact with the guest OS, using the convenience console device - (which may be useful to assert the effectiveness and correctness of - command line arguments or QMP commands) - - * Interact with external data files that accompany the test itself - (see ``self.get_data()``) - - * Download (and cache) remote data files, such as firmware and kernel - images - - * Have access to a library of guest OS images (by means of the - ``avocado.utils.vmimage`` library) - - * Make use of various other test related utilities available at the - test class itself and at the utility library: - - - http://avocado-framework.readthedocs.io/en/latest/api/test/avocado.html#avocado.Test - - http://avocado-framework.readthedocs.io/en/latest/api/utils/avocado.utils.html - -Running tests -------------- - -You can run the avocado tests simply by executing: - -.. code:: - - make check-avocado - -This involves the automatic installation, from PyPI, of all the -necessary avocado-framework dependencies into the QEMU venv within the -build tree (at ``./pyvenv``). Test results are also saved within the -build tree (at ``tests/results``). - -Note: the build environment must be using a Python 3 stack, and have -the ``venv`` and ``pip`` packages installed. If necessary, make sure -``configure`` is called with ``--python=`` and that those modules are -available. On Debian and Ubuntu based systems, depending on the -specific version, they may be on packages named ``python3-venv`` and -``python3-pip``. - -It is also possible to run tests based on tags using the -``make check-avocado`` command and the ``AVOCADO_TAGS`` environment -variable: - -.. code:: - - make check-avocado AVOCADO_TAGS=quick - -Note that tags separated with commas have an AND behavior, while tags -separated by spaces have an OR behavior. For more information on Avocado -tags, see: - - https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/tags.html - -To run a single test file, a couple of them, or a test within a file -using the ``make check-avocado`` command, set the ``AVOCADO_TESTS`` -environment variable with the test files or test names. To run all -tests from a single file, use: - - .. code:: - - make check-avocado AVOCADO_TESTS=$FILEPATH - -The same is valid to run tests from multiple test files: - - .. code:: - - make check-avocado AVOCADO_TESTS='$FILEPATH1 $FILEPATH2' - -To run a single test within a file, use: - - .. code:: - - make check-avocado AVOCADO_TESTS=$FILEPATH:$TESTCLASS.$TESTNAME - -The same is valid to run single tests from multiple test files: - - .. code:: - - make check-avocado AVOCADO_TESTS='$FILEPATH1:$TESTCLASS1.$TESTNAME1 $FILEPATH2:$TESTCLASS2.$TESTNAME2' - -The scripts installed inside the virtual environment may be used -without an "activation". For instance, the Avocado test runner -may be invoked by running: - - .. code:: - - pyvenv/bin/avocado run $OPTION1 $OPTION2 tests/avocado/ - -Note that if ``make check-avocado`` was not executed before, it is -possible to create the Python virtual environment with the dependencies -needed running: - - .. code:: - - make check-venv - -It is also possible to run tests from a single file or a single test within -a test file. To run tests from a single file within the build tree, use: - - .. code:: - - pyvenv/bin/avocado run tests/avocado/$TESTFILE - -To run a single test within a test file, use: - - .. code:: - - pyvenv/bin/avocado run tests/avocado/$TESTFILE:$TESTCLASS.$TESTNAME - -Valid test names are visible in the output from any previous execution -of Avocado or ``make check-avocado``, and can also be queried using: - - .. code:: - - pyvenv/bin/avocado list tests/avocado - -Manual Installation -------------------- - -To manually install Avocado and its dependencies, run: - -.. code:: - - pip install --user avocado-framework - -Alternatively, follow the instructions on this link: - - https://avocado-framework.readthedocs.io/en/latest/guides/user/chapters/installing.html - -Overview --------- - -The ``tests/avocado/avocado_qemu`` directory provides the -``avocado_qemu`` Python module, containing the ``avocado_qemu.QemuSystemTest`` -class. Here's a simple usage example: - -.. code:: - - from avocado_qemu import QemuSystemTest - - - class Version(QemuSystemTest): - """ - :avocado: tags=quick - """ - def test_qmp_human_info_version(self): - self.vm.launch() - res = self.vm.cmd('human-monitor-command', - command_line='info version') - self.assertRegex(res, r'^(\d+\.\d+\.\d)') - -To execute your test, run: - -.. code:: - - avocado run version.py - -Tests may be classified according to a convention by using docstring -directives such as ``:avocado: tags=TAG1,TAG2``. To run all tests -in the current directory, tagged as "quick", run: - -.. code:: - - avocado run -t quick . - -The ``avocado_qemu.QemuSystemTest`` base test class -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``avocado_qemu.QemuSystemTest`` class has a number of characteristics -that are worth being mentioned right away. - -First of all, it attempts to give each test a ready to use QEMUMachine -instance, available at ``self.vm``. Because many tests will tweak the -QEMU command line, launching the QEMUMachine (by using ``self.vm.launch()``) -is left to the test writer. - -The base test class has also support for tests with more than one -QEMUMachine. The way to get machines is through the ``self.get_vm()`` -method which will return a QEMUMachine instance. The ``self.get_vm()`` -method accepts arguments that will be passed to the QEMUMachine creation -and also an optional ``name`` attribute so you can identify a specific -machine and get it more than once through the tests methods. A simple -and hypothetical example follows: - -.. code:: - - from avocado_qemu import QemuSystemTest - - - class MultipleMachines(QemuSystemTest): - def test_multiple_machines(self): - first_machine = self.get_vm() - second_machine = self.get_vm() - self.get_vm(name='third_machine').launch() - - first_machine.launch() - second_machine.launch() - - first_res = first_machine.cmd( - 'human-monitor-command', - command_line='info version') - - second_res = second_machine.cmd( - 'human-monitor-command', - command_line='info version') - - third_res = self.get_vm(name='third_machine').cmd( - 'human-monitor-command', - command_line='info version') - - self.assertEqual(first_res, second_res, third_res) - -At test "tear down", ``avocado_qemu.QemuSystemTest`` handles all the -QEMUMachines shutdown. - -The ``avocado_qemu.LinuxTest`` base test class -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The ``avocado_qemu.LinuxTest`` is further specialization of the -``avocado_qemu.QemuSystemTest`` class, so it contains all the characteristics -of the later plus some extra features. - -First of all, this base class is intended for tests that need to -interact with a fully booted and operational Linux guest. At this -time, it uses a Fedora 31 guest image. The most basic example looks -like this: - -.. code:: - - from avocado_qemu import LinuxTest - - - class SomeTest(LinuxTest): - - def test(self): - self.launch_and_wait() - self.ssh_command('some_command_to_be_run_in_the_guest') - -Please refer to tests that use ``avocado_qemu.LinuxTest`` under -``tests/avocado`` for more examples. - -QEMUMachine ------------ - -The QEMUMachine API is already widely used in the Python iotests, -device-crash-test and other Python scripts. It's a wrapper around the -execution of a QEMU binary, giving its users: - - * the ability to set command line arguments to be given to the QEMU - binary - - * a ready to use QMP connection and interface, which can be used to - send commands and inspect its results, as well as asynchronous - events - - * convenience methods to set commonly used command line arguments in - a more succinct and intuitive way - -QEMU binary selection -^^^^^^^^^^^^^^^^^^^^^ - -The QEMU binary used for the ``self.vm`` QEMUMachine instance will -primarily depend on the value of the ``qemu_bin`` parameter. If it's -not explicitly set, its default value will be the result of a dynamic -probe in the same source tree. A suitable binary will be one that -targets the architecture matching host machine. - -Based on this description, test writers will usually rely on one of -the following approaches: - -1) Set ``qemu_bin``, and use the given binary - -2) Do not set ``qemu_bin``, and use a QEMU binary named like - "qemu-system-${arch}", either in the current - working directory, or in the current source tree. - -The resulting ``qemu_bin`` value will be preserved in the -``avocado_qemu.QemuSystemTest`` as an attribute with the same name. - -Attribute reference -------------------- - -Test -^^^^ - -Besides the attributes and methods that are part of the base -``avocado.Test`` class, the following attributes are available on any -``avocado_qemu.QemuSystemTest`` instance. - -vm -"" - -A QEMUMachine instance, initially configured according to the given -``qemu_bin`` parameter. - -arch -"""" - -The architecture can be used on different levels of the stack, e.g. by -the framework or by the test itself. At the framework level, it will -currently influence the selection of a QEMU binary (when one is not -explicitly given). - -Tests are also free to use this attribute value, for their own needs. -A test may, for instance, use the same value when selecting the -architecture of a kernel or disk image to boot a VM with. - -The ``arch`` attribute will be set to the test parameter of the same -name. If one is not given explicitly, it will either be set to -``None``, or, if the test is tagged with one (and only one) -``:avocado: tags=arch:VALUE`` tag, it will be set to ``VALUE``. - -cpu -""" - -The cpu model that will be set to all QEMUMachine instances created -by the test. - -The ``cpu`` attribute will be set to the test parameter of the same -name. If one is not given explicitly, it will either be set to -``None ``, or, if the test is tagged with one (and only one) -``:avocado: tags=cpu:VALUE`` tag, it will be set to ``VALUE``. - -machine -""""""" - -The machine type that will be set to all QEMUMachine instances created -by the test. - -The ``machine`` attribute will be set to the test parameter of the same -name. If one is not given explicitly, it will either be set to -``None``, or, if the test is tagged with one (and only one) -``:avocado: tags=machine:VALUE`` tag, it will be set to ``VALUE``. - -qemu_bin -"""""""" - -The preserved value of the ``qemu_bin`` parameter or the result of the -dynamic probe for a QEMU binary in the current working directory or -source tree. - -LinuxTest -^^^^^^^^^ - -Besides the attributes present on the ``avocado_qemu.QemuSystemTest`` base -class, the ``avocado_qemu.LinuxTest`` adds the following attributes: - -distro -"""""" - -The name of the Linux distribution used as the guest image for the -test. The name should match the **Provider** column on the list -of images supported by the avocado.utils.vmimage library: - -https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images - -distro_version -"""""""""""""" - -The version of the Linux distribution as the guest image for the -test. The name should match the **Version** column on the list -of images supported by the avocado.utils.vmimage library: - -https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images - -distro_checksum -""""""""""""""" - -The sha256 hash of the guest image file used for the test. - -If this value is not set in the code or by a test parameter (with the -same name), no validation on the integrity of the image will be -performed. - -Parameter reference -------------------- - -To understand how Avocado parameters are accessed by tests, and how -they can be passed to tests, please refer to:: - - https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#accessing-test-parameters - -Parameter values can be easily seen in the log files, and will look -like the following: - -.. code:: - - PARAMS (key=qemu_bin, path=*, default=./qemu-system-x86_64) => './qemu-system-x86_64 - -Test -^^^^ - -arch -"""" - -The architecture that will influence the selection of a QEMU binary -(when one is not explicitly given). - -Tests are also free to use this parameter value, for their own needs. -A test may, for instance, use the same value when selecting the -architecture of a kernel or disk image to boot a VM with. - -This parameter has a direct relation with the ``arch`` attribute. If -not given, it will default to None. - -cpu -""" - -The cpu model that will be set to all QEMUMachine instances created -by the test. - -machine -""""""" - -The machine type that will be set to all QEMUMachine instances created -by the test. - -qemu_bin -"""""""" - -The exact QEMU binary to be used on QEMUMachine. - -LinuxTest -^^^^^^^^^ - -Besides the parameters present on the ``avocado_qemu.QemuSystemTest`` base -class, the ``avocado_qemu.LinuxTest`` adds the following parameters: - -distro -"""""" - -The name of the Linux distribution used as the guest image for the -test. The name should match the **Provider** column on the list -of images supported by the avocado.utils.vmimage library: - -https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images - -distro_version -"""""""""""""" - -The version of the Linux distribution as the guest image for the -test. The name should match the **Version** column on the list -of images supported by the avocado.utils.vmimage library: - -https://avocado-framework.readthedocs.io/en/latest/guides/writer/libs/vmimage.html#supported-images - -distro_checksum -""""""""""""""" - -The sha256 hash of the guest image file used for the test. - -If this value is not set in the code or by this parameter no -validation on the integrity of the image will be performed. - -Skipping tests --------------- - -The Avocado framework provides Python decorators which allow for easily skip -tests running under certain conditions. For example, on the lack of a binary -on the test system or when the running environment is a CI system. For further -information about those decorators, please refer to:: - - https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#skipping-tests - -While the conditions for skipping tests are often specifics of each one, there -are recurring scenarios identified by the QEMU developers and the use of -environment variables became a kind of standard way to enable/disable tests. - -Here is a list of the most used variables: - -AVOCADO_ALLOW_LARGE_STORAGE -^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Tests which are going to fetch or produce assets considered *large* are not -going to run unless that ``AVOCADO_ALLOW_LARGE_STORAGE=1`` is exported on -the environment. - -The definition of *large* is a bit arbitrary here, but it usually means an -asset which occupies at least 1GB of size on disk when uncompressed. - -SPEED -^^^^^ -Tests which have a long runtime will not be run unless ``SPEED=slow`` is -exported on the environment. - -The definition of *long* is a bit arbitrary here, and it depends on the -usefulness of the test too. A unique test is worth spending more time on, -small variations on existing tests perhaps less so. As a rough guide, -a test or set of similar tests which take more than 100 seconds to -complete. - -AVOCADO_ALLOW_UNTRUSTED_CODE -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -There are tests which will boot a kernel image or firmware that can be -considered not safe to run on the developer's workstation, thus they are -skipped by default. The definition of *not safe* is also arbitrary but -usually it means a blob which either its source or build process aren't -public available. - -You should export ``AVOCADO_ALLOW_UNTRUSTED_CODE=1`` on the environment in -order to allow tests which make use of those kind of assets. - -AVOCADO_TIMEOUT_EXPECTED -^^^^^^^^^^^^^^^^^^^^^^^^ -The Avocado framework has a timeout mechanism which interrupts tests to avoid the -test suite of getting stuck. The timeout value can be set via test parameter or -property defined in the test class, for further details:: - - https://avocado-framework.readthedocs.io/en/latest/guides/writer/chapters/writing.html#setting-a-test-timeout - -Even though the timeout can be set by the test developer, there are some tests -that may not have a well-defined limit of time to finish under certain -conditions. For example, tests that take longer to execute when QEMU is -compiled with debug flags. Therefore, the ``AVOCADO_TIMEOUT_EXPECTED`` variable -has been used to determine whether those tests should run or not. - -QEMU_TEST_FLAKY_TESTS -^^^^^^^^^^^^^^^^^^^^^ -Some tests are not working reliably and thus are disabled by default. -This includes tests that don't run reliably on GitLab's CI which -usually expose real issues that are rarely seen on developer machines -due to the constraints of the CI environment. If you encounter a -similar situation then raise a bug and then mark the test as shown on -the code snippet below: - -.. code:: - - # See https://gitlab.com/qemu-project/qemu/-/issues/nnnn - @skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab') - def test(self): - do_something() - -You can also add ``:avocado: tags=flaky`` to the test meta-data so -only the flaky tests can be run as a group: - -.. code:: - - env QEMU_TEST_FLAKY_TESTS=1 ./pyvenv/bin/avocado \ - run tests/avocado -filter-by-tags=flaky - -Tests should not live in this state forever and should either be fixed -or eventually removed. - - -Uninstalling Avocado --------------------- - -If you've followed the manual installation instructions above, you can -easily uninstall Avocado. Start by listing the packages you have -installed:: - - pip list --user - -And remove any package you want with:: - - pip uninstall - -If you've used ``make check-avocado``, the Python virtual environment where -Avocado is installed will be cleaned up as part of ``make check-clean``. diff --git a/docs/devel/testing/functional.rst b/docs/devel/testing/functional.rst index 9bc973392a..8030cb4299 100644 --- a/docs/devel/testing/functional.rst +++ b/docs/devel/testing/functional.rst @@ -6,9 +6,6 @@ Functional testing with Python The ``tests/functional`` directory hosts functional tests written in Python. They are usually higher level tests, and may interact with external resources and with various guest operating systems. -The functional tests have initially evolved from the Avocado tests, so there -is a lot of similarity to those tests here (see :ref:`checkavocado-ref` for -details about the Avocado tests). The tests should be written in the style of the Python `unittest`_ framework, using stdio for the TAP protocol. The folder ``tests/functional/qemu_test`` diff --git a/docs/devel/testing/index.rst b/docs/devel/testing/index.rst index 1171f7db8f..ccc2fc6cbc 100644 --- a/docs/devel/testing/index.rst +++ b/docs/devel/testing/index.rst @@ -10,7 +10,6 @@ testing infrastructure. main qtest functional - avocado acpi-bits ci fuzzing diff --git a/docs/devel/testing/main.rst b/docs/devel/testing/main.rst index e56da22edf..6b18ed875c 100644 --- a/docs/devel/testing/main.rst +++ b/docs/devel/testing/main.rst @@ -919,21 +919,6 @@ Python. You can run the functional tests simply by executing: See :ref:`checkfunctional-ref` for more details. -Integration tests using the Avocado Framework ---------------------------------------------- - -The ``tests/avocado`` directory hosts integration tests. They're usually -higher level tests, and may interact with external resources and with -various guest operating systems. - -You can run the avocado tests simply by executing: - -.. code:: - - make check-avocado - -See :ref:`checkavocado-ref` for more details. - .. _checktcg-ref: Testing with "make check-tcg" diff --git a/pythondeps.toml b/pythondeps.toml index c03c9df81b..7eaaa0fed1 100644 --- a/pythondeps.toml +++ b/pythondeps.toml @@ -27,9 +27,5 @@ pycotap = { accepted = ">=1.1.0", installed = "1.3.1" } sphinx = { accepted = ">=3.4.3", installed = "5.3.0", canary = "sphinx-build" } sphinx_rtd_theme = { accepted = ">=0.5", installed = "1.1.1" } -[avocado] -# Note that qemu.git/python/ is always implicitly installed. -# Prefer an LTS version when updating the accepted versions of -# avocado-framework, for example right now the limit is 92.x. -avocado-framework = { accepted = "(>=103.0, <104.0)", installed = "103.0", canary = "avocado" } -pycdlib = { accepted = ">=1.11.0" } +[testdeps] +qemu.qmp = { accepted = ">=0.0.3", installed = "0.0.3" } diff --git a/tests/Makefile.include b/tests/Makefile.include index 010369bd3a..23fb722d42 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -18,7 +18,6 @@ ifneq ($(filter $(all-check-targets), check-softfloat),) @echo " $(MAKE) check-tcg Run TCG tests" @echo " $(MAKE) check-softfloat Run FPU emulation tests" endif - @echo " $(MAKE) check-avocado Run avocado (integration) tests for currently configured targets" @echo @echo " $(MAKE) check-report.junit.xml Generates an aggregated XML test report" @echo " $(MAKE) check-venv Creates a Python venv for tests" @@ -26,7 +25,6 @@ endif @echo @echo "The following are useful for CI builds" @echo " $(MAKE) check-build Build most test binaries" - @echo " $(MAKE) get-vm-images Downloads all images used by avocado tests, according to configured targets (~350 MB each, 1.5 GB max)" @echo @echo @echo "The variable SPEED can be set to control the gtester speed setting." @@ -86,26 +84,12 @@ distclean-tcg: $(DISTCLEAN_TCG_TARGET_RULES) # Python venv for running tests -.PHONY: check-venv check-avocado check-acceptance check-acceptance-deprecated-warning +.PHONY: check-venv # Build up our target list from the filtered list of ninja targets TARGETS=$(patsubst libqemu-%.a, %, $(filter libqemu-%.a, $(ninja-targets))) TESTS_VENV_TOKEN=$(BUILD_DIR)/pyvenv/tests.group -TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results -ifndef AVOCADO_TESTS - AVOCADO_TESTS=tests/avocado -endif -# Controls the output generated by Avocado when running tests. -# Any number of command separated loggers are accepted. For more -# information please refer to "avocado --help". -AVOCADO_SHOW?=app -ifndef AVOCADO_TAGS - AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \ - $(filter %-softmmu,$(TARGETS))) -else - AVOCADO_CMDLINE_TAGS=$(addprefix -t , $(AVOCADO_TAGS)) -endif quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ $(PYTHON) -m pip -q --disable-pip-version-check $1, \ @@ -113,47 +97,11 @@ quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \ $(TESTS_VENV_TOKEN): $(SRC_PATH)/pythondeps.toml $(call quiet-venv-pip,install -e "$(SRC_PATH)/python/") - $(MKVENV_ENSUREGROUP) $< avocado + $(MKVENV_ENSUREGROUP) $< testdeps $(call quiet-command, touch $@) -$(TESTS_RESULTS_DIR): - $(call quiet-command, mkdir -p $@, \ - MKDIR, $@) - check-venv: $(TESTS_VENV_TOKEN) -FEDORA_31_ARCHES_TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGETS))) -FEDORA_31_ARCHES_CANDIDATES=$(patsubst ppc64,ppc64le,$(FEDORA_31_ARCHES_TARGETS)) -FEDORA_31_ARCHES := x86_64 aarch64 ppc64le s390x -FEDORA_31_DOWNLOAD=$(filter $(FEDORA_31_ARCHES),$(FEDORA_31_ARCHES_CANDIDATES)) - -# download one specific Fedora 31 image -get-vm-image-fedora-31-%: check-venv - $(call quiet-command, \ - $(PYTHON) -m avocado vmimage get \ - --distro=fedora --distro-version=31 --arch=$*, \ - "AVOCADO", "Downloading avocado tests VM image for $*") - -# download all vm images, according to defined targets -get-vm-images: check-venv $(patsubst %,get-vm-image-fedora-31-%, $(FEDORA_31_DOWNLOAD)) - -check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images - $(call quiet-command, \ - $(PYTHON) -m avocado \ - --show=$(AVOCADO_SHOW) run --job-results-dir=$(TESTS_RESULTS_DIR) \ - $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \ - --filter-by-tags-include-empty-key) \ - $(AVOCADO_CMDLINE_TAGS) --max-parallel-tasks=1 \ - $(if $(GITLAB_CI),,--failfast) $(AVOCADO_TESTS), \ - "AVOCADO", "tests/avocado") - -check-acceptance-deprecated-warning: - @echo - @echo "Note '$(MAKE) check-acceptance' is deprecated, use '$(MAKE) check-avocado' instead." - @echo - -check-acceptance: check-acceptance-deprecated-warning | check-avocado - FUNCTIONAL_TARGETS=$(patsubst %-softmmu,check-functional-%, $(filter %-softmmu,$(TARGETS))) .PHONY: $(FUNCTIONAL_TARGETS) $(FUNCTIONAL_TARGETS): @@ -166,13 +114,13 @@ check-functional: # Consolidated targets -.PHONY: check check-clean get-vm-images +.PHONY: check check-clean check: check-build: run-ninja check-clean: - rm -rf $(TESTS_RESULTS_DIR) + rm -rf $(BUILD_DIR)/tests/functional clean: check-clean clean-tcg distclean: distclean-tcg diff --git a/tests/avocado/README.rst b/tests/avocado/README.rst deleted file mode 100644 index 94488371bb..0000000000 --- a/tests/avocado/README.rst +++ /dev/null @@ -1,10 +0,0 @@ -============================================= -Integration tests using the Avocado Framework -============================================= - -This directory contains integration tests. They're usually higher -level, and may interact with external resources and with various -guest operating systems. - -For more information, please refer to ``docs/devel/testing.rst``, -section "Integration tests using the Avocado Framework". diff --git a/tests/avocado/avocado_qemu/__init__.py b/tests/avocado/avocado_qemu/__init__.py deleted file mode 100644 index 93c3460242..0000000000 --- a/tests/avocado/avocado_qemu/__init__.py +++ /dev/null @@ -1,424 +0,0 @@ -# Test class and utilities for functional tests -# -# Copyright (c) 2018 Red Hat, Inc. -# -# Author: -# Cleber Rosa -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import logging -import os -import subprocess -import sys -import tempfile -import time -import uuid - -import avocado -from avocado.utils import ssh -from avocado.utils.path import find_command - -from qemu.machine import QEMUMachine -from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available, - tcg_available) - - -#: The QEMU build root directory. It may also be the source directory -#: if building from the source dir, but it's safer to use BUILD_DIR for -#: that purpose. Be aware that if this code is moved outside of a source -#: and build tree, it will not be accurate. -BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))) - - -def has_cmd(name, args=None): - """ - This function is for use in a @avocado.skipUnless decorator, e.g.: - - @skipUnless(*has_cmd('sudo -n', ('sudo', '-n', 'true'))) - def test_something_that_needs_sudo(self): - ... - """ - - if args is None: - args = ('which', name) - - try: - _, stderr, exitcode = run_cmd(args) - except Exception as e: - exitcode = -1 - stderr = str(e) - - if exitcode != 0: - cmd_line = ' '.join(args) - err = f'{name} required, but "{cmd_line}" failed: {stderr.strip()}' - return (False, err) - else: - return (True, '') - -def has_cmds(*cmds): - """ - This function is for use in a @avocado.skipUnless decorator and - allows checking for the availability of multiple commands, e.g.: - - @skipUnless(*has_cmds(('cmd1', ('cmd1', '--some-parameter')), - 'cmd2', 'cmd3')) - def test_something_that_needs_cmd1_and_cmd2(self): - ... - """ - - for cmd in cmds: - if isinstance(cmd, str): - cmd = (cmd,) - - ok, errstr = has_cmd(*cmd) - if not ok: - return (False, errstr) - - return (True, '') - -def run_cmd(args): - subp = subprocess.Popen(args, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - universal_newlines=True) - stdout, stderr = subp.communicate() - ret = subp.returncode - - return (stdout, stderr, ret) - -def is_readable_executable_file(path): - return os.path.isfile(path) and os.access(path, os.R_OK | os.X_OK) - - -def pick_default_qemu_bin(bin_prefix='qemu-system-', arch=None): - """ - Picks the path of a QEMU binary, starting either in the current working - directory or in the source tree root directory. - - :param arch: the arch to use when looking for a QEMU binary (the target - will match the arch given). If None (the default), arch - will be the current host system arch (as given by - :func:`os.uname`). - :type arch: str - :returns: the path to the default QEMU binary or None if one could not - be found - :rtype: str or None - """ - if arch is None: - arch = os.uname()[4] - # qemu binary path does not match arch for powerpc, handle it - if 'ppc64le' in arch: - arch = 'ppc64' - qemu_bin_name = bin_prefix + arch - qemu_bin_paths = [ - os.path.join(".", qemu_bin_name), - os.path.join(BUILD_DIR, qemu_bin_name), - os.path.join(BUILD_DIR, "build", qemu_bin_name), - ] - for path in qemu_bin_paths: - if is_readable_executable_file(path): - return path - return None - - -def _console_interaction(test, success_message, failure_message, - send_string, keep_sending=False, vm=None): - assert not keep_sending or send_string - if vm is None: - vm = test.vm - console = vm.console_file - console_logger = logging.getLogger('console') - while True: - if send_string: - vm.console_socket.sendall(send_string.encode()) - if not keep_sending: - send_string = None # send only once - - # Only consume console output if waiting for something - if success_message is None and failure_message is None: - if send_string is None: - break - continue - - try: - msg = console.readline().decode().strip() - except UnicodeDecodeError: - msg = None - if not msg: - continue - console_logger.debug(msg) - if success_message is None or success_message in msg: - break - if failure_message and failure_message in msg: - console.close() - fail = 'Failure message found in console: "%s". Expected: "%s"' % \ - (failure_message, success_message) - test.fail(fail) - -def interrupt_interactive_console_until_pattern(test, success_message, - failure_message=None, - interrupt_string='\r'): - """ - Keep sending a string to interrupt a console prompt, while logging the - console output. Typical use case is to break a boot loader prompt, such: - - Press a key within 5 seconds to interrupt boot process. - 5 - 4 - 3 - 2 - 1 - Booting default image... - - :param test: an Avocado test containing a VM that will have its console - read and probed for a success or failure message - :type test: :class:`avocado_qemu.QemuSystemTest` - :param success_message: if this message appears, test succeeds - :param failure_message: if this message appears, test fails - :param interrupt_string: a string to send to the console before trying - to read a new line - """ - _console_interaction(test, success_message, failure_message, - interrupt_string, True) - -def wait_for_console_pattern(test, success_message, failure_message=None, - vm=None): - """ - Waits for messages to appear on the console, while logging the content - - :param test: an Avocado test containing a VM that will have its console - read and probed for a success or failure message - :type test: :class:`avocado_qemu.QemuSystemTest` - :param success_message: if this message appears, test succeeds - :param failure_message: if this message appears, test fails - """ - _console_interaction(test, success_message, failure_message, None, vm=vm) - -def exec_command(test, command): - """ - Send a command to a console (appending CRLF characters), while logging - the content. - - :param test: an Avocado test containing a VM. - :type test: :class:`avocado_qemu.QemuSystemTest` - :param command: the command to send - :type command: str - """ - _console_interaction(test, None, None, command + '\r') - -def exec_command_and_wait_for_pattern(test, command, - success_message, failure_message=None): - """ - Send a command to a console (appending CRLF characters), then wait - for success_message to appear on the console, while logging the. - content. Mark the test as failed if failure_message is found instead. - - :param test: an Avocado test containing a VM that will have its console - read and probed for a success or failure message - :type test: :class:`avocado_qemu.QemuSystemTest` - :param command: the command to send - :param success_message: if this message appears, test succeeds - :param failure_message: if this message appears, test fails - """ - _console_interaction(test, success_message, failure_message, command + '\r') - -class QemuBaseTest(avocado.Test): - - # default timeout for all tests, can be overridden - timeout = 120 - - def _get_unique_tag_val(self, tag_name): - """ - Gets a tag value, if unique for a key - """ - vals = self.tags.get(tag_name, []) - if len(vals) == 1: - return vals.pop() - return None - - def setUp(self, bin_prefix): - self.arch = self.params.get('arch', - default=self._get_unique_tag_val('arch')) - - self.cpu = self.params.get('cpu', - default=self._get_unique_tag_val('cpu')) - - default_qemu_bin = pick_default_qemu_bin(bin_prefix, arch=self.arch) - self.qemu_bin = self.params.get('qemu_bin', - default=default_qemu_bin) - if self.qemu_bin is None: - self.cancel("No QEMU binary defined or found in the build tree") - - def fetch_asset(self, name, - asset_hash, algorithm=None, - locations=None, expire=None, - find_only=False, cancel_on_missing=True): - return super().fetch_asset(name, - asset_hash=asset_hash, - algorithm=algorithm, - locations=locations, - expire=expire, - find_only=find_only, - cancel_on_missing=cancel_on_missing) - - -class QemuSystemTest(QemuBaseTest): - """Facilitates system emulation tests.""" - - def setUp(self): - self._vms = {} - - super().setUp('qemu-system-') - - accel_required = self._get_unique_tag_val('accel') - if accel_required: - self.require_accelerator(accel_required) - - self.machine = self.params.get('machine', - default=self._get_unique_tag_val('machine')) - - def require_accelerator(self, accelerator): - """ - Requires an accelerator to be available for the test to continue - - It takes into account the currently set qemu binary. - - If the check fails, the test is canceled. If the check itself - for the given accelerator is not available, the test is also - canceled. - - :param accelerator: name of the accelerator, such as "kvm" or "tcg" - :type accelerator: str - """ - checker = {'tcg': tcg_available, - 'kvm': kvm_available}.get(accelerator) - if checker is None: - self.cancel("Don't know how to check for the presence " - "of accelerator %s" % accelerator) - if not checker(qemu_bin=self.qemu_bin): - self.cancel("%s accelerator does not seem to be " - "available" % accelerator) - - def require_netdev(self, netdevname): - netdevhelp = run_cmd([self.qemu_bin, - '-M', 'none', '-netdev', 'help'])[0]; - if netdevhelp.find('\n' + netdevname + '\n') < 0: - self.cancel('no support for user networking') - - def _new_vm(self, name, *args): - self._sd = tempfile.TemporaryDirectory(prefix="qemu_") - vm = QEMUMachine(self.qemu_bin, base_temp_dir=self.workdir, - log_dir=self.logdir) - self.log.debug('QEMUMachine "%s" created', name) - self.log.debug('QEMUMachine "%s" temp_dir: %s', name, vm.temp_dir) - self.log.debug('QEMUMachine "%s" log_dir: %s', name, vm.log_dir) - if args: - vm.add_args(*args) - return vm - - def get_qemu_img(self): - self.log.debug('Looking for and selecting a qemu-img binary') - - # If qemu-img has been built, use it, otherwise the system wide one - # will be used. - qemu_img = os.path.join(BUILD_DIR, 'qemu-img') - if not os.path.exists(qemu_img): - qemu_img = find_command('qemu-img', False) - if qemu_img is False: - self.cancel('Could not find "qemu-img"') - - return qemu_img - - @property - def vm(self): - return self.get_vm(name='default') - - def get_vm(self, *args, name=None): - if not name: - name = str(uuid.uuid4()) - if self._vms.get(name) is None: - self._vms[name] = self._new_vm(name, *args) - if self.cpu is not None: - self._vms[name].add_args('-cpu', self.cpu) - if self.machine is not None: - self._vms[name].set_machine(self.machine) - return self._vms[name] - - def set_vm_arg(self, arg, value): - """ - Set an argument to list of extra arguments to be given to the QEMU - binary. If the argument already exists then its value is replaced. - - :param arg: the QEMU argument, such as "-cpu" in "-cpu host" - :type arg: str - :param value: the argument value, such as "host" in "-cpu host" - :type value: str - """ - if not arg or not value: - return - if arg not in self.vm.args: - self.vm.args.extend([arg, value]) - else: - idx = self.vm.args.index(arg) + 1 - if idx < len(self.vm.args): - self.vm.args[idx] = value - else: - self.vm.args.append(value) - - def tearDown(self): - for vm in self._vms.values(): - vm.shutdown() - self._sd = None - super().tearDown() - - -class LinuxSSHMixIn: - """Contains utility methods for interacting with a guest via SSH.""" - - def ssh_connect(self, username, credential, credential_is_key=True): - self.ssh_logger = logging.getLogger('ssh') - res = self.vm.cmd('human-monitor-command', - command_line='info usernet') - port = get_info_usernet_hostfwd_port(res) - self.assertIsNotNone(port) - self.assertGreater(port, 0) - self.log.debug('sshd listening on port: %d', port) - if credential_is_key: - self.ssh_session = ssh.Session('127.0.0.1', port=port, - user=username, key=credential) - else: - self.ssh_session = ssh.Session('127.0.0.1', port=port, - user=username, password=credential) - for i in range(10): - try: - self.ssh_session.connect() - return - except: - time.sleep(i) - self.fail('ssh connection timeout') - - def ssh_command(self, command): - self.ssh_logger.info(command) - result = self.ssh_session.cmd(command) - stdout_lines = [line.rstrip() for line - in result.stdout_text.splitlines()] - for line in stdout_lines: - self.ssh_logger.info(line) - stderr_lines = [line.rstrip() for line - in result.stderr_text.splitlines()] - for line in stderr_lines: - self.ssh_logger.warning(line) - - self.assertEqual(result.exit_status, 0, - f'Guest command failed: {command}') - return stdout_lines, stderr_lines - - def ssh_command_output_contains(self, cmd, exp): - stdout, _ = self.ssh_command(cmd) - for line in stdout: - if exp in line: - break - else: - self.fail('"%s" output does not contain "%s"' % (cmd, exp)) diff --git a/tests/avocado/avocado_qemu/linuxtest.py b/tests/avocado/avocado_qemu/linuxtest.py deleted file mode 100644 index 66fb9f1507..0000000000 --- a/tests/avocado/avocado_qemu/linuxtest.py +++ /dev/null @@ -1,253 +0,0 @@ -# Test class and utilities for functional Linux-based tests -# -# Copyright (c) 2018 Red Hat, Inc. -# -# Author: -# Cleber Rosa -# -# This work is licensed under the terms of the GNU GPL, version 2 or -# later. See the COPYING file in the top-level directory. - -import os -import shutil - -from avocado.utils import cloudinit, datadrainer, process, vmimage - -from avocado_qemu import LinuxSSHMixIn -from avocado_qemu import QemuSystemTest - -if os.path.islink(os.path.dirname(os.path.dirname(__file__))): - # The link to the avocado tests dir in the source code directory - lnk = os.path.dirname(os.path.dirname(__file__)) - #: The QEMU root source directory - SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk))) -else: - SOURCE_DIR = BUILD_DIR - -class LinuxDistro: - """Represents a Linux distribution - - Holds information of known distros. - """ - #: A collection of known distros and their respective image checksum - KNOWN_DISTROS = { - 'fedora': { - '31': { - 'x86_64': - {'checksum': ('e3c1b309d9203604922d6e255c2c5d09' - '8a309c2d46215d8fc026954f3c5c27a0'), - 'pxeboot_url': ('https://archives.fedoraproject.org/' - 'pub/archive/fedora/linux/releases/31/' - 'Everything/x86_64/os/images/pxeboot/'), - 'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-' - '08a96687f73c ro no_timer_check ' - 'net.ifnames=0 console=tty1 ' - 'console=ttyS0,115200n8'), - }, - 'aarch64': - {'checksum': ('1e18d9c0cf734940c4b5d5ec592facae' - 'd2af0ad0329383d5639c997fdf16fe49'), - 'pxeboot_url': 'https://archives.fedoraproject.org/' - 'pub/archive/fedora/linux/releases/31/' - 'Everything/aarch64/os/images/pxeboot/', - 'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-' - '355e8475b0a7 ro earlyprintk=pl011,0x9000000' - ' ignore_loglevel no_timer_check' - ' printk.time=1 rd_NO_PLYMOUTH' - ' console=ttyAMA0'), - }, - 'ppc64': - {'checksum': ('7c3528b85a3df4b2306e892199a9e1e4' - '3f991c506f2cc390dc4efa2026ad2f58')}, - 's390x': - {'checksum': ('4caaab5a434fd4d1079149a072fdc789' - '1e354f834d355069ca982fdcaf5a122d')}, - }, - '32': { - 'aarch64': - {'checksum': ('b367755c664a2d7a26955bbfff985855' - 'adfa2ca15e908baf15b4b176d68d3967'), - 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/' - 'releases/32/Server/aarch64/os/images/' - 'pxeboot/'), - 'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-' - '14d95c0e90c5 ro no_timer_check net.ifnames=0' - ' console=tty1 console=ttyS0,115200n8'), - }, - }, - '33': { - 'aarch64': - {'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1' - 'a81f386a17f969c1d1c7c87031008a6b'), - 'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/' - 'releases/33/Server/aarch64/os/images/' - 'pxeboot/'), - 'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-' - '1126a0208f8a ro no_timer_check net.ifnames=0' - ' console=tty1 console=ttyS0,115200n8' - ' console=tty0'), - }, - }, - } - } - - def __init__(self, name, version, arch): - self.name = name - self.version = version - self.arch = arch - try: - info = self.KNOWN_DISTROS.get(name).get(version).get(arch) - except AttributeError: - # Unknown distro - info = None - self._info = info or {} - - @property - def checksum(self): - """Gets the cloud-image file checksum""" - return self._info.get('checksum', None) - - @checksum.setter - def checksum(self, value): - self._info['checksum'] = value - - @property - def pxeboot_url(self): - """Gets the repository url where pxeboot files can be found""" - return self._info.get('pxeboot_url', None) - - @property - def default_kernel_params(self): - """Gets the default kernel parameters""" - return self._info.get('kernel_params', None) - - -class LinuxTest(LinuxSSHMixIn, QemuSystemTest): - """Facilitates having a cloud-image Linux based available. - - For tests that intend to interact with guests, this is a better choice - to start with than the more vanilla `QemuSystemTest` class. - """ - - distro = None - username = 'root' - password = 'password' - smp = '2' - memory = '1024' - - def _set_distro(self): - distro_name = self.params.get( - 'distro', - default=self._get_unique_tag_val('distro')) - if not distro_name: - distro_name = 'fedora' - - distro_version = self.params.get( - 'distro_version', - default=self._get_unique_tag_val('distro_version')) - if not distro_version: - distro_version = '31' - - self.distro = LinuxDistro(distro_name, distro_version, self.arch) - - # The distro checksum behaves differently than distro name and - # version. First, it does not respect a tag with the same - # name, given that it's not expected to be used for filtering - # (distro name versions are the natural choice). Second, the - # order of precedence is: parameter, attribute and then value - # from KNOWN_DISTROS. - distro_checksum = self.params.get('distro_checksum', - default=None) - if distro_checksum: - self.distro.checksum = distro_checksum - - def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'): - super().setUp() - self.require_netdev('user') - self._set_distro() - self.vm.add_args('-smp', self.smp) - self.vm.add_args('-m', self.memory) - # The following network device allows for SSH connections - self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', - '-device', '%s,netdev=vnet' % network_device_type) - self.set_up_boot() - if ssh_pubkey is None: - ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys() - self.set_up_cloudinit(ssh_pubkey) - - def set_up_existing_ssh_keys(self): - ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub') - source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa') - ssh_dir = os.path.join(self.workdir, '.ssh') - os.mkdir(ssh_dir, mode=0o700) - ssh_private_key = os.path.join(ssh_dir, - os.path.basename(source_private_key)) - shutil.copyfile(source_private_key, ssh_private_key) - os.chmod(ssh_private_key, 0o600) - return (ssh_public_key, ssh_private_key) - - def download_boot(self): - # Set the qemu-img binary. - # If none is available, the test will cancel. - vmimage.QEMU_IMG = super().get_qemu_img() - - self.log.info('Downloading/preparing boot image') - # Fedora 31 only provides ppc64le images - image_arch = self.arch - if self.distro.name == 'fedora': - if image_arch == 'ppc64': - image_arch = 'ppc64le' - - try: - boot = vmimage.get( - self.distro.name, arch=image_arch, version=self.distro.version, - checksum=self.distro.checksum, - algorithm='sha256', - cache_dir=self.cache_dirs[0], - snapshot_dir=self.workdir) - except: - self.cancel('Failed to download/prepare boot image') - return boot.path - - def prepare_cloudinit(self, ssh_pubkey=None): - self.log.info('Preparing cloudinit image') - try: - cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso') - pubkey_content = None - if ssh_pubkey: - with open(ssh_pubkey) as pubkey: - pubkey_content = pubkey.read() - cloudinit.iso(cloudinit_iso, self.name, - username=self.username, - password=self.password, - # QEMU's hard coded usermode router address - phone_home_host='10.0.2.2', - phone_home_port=self.phone_server.server_port, - authorized_key=pubkey_content) - except Exception: - self.cancel('Failed to prepare the cloudinit image') - return cloudinit_iso - - def set_up_boot(self): - path = self.download_boot() - self.vm.add_args('-drive', 'file=%s' % path) - - def set_up_cloudinit(self, ssh_pubkey=None): - self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0), - self.name) - cloudinit_iso = self.prepare_cloudinit(ssh_pubkey) - self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso) - - def launch_and_wait(self, set_up_ssh_connection=True): - self.vm.set_console() - self.vm.launch() - console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(), - logger=self.log.getChild('console')) - console_drainer.start() - self.log.info('VM launched, waiting for boot confirmation from guest') - while not self.phone_server.instance_phoned_back: - self.phone_server.handle_request() - - if set_up_ssh_connection: - self.log.info('Setting up the SSH connection') - self.ssh_connect(self.username, self.ssh_key) From 858640eaee9f3039580118f5629825825cea311a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 27 Mar 2025 21:13:05 +0100 Subject: [PATCH 0071/2760] tests/functional: Remove semicolons at the end of lines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Yes, we are all C coders who try to write Python code for testing... but still, let's better avoid semicolons at the end of the lines to keep "pylint" happy! Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Nina Schoetterl-Glausch Reviewed-by: Cédric Le Goater Message-ID: <20250327201305.996241-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/aspeed.py | 2 +- tests/functional/test_aarch64_aspeed.py | 2 +- tests/functional/test_arm_aspeed_ast2500.py | 6 ++-- tests/functional/test_arm_aspeed_ast2600.py | 36 +++++++++---------- tests/functional/test_arm_aspeed_bletchley.py | 4 +-- tests/functional/test_arm_aspeed_palmetto.py | 4 +-- tests/functional/test_arm_aspeed_romulus.py | 4 +-- .../functional/test_arm_aspeed_witherspoon.py | 4 +-- tests/functional/test_arm_bpim2u.py | 2 +- tests/functional/test_arm_cubieboard.py | 2 +- tests/functional/test_arm_orangepi.py | 2 +- tests/functional/test_s390x_topology.py | 12 +++---- 12 files changed, 40 insertions(+), 40 deletions(-) diff --git a/tests/functional/aspeed.py b/tests/functional/aspeed.py index 77dc8930fa..7a40d5dda7 100644 --- a/tests/functional/aspeed.py +++ b/tests/functional/aspeed.py @@ -44,7 +44,7 @@ class AspeedTest(LinuxKernelTest): def do_test_arm_aspeed_buildroot_poweroff(self): exec_command_and_wait_for_pattern(self, 'poweroff', - 'System halted'); + 'System halted') def do_test_arm_aspeed_sdk_start(self, image): self.require_netdev('user') diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index c25c966278..c7f3b3b319 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -85,7 +85,7 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ', - 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d'); + 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d') exec_command_and_wait_for_pattern(self, 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0') self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/test_arm_aspeed_ast2500.py index 1ffba6c995..ddc6459f71 100755 --- a/tests/functional/test_arm_aspeed_ast2500.py +++ b/tests/functional/test_arm_aspeed_ast2500.py @@ -22,17 +22,17 @@ class AST2500Machine(AspeedTest): image_path = self.ASSET_BR2_202411_AST2500_FLASH.fetch() self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); + 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test') self.do_test_arm_aspeed_buildroot_start(image_path, '0x0', 'ast2500-evb login:') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', - 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); + 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d') exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '0') self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + property='temperature', value=18000) exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000') diff --git a/tests/functional/test_arm_aspeed_ast2600.py b/tests/functional/test_arm_aspeed_ast2600.py index 6ae4ed636a..5ef52f0659 100755 --- a/tests/functional/test_arm_aspeed_ast2600.py +++ b/tests/functional/test_arm_aspeed_ast2600.py @@ -27,38 +27,38 @@ class AST2600Machine(AspeedTest): image_path = self.ASSET_BR2_202411_AST2600_FLASH.fetch() self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test'); + 'tmp105,bus=aspeed.i2c.bus.3,address=0x4d,id=tmp-test') self.vm.add_args('-device', - 'ds1338,bus=aspeed.i2c.bus.3,address=0x32'); + 'ds1338,bus=aspeed.i2c.bus.3,address=0x32') self.vm.add_args('-device', - 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42'); + 'i2c-echo,bus=aspeed.i2c.bus.3,address=0x42') self.do_test_arm_aspeed_buildroot_start(image_path, '0xf00', 'ast2600-evb login:') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-3/device/new_device', - 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d'); + 'i2c i2c-3: new_device: Instantiated device lm75 at 0x4d') exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '0') self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + property='temperature', value=18000) exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon1/temp1_input', '18000') exec_command_and_wait_for_pattern(self, 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-3/device/new_device', - 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32'); + 'i2c i2c-3: new_device: Instantiated device ds1307 at 0x32') year = time.strftime("%Y") - exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year); + exec_command_and_wait_for_pattern(self, 'hwclock -f /dev/rtc1', year) exec_command_and_wait_for_pattern(self, 'echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-3/new_device', - 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64'); + 'i2c i2c-3: new_device: Instantiated device slave-24c02 at 0x64') exec_command_and_wait_for_pattern(self, - 'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#'); + 'i2cset -y 3 0x42 0x64 0x00 0xaa i', '#') exec_command_and_wait_for_pattern(self, 'hexdump /sys/bus/i2c/devices/3-1064/slave-eeprom', - '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff'); + '0000000 ffaa ffff ffff ffff ffff ffff ffff ffff') self.do_test_arm_aspeed_buildroot_poweroff() ASSET_BR2_202302_AST2600_TPM_FLASH = Asset( @@ -90,10 +90,10 @@ class AST2600Machine(AspeedTest): exec_command_and_wait_for_pattern(self, 'echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device', - 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)'); + 'tpm_tis_i2c 12-002e: 2.0 TPM (device-id 0x1, rev-id 1)') exec_command_and_wait_for_pattern(self, 'cat /sys/class/tpm/tpm0/pcr-sha256/0', - 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0'); + 'B804724EA13F52A9072BA87FE8FDCC497DFC9DF9AA15B9088694639C431688E0') self.do_test_arm_aspeed_buildroot_poweroff() @@ -107,9 +107,9 @@ class AST2600Machine(AspeedTest): self.archive_extract(self.ASSET_SDK_V806_AST2600_A2) self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test'); + 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test') self.vm.add_args('-device', - 'ds1338,bus=aspeed.i2c.bus.5,address=0x32'); + 'ds1338,bus=aspeed.i2c.bus.5,address=0x32') self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2600-a2", "image-bmc")) @@ -120,20 +120,20 @@ class AST2600Machine(AspeedTest): exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', - 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d'); + 'i2c i2c-5: new_device: Instantiated device lm75 at 0x4d') exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon19/temp1_input', '0') self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000); + property='temperature', value=18000) exec_command_and_wait_for_pattern(self, 'cat /sys/class/hwmon/hwmon19/temp1_input', '18000') exec_command_and_wait_for_pattern(self, 'echo ds1307 0x32 > /sys/class/i2c-dev/i2c-5/device/new_device', - 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32'); + 'i2c i2c-5: new_device: Instantiated device ds1307 at 0x32') year = time.strftime("%Y") exec_command_and_wait_for_pattern(self, - '/sbin/hwclock -f /dev/rtc1', year); + '/sbin/hwclock -f /dev/rtc1', year) if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_bletchley.py b/tests/functional/test_arm_aspeed_bletchley.py index 0da856c5ed..5a60b24b3d 100644 --- a/tests/functional/test_arm_aspeed_bletchley.py +++ b/tests/functional/test_arm_aspeed_bletchley.py @@ -12,14 +12,14 @@ class BletchleyMachine(AspeedTest): ASSET_BLETCHLEY_FLASH = Asset( 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/bletchley-bmc/openbmc-20250128071329/obmc-phosphor-image-bletchley-20250128071329.static.mtd.xz', - 'db21d04d47d7bb2a276f59d308614b4dfb70b9c7c81facbbca40a3977a2d8844'); + 'db21d04d47d7bb2a276f59d308614b4dfb70b9c7c81facbbca40a3977a2d8844') def test_arm_ast2600_bletchley_openbmc(self): image_path = self.uncompress(self.ASSET_BLETCHLEY_FLASH) self.do_test_arm_aspeed_openbmc('bletchley-bmc', image=image_path, uboot='2019.04', cpu_id='0xf00', - soc='AST2600 rev A3'); + soc='AST2600 rev A3') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_palmetto.py b/tests/functional/test_arm_aspeed_palmetto.py index 35d832bc98..ff0b821be6 100755 --- a/tests/functional/test_arm_aspeed_palmetto.py +++ b/tests/functional/test_arm_aspeed_palmetto.py @@ -12,14 +12,14 @@ class PalmettoMachine(AspeedTest): ASSET_PALMETTO_FLASH = Asset( 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/palmetto-bmc/openbmc-20250128071432/obmc-phosphor-image-palmetto-20250128071432.static.mtd', - 'bce7c392eec75c707a91cfc8fad7ca9a69d7e4f10df936930d65c1cb9897ac81'); + 'bce7c392eec75c707a91cfc8fad7ca9a69d7e4f10df936930d65c1cb9897ac81') def test_arm_ast2400_palmetto_openbmc(self): image_path = self.ASSET_PALMETTO_FLASH.fetch() self.do_test_arm_aspeed_openbmc('palmetto-bmc', image=image_path, uboot='2019.04', cpu_id='0x0', - soc='AST2400 rev A1'); + soc='AST2400 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_romulus.py b/tests/functional/test_arm_aspeed_romulus.py index b97ed951b1..0447212bbf 100755 --- a/tests/functional/test_arm_aspeed_romulus.py +++ b/tests/functional/test_arm_aspeed_romulus.py @@ -12,14 +12,14 @@ class RomulusMachine(AspeedTest): ASSET_ROMULUS_FLASH = Asset( 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/romulus-bmc/openbmc-20250128071340/obmc-phosphor-image-romulus-20250128071340.static.mtd', - '6d031376440c82ed9d087d25e9fa76aea75b42f80daa252ec402c0bc3cf6cf5b'); + '6d031376440c82ed9d087d25e9fa76aea75b42f80daa252ec402c0bc3cf6cf5b') def test_arm_ast2500_romulus_openbmc(self): image_path = self.ASSET_ROMULUS_FLASH.fetch() self.do_test_arm_aspeed_openbmc('romulus-bmc', image=image_path, uboot='2019.04', cpu_id='0x0', - soc='AST2500 rev A1'); + soc='AST2500 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_aspeed_witherspoon.py b/tests/functional/test_arm_aspeed_witherspoon.py index ea1ce89b05..51a2d47af2 100644 --- a/tests/functional/test_arm_aspeed_witherspoon.py +++ b/tests/functional/test_arm_aspeed_witherspoon.py @@ -12,14 +12,14 @@ class WitherspoonMachine(AspeedTest): ASSET_WITHERSPOON_FLASH = Asset( 'https://github.com/legoater/qemu-aspeed-boot/raw/master/images/witherspoon-bmc/openbmc-20240618035022/obmc-phosphor-image-witherspoon-20240618035022.ubi.mtd', - '937d9ed449ea6c6cbed983519088a42d0cafe276bcfe4fce07772ca6673f9213'); + '937d9ed449ea6c6cbed983519088a42d0cafe276bcfe4fce07772ca6673f9213') def test_arm_ast2500_witherspoon_openbmc(self): image_path = self.ASSET_WITHERSPOON_FLASH.fetch() self.do_test_arm_aspeed_openbmc('witherspoon-bmc', image=image_path, uboot='2016.07', cpu_id='0x0', - soc='AST2500 rev A1'); + soc='AST2500 rev A1') if __name__ == '__main__': AspeedTest.main() diff --git a/tests/functional/test_arm_bpim2u.py b/tests/functional/test_arm_bpim2u.py index 8de6ccba88..8bed64b702 100755 --- a/tests/functional/test_arm_bpim2u.py +++ b/tests/functional/test_arm_bpim2u.py @@ -163,7 +163,7 @@ class BananaPiMachine(LinuxKernelTest): self, 'Hit any key to stop autoboot:', '=>') exec_command_and_wait_for_pattern(self, "setenv extraargs '" + kernel_command_line + "'", '=>') - exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern( 'Please press Enter to activate this console.') diff --git a/tests/functional/test_arm_cubieboard.py b/tests/functional/test_arm_cubieboard.py index b87a28154d..1eaca0272b 100755 --- a/tests/functional/test_arm_cubieboard.py +++ b/tests/functional/test_arm_cubieboard.py @@ -128,7 +128,7 @@ class CubieboardMachine(LinuxKernelTest): self, 'Hit any key to stop autoboot:', '=>') exec_command_and_wait_for_pattern(self, "setenv extraargs '" + kernel_command_line + "'", '=>') - exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern( 'Please press Enter to activate this console.') diff --git a/tests/functional/test_arm_orangepi.py b/tests/functional/test_arm_orangepi.py index 1815f56e02..f9bfa8c78d 100755 --- a/tests/functional/test_arm_orangepi.py +++ b/tests/functional/test_arm_orangepi.py @@ -174,7 +174,7 @@ class OrangePiMachine(LinuxKernelTest): exec_command_and_wait_for_pattern(self, ' ', '=>') exec_command_and_wait_for_pattern(self, "setenv extraargs '" + kernel_command_line + "'", '=>') - exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...'); + exec_command_and_wait_for_pattern(self, 'boot', 'Starting kernel ...') self.wait_for_console_pattern('systemd[1]: Hostname set ' + 'to ') diff --git a/tests/functional/test_s390x_topology.py b/tests/functional/test_s390x_topology.py index eefd9729cb..1b5dc65135 100755 --- a/tests/functional/test_s390x_topology.py +++ b/tests/functional/test_s390x_topology.py @@ -217,12 +217,12 @@ class S390CPUTopology(QemuSystemTest): self.assertEqual(res['return']['polarization'], 'horizontal') self.check_topology(0, 0, 0, 0, 'medium', False) - self.guest_set_dispatching('1'); + self.guest_set_dispatching('1') res = self.vm.qmp('query-s390x-cpu-polarization') self.assertEqual(res['return']['polarization'], 'vertical') self.check_topology(0, 0, 0, 0, 'medium', False) - self.guest_set_dispatching('0'); + self.guest_set_dispatching('0') res = self.vm.qmp('query-s390x-cpu-polarization') self.assertEqual(res['return']['polarization'], 'horizontal') self.check_topology(0, 0, 0, 0, 'medium', False) @@ -283,7 +283,7 @@ class S390CPUTopology(QemuSystemTest): self.check_polarization('vertical:high') self.check_topology(0, 0, 0, 0, 'high', False) - self.guest_set_dispatching('0'); + self.guest_set_dispatching('0') self.check_polarization("horizontal") self.check_topology(0, 0, 0, 0, 'high', False) @@ -310,11 +310,11 @@ class S390CPUTopology(QemuSystemTest): self.check_topology(0, 0, 0, 0, 'high', True) self.check_polarization("horizontal") - self.guest_set_dispatching('1'); + self.guest_set_dispatching('1') self.check_topology(0, 0, 0, 0, 'high', True) self.check_polarization("vertical:high") - self.guest_set_dispatching('0'); + self.guest_set_dispatching('0') self.check_topology(0, 0, 0, 0, 'high', True) self.check_polarization("horizontal") @@ -360,7 +360,7 @@ class S390CPUTopology(QemuSystemTest): self.check_topology(0, 0, 0, 0, 'high', True) - self.guest_set_dispatching('1'); + self.guest_set_dispatching('1') self.check_topology(0, 0, 0, 0, 'high', True) From 99fb9256b761c3cec4a82d2e9597b6cf24ae1285 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 16:54:57 +0200 Subject: [PATCH 0072/2760] tests/functional: Remove unnecessary import statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pylint complains about these unnecessary import statements, so let's remove them. Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250414145457.261734-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- tests/functional/qemu_test/ports.py | 3 +-- tests/functional/qemu_test/tuxruntest.py | 2 -- tests/functional/qemu_test/uncompress.py | 2 +- tests/functional/test_aarch64_rme_sbsaref.py | 6 ++---- tests/functional/test_aarch64_rme_virt.py | 2 -- tests/functional/test_aarch64_sbsaref_alpine.py | 3 --- tests/functional/test_aarch64_sbsaref_freebsd.py | 2 -- tests/functional/test_aarch64_tcg_plugins.py | 1 - tests/functional/test_aarch64_virt.py | 8 ++------ tests/functional/test_arm_aspeed_ast2500.py | 3 +-- tests/functional/test_arm_cubieboard.py | 2 -- tests/functional/test_arm_quanta_gsj.py | 2 -- tests/functional/test_arm_smdkc210.py | 2 -- tests/functional/test_migration.py | 3 +-- tests/functional/test_mips64el_replay.py | 6 +----- tests/functional/test_mips_replay.py | 2 +- tests/functional/test_mipsel_replay.py | 2 +- tests/functional/test_ppc64_hv.py | 8 ++++---- tests/functional/test_vnc.py | 4 ++-- tests/functional/test_x86_64_kvm_xen.py | 2 -- 20 files changed, 17 insertions(+), 48 deletions(-) diff --git a/tests/functional/qemu_test/ports.py b/tests/functional/qemu_test/ports.py index cc39939d48..631b77abf6 100644 --- a/tests/functional/qemu_test/ports.py +++ b/tests/functional/qemu_test/ports.py @@ -10,12 +10,11 @@ import fcntl import os import socket -import sys -import tempfile from .config import BUILD_DIR from typing import List + class Ports(): PORTS_ADDR = '127.0.0.1' diff --git a/tests/functional/qemu_test/tuxruntest.py b/tests/functional/qemu_test/tuxruntest.py index c2bd5baaae..6c442ff0dc 100644 --- a/tests/functional/qemu_test/tuxruntest.py +++ b/tests/functional/qemu_test/tuxruntest.py @@ -10,8 +10,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later import os -import stat -from subprocess import check_call, DEVNULL from qemu_test import QemuSystemTest from qemu_test import exec_command_and_wait_for_pattern diff --git a/tests/functional/qemu_test/uncompress.py b/tests/functional/qemu_test/uncompress.py index ce79da1b68..b7ef8f759b 100644 --- a/tests/functional/qemu_test/uncompress.py +++ b/tests/functional/qemu_test/uncompress.py @@ -13,7 +13,7 @@ import os import stat import shutil from urllib.parse import urlparse -from subprocess import run, CalledProcessError, DEVNULL +from subprocess import run, CalledProcessError from .asset import Asset diff --git a/tests/functional/test_aarch64_rme_sbsaref.py b/tests/functional/test_aarch64_rme_sbsaref.py index 0f4f6103a1..746770e776 100755 --- a/tests/functional/test_aarch64_rme_sbsaref.py +++ b/tests/functional/test_aarch64_rme_sbsaref.py @@ -9,15 +9,13 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import time import os -import logging -from qemu_test import QemuSystemTest, Asset -from qemu_test import exec_command, wait_for_console_pattern +from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern from qemu_test import exec_command_and_wait_for_pattern from test_aarch64_rme_virt import test_realms_guest + class Aarch64RMESbsaRefMachine(QemuSystemTest): # Stack is built with OP-TEE build environment from those instructions: diff --git a/tests/functional/test_aarch64_rme_virt.py b/tests/functional/test_aarch64_rme_virt.py index a1abf584f0..8452d27928 100755 --- a/tests/functional/test_aarch64_rme_virt.py +++ b/tests/functional/test_aarch64_rme_virt.py @@ -9,9 +9,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import time import os -import logging from qemu_test import QemuSystemTest, Asset from qemu_test import exec_command, wait_for_console_pattern diff --git a/tests/functional/test_aarch64_sbsaref_alpine.py b/tests/functional/test_aarch64_sbsaref_alpine.py index c660cc7a40..6108ec65a5 100755 --- a/tests/functional/test_aarch64_sbsaref_alpine.py +++ b/tests/functional/test_aarch64_sbsaref_alpine.py @@ -10,11 +10,8 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import QemuSystemTest, Asset, skipSlowTest from qemu_test import wait_for_console_pattern -from unittest import skipUnless from test_aarch64_sbsaref import fetch_firmware diff --git a/tests/functional/test_aarch64_sbsaref_freebsd.py b/tests/functional/test_aarch64_sbsaref_freebsd.py index bd6728dc70..26dfc5878b 100755 --- a/tests/functional/test_aarch64_sbsaref_freebsd.py +++ b/tests/functional/test_aarch64_sbsaref_freebsd.py @@ -10,8 +10,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import QemuSystemTest, Asset, skipSlowTest from qemu_test import wait_for_console_pattern from test_aarch64_sbsaref import fetch_firmware diff --git a/tests/functional/test_aarch64_tcg_plugins.py b/tests/functional/test_aarch64_tcg_plugins.py index 4ea71f5f88..cb7e9298fb 100755 --- a/tests/functional/test_aarch64_tcg_plugins.py +++ b/tests/functional/test_aarch64_tcg_plugins.py @@ -13,7 +13,6 @@ import tempfile import mmap -import os import re from qemu.machine.machine import VMLaunchFailure diff --git a/tests/functional/test_aarch64_virt.py b/tests/functional/test_aarch64_virt.py index 884aad7af6..4d0ad90ff8 100755 --- a/tests/functional/test_aarch64_virt.py +++ b/tests/functional/test_aarch64_virt.py @@ -13,12 +13,8 @@ import logging from subprocess import check_call, DEVNULL -from qemu.machine.machine import VMLaunchFailure - -from qemu_test import QemuSystemTest, Asset -from qemu_test import exec_command, exec_command_and_wait_for_pattern -from qemu_test import wait_for_console_pattern -from qemu_test import skipIfMissingCommands, get_qemu_img +from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern +from qemu_test import wait_for_console_pattern, get_qemu_img class Aarch64VirtMachine(QemuSystemTest): diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/test_arm_aspeed_ast2500.py index ddc6459f71..a3b44572fc 100755 --- a/tests/functional/test_arm_aspeed_ast2500.py +++ b/tests/functional/test_arm_aspeed_ast2500.py @@ -4,9 +4,8 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset +from qemu_test import Asset, exec_command_and_wait_for_pattern from aspeed import AspeedTest -from qemu_test import exec_command_and_wait_for_pattern class AST2500Machine(AspeedTest): diff --git a/tests/functional/test_arm_cubieboard.py b/tests/functional/test_arm_cubieboard.py index 1eaca0272b..b536c2f77a 100755 --- a/tests/functional/test_arm_cubieboard.py +++ b/tests/functional/test_arm_cubieboard.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern from qemu_test import interrupt_interactive_console_until_pattern from qemu_test import skipBigDataTest diff --git a/tests/functional/test_arm_quanta_gsj.py b/tests/functional/test_arm_quanta_gsj.py index da60aeb659..cb0545f7bf 100755 --- a/tests/functional/test_arm_quanta_gsj.py +++ b/tests/functional/test_arm_quanta_gsj.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import LinuxKernelTest, Asset, exec_command_and_wait_for_pattern from qemu_test import interrupt_interactive_console_until_pattern, skipSlowTest diff --git a/tests/functional/test_arm_smdkc210.py b/tests/functional/test_arm_smdkc210.py index 0fda45c63a..3154e7f732 100755 --- a/tests/functional/test_arm_smdkc210.py +++ b/tests/functional/test_arm_smdkc210.py @@ -4,8 +4,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu_test import LinuxKernelTest, Asset diff --git a/tests/functional/test_migration.py b/tests/functional/test_migration.py index 181223a69e..c4393c3543 100755 --- a/tests/functional/test_migration.py +++ b/tests/functional/test_migration.py @@ -11,14 +11,13 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. - import tempfile -import os import time from qemu_test import QemuSystemTest, skipIfMissingCommands from qemu_test.ports import Ports + class MigrationTest(QemuSystemTest): timeout = 10 diff --git a/tests/functional/test_mips64el_replay.py b/tests/functional/test_mips64el_replay.py index 4f63d7fb34..26a6ccff3f 100755 --- a/tests/functional/test_mips64el_replay.py +++ b/tests/functional/test_mips64el_replay.py @@ -4,11 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os -import logging - -from qemu_test import Asset, exec_command_and_wait_for_pattern -from qemu_test import skipIfMissingImports, skipFlakyTest, skipUntrustedTest +from qemu_test import Asset, skipUntrustedTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_mips_replay.py b/tests/functional/test_mips_replay.py index eda031ccad..4327481e35 100755 --- a/tests/functional/test_mips_replay.py +++ b/tests/functional/test_mips_replay.py @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, skipSlowTest, exec_command_and_wait_for_pattern +from qemu_test import Asset, skipSlowTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_mipsel_replay.py b/tests/functional/test_mipsel_replay.py index 0a330de43f..5f4796cf89 100644 --- a/tests/functional/test_mipsel_replay.py +++ b/tests/functional/test_mipsel_replay.py @@ -4,7 +4,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -from qemu_test import Asset, wait_for_console_pattern, skipSlowTest +from qemu_test import Asset, skipSlowTest from replay_kernel import ReplayKernelBase diff --git a/tests/functional/test_ppc64_hv.py b/tests/functional/test_ppc64_hv.py index 1920e91f18..d87f440fa7 100755 --- a/tests/functional/test_ppc64_hv.py +++ b/tests/functional/test_ppc64_hv.py @@ -9,14 +9,14 @@ # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. +import os +import subprocess + +from datetime import datetime from qemu_test import QemuSystemTest, Asset from qemu_test import wait_for_console_pattern, exec_command from qemu_test import skipIfMissingCommands, skipBigDataTest from qemu_test import exec_command_and_wait_for_pattern -import os -import time -import subprocess -from datetime import datetime # Alpine is a light weight distro that supports QEMU. These tests boot # that on the machine then run a QEMU guest inside it in KVM mode, diff --git a/tests/functional/test_vnc.py b/tests/functional/test_vnc.py index d4e9dd0279..5c0ee5f927 100755 --- a/tests/functional/test_vnc.py +++ b/tests/functional/test_vnc.py @@ -11,12 +11,12 @@ # later. See the COPYING file in the top-level directory. import socket -from typing import List -from qemu.machine.machine import VMLaunchFailure +from qemu.machine.machine import VMLaunchFailure from qemu_test import QemuSystemTest from qemu_test.ports import Ports + VNC_ADDR = '127.0.0.1' def check_connect(port: int) -> bool: diff --git a/tests/functional/test_x86_64_kvm_xen.py b/tests/functional/test_x86_64_kvm_xen.py index c6abf6bba3..a5d445023c 100755 --- a/tests/functional/test_x86_64_kvm_xen.py +++ b/tests/functional/test_x86_64_kvm_xen.py @@ -11,8 +11,6 @@ # # SPDX-License-Identifier: GPL-2.0-or-later -import os - from qemu.machine import machine from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern From 12c6b6153063aafcdbadca8fee7eac793ef85e4b Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Mon, 14 Apr 2025 14:15:20 +0200 Subject: [PATCH 0073/2760] MAINTAINERS: Add functional tests that are not covered yet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some functional tests are currently not covered by the entries in MAINTAINERS yet, so scripts/get_maintainers.pl fails to suggest the right people who should be CC:-ed for related patches. Add the uncovered tests to the right sections to close this gap. Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250414121520.213665-1-thuth@redhat.com> Signed-off-by: Thomas Huth --- MAINTAINERS | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5fd757c5dd..c6d9b022f9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -475,6 +475,7 @@ F: docs/system/i386/sgx.rst F: target/i386/kvm/ F: target/i386/sev* F: scripts/kvm/vmxcap +F: tests/functional/test_x86_64_hotplug_cpu.py Xen emulation on X86 KVM CPUs M: David Woodhouse @@ -626,6 +627,7 @@ S: Maintained F: hw/alpha/ F: hw/isa/smc37c669-superio.c F: tests/tcg/alpha/system/ +F: tests/functional/test_alpha_clipper.py ARM Machines ------------ @@ -950,7 +952,7 @@ F: hw/misc/sbsa_ec.c F: hw/watchdog/sbsa_gwdt.c F: include/hw/watchdog/sbsa_gwdt.h F: docs/system/arm/sbsa.rst -F: tests/functional/test_aarch64_sbsaref*.py +F: tests/functional/test_aarch64_*sbsaref*.py Sharp SL-5500 (Collie) PDA M: Peter Maydell @@ -1019,9 +1021,10 @@ S: Maintained F: hw/arm/virt* F: include/hw/arm/virt.h F: docs/system/arm/virt.rst -F: tests/functional/test_aarch64_virt*.py +F: tests/functional/test_aarch64_*virt*.py F: tests/functional/test_aarch64_tuxrun.py F: tests/functional/test_arm_tuxrun.py +F: tests/functional/test_arm_virt.py Xilinx Zynq M: Edgar E. Iglesias @@ -1262,6 +1265,7 @@ F: hw/m68k/mcf_intc.c F: hw/char/mcf_uart.c F: hw/net/mcf_fec.c F: include/hw/m68k/mcf*.h +F: tests/functional/test_m68k_mcf5208evb.py NeXTcube M: Thomas Huth @@ -1406,6 +1410,7 @@ S: Maintained F: docs/system/openrisc/or1k-sim.rst F: hw/intc/ompic.c F: hw/openrisc/openrisc_sim.c +F: tests/functional/test_or1k_sim.py PowerPC Machines ---------------- @@ -1827,6 +1832,7 @@ F: include/hw/isa/apm.h F: tests/unit/test-x86-topo.c F: tests/qtest/test-x86-cpuid-compat.c F: tests/functional/test_i386_tuxrun.py +F: tests/functional/test_linux_initrd.py F: tests/functional/test_mem_addr_space.py F: tests/functional/test_pc_cpu_hotplug_props.py F: tests/functional/test_x86_64_tuxrun.py @@ -3150,6 +3156,7 @@ F: include/ui/ F: qapi/ui.json F: util/drm.c F: docs/devel/ui.rst +F: tests/functional/test_vnc.py Cocoa graphics M: Peter Maydell @@ -3815,6 +3822,7 @@ F: configs/targets/*linux-user.mak F: scripts/qemu-binfmt-conf.sh F: scripts/update-syscalltbl.sh F: scripts/update-mips-syscall-args.sh +F: tests/functional/test_arm_bflt.py Tiny Code Generator (TCG) ------------------------- @@ -4187,6 +4195,7 @@ F: hw/remote/vfio-user-obj.c F: include/hw/remote/vfio-user-obj.h F: hw/remote/iommu.c F: include/hw/remote/iommu.h +F: tests/functional/test_multiprocess.py EBPF: M: Jason Wang From 8163eeee4e5b6ce5ecb2f7300b80ae8a6f868afd Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:40 +0800 Subject: [PATCH 0074/2760] rust/hpet: convert num_timers to u8 type The C version of HPET uses the uint8_t type for num_timers, and usize type in Rust version will break migration between the C and Rust versions. So convert num_timers' type to u8 (consistent with the C version of HPET) to make it friendly for vmstate support. Note the commit 7bda68e8e2b0 ("qdev, rust/hpet: fix type of HPET 'timers property") supports the usize type property, but the uint8 property has to be re-supported now. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-7-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/hpet.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index 3ae3ec25f1..1afa891362 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -12,7 +12,7 @@ use std::{ use qemu_api::{ bindings::{ address_space_memory, address_space_stl_le, qdev_prop_bit, qdev_prop_bool, - qdev_prop_uint32, qdev_prop_usize, + qdev_prop_uint32, qdev_prop_uint8, }, c_str, cell::{BqlCell, BqlRefCell}, @@ -34,9 +34,9 @@ use crate::fw_cfg::HPETFwConfig; const HPET_REG_SPACE_LEN: u64 = 0x400; // 1024 bytes /// Minimum recommended hardware implementation. -const HPET_MIN_TIMERS: usize = 3; +const HPET_MIN_TIMERS: u8 = 3; /// Maximum timers in each timer block. -const HPET_MAX_TIMERS: usize = 32; +const HPET_MAX_TIMERS: u8 = 32; /// Flags that HPETState.flags supports. const HPET_FLAG_MSI_SUPPORT_SHIFT: usize = 0; @@ -559,14 +559,19 @@ pub struct HPETState { /// HPET timer array managed by this timer block. #[doc(alias = "timer")] - timers: [BqlRefCell; HPET_MAX_TIMERS], - num_timers: BqlCell, + timers: [BqlRefCell; HPET_MAX_TIMERS as usize], + num_timers: BqlCell, /// Instance id (HPET timer block ID). hpet_id: BqlCell, } impl HPETState { + // Get num_timers with `usize` type, which is useful to play with array index. + fn get_num_timers(&self) -> usize { + self.num_timers.get().into() + } + const fn has_msi_flag(&self) -> bool { self.flags & (1 << HPET_FLAG_MSI_SUPPORT_SHIFT) != 0 } @@ -628,7 +633,7 @@ impl HPETState { self.hpet_offset .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns()); - for timer in self.timers.iter().take(self.num_timers.get()) { + for timer in self.timers.iter().take(self.get_num_timers()) { let mut t = timer.borrow_mut(); if t.is_int_enabled() && t.is_int_active() { @@ -640,7 +645,7 @@ impl HPETState { // Halt main counter and disable interrupt generation. self.counter.set(self.get_ticks()); - for timer in self.timers.iter().take(self.num_timers.get()) { + for timer in self.timers.iter().take(self.get_num_timers()) { timer.borrow_mut().del_timer(); } } @@ -663,7 +668,7 @@ impl HPETState { let new_val = val << shift; let cleared = new_val & self.int_status.get(); - for (index, timer) in self.timers.iter().take(self.num_timers.get()).enumerate() { + for (index, timer) in self.timers.iter().take(self.get_num_timers()).enumerate() { if cleared & (1 << index) != 0 { timer.borrow_mut().update_irq(false); } @@ -737,7 +742,7 @@ impl HPETState { 1 << HPET_CAP_COUNT_SIZE_CAP_SHIFT | 1 << HPET_CAP_LEG_RT_CAP_SHIFT | HPET_CAP_VENDER_ID_VALUE << HPET_CAP_VENDER_ID_SHIFT | - ((self.num_timers.get() - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer + ((self.get_num_timers() - 1) as u64) << HPET_CAP_NUM_TIM_SHIFT | // indicate the last timer (HPET_CLK_PERIOD * FS_PER_NS) << HPET_CAP_CNT_CLK_PERIOD_SHIFT, // 10 ns ); @@ -746,7 +751,7 @@ impl HPETState { } fn reset_hold(&self, _type: ResetType) { - for timer in self.timers.iter().take(self.num_timers.get()) { + for timer in self.timers.iter().take(self.get_num_timers()) { timer.borrow_mut().reset(); } @@ -774,7 +779,7 @@ impl HPETState { GlobalRegister::try_from(addr).map(HPETRegister::Global) } else { let timer_id: usize = ((addr - 0x100) / 0x20) as usize; - if timer_id <= self.num_timers.get() { + if timer_id <= self.get_num_timers() { // TODO: Add trace point - trace_hpet_ram_[read|write]_timer_id(timer_id) TimerRegister::try_from(addr & 0x18) .map(|reg| HPETRegister::Timer(&self.timers[timer_id], reg)) @@ -859,8 +864,8 @@ qemu_api::declare_properties! { c_str!("timers"), HPETState, num_timers, - unsafe { &qdev_prop_usize }, - usize, + unsafe { &qdev_prop_uint8 }, + u8, default = HPET_MIN_TIMERS ), qemu_api::define_property!( From 64e1256b21395eb7c8a9419faba4187dea73970d Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:41 +0800 Subject: [PATCH 0075/2760] rust/hpet: convert HPETTimer index to u8 type The C version of HPET uses the uint8_t type for timer index ("tn"), and usize type in Rust version will break migration between the C and Rust versions. So convert HPETTimer index' type to u8 (consistent with the C version of HPET) to make it friendly for vmstate support. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-8-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/hpet.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index 1afa891362..dc8a23f29d 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -184,7 +184,7 @@ fn timer_handler(timer_cell: &BqlRefCell) { pub struct HPETTimer { /// timer N index within the timer block (`HPETState`) #[doc(alias = "tn")] - index: usize, + index: u8, qemu_timer: Timer, /// timer block abstraction containing this timer state: NonNull, @@ -210,7 +210,7 @@ pub struct HPETTimer { } impl HPETTimer { - fn init(&mut self, index: usize, state: &HPETState) { + fn init(&mut self, index: u8, state: &HPETState) { *self = HPETTimer { index, // SAFETY: the HPETTimer will only be used after the timer @@ -235,7 +235,7 @@ impl HPETTimer { Timer::NS, 0, timer_handler, - &state.timers[self.index], + &state.timers[self.index as usize], ) } @@ -246,7 +246,7 @@ impl HPETTimer { } fn is_int_active(&self) -> bool { - self.get_state().is_timer_int_active(self.index) + self.get_state().is_timer_int_active(self.index.into()) } const fn is_fsb_route_enabled(&self) -> bool { @@ -611,7 +611,7 @@ impl HPETState { fn init_timer(&self) { for (index, timer) in self.timers.iter().enumerate() { - timer.borrow_mut().init(index, self); + timer.borrow_mut().init(index.try_into().unwrap(), self); } } From ad3ab01bb7380f8cc8cf86dd260ce751148d6d21 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:43 +0800 Subject: [PATCH 0076/2760] rust/hpet: Fix a clippy error Carge clippy complained about: error: casts from `u8` to `u32` can be expressed infallibly using `From` So use `From` to convert `u8` to `u32`. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-10-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/hpet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index dc8a23f29d..cbd2ed4f6b 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -353,7 +353,7 @@ impl HPETTimer { // still operate and generate appropriate status bits, but // will not cause an interrupt" self.get_state() - .update_int_status(self.index as u32, set && self.is_int_level_triggered()); + .update_int_status(self.index.into(), set && self.is_int_level_triggered()); self.set_irq(set); } From d031d2fac9b94126ed0cd440da9e69e229d88aef Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:38 +0800 Subject: [PATCH 0077/2760] rust/vmstate_test: Fix typo in test_vmstate_macro_array_of_pointer_wrapped() test_vmstate_macro_array_of_pointer_wrapped() tests the 3rd element, so fix the index. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-5-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/tests/vmstate_tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs index b8d8b45b19..8b93492a68 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -383,12 +383,12 @@ fn test_vmstate_macro_array_of_pointer_wrapped() { ); assert_eq!(foo_fields[3].offset, (FOO_ARRAY_MAX + 2) * PTR_SIZE); assert_eq!(foo_fields[3].num_offset, 0); - assert_eq!(foo_fields[2].info, unsafe { &vmstate_info_uint8 }); + assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_uint8 }); assert_eq!(foo_fields[3].version_id, 0); assert_eq!(foo_fields[3].size, PTR_SIZE); assert_eq!(foo_fields[3].num, FOO_ARRAY_MAX as i32); assert_eq!( - foo_fields[2].flags.0, + foo_fields[3].flags.0, VMStateFlags::VMS_ARRAY.0 | VMStateFlags::VMS_ARRAY_OF_POINTER.0 ); assert!(foo_fields[3].vmsd.is_null()); From efc5603292bfde97fd82fabcedce86310bedbc65 Mon Sep 17 00:00:00 2001 From: Rakesh Jeyasingh Date: Mon, 7 Apr 2025 23:43:26 +0530 Subject: [PATCH 0078/2760] rust/hw/char/pl011: Extract extract DR read logic into separate function - Split `read()` DR case into `read_data_register()` Signed-off-by: Rakesh Jeyasingh Link: https://lore.kernel.org/r/20250407181327.171563-2-rakeshjb010@gmail.com Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 39 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index bf88e0b00a..87153cdae1 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -190,25 +190,7 @@ impl PL011Registers { let mut update = false; let result = match offset { - DR => { - self.flags.set_receive_fifo_full(false); - let c = self.read_fifo[self.read_pos]; - if self.read_count > 0 { - self.read_count -= 1; - self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1); - } - if self.read_count == 0 { - self.flags.set_receive_fifo_empty(true); - } - if self.read_count + 1 == self.read_trigger { - self.int_level &= !Interrupt::RX.0; - } - // Update error bits. - self.receive_status_error_clear.set_from_data(c); - // Must call qemu_chr_fe_accept_input - update = true; - u32::from(c) - } + DR => self.read_data_register(&mut update), RSR => u32::from(self.receive_status_error_clear), FR => u32::from(self.flags), FBRD => self.fbrd, @@ -306,6 +288,25 @@ impl PL011Registers { false } + fn read_data_register(&mut self, update: &mut bool) -> u32 { + self.flags.set_receive_fifo_full(false); + let c = self.read_fifo[self.read_pos]; + + if self.read_count > 0 { + self.read_count -= 1; + self.read_pos = (self.read_pos + 1) & (self.fifo_depth() - 1); + } + if self.read_count == 0 { + self.flags.set_receive_fifo_empty(true); + } + if self.read_count + 1 == self.read_trigger { + self.int_level &= !Interrupt::RX.0; + } + self.receive_status_error_clear.set_from_data(c); + *update = true; + u32::from(c) + } + #[inline] #[must_use] fn loopback_tx(&mut self, value: registers::Data) -> bool { From 6d8c6dee3a767e7650e5d0640e13adb9f01fa37c Mon Sep 17 00:00:00 2001 From: Rakesh Jeyasingh Date: Mon, 7 Apr 2025 23:43:27 +0530 Subject: [PATCH 0079/2760] rust/hw/char/pl011: Extract DR write logic into separate function - Split `write()` DR case into `write_data_register()` Signed-off-by: Rakesh Jeyasingh Link: https://lore.kernel.org/r/20250407181327.171563-3-rakeshjb010@gmail.com Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index 87153cdae1..bb2a0f207a 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -221,12 +221,7 @@ impl PL011Registers { // eprintln!("write offset {offset} value {value}"); use RegisterOffset::*; match offset { - DR => { - // interrupts always checked - let _ = self.loopback_tx(value.into()); - self.int_level |= Interrupt::TX.0; - return true; - } + DR => return self.write_data_register(value), RSR => { self.receive_status_error_clear = 0.into(); } @@ -307,6 +302,13 @@ impl PL011Registers { u32::from(c) } + fn write_data_register(&mut self, value: u32) -> bool { + // interrupts always checked + let _ = self.loopback_tx(value.into()); + self.int_level |= Interrupt::TX.0; + true + } + #[inline] #[must_use] fn loopback_tx(&mut self, value: registers::Data) -> bool { From cfac5cdff51ba72780a22bc63a7c8092c8761af3 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:00 -0700 Subject: [PATCH 0080/2760] exec/tswap: target code can use TARGET_BIG_ENDIAN instead of target_words_bigendian() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-2-pierrick.bouvier@linaro.org> --- cpu-target.c | 1 + include/exec/tswap.h | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index cae77374b3..519b0f8900 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -155,6 +155,7 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...) abort(); } +#undef target_words_bigendian bool target_words_bigendian(void) { return TARGET_BIG_ENDIAN; diff --git a/include/exec/tswap.h b/include/exec/tswap.h index ecd4faef01..2683da0adb 100644 --- a/include/exec/tswap.h +++ b/include/exec/tswap.h @@ -13,13 +13,14 @@ /** * target_words_bigendian: * Returns true if the (default) endianness of the target is big endian, - * false otherwise. Note that in target-specific code, you can use - * TARGET_BIG_ENDIAN directly instead. On the other hand, common - * code should normally never need to know about the endianness of the - * target, so please do *not* use this function unless you know very well - * what you are doing! + * false otherwise. Common code should normally never need to know about the + * endianness of the target, so please do *not* use this function unless you + * know very well what you are doing! */ bool target_words_bigendian(void); +#ifdef COMPILING_PER_TARGET +#define target_words_bigendian() TARGET_BIG_ENDIAN +#endif /* * If we're in target-specific code, we can hard-code the swapping From 663310b05c43e59cfe97b9add7b645b3f495cd42 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:01 -0700 Subject: [PATCH 0081/2760] exec/tswap: implement {ld,st}.*_p as functions instead of macros Defining functions allows to use them from common code, by not depending on TARGET_BIG_ENDIAN. Remove previous macros from exec/cpu-all.h. By moving them out of cpu-all.h, we'll be able to break dependency on cpu.h for memory related functions coming in next commits. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-3-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 25 --------------- include/exec/tswap.h | 70 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 25 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 47b14446b8..d000fe4871 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -26,31 +26,6 @@ #include "exec/tswap.h" #include "hw/core/cpu.h" -/* Target-endianness CPU memory access functions. These fit into the - * {ld,st}{type}{sign}{size}{endian}_p naming scheme described in bswap.h. - */ -#if TARGET_BIG_ENDIAN -#define lduw_p(p) lduw_be_p(p) -#define ldsw_p(p) ldsw_be_p(p) -#define ldl_p(p) ldl_be_p(p) -#define ldq_p(p) ldq_be_p(p) -#define stw_p(p, v) stw_be_p(p, v) -#define stl_p(p, v) stl_be_p(p, v) -#define stq_p(p, v) stq_be_p(p, v) -#define ldn_p(p, sz) ldn_be_p(p, sz) -#define stn_p(p, sz, v) stn_be_p(p, sz, v) -#else -#define lduw_p(p) lduw_le_p(p) -#define ldsw_p(p) ldsw_le_p(p) -#define ldl_p(p) ldl_le_p(p) -#define ldq_p(p) ldq_le_p(p) -#define stw_p(p, v) stw_le_p(p, v) -#define stl_p(p, v) stl_le_p(p, v) -#define stq_p(p, v) stq_le_p(p, v) -#define ldn_p(p, sz) ldn_le_p(p, sz) -#define stn_p(p, sz, v) stn_le_p(p, sz, v) -#endif - /* MMU memory access macros */ #if !defined(CONFIG_USER_ONLY) diff --git a/include/exec/tswap.h b/include/exec/tswap.h index 2683da0adb..84060a4999 100644 --- a/include/exec/tswap.h +++ b/include/exec/tswap.h @@ -80,4 +80,74 @@ static inline void tswap64s(uint64_t *s) } } +/* Return ld{word}_{le,be}_p following target endianness. */ +#define LOAD_IMPL(word, args...) \ +do { \ + if (target_words_bigendian()) { \ + return glue(glue(ld, word), _be_p)(args); \ + } else { \ + return glue(glue(ld, word), _le_p)(args); \ + } \ +} while (0) + +static inline int lduw_p(const void *ptr) +{ + LOAD_IMPL(uw, ptr); +} + +static inline int ldsw_p(const void *ptr) +{ + LOAD_IMPL(sw, ptr); +} + +static inline int ldl_p(const void *ptr) +{ + LOAD_IMPL(l, ptr); +} + +static inline uint64_t ldq_p(const void *ptr) +{ + LOAD_IMPL(q, ptr); +} + +static inline uint64_t ldn_p(const void *ptr, int sz) +{ + LOAD_IMPL(n, ptr, sz); +} + +#undef LOAD_IMPL + +/* Call st{word}_{le,be}_p following target endianness. */ +#define STORE_IMPL(word, args...) \ +do { \ + if (target_words_bigendian()) { \ + glue(glue(st, word), _be_p)(args); \ + } else { \ + glue(glue(st, word), _le_p)(args); \ + } \ +} while (0) + + +static inline void stw_p(void *ptr, uint16_t v) +{ + STORE_IMPL(w, ptr, v); +} + +static inline void stl_p(void *ptr, uint32_t v) +{ + STORE_IMPL(l, ptr, v); +} + +static inline void stq_p(void *ptr, uint64_t v) +{ + STORE_IMPL(q, ptr, v); +} + +static inline void stn_p(void *ptr, int sz, uint64_t v) +{ + STORE_IMPL(n, ptr, sz, v); +} + +#undef STORE_IMPL + #endif /* TSWAP_H */ From 3dd08a6920a3bfbc51da7fdf7b87c1f8d876a457 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:02 -0700 Subject: [PATCH 0082/2760] exec/memory_ldst: extract memory_ldst declarations from cpu-all.h They are now accessible through exec/memory.h instead, and we make sure all variants are available for common or target dependent code. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-4-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 12 ------------ include/exec/memory_ldst.h.inc | 4 ---- 2 files changed, 16 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index d000fe4871..7e8d66de31 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -32,18 +32,6 @@ #include "exec/hwaddr.h" -#define SUFFIX -#define ARG1 as -#define ARG1_DECL AddressSpace *as -#define TARGET_ENDIANNESS -#include "exec/memory_ldst.h.inc" - -#define SUFFIX _cached_slow -#define ARG1 cache -#define ARG1_DECL MemoryRegionCache *cache -#define TARGET_ENDIANNESS -#include "exec/memory_ldst.h.inc" - static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val) { address_space_stl_notdirty(as, addr, val, diff --git a/include/exec/memory_ldst.h.inc b/include/exec/memory_ldst.h.inc index 92ad74e956..7270235c60 100644 --- a/include/exec/memory_ldst.h.inc +++ b/include/exec/memory_ldst.h.inc @@ -19,7 +19,6 @@ * License along with this library; if not, see . */ -#ifdef TARGET_ENDIANNESS uint16_t glue(address_space_lduw, SUFFIX)(ARG1_DECL, hwaddr addr, MemTxAttrs attrs, MemTxResult *result); uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL, @@ -34,7 +33,6 @@ void glue(address_space_stl, SUFFIX)(ARG1_DECL, hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result); void glue(address_space_stq, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); -#else uint8_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, hwaddr addr, MemTxAttrs attrs, MemTxResult *result); uint16_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL, @@ -63,9 +61,7 @@ void glue(address_space_stq_le, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result); -#endif #undef ARG1_DECL #undef ARG1 #undef SUFFIX -#undef TARGET_ENDIANNESS From 713b5e1dccd1219f663f274a89b17e322e617ef9 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:03 -0700 Subject: [PATCH 0083/2760] exec/memory_ldst_phys: extract memory_ldst_phys declarations from cpu-all.h They are now accessible through exec/memory.h instead, and we make sure all variants are available for common or target dependent code. Move stl_phys_notdirty function as well. Cached endianness agnostic version rely on st/ld*_p, which is available through tswap.h. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-5-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 31 ----------------------------- include/exec/memory.h | 10 ++++++++++ include/exec/memory_ldst_phys.h.inc | 5 +---- 3 files changed, 11 insertions(+), 35 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 7e8d66de31..66a4252269 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -25,37 +25,6 @@ #include "exec/memory.h" #include "exec/tswap.h" #include "hw/core/cpu.h" - -/* MMU memory access macros */ - -#if !defined(CONFIG_USER_ONLY) - -#include "exec/hwaddr.h" - -static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val) -{ - address_space_stl_notdirty(as, addr, val, - MEMTXATTRS_UNSPECIFIED, NULL); -} - -#define SUFFIX -#define ARG1 as -#define ARG1_DECL AddressSpace *as -#define TARGET_ENDIANNESS -#include "exec/memory_ldst_phys.h.inc" - -/* Inline fast path for direct RAM access. */ -#define ENDIANNESS -#include "exec/memory_ldst_cached.h.inc" - -#define SUFFIX _cached -#define ARG1 cache -#define ARG1_DECL MemoryRegionCache *cache -#define TARGET_ENDIANNESS -#include "exec/memory_ldst_phys.h.inc" -#endif - -/* page related stuff */ #include "exec/cpu-defs.h" #include "exec/target_page.h" diff --git a/include/exec/memory.h b/include/exec/memory.h index e1c196a0c2..cc5915033c 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -21,6 +21,7 @@ #include "exec/memattrs.h" #include "exec/memop.h" #include "exec/ramlist.h" +#include "exec/tswap.h" #include "qemu/bswap.h" #include "qemu/queue.h" #include "qemu/int128.h" @@ -2732,6 +2733,12 @@ MemTxResult address_space_write_rom(AddressSpace *as, hwaddr addr, #define ARG1_DECL AddressSpace *as #include "exec/memory_ldst.h.inc" +static inline void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val) +{ + address_space_stl_notdirty(as, addr, val, + MEMTXATTRS_UNSPECIFIED, NULL); +} + #define SUFFIX #define ARG1 as #define ARG1_DECL AddressSpace *as @@ -2798,6 +2805,9 @@ static inline void address_space_stb_cached(MemoryRegionCache *cache, } } +#define ENDIANNESS +#include "exec/memory_ldst_cached.h.inc" + #define ENDIANNESS _le #include "exec/memory_ldst_cached.h.inc" diff --git a/include/exec/memory_ldst_phys.h.inc b/include/exec/memory_ldst_phys.h.inc index ecd678610d..db67de7525 100644 --- a/include/exec/memory_ldst_phys.h.inc +++ b/include/exec/memory_ldst_phys.h.inc @@ -19,7 +19,6 @@ * License along with this library; if not, see . */ -#ifdef TARGET_ENDIANNESS static inline uint16_t glue(lduw_phys, SUFFIX)(ARG1_DECL, hwaddr addr) { return glue(address_space_lduw, SUFFIX)(ARG1, addr, @@ -55,7 +54,7 @@ static inline void glue(stq_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t val) glue(address_space_stq, SUFFIX)(ARG1, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); } -#else + static inline uint8_t glue(ldub_phys, SUFFIX)(ARG1_DECL, hwaddr addr) { return glue(address_space_ldub, SUFFIX)(ARG1, addr, @@ -139,9 +138,7 @@ static inline void glue(stq_be_phys, SUFFIX)(ARG1_DECL, hwaddr addr, uint64_t va glue(address_space_stq_be, SUFFIX)(ARG1, addr, val, MEMTXATTRS_UNSPECIFIED, NULL); } -#endif #undef ARG1_DECL #undef ARG1 #undef SUFFIX -#undef TARGET_ENDIANNESS From 82b75e943bdeb04c414767f8beff31d63dc5f2d3 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:04 -0700 Subject: [PATCH 0084/2760] exec/memory.h: make devend_memop "target defines" agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Will allow to make system/memory.c common later. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-6-pierrick.bouvier@linaro.org> --- include/exec/memory.h | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index cc5915033c..577f473446 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -3138,25 +3138,17 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, MemTxResult address_space_set(AddressSpace *as, hwaddr addr, uint8_t c, hwaddr len, MemTxAttrs attrs); -#ifdef COMPILING_PER_TARGET /* enum device_endian to MemOp. */ static inline MemOp devend_memop(enum device_endian end) { QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); -#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN - /* Swap if non-host endianness or native (target) endianness */ - return (end == DEVICE_HOST_ENDIAN) ? 0 : MO_BSWAP; -#else - const int non_host_endianness = - DEVICE_LITTLE_ENDIAN ^ DEVICE_BIG_ENDIAN ^ DEVICE_HOST_ENDIAN; - - /* In this case, native (target) endianness needs no swap. */ - return (end == non_host_endianness) ? MO_BSWAP : 0; -#endif + bool big_endian = (end == DEVICE_NATIVE_ENDIAN + ? target_words_bigendian() + : end == DEVICE_BIG_ENDIAN); + return big_endian ? MO_BE : MO_LE; } -#endif /* COMPILING_PER_TARGET */ /* * Inhibit technologies that require discarding of pages in RAM blocks, e.g., From 2ec0dc245f1e0505a75eb8fdd69acf857999d735 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:05 -0700 Subject: [PATCH 0085/2760] codebase: prepare to remove cpu.h from exec/exec-all.h Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-7-pierrick.bouvier@linaro.org> --- hw/ppc/spapr_nested.c | 1 + hw/sh4/sh7750.c | 1 + include/tcg/tcg-op.h | 1 + page-vary-target.c | 2 +- target/ppc/helper_regs.h | 2 ++ target/ppc/tcg-excp_helper.c | 1 + target/riscv/bitmanip_helper.c | 2 +- 7 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c index 201f629203..a79e398c13 100644 --- a/hw/ppc/spapr_nested.c +++ b/hw/ppc/spapr_nested.c @@ -2,6 +2,7 @@ #include "qemu/cutils.h" #include "exec/exec-all.h" #include "exec/cputlb.h" +#include "exec/target_long.h" #include "helper_regs.h" #include "hw/ppc/ppc.h" #include "hw/ppc/spapr.h" diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index 6faf0e3ca8..41306fb600 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -29,6 +29,7 @@ #include "hw/irq.h" #include "hw/sh4/sh.h" #include "system/system.h" +#include "target/sh4/cpu.h" #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "sh7750_regs.h" diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index a02850583b..bc46b5570c 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -9,6 +9,7 @@ #define TCG_TCG_OP_H #include "tcg/tcg-op-common.h" +#include "exec/target_long.h" #ifndef TARGET_LONG_BITS #error must include QEMU headers diff --git a/page-vary-target.c b/page-vary-target.c index 3f81144cda..84ddeb7c26 100644 --- a/page-vary-target.c +++ b/page-vary-target.c @@ -21,7 +21,7 @@ #include "qemu/osdep.h" #include "exec/page-vary.h" -#include "exec/exec-all.h" +#include "exec/target_page.h" bool set_preferred_target_page_bits(int bits) { diff --git a/target/ppc/helper_regs.h b/target/ppc/helper_regs.h index 8196c1346d..b928c2c452 100644 --- a/target/ppc/helper_regs.h +++ b/target/ppc/helper_regs.h @@ -20,6 +20,8 @@ #ifndef HELPER_REGS_H #define HELPER_REGS_H +#include "target/ppc/cpu.h" + void hreg_swap_gpr_tgpr(CPUPPCState *env); void hreg_compute_hflags(CPUPPCState *env); void hreg_update_pmu_hflags(CPUPPCState *env); diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c index 5a189dc3d7..c422648cfd 100644 --- a/target/ppc/tcg-excp_helper.c +++ b/target/ppc/tcg-excp_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "qemu/log.h" +#include "target/ppc/cpu.h" #include "exec/cpu_ldst.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/riscv/bitmanip_helper.c b/target/riscv/bitmanip_helper.c index b99c4a39a1..e9c8d7f778 100644 --- a/target/riscv/bitmanip_helper.c +++ b/target/riscv/bitmanip_helper.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" +#include "exec/target_long.h" #include "exec/helper-proto.h" #include "tcg/tcg.h" From eab9254fecb57666cd6e550b57d6e56321bc9ba7 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:06 -0700 Subject: [PATCH 0086/2760] exec/exec-all: remove dependency on cpu.h Previous commit changed files relying transitively on it. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-8-pierrick.bouvier@linaro.org> --- include/exec/exec-all.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index dd5c40f223..19b0eda44a 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -20,7 +20,6 @@ #ifndef EXEC_ALL_H #define EXEC_ALL_H -#include "cpu.h" #if defined(CONFIG_USER_ONLY) #include "exec/cpu_ldst.h" #endif From 9ed7bcff051217d4cdeefc97ef3f4b41ab2fbfbe Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:07 -0700 Subject: [PATCH 0087/2760] exec/memory-internal: remove dependency on cpu.h Needed so compilation units including it can be common. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-9-pierrick.bouvier@linaro.org> --- include/exec/memory-internal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index 100c1237ac..b729f3b25a 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -20,8 +20,6 @@ #ifndef MEMORY_INTERNAL_H #define MEMORY_INTERNAL_H -#include "cpu.h" - #ifndef CONFIG_USER_ONLY static inline AddressSpaceDispatch *flatview_to_dispatch(FlatView *fv) { From ede39130af7d325e8dbc6b533a86cb384fdee65d Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:08 -0700 Subject: [PATCH 0088/2760] exec/ram_addr: remove dependency on cpu.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed so compilation units including it can be common. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-10-pierrick.bouvier@linaro.org> --- include/exec/ram_addr.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index e4c28fbec9..f5d574261a 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -20,13 +20,14 @@ #define RAM_ADDR_H #ifndef CONFIG_USER_ONLY -#include "cpu.h" #include "system/xen.h" #include "system/tcg.h" #include "exec/cputlb.h" #include "exec/ramlist.h" #include "exec/ramblock.h" #include "exec/exec-all.h" +#include "exec/memory.h" +#include "exec/target_page.h" #include "qemu/rcu.h" #include "exec/hwaddr.h" From d21be2b61976c57ede5db6e8aa96e57e5e27bf16 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:09 -0700 Subject: [PATCH 0089/2760] system/kvm: make kvm_flush_coalesced_mmio_buffer() accessible for common code This function is used by system/physmem.c will be turn into common code in next commit. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-11-pierrick.bouvier@linaro.org> --- include/system/kvm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/system/kvm.h b/include/system/kvm.h index ab17c09a55..21da3b8b05 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -210,11 +210,11 @@ bool kvm_arm_supports_user_irq(void); int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_on_sigbus(int code, void *addr); +void kvm_flush_coalesced_mmio_buffer(void); + #ifdef COMPILING_PER_TARGET #include "cpu.h" -void kvm_flush_coalesced_mmio_buffer(void); - /** * kvm_update_guest_debug(): ensure KVM debug structures updated * @cs: the CPUState for this cpu From dea4acbdef980d92cbee60df16e8209946bf026f Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:10 -0700 Subject: [PATCH 0090/2760] exec/ram_addr: call xen_hvm_modified_memory only if xen is enabled Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-12-pierrick.bouvier@linaro.org> --- include/exec/ram_addr.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index f5d574261a..92e8708af7 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -339,7 +339,9 @@ static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start, } } - xen_hvm_modified_memory(start, length); + if (xen_enabled()) { + xen_hvm_modified_memory(start, length); + } } #if !defined(_WIN32) @@ -415,7 +417,9 @@ uint64_t cpu_physical_memory_set_dirty_lebitmap(unsigned long *bitmap, } } - xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS); + if (xen_enabled()) { + xen_hvm_modified_memory(start, pages << TARGET_PAGE_BITS); + } } else { uint8_t clients = tcg_enabled() ? DIRTY_CLIENTS_ALL : DIRTY_CLIENTS_NOCODE; From 105d7ea0a574a7db79cd378fe563e0ce51e38dda Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:11 -0700 Subject: [PATCH 0091/2760] hw/xen: add stubs for various functions Those symbols are used by system/physmem.c, and are called only if xen_enabled() (which happens only if CONFIG_XEN is set and xen is available). So we can crash the stubs in case those are called, as they are linked only when CONFIG_XEN is not set. Acked-by: Richard Henderson Reviewed-by: Anthony PERARD Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-13-pierrick.bouvier@linaro.org> --- hw/xen/meson.build | 3 +++ hw/xen/xen_stubs.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 hw/xen/xen_stubs.c diff --git a/hw/xen/meson.build b/hw/xen/meson.build index 4a486e3673..a1850e7698 100644 --- a/hw/xen/meson.build +++ b/hw/xen/meson.build @@ -9,6 +9,9 @@ system_ss.add(when: ['CONFIG_XEN_BUS'], if_true: files( system_ss.add(when: ['CONFIG_XEN', xen], if_true: files( 'xen-operations.c', +), +if_false: files( + 'xen_stubs.c', )) xen_specific_ss = ss.source_set() diff --git a/hw/xen/xen_stubs.c b/hw/xen/xen_stubs.c new file mode 100644 index 0000000000..5e565df392 --- /dev/null +++ b/hw/xen/xen_stubs.c @@ -0,0 +1,51 @@ +/* + * Various stubs for xen functions + * + * Those functions are used only if xen_enabled(). This file is linked only if + * CONFIG_XEN is not set, so they should never be called. + * + * Copyright (c) 2025 Linaro, Ltd. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "system/xen.h" +#include "system/xen-mapcache.h" + +void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) +{ + g_assert_not_reached(); +} + +void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, + struct MemoryRegion *mr, Error **errp) +{ + g_assert_not_reached(); +} + +bool xen_mr_is_memory(MemoryRegion *mr) +{ + g_assert_not_reached(); +} + +void xen_invalidate_map_cache_entry(uint8_t *buffer) +{ + g_assert_not_reached(); +} + +ram_addr_t xen_ram_addr_from_mapcache(void *ptr) +{ + g_assert_not_reached(); +} + +uint8_t *xen_map_cache(MemoryRegion *mr, + hwaddr phys_addr, + hwaddr size, + ram_addr_t ram_addr_offset, + uint8_t lock, + bool dma, + bool is_write) +{ + g_assert_not_reached(); +} From d3ab5b56630ba8e68af62aabb5a829e5f55b4dd7 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:12 -0700 Subject: [PATCH 0092/2760] system/xen: remove inline stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-14-pierrick.bouvier@linaro.org> --- include/system/xen-mapcache.h | 41 ----------------------------------- include/system/xen.h | 21 +++--------------- 2 files changed, 3 insertions(+), 59 deletions(-) diff --git a/include/system/xen-mapcache.h b/include/system/xen-mapcache.h index b68f196ddd..bb454a7c96 100644 --- a/include/system/xen-mapcache.h +++ b/include/system/xen-mapcache.h @@ -14,8 +14,6 @@ typedef hwaddr (*phys_offset_to_gaddr_t)(hwaddr phys_offset, ram_addr_t size); -#ifdef CONFIG_XEN_IS_POSSIBLE - void xen_map_cache_init(phys_offset_to_gaddr_t f, void *opaque); uint8_t *xen_map_cache(MemoryRegion *mr, hwaddr phys_addr, hwaddr size, @@ -28,44 +26,5 @@ void xen_invalidate_map_cache(void); uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr, hwaddr new_phys_addr, hwaddr size); -#else - -static inline void xen_map_cache_init(phys_offset_to_gaddr_t f, - void *opaque) -{ -} - -static inline uint8_t *xen_map_cache(MemoryRegion *mr, - hwaddr phys_addr, - hwaddr size, - ram_addr_t ram_addr_offset, - uint8_t lock, - bool dma, - bool is_write) -{ - abort(); -} - -static inline ram_addr_t xen_ram_addr_from_mapcache(void *ptr) -{ - abort(); -} - -static inline void xen_invalidate_map_cache_entry(uint8_t *buffer) -{ -} - -static inline void xen_invalidate_map_cache(void) -{ -} - -static inline uint8_t *xen_replace_cache_entry(hwaddr old_phys_addr, - hwaddr new_phys_addr, - hwaddr size) -{ - abort(); -} - -#endif #endif /* XEN_MAPCACHE_H */ diff --git a/include/system/xen.h b/include/system/xen.h index 990c19a8ef..5f41915732 100644 --- a/include/system/xen.h +++ b/include/system/xen.h @@ -25,30 +25,15 @@ #endif /* COMPILING_PER_TARGET */ #ifdef CONFIG_XEN_IS_POSSIBLE - extern bool xen_allowed; - #define xen_enabled() (xen_allowed) +#else /* !CONFIG_XEN_IS_POSSIBLE */ +#define xen_enabled() 0 +#endif /* CONFIG_XEN_IS_POSSIBLE */ void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length); void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, struct MemoryRegion *mr, Error **errp); - -#else /* !CONFIG_XEN_IS_POSSIBLE */ - -#define xen_enabled() 0 -static inline void xen_hvm_modified_memory(ram_addr_t start, ram_addr_t length) -{ - /* nothing */ -} -static inline void xen_ram_alloc(ram_addr_t ram_addr, ram_addr_t size, - MemoryRegion *mr, Error **errp) -{ - g_assert_not_reached(); -} - -#endif /* CONFIG_XEN_IS_POSSIBLE */ - bool xen_mr_is_memory(MemoryRegion *mr); bool xen_mr_is_grants(MemoryRegion *mr); #endif From 822baa8242a38b0b5dfcd05a859f2f50ea229539 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:13 -0700 Subject: [PATCH 0093/2760] system/physmem: compilation unit is now common to all targets Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-15-pierrick.bouvier@linaro.org> --- system/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/meson.build b/system/meson.build index eec07a9451..bd82ef132e 100644 --- a/system/meson.build +++ b/system/meson.build @@ -3,7 +3,6 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( 'ioport.c', 'globals-target.c', 'memory.c', - 'physmem.c', )]) system_ss.add(files( @@ -16,6 +15,7 @@ system_ss.add(files( 'dma-helpers.c', 'globals.c', 'memory_mapping.c', + 'physmem.c', 'qdev-monitor.c', 'qtest.c', 'rtc.c', From 5519a52c0c269926572300cf2cd7f2f77ab28f87 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:14 -0700 Subject: [PATCH 0094/2760] include/exec/memory: extract devend_big_endian from devend_memop we'll use it in system/memory.c. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-16-pierrick.bouvier@linaro.org> --- include/exec/memory.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/include/exec/memory.h b/include/exec/memory.h index 577f473446..fc07f69916 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -3138,16 +3138,22 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, MemTxResult address_space_set(AddressSpace *as, hwaddr addr, uint8_t c, hwaddr len, MemTxAttrs attrs); -/* enum device_endian to MemOp. */ -static inline MemOp devend_memop(enum device_endian end) +/* returns true if end is big endian. */ +static inline bool devend_big_endian(enum device_endian end) { QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); - bool big_endian = (end == DEVICE_NATIVE_ENDIAN - ? target_words_bigendian() - : end == DEVICE_BIG_ENDIAN); - return big_endian ? MO_BE : MO_LE; + if (end == DEVICE_NATIVE_ENDIAN) { + return target_words_bigendian(); + } + return end == DEVICE_BIG_ENDIAN; +} + +/* enum device_endian to MemOp. */ +static inline MemOp devend_memop(enum device_endian end) +{ + return devend_big_endian(end) ? MO_BE : MO_LE; } /* From a54240931ca6a7968123622f3134eba1e2cccb8a Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:15 -0700 Subject: [PATCH 0095/2760] include/exec/memory: move devend functions to memory-internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only system/physmem.c and system/memory.c use those functions, so we can move then to internal header. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-17-pierrick.bouvier@linaro.org> --- include/exec/memory-internal.h | 19 +++++++++++++++++++ include/exec/memory.h | 18 ------------------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/include/exec/memory-internal.h b/include/exec/memory-internal.h index b729f3b25a..c75178a3d6 100644 --- a/include/exec/memory-internal.h +++ b/include/exec/memory-internal.h @@ -43,5 +43,24 @@ void address_space_dispatch_free(AddressSpaceDispatch *d); void mtree_print_dispatch(struct AddressSpaceDispatch *d, MemoryRegion *root); + +/* returns true if end is big endian. */ +static inline bool devend_big_endian(enum device_endian end) +{ + QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && + DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); + + if (end == DEVICE_NATIVE_ENDIAN) { + return target_words_bigendian(); + } + return end == DEVICE_BIG_ENDIAN; +} + +/* enum device_endian to MemOp. */ +static inline MemOp devend_memop(enum device_endian end) +{ + return devend_big_endian(end) ? MO_BE : MO_LE; +} + #endif #endif diff --git a/include/exec/memory.h b/include/exec/memory.h index fc07f69916..2f84a7cfed 100644 --- a/include/exec/memory.h +++ b/include/exec/memory.h @@ -3138,24 +3138,6 @@ address_space_write_cached(MemoryRegionCache *cache, hwaddr addr, MemTxResult address_space_set(AddressSpace *as, hwaddr addr, uint8_t c, hwaddr len, MemTxAttrs attrs); -/* returns true if end is big endian. */ -static inline bool devend_big_endian(enum device_endian end) -{ - QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && - DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); - - if (end == DEVICE_NATIVE_ENDIAN) { - return target_words_bigendian(); - } - return end == DEVICE_BIG_ENDIAN; -} - -/* enum device_endian to MemOp. */ -static inline MemOp devend_memop(enum device_endian end) -{ - return devend_big_endian(end) ? MO_BE : MO_LE; -} - /* * Inhibit technologies that require discarding of pages in RAM blocks, e.g., * to manage the actual amount of memory consumed by the VM (then, the memory From 94f5cd62b81d9f6785ebfb9acd41ae253ff32865 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:16 -0700 Subject: [PATCH 0096/2760] system/memory: make compilation unit common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-18-pierrick.bouvier@linaro.org> --- system/memory.c | 17 +++++------------ system/meson.build | 2 +- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/system/memory.c b/system/memory.c index 4c829793a0..eddd21a6cd 100644 --- a/system/memory.c +++ b/system/memory.c @@ -353,15 +353,6 @@ static void flatview_simplify(FlatView *view) } } -static bool memory_region_big_endian(MemoryRegion *mr) -{ -#if TARGET_BIG_ENDIAN - return mr->ops->endianness != DEVICE_LITTLE_ENDIAN; -#else - return mr->ops->endianness == DEVICE_BIG_ENDIAN; -#endif -} - static void adjust_endianness(MemoryRegion *mr, uint64_t *data, MemOp op) { if ((op & MO_BSWAP) != devend_memop(mr->ops->endianness)) { @@ -563,7 +554,7 @@ static MemTxResult access_with_adjusted_size(hwaddr addr, /* FIXME: support unaligned access? */ access_size = MAX(MIN(size, access_size_max), access_size_min); access_mask = MAKE_64BIT_MASK(0, access_size * 8); - if (memory_region_big_endian(mr)) { + if (devend_big_endian(mr->ops->endianness)) { for (i = 0; i < size; i += access_size) { r |= access_fn(mr, addr + i, value, access_size, (size - access_size - i) * 8, access_mask, attrs); @@ -2584,7 +2575,8 @@ void memory_region_add_eventfd(MemoryRegion *mr, unsigned i; if (size) { - adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); + MemOp mop = (target_words_bigendian() ? MO_BE : MO_LE) | size_memop(size); + adjust_endianness(mr, &mrfd.data, mop); } memory_region_transaction_begin(); for (i = 0; i < mr->ioeventfd_nb; ++i) { @@ -2619,7 +2611,8 @@ void memory_region_del_eventfd(MemoryRegion *mr, unsigned i; if (size) { - adjust_endianness(mr, &mrfd.data, size_memop(size) | MO_TE); + MemOp mop = (target_words_bigendian() ? MO_BE : MO_LE) | size_memop(size); + adjust_endianness(mr, &mrfd.data, mop); } memory_region_transaction_begin(); for (i = 0; i < mr->ioeventfd_nb; ++i) { diff --git a/system/meson.build b/system/meson.build index bd82ef132e..4f44b78df3 100644 --- a/system/meson.build +++ b/system/meson.build @@ -2,7 +2,6 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( 'arch_init.c', 'ioport.c', 'globals-target.c', - 'memory.c', )]) system_ss.add(files( @@ -15,6 +14,7 @@ system_ss.add(files( 'dma-helpers.c', 'globals.c', 'memory_mapping.c', + 'memory.c', 'physmem.c', 'qdev-monitor.c', 'qtest.c', From 0ac7e071c5d5ada2fc12626e267851fd1c10974a Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 17 Mar 2025 11:34:17 -0700 Subject: [PATCH 0097/2760] system/ioport: make compilation unit common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250317183417.285700-19-pierrick.bouvier@linaro.org> --- system/ioport.c | 1 - system/meson.build | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/system/ioport.c b/system/ioport.c index 55c2a75239..89daae9d60 100644 --- a/system/ioport.c +++ b/system/ioport.c @@ -26,7 +26,6 @@ */ #include "qemu/osdep.h" -#include "cpu.h" #include "exec/ioport.h" #include "exec/memory.h" #include "exec/address-spaces.h" diff --git a/system/meson.build b/system/meson.build index 4f44b78df3..063301c3ad 100644 --- a/system/meson.build +++ b/system/meson.build @@ -1,6 +1,5 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( 'arch_init.c', - 'ioport.c', 'globals-target.c', )]) @@ -13,6 +12,7 @@ system_ss.add(files( 'dirtylimit.c', 'dma-helpers.c', 'globals.c', + 'ioport.c', 'memory_mapping.c', 'memory.c', 'physmem.c', From c4b45298a9b87dc8195aeb3f6439629be9881a17 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Mar 2025 12:57:24 -0700 Subject: [PATCH 0098/2760] accel/tcg: Build user-exec-stub.c once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_USER_ONLY == !CONFIG_SYSTEM_ONLY. Therefore it's cleaner to just add to user_ss. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 38ff227eb0..14bf797fda 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -12,7 +12,6 @@ tcg_specific_ss.add(files( 'translator.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) -tcg_specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_false: files('user-exec-stub.c')) if get_option('plugins') tcg_specific_ss.add(files('plugin-gen.c')) endif @@ -22,6 +21,10 @@ specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( 'cputlb.c', )) +user_ss.add(when: ['CONFIG_TCG'], if_true: files( + 'user-exec-stub.c', +)) + system_ss.add(when: ['CONFIG_TCG'], if_true: files( 'icount-common.c', 'monitor.c', From e9358339c5dc7aab0b48d35b57371efae1737046 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 10 Mar 2025 13:15:22 -0700 Subject: [PATCH 0099/2760] accel/tcg: Build plugin-gen.c once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We assert that env immediately follows CPUState in cpu-all.h. Change the offsetof expressions to be based on CPUState instead of ArchCPU. Reviewed-by: Alex Bennée Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 7 ++++--- accel/tcg/plugin-gen.c | 13 +++++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 14bf797fda..185830d0f5 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -3,6 +3,10 @@ common_ss.add(when: 'CONFIG_TCG', if_true: files( 'tcg-runtime.c', 'tcg-runtime-gvec.c', )) +if get_option('plugins') + common_ss.add(when: 'CONFIG_TCG', if_true: files('plugin-gen.c')) +endif + tcg_specific_ss = ss.source_set() tcg_specific_ss.add(files( 'tcg-all.c', @@ -12,9 +16,6 @@ tcg_specific_ss.add(files( 'translator.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) -if get_option('plugins') - tcg_specific_ss.add(files('plugin-gen.c')) -endif specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( diff --git a/accel/tcg/plugin-gen.c b/accel/tcg/plugin-gen.c index 7e5f040bf7..c1da753894 100644 --- a/accel/tcg/plugin-gen.c +++ b/accel/tcg/plugin-gen.c @@ -22,13 +22,12 @@ #include "qemu/osdep.h" #include "qemu/plugin.h" #include "qemu/log.h" -#include "cpu.h" #include "tcg/tcg.h" #include "tcg/tcg-temp-internal.h" -#include "tcg/tcg-op.h" -#include "exec/exec-all.h" +#include "tcg/tcg-op-common.h" #include "exec/plugin-gen.h" #include "exec/translator.h" +#include "exec/translation-block.h" enum plugin_gen_from { PLUGIN_GEN_FROM_TB, @@ -89,15 +88,13 @@ static void gen_enable_mem_helper(struct qemu_plugin_tb *ptb, qemu_plugin_add_dyn_cb_arr(arr); tcg_gen_st_ptr(tcg_constant_ptr((intptr_t)arr), tcg_env, - offsetof(CPUState, neg.plugin_mem_cbs) - - offsetof(ArchCPU, env)); + offsetof(CPUState, neg.plugin_mem_cbs) - sizeof(CPUState)); } static void gen_disable_mem_helper(void) { tcg_gen_st_ptr(tcg_constant_ptr(0), tcg_env, - offsetof(CPUState, neg.plugin_mem_cbs) - - offsetof(ArchCPU, env)); + offsetof(CPUState, neg.plugin_mem_cbs) - sizeof(CPUState)); } static TCGv_i32 gen_cpu_index(void) @@ -113,7 +110,7 @@ static TCGv_i32 gen_cpu_index(void) } TCGv_i32 cpu_index = tcg_temp_ebb_new_i32(); tcg_gen_ld_i32(cpu_index, tcg_env, - -offsetof(ArchCPU, env) + offsetof(CPUState, cpu_index)); + offsetof(CPUState, cpu_index) - sizeof(CPUState)); return cpu_index; } From 66269bb96999395906e0e38ca7e59f92ab371933 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Mar 2025 18:20:00 -0700 Subject: [PATCH 0100/2760] accel/tcg: Fix cpu_ld*_code_mmu for user mode These routines are buggy in multiple ways: - Use of target-endian loads, then a bswap that depends on the host endiannness. - A non-unwinding code load must set_helper_retaddr 1, which is magic within adjust_signal_pc. - cpu_ldq_code_mmu used MMU_DATA_LOAD The bugs are hidden because all current uses of cpu_ld*_code_mmu are from system mode. Fixes: 2899062614a ("accel/tcg: Add cpu_ld*_code_mmu") Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 41 ++++------------------------------------- 1 file changed, 4 insertions(+), 37 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 2322181b15..629a1c9ce6 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1257,58 +1257,25 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - void *haddr; - uint8_t ret; - - haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); - ret = ldub_p(haddr); - clear_helper_retaddr(); - return ret; + return do_ld1_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - void *haddr; - uint16_t ret; - - haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); - ret = lduw_p(haddr); - clear_helper_retaddr(); - if (get_memop(oi) & MO_BSWAP) { - ret = bswap16(ret); - } - return ret; + return do_ld2_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - void *haddr; - uint32_t ret; - - haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_INST_FETCH); - ret = ldl_p(haddr); - clear_helper_retaddr(); - if (get_memop(oi) & MO_BSWAP) { - ret = bswap32(ret); - } - return ret; + return do_ld4_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) { - void *haddr; - uint64_t ret; - - haddr = cpu_mmu_lookup(env_cpu(env), addr, oi, ra, MMU_DATA_LOAD); - ret = ldq_p(haddr); - clear_helper_retaddr(); - if (get_memop(oi) & MO_BSWAP) { - ret = bswap64(ret); - } - return ret; + return do_ld8_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } #include "ldst_common.c.inc" From 446321b3234a67ef4576847596ca2859f3b2f89a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 12:52:36 -0700 Subject: [PATCH 0101/2760] include/exec: Use vaddr for *_mmu guest memory access routines Use vaddr only for the newest api, because it has the least number of uses and therefore is the easiest to audit. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/atomic_template.h | 16 ++++++------- accel/tcg/cputlb.c | 8 +++---- accel/tcg/ldst_common.c.inc | 20 ++++++++-------- accel/tcg/user-exec.c | 8 +++---- include/exec/cpu_ldst.h | 48 ++++++++++++++++++------------------- 5 files changed, 50 insertions(+), 50 deletions(-) diff --git a/accel/tcg/atomic_template.h b/accel/tcg/atomic_template.h index 89593b2502..08a475c10c 100644 --- a/accel/tcg/atomic_template.h +++ b/accel/tcg/atomic_template.h @@ -77,7 +77,7 @@ # define END _le #endif -ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, vaddr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { @@ -101,7 +101,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, } #if DATA_SIZE < 16 -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, vaddr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, @@ -120,7 +120,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, } #define GEN_ATOMIC_HELPER(X) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, vaddr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ @@ -156,7 +156,7 @@ GEN_ATOMIC_HELPER(xor_fetch) * of CF_PARALLEL's value, we'll trace just a read and a write. */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, vaddr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, cmp, old, new, val = xval; \ @@ -202,7 +202,7 @@ GEN_ATOMIC_HELPER_FN(umax_fetch, MAX, DATA_TYPE, new) # define END _be #endif -ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, +ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, vaddr addr, ABI_TYPE cmpv, ABI_TYPE newv, MemOpIdx oi, uintptr_t retaddr) { @@ -226,7 +226,7 @@ ABI_TYPE ATOMIC_NAME(cmpxchg)(CPUArchState *env, abi_ptr addr, } #if DATA_SIZE < 16 -ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, +ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, vaddr addr, ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) { DATA_TYPE *haddr = atomic_mmu_lookup(env_cpu(env), addr, oi, @@ -245,7 +245,7 @@ ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, abi_ptr addr, ABI_TYPE val, } #define GEN_ATOMIC_HELPER(X) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, vaddr addr, \ ABI_TYPE val, MemOpIdx oi, uintptr_t retaddr) \ { \ DATA_TYPE *haddr, ret; \ @@ -278,7 +278,7 @@ GEN_ATOMIC_HELPER(xor_fetch) * of CF_PARALLEL's value, we'll trace just a read and a write. */ #define GEN_ATOMIC_HELPER_FN(X, FN, XDATA_TYPE, RET) \ -ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, abi_ptr addr, \ +ABI_TYPE ATOMIC_NAME(X)(CPUArchState *env, vaddr addr, \ ABI_TYPE xval, MemOpIdx oi, uintptr_t retaddr) \ { \ XDATA_TYPE *haddr, ldo, ldn, old, new, val = xval; \ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index fb22048876..b03998f926 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2925,25 +2925,25 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) return do_ld8_mmu(cs, addr, oi, 0, MMU_INST_FETCH); } -uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, +uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t retaddr) { return do_ld1_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } -uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, +uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t retaddr) { return do_ld2_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } -uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t retaddr) { return do_ld4_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } -uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t retaddr) { return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index ebbf380d76..0447c0bb92 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -135,7 +135,7 @@ static void plugin_load_cb(CPUArchState *env, abi_ptr addr, } } -uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) +uint8_t cpu_ldb_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { uint8_t ret; @@ -145,7 +145,7 @@ uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra) return ret; } -uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, +uint16_t cpu_ldw_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { uint16_t ret; @@ -156,7 +156,7 @@ uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr addr, return ret; } -uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_ldl_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { uint32_t ret; @@ -167,7 +167,7 @@ uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr addr, return ret; } -uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_ldq_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { uint64_t ret; @@ -178,7 +178,7 @@ uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr addr, return ret; } -Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, +Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { Int128 ret; @@ -205,14 +205,14 @@ static void plugin_store_cb(CPUArchState *env, abi_ptr addr, } } -void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, +void cpu_stb_mmu(CPUArchState *env, vaddr addr, uint8_t val, MemOpIdx oi, uintptr_t retaddr) { helper_stb_mmu(env, addr, val, oi, retaddr); plugin_store_cb(env, addr, val, 0, oi); } -void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, +void cpu_stw_mmu(CPUArchState *env, vaddr addr, uint16_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_16); @@ -220,7 +220,7 @@ void cpu_stw_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, plugin_store_cb(env, addr, val, 0, oi); } -void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, +void cpu_stl_mmu(CPUArchState *env, vaddr addr, uint32_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_32); @@ -228,7 +228,7 @@ void cpu_stl_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, plugin_store_cb(env, addr, val, 0, oi); } -void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, +void cpu_stq_mmu(CPUArchState *env, vaddr addr, uint64_t val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_64); @@ -236,7 +236,7 @@ void cpu_stq_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, plugin_store_cb(env, addr, val, 0, oi); } -void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, +void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t retaddr) { tcg_debug_assert((get_memop(oi) & MO_SIZE) == MO_128); diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 629a1c9ce6..dec17435c5 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1254,25 +1254,25 @@ uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) return ret; } -uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, +uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { return do_ld1_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } -uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, +uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { return do_ld2_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } -uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { return do_ld4_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); } -uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { return do_ld8_mmu(env_cpu(env), addr, oi, ra ? ra : 1, MMU_INST_FETCH); diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 769e9fc440..ddd8e0cf48 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -157,48 +157,48 @@ void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint64_t val, int mmu_idx, uintptr_t ra); -uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra); -uint16_t cpu_ldw_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra); -uint32_t cpu_ldl_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra); -uint64_t cpu_ldq_mmu(CPUArchState *env, abi_ptr ptr, MemOpIdx oi, uintptr_t ra); -Int128 cpu_ld16_mmu(CPUArchState *env, abi_ptr addr, MemOpIdx oi, uintptr_t ra); +uint8_t cpu_ldb_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint16_t cpu_ldw_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint32_t cpu_ldl_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint64_t cpu_ldq_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); -void cpu_stb_mmu(CPUArchState *env, abi_ptr ptr, uint8_t val, +void cpu_stb_mmu(CPUArchState *env, vaddr ptr, uint8_t val, MemOpIdx oi, uintptr_t ra); -void cpu_stw_mmu(CPUArchState *env, abi_ptr ptr, uint16_t val, +void cpu_stw_mmu(CPUArchState *env, vaddr ptr, uint16_t val, MemOpIdx oi, uintptr_t ra); -void cpu_stl_mmu(CPUArchState *env, abi_ptr ptr, uint32_t val, +void cpu_stl_mmu(CPUArchState *env, vaddr ptr, uint32_t val, MemOpIdx oi, uintptr_t ra); -void cpu_stq_mmu(CPUArchState *env, abi_ptr ptr, uint64_t val, +void cpu_stq_mmu(CPUArchState *env, vaddr ptr, uint64_t val, MemOpIdx oi, uintptr_t ra); -void cpu_st16_mmu(CPUArchState *env, abi_ptr addr, Int128 val, +void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, MemOpIdx oi, uintptr_t ra); -uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, vaddr addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, vaddr addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, vaddr addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); -uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, vaddr addr, uint64_t cmpv, uint64_t newv, MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, vaddr addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, vaddr addr, uint32_t cmpv, uint32_t newv, MemOpIdx oi, uintptr_t retaddr); -uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, vaddr addr, uint64_t cmpv, uint64_t newv, MemOpIdx oi, uintptr_t retaddr); #define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \ TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \ - (CPUArchState *env, abi_ptr addr, TYPE val, \ + (CPUArchState *env, vaddr addr, TYPE val, \ MemOpIdx oi, uintptr_t retaddr); #ifdef CONFIG_ATOMIC64 @@ -244,10 +244,10 @@ GEN_ATOMIC_HELPER_ALL(xchg) #undef GEN_ATOMIC_HELPER_ALL #undef GEN_ATOMIC_HELPER -Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, abi_ptr addr, +Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, vaddr addr, Int128 cmpv, Int128 newv, MemOpIdx oi, uintptr_t retaddr); -Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, abi_ptr addr, +Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, vaddr addr, Int128 cmpv, Int128 newv, MemOpIdx oi, uintptr_t retaddr); @@ -297,13 +297,13 @@ Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, abi_ptr addr, # define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra #endif -uint8_t cpu_ldb_code_mmu(CPUArchState *env, abi_ptr addr, +uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); -uint16_t cpu_ldw_code_mmu(CPUArchState *env, abi_ptr addr, +uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); -uint32_t cpu_ldl_code_mmu(CPUArchState *env, abi_ptr addr, +uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); -uint64_t cpu_ldq_code_mmu(CPUArchState *env, abi_ptr addr, +uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr); From 0b6426ba6c218fa807fe97258d75cb4bc84c860d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 13:03:37 -0700 Subject: [PATCH 0102/2760] include/exec: Split out cpu-ldst-common.h Split out the *_mmu api, which no longer uses target specific argument types. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/cpu-ldst-common.h | 122 +++++++++++++++++++++++++++++++++ include/exec/cpu_ldst.h | 108 +---------------------------- 2 files changed, 123 insertions(+), 107 deletions(-) create mode 100644 include/exec/cpu-ldst-common.h diff --git a/include/exec/cpu-ldst-common.h b/include/exec/cpu-ldst-common.h new file mode 100644 index 0000000000..c46a6ade5d --- /dev/null +++ b/include/exec/cpu-ldst-common.h @@ -0,0 +1,122 @@ +/* + * Software MMU support + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef CPU_LDST_COMMON_H +#define CPU_LDST_COMMON_H + +#ifndef CONFIG_TCG +#error Can only include this header with TCG +#endif + +#include "exec/memopidx.h" +#include "exec/vaddr.h" +#include "exec/mmu-access-type.h" +#include "qemu/int128.h" + +uint8_t cpu_ldb_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint16_t cpu_ldw_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint32_t cpu_ldl_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +uint64_t cpu_ldq_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); +Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); + +void cpu_stb_mmu(CPUArchState *env, vaddr ptr, uint8_t val, + MemOpIdx oi, uintptr_t ra); +void cpu_stw_mmu(CPUArchState *env, vaddr ptr, uint16_t val, + MemOpIdx oi, uintptr_t ra); +void cpu_stl_mmu(CPUArchState *env, vaddr ptr, uint32_t val, + MemOpIdx oi, uintptr_t ra); +void cpu_stq_mmu(CPUArchState *env, vaddr ptr, uint64_t val, + MemOpIdx oi, uintptr_t ra); +void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, + MemOpIdx oi, uintptr_t ra); + +uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, vaddr addr, + uint32_t cmpv, uint32_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, vaddr addr, + uint32_t cmpv, uint32_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, vaddr addr, + uint32_t cmpv, uint32_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, vaddr addr, + uint64_t cmpv, uint64_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, vaddr addr, + uint32_t cmpv, uint32_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, vaddr addr, + uint32_t cmpv, uint32_t newv, + MemOpIdx oi, uintptr_t retaddr); +uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, vaddr addr, + uint64_t cmpv, uint64_t newv, + MemOpIdx oi, uintptr_t retaddr); + +#define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \ +TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \ + (CPUArchState *env, vaddr addr, TYPE val, \ + MemOpIdx oi, uintptr_t retaddr); + +#ifdef CONFIG_ATOMIC64 +#define GEN_ATOMIC_HELPER_ALL(NAME) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, b) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, w_le) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, w_be) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, l_le) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, l_be) \ + GEN_ATOMIC_HELPER(NAME, uint64_t, q_le) \ + GEN_ATOMIC_HELPER(NAME, uint64_t, q_be) +#else +#define GEN_ATOMIC_HELPER_ALL(NAME) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, b) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, w_le) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, w_be) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, l_le) \ + GEN_ATOMIC_HELPER(NAME, uint32_t, l_be) +#endif + +GEN_ATOMIC_HELPER_ALL(fetch_add) +GEN_ATOMIC_HELPER_ALL(fetch_sub) +GEN_ATOMIC_HELPER_ALL(fetch_and) +GEN_ATOMIC_HELPER_ALL(fetch_or) +GEN_ATOMIC_HELPER_ALL(fetch_xor) +GEN_ATOMIC_HELPER_ALL(fetch_smin) +GEN_ATOMIC_HELPER_ALL(fetch_umin) +GEN_ATOMIC_HELPER_ALL(fetch_smax) +GEN_ATOMIC_HELPER_ALL(fetch_umax) + +GEN_ATOMIC_HELPER_ALL(add_fetch) +GEN_ATOMIC_HELPER_ALL(sub_fetch) +GEN_ATOMIC_HELPER_ALL(and_fetch) +GEN_ATOMIC_HELPER_ALL(or_fetch) +GEN_ATOMIC_HELPER_ALL(xor_fetch) +GEN_ATOMIC_HELPER_ALL(smin_fetch) +GEN_ATOMIC_HELPER_ALL(umin_fetch) +GEN_ATOMIC_HELPER_ALL(smax_fetch) +GEN_ATOMIC_HELPER_ALL(umax_fetch) + +GEN_ATOMIC_HELPER_ALL(xchg) + +#undef GEN_ATOMIC_HELPER_ALL +#undef GEN_ATOMIC_HELPER + +Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, vaddr addr, + Int128 cmpv, Int128 newv, + MemOpIdx oi, uintptr_t retaddr); +Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, vaddr addr, + Int128 cmpv, Int128 newv, + MemOpIdx oi, uintptr_t retaddr); + +uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, + MemOpIdx oi, uintptr_t ra); +uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr, + MemOpIdx oi, uintptr_t ra); +uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, + MemOpIdx oi, uintptr_t ra); +uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, + MemOpIdx oi, uintptr_t ra); + +#endif /* CPU_LDST_COMMON_H */ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index ddd8e0cf48..1fbdbe59ae 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -66,11 +66,8 @@ #error Can only include this header with TCG #endif -#include "exec/memopidx.h" -#include "exec/vaddr.h" +#include "exec/cpu-ldst-common.h" #include "exec/abi_ptr.h" -#include "exec/mmu-access-type.h" -#include "qemu/int128.h" #if defined(CONFIG_USER_ONLY) #include "user/guest-host.h" @@ -157,100 +154,6 @@ void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint64_t val, int mmu_idx, uintptr_t ra); -uint8_t cpu_ldb_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); -uint16_t cpu_ldw_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); -uint32_t cpu_ldl_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); -uint64_t cpu_ldq_mmu(CPUArchState *env, vaddr ptr, MemOpIdx oi, uintptr_t ra); -Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); - -void cpu_stb_mmu(CPUArchState *env, vaddr ptr, uint8_t val, - MemOpIdx oi, uintptr_t ra); -void cpu_stw_mmu(CPUArchState *env, vaddr ptr, uint16_t val, - MemOpIdx oi, uintptr_t ra); -void cpu_stl_mmu(CPUArchState *env, vaddr ptr, uint32_t val, - MemOpIdx oi, uintptr_t ra); -void cpu_stq_mmu(CPUArchState *env, vaddr ptr, uint64_t val, - MemOpIdx oi, uintptr_t ra); -void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, - MemOpIdx oi, uintptr_t ra); - -uint32_t cpu_atomic_cmpxchgb_mmu(CPUArchState *env, vaddr addr, - uint32_t cmpv, uint32_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgw_le_mmu(CPUArchState *env, vaddr addr, - uint32_t cmpv, uint32_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgl_le_mmu(CPUArchState *env, vaddr addr, - uint32_t cmpv, uint32_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint64_t cpu_atomic_cmpxchgq_le_mmu(CPUArchState *env, vaddr addr, - uint64_t cmpv, uint64_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgw_be_mmu(CPUArchState *env, vaddr addr, - uint32_t cmpv, uint32_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint32_t cpu_atomic_cmpxchgl_be_mmu(CPUArchState *env, vaddr addr, - uint32_t cmpv, uint32_t newv, - MemOpIdx oi, uintptr_t retaddr); -uint64_t cpu_atomic_cmpxchgq_be_mmu(CPUArchState *env, vaddr addr, - uint64_t cmpv, uint64_t newv, - MemOpIdx oi, uintptr_t retaddr); - -#define GEN_ATOMIC_HELPER(NAME, TYPE, SUFFIX) \ -TYPE cpu_atomic_ ## NAME ## SUFFIX ## _mmu \ - (CPUArchState *env, vaddr addr, TYPE val, \ - MemOpIdx oi, uintptr_t retaddr); - -#ifdef CONFIG_ATOMIC64 -#define GEN_ATOMIC_HELPER_ALL(NAME) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, b) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, w_le) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, w_be) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, l_le) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, l_be) \ - GEN_ATOMIC_HELPER(NAME, uint64_t, q_le) \ - GEN_ATOMIC_HELPER(NAME, uint64_t, q_be) -#else -#define GEN_ATOMIC_HELPER_ALL(NAME) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, b) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, w_le) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, w_be) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, l_le) \ - GEN_ATOMIC_HELPER(NAME, uint32_t, l_be) -#endif - -GEN_ATOMIC_HELPER_ALL(fetch_add) -GEN_ATOMIC_HELPER_ALL(fetch_sub) -GEN_ATOMIC_HELPER_ALL(fetch_and) -GEN_ATOMIC_HELPER_ALL(fetch_or) -GEN_ATOMIC_HELPER_ALL(fetch_xor) -GEN_ATOMIC_HELPER_ALL(fetch_smin) -GEN_ATOMIC_HELPER_ALL(fetch_umin) -GEN_ATOMIC_HELPER_ALL(fetch_smax) -GEN_ATOMIC_HELPER_ALL(fetch_umax) - -GEN_ATOMIC_HELPER_ALL(add_fetch) -GEN_ATOMIC_HELPER_ALL(sub_fetch) -GEN_ATOMIC_HELPER_ALL(and_fetch) -GEN_ATOMIC_HELPER_ALL(or_fetch) -GEN_ATOMIC_HELPER_ALL(xor_fetch) -GEN_ATOMIC_HELPER_ALL(smin_fetch) -GEN_ATOMIC_HELPER_ALL(umin_fetch) -GEN_ATOMIC_HELPER_ALL(smax_fetch) -GEN_ATOMIC_HELPER_ALL(umax_fetch) - -GEN_ATOMIC_HELPER_ALL(xchg) - -#undef GEN_ATOMIC_HELPER_ALL -#undef GEN_ATOMIC_HELPER - -Int128 cpu_atomic_cmpxchgo_le_mmu(CPUArchState *env, vaddr addr, - Int128 cmpv, Int128 newv, - MemOpIdx oi, uintptr_t retaddr); -Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, vaddr addr, - Int128 cmpv, Int128 newv, - MemOpIdx oi, uintptr_t retaddr); - #if TARGET_BIG_ENDIAN # define cpu_lduw_data cpu_lduw_be_data # define cpu_ldsw_data cpu_ldsw_be_data @@ -297,15 +200,6 @@ Int128 cpu_atomic_cmpxchgo_be_mmu(CPUArchState *env, vaddr addr, # define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra #endif -uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, - MemOpIdx oi, uintptr_t ra); -uint16_t cpu_ldw_code_mmu(CPUArchState *env, vaddr addr, - MemOpIdx oi, uintptr_t ra); -uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, - MemOpIdx oi, uintptr_t ra); -uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, - MemOpIdx oi, uintptr_t ra); - uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr); uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr); uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr); From efe25c260cd69dcfc948e1622bedbdec953569a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:04:59 -0700 Subject: [PATCH 0103/2760] include/exec: Split out accel/tcg/cpu-mmu-index.h The implementation of cpu_mmu_index was split between cpu-common.h and cpu-all.h, depending on CONFIG_USER_ONLY. We already have the plumbing common to user and system mode. Using MMU_USER_IDX requires the cpu.h for a specific target, and so is restricted to when we're compiling per-target. Include the new header only where needed. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/accel/tcg/cpu-mmu-index.h | 41 +++++++++++++++++++++++++++++++ include/exec/cpu-all.h | 6 ----- include/exec/cpu-common.h | 20 --------------- include/exec/cpu_ldst.h | 1 + semihosting/uaccess.c | 1 + target/arm/gdbstub64.c | 3 +++ target/hppa/mem_helper.c | 1 + target/i386/tcg/translate.c | 1 + target/loongarch/cpu_helper.c | 1 + target/microblaze/helper.c | 1 + target/microblaze/mmu.c | 1 + target/openrisc/translate.c | 1 + target/sparc/cpu.c | 1 + target/sparc/mmu_helper.c | 1 + target/tricore/helper.c | 1 + target/xtensa/mmu_helper.c | 1 + 16 files changed, 56 insertions(+), 26 deletions(-) create mode 100644 include/accel/tcg/cpu-mmu-index.h diff --git a/include/accel/tcg/cpu-mmu-index.h b/include/accel/tcg/cpu-mmu-index.h new file mode 100644 index 0000000000..8d1cb53bfa --- /dev/null +++ b/include/accel/tcg/cpu-mmu-index.h @@ -0,0 +1,41 @@ +/* + * cpu_mmu_index() + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_CPU_MMU_INDEX_H +#define ACCEL_TCG_CPU_MMU_INDEX_H + +#include "hw/core/cpu.h" +#include "tcg/debug-assert.h" +#ifdef COMPILING_PER_TARGET +# ifdef CONFIG_USER_ONLY +# include "cpu.h" +# endif +#endif + +/** + * cpu_mmu_index: + * @env: The cpu environment + * @ifetch: True for code access, false for data access. + * + * Return the core mmu index for the current translation regime. + * This function is used by generic TCG code paths. + */ +static inline int cpu_mmu_index(CPUState *cs, bool ifetch) +{ +#ifdef COMPILING_PER_TARGET +# ifdef CONFIG_USER_ONLY + return MMU_USER_IDX; +# endif +#endif + + int ret = cs->cc->mmu_index(cs, ifetch); + tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES); + return ret; +} + +#endif /* ACCEL_TCG_CPU_MMU_INDEX_H */ diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 66a4252269..33b9dc81eb 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -34,8 +34,6 @@ CPUArchState *cpu_copy(CPUArchState *env); #ifdef CONFIG_USER_ONLY -static inline int cpu_mmu_index(CPUState *cs, bool ifetch); - /* * Allow some level of source compatibility with softmmu. We do not * support any of the more exotic features, so only invalid pages may @@ -45,10 +43,6 @@ static inline int cpu_mmu_index(CPUState *cs, bool ifetch); #define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2)) #define TLB_WATCHPOINT 0 -static inline int cpu_mmu_index(CPUState *cs, bool ifetch) -{ - return MMU_USER_IDX; -} #else /* diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 3771b2130c..be032e1a49 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -272,24 +272,4 @@ static inline CPUState *env_cpu(CPUArchState *env) return (CPUState *)env_cpu_const(env); } -#ifndef CONFIG_USER_ONLY -/** - * cpu_mmu_index: - * @env: The cpu environment - * @ifetch: True for code access, false for data access. - * - * Return the core mmu index for the current translation regime. - * This function is used by generic TCG code paths. - * - * The user-only version of this function is inline in cpu-all.h, - * where it always returns MMU_USER_IDX. - */ -static inline int cpu_mmu_index(CPUState *cs, bool ifetch) -{ - int ret = cs->cc->mmu_index(cs, ifetch); - tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES); - return ret; -} -#endif /* !CONFIG_USER_ONLY */ - #endif /* CPU_COMMON_H */ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 1fbdbe59ae..740f5d937f 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -67,6 +67,7 @@ #endif #include "exec/cpu-ldst-common.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/abi_ptr.h" #if defined(CONFIG_USER_ONLY) diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index 382a366ce3..2e33596428 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "exec/cpu-all.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "semihosting/uaccess.h" diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 1a4dbec567..be38016fc7 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -27,6 +27,9 @@ #include #include "mte_user_helper.h" #endif +#ifdef CONFIG_TCG +#include "accel/tcg/cpu-mmu-index.h" +#endif int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) { diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index fb1d93ef1f..a1ade9079e 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "hw/core/cpu.h" diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index abe210cc4e..6418d4bb03 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -20,6 +20,7 @@ #include "qemu/host-utils.h" #include "cpu.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/translation-block.h" #include "tcg/tcg-op.h" diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 930466ca48..f8965cd155 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "accel/tcg/cpu-mmu-index.h" #include "internals.h" #include "cpu-csr.h" diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 27fc929bee..022c98f0c3 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" #include "qemu/host-utils.h" #include "exec/log.h" diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index f8587d5ac4..2d18659b99 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -22,6 +22,7 @@ #include "qemu/log.h" #include "cpu.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" static unsigned int tlb_decode_size(unsigned int f) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index 7a6af183ae..da033bffff 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "qemu/log.h" diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 5716120117..57fbf16ad2 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "qemu/module.h" #include "qemu/qemu-print.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/translation-block.h" #include "hw/qdev-properties.h" diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 3821cd91ec..78cb24a8e2 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -21,6 +21,7 @@ #include "qemu/log.h" #include "cpu.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" #include "qemu/qemu-print.h" #include "trace.h" diff --git a/target/tricore/helper.c b/target/tricore/helper.c index a64412e6bd..b1ee126112 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -20,6 +20,7 @@ #include "hw/registerfields.h" #include "cpu.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" #include "fpu/softfloat-helpers.h" #include "qemu/qemu-print.h" diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 63be741a42..40b02f0a2c 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -33,6 +33,7 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "exec/cputlb.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/page-protection.h" From a333692c48c916f0416b982ecefdcc9452088b41 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 13:45:24 -0700 Subject: [PATCH 0104/2760] include/exec: Inline *_mmuidx_ra memory operations These need to be per-target for 'abi_ptr'. Expand inline to the *_mmu api with trivial massaging of the arguments. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/ldst_common.c.inc | 118 -------------------------- include/exec/cpu_ldst.h | 163 ++++++++++++++++++++++++++++-------- 2 files changed, 129 insertions(+), 152 deletions(-) diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 0447c0bb92..99a56df3fb 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -248,124 +248,6 @@ void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, * Wrappers of the above */ -uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); - return cpu_ldb_mmu(env, addr, oi, ra); -} - -int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra); -} - -uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx); - return cpu_ldw_mmu(env, addr, oi, ra); -} - -int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra); -} - -uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx); - return cpu_ldl_mmu(env, addr, oi, ra); -} - -uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx); - return cpu_ldq_mmu(env, addr, oi, ra); -} - -uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx); - return cpu_ldw_mmu(env, addr, oi, ra); -} - -int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra); -} - -uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx); - return cpu_ldl_mmu(env, addr, oi, ra); -} - -uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx); - return cpu_ldq_mmu(env, addr, oi, ra); -} - -void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); - cpu_stb_mmu(env, addr, val, oi, ra); -} - -void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx); - cpu_stw_mmu(env, addr, val, oi, ra); -} - -void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx); - cpu_stl_mmu(env, addr, val, oi, ra); -} - -void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx); - cpu_stq_mmu(env, addr, val, oi, ra); -} - -void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx); - cpu_stw_mmu(env, addr, val, oi, ra); -} - -void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx); - cpu_stl_mmu(env, addr, val, oi, ra); -} - -void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, - int mmu_idx, uintptr_t ra) -{ - MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx); - cpu_stq_mmu(env, addr, val, oi, ra); -} - -/*--------------------------*/ - uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) { int mmu_index = cpu_mmu_index(env_cpu(env), false); diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 740f5d937f..8e8b9b53f7 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -119,41 +119,136 @@ void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr, void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr, uint64_t val, uintptr_t ra); -uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -int cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint32_t cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -int cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint32_t cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint64_t cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint32_t cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -int cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint32_t cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); -uint64_t cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, - int mmu_idx, uintptr_t ra); +static inline uint32_t +cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); + return cpu_ldb_mmu(env, addr, oi, ra); +} -void cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, - int mmu_idx, uintptr_t ra); -void cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, - int mmu_idx, uintptr_t ra); -void cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, - int mmu_idx, uintptr_t ra); -void cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint64_t val, - int mmu_idx, uintptr_t ra); -void cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, - int mmu_idx, uintptr_t ra); -void cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint32_t val, - int mmu_idx, uintptr_t ra); -void cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr ptr, uint64_t val, - int mmu_idx, uintptr_t ra); +static inline int +cpu_ldsb_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) +{ + return (int8_t)cpu_ldub_mmuidx_ra(env, addr, mmu_idx, ra); +} + +static inline uint32_t +cpu_lduw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx); + return cpu_ldw_mmu(env, addr, oi, ra); +} + +static inline int +cpu_ldsw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return (int16_t)cpu_lduw_be_mmuidx_ra(env, addr, mmu_idx, ra); +} + +static inline uint32_t +cpu_ldl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx); + return cpu_ldl_mmu(env, addr, oi, ra); +} + +static inline uint64_t +cpu_ldq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx); + return cpu_ldq_mmu(env, addr, oi, ra); +} + +static inline uint32_t +cpu_lduw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx); + return cpu_ldw_mmu(env, addr, oi, ra); +} + +static inline int +cpu_ldsw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + return (int16_t)cpu_lduw_le_mmuidx_ra(env, addr, mmu_idx, ra); +} + +static inline uint32_t +cpu_ldl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx); + return cpu_ldl_mmu(env, addr, oi, ra); +} + +static inline uint64_t +cpu_ldq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx); + return cpu_ldq_mmu(env, addr, oi, ra); +} + +static inline void +cpu_stb_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); + cpu_stb_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stw_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUW | MO_UNALN, mmu_idx); + cpu_stw_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stl_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUL | MO_UNALN, mmu_idx); + cpu_stl_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stq_be_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_BEUQ | MO_UNALN, mmu_idx); + cpu_stq_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stw_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUW | MO_UNALN, mmu_idx); + cpu_stw_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stl_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint32_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUL | MO_UNALN, mmu_idx); + cpu_stl_mmu(env, addr, val, oi, ra); +} + +static inline void +cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, + int mmu_idx, uintptr_t ra) +{ + MemOpIdx oi = make_memop_idx(MO_LEUQ | MO_UNALN, mmu_idx); + cpu_stq_mmu(env, addr, val, oi, ra); +} #if TARGET_BIG_ENDIAN # define cpu_lduw_data cpu_lduw_be_data From ef6ffba62afabd1a7d42bbec93d299799576c7af Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 13:56:02 -0700 Subject: [PATCH 0105/2760] include/exec: Inline *_data_ra memory operations These need to be per-target for 'abi_ptr'. Expand inline to the *_mmuidx_ra api with a lookup of the target's cpu_mmu_index(). Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/ldst_common.c.inc | 108 --------------------------- include/exec/cpu_ldst.h | 144 +++++++++++++++++++++++++++++------- 2 files changed, 118 insertions(+), 134 deletions(-) diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 99a56df3fb..2f203290db 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -248,114 +248,6 @@ void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, * Wrappers of the above */ -uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_ldub_mmuidx_ra(env, addr, mmu_index, ra); -} - -int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - return (int8_t)cpu_ldub_data_ra(env, addr, ra); -} - -uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_lduw_be_mmuidx_ra(env, addr, mmu_index, ra); -} - -int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - return (int16_t)cpu_lduw_be_data_ra(env, addr, ra); -} - -uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_ldl_be_mmuidx_ra(env, addr, mmu_index, ra); -} - -uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_ldq_be_mmuidx_ra(env, addr, mmu_index, ra); -} - -uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_lduw_le_mmuidx_ra(env, addr, mmu_index, ra); -} - -int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - return (int16_t)cpu_lduw_le_data_ra(env, addr, ra); -} - -uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_ldl_le_mmuidx_ra(env, addr, mmu_index, ra); -} - -uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - return cpu_ldq_le_mmuidx_ra(env, addr, mmu_index, ra); -} - -void cpu_stb_data_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stb_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stw_be_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stl_be_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr, - uint64_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stq_be_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stw_le_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr, - uint32_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stl_le_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr, - uint64_t val, uintptr_t ra) -{ - int mmu_index = cpu_mmu_index(env_cpu(env), false); - cpu_stq_le_mmuidx_ra(env, addr, val, mmu_index, ra); -} - -/*--------------------------*/ - uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr) { return cpu_ldub_data_ra(env, addr, 0); diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 8e8b9b53f7..2eda652a38 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -85,17 +85,6 @@ int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr); uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr); uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_ldub_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -int cpu_ldsb_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint32_t cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -int cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint32_t cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint64_t cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint32_t cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -int cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint32_t cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); -uint64_t cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr ptr, uintptr_t ra); - void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val); void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); @@ -104,21 +93,6 @@ void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val); -void cpu_stb_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t ra); -void cpu_stw_be_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t ra); -void cpu_stl_be_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t ra); -void cpu_stq_be_data_ra(CPUArchState *env, abi_ptr ptr, - uint64_t val, uintptr_t ra); -void cpu_stw_le_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t ra); -void cpu_stl_le_data_ra(CPUArchState *env, abi_ptr ptr, - uint32_t val, uintptr_t ra); -void cpu_stq_le_data_ra(CPUArchState *env, abi_ptr ptr, - uint64_t val, uintptr_t ra); - static inline uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) { @@ -250,6 +224,124 @@ cpu_stq_le_mmuidx_ra(CPUArchState *env, abi_ptr addr, uint64_t val, cpu_stq_mmu(env, addr, val, oi, ra); } +/*--------------------------*/ + +static inline uint32_t +cpu_ldub_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_ldub_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline int +cpu_ldsb_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + return (int8_t)cpu_ldub_data_ra(env, addr, ra); +} + +static inline uint32_t +cpu_lduw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_lduw_be_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline int +cpu_ldsw_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + return (int16_t)cpu_lduw_be_data_ra(env, addr, ra); +} + +static inline uint32_t +cpu_ldl_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_ldl_be_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline uint64_t +cpu_ldq_be_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_ldq_be_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline uint32_t +cpu_lduw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_lduw_le_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline int +cpu_ldsw_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + return (int16_t)cpu_lduw_le_data_ra(env, addr, ra); +} + +static inline uint32_t +cpu_ldl_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_ldl_le_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline uint64_t +cpu_ldq_le_data_ra(CPUArchState *env, abi_ptr addr, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + return cpu_ldq_le_mmuidx_ra(env, addr, mmu_index, ra); +} + +static inline void +cpu_stb_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stb_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stw_be_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stw_be_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stl_be_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stl_be_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stq_be_data_ra(CPUArchState *env, abi_ptr addr, uint64_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stq_be_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stw_le_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stw_le_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stl_le_data_ra(CPUArchState *env, abi_ptr addr, uint32_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stl_le_mmuidx_ra(env, addr, val, mmu_index, ra); +} + +static inline void +cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr, uint64_t val, uintptr_t ra) +{ + int mmu_index = cpu_mmu_index(env_cpu(env), false); + cpu_stq_le_mmuidx_ra(env, addr, val, mmu_index, ra); +} + #if TARGET_BIG_ENDIAN # define cpu_lduw_data cpu_lduw_be_data # define cpu_ldsw_data cpu_ldsw_be_data From 0a29f11676d5b834f980a818d35b23d20d7ea226 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 14:08:55 -0700 Subject: [PATCH 0106/2760] include/exec: Inline *_data memory operations These need to be per-target for 'abi_ptr'. Expand inline to the *_data_ra api with ra == 0. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/ldst_common.c.inc | 89 -------------------------- include/exec/cpu_ldst.h | 123 ++++++++++++++++++++++++++++++------ 2 files changed, 104 insertions(+), 108 deletions(-) diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 2f203290db..9791a4e9ef 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -243,92 +243,3 @@ void cpu_st16_mmu(CPUArchState *env, vaddr addr, Int128 val, do_st16_mmu(env_cpu(env), addr, val, oi, retaddr); plugin_store_cb(env, addr, int128_getlo(val), int128_gethi(val), oi); } - -/* - * Wrappers of the above - */ - -uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_ldub_data_ra(env, addr, 0); -} - -int cpu_ldsb_data(CPUArchState *env, abi_ptr addr) -{ - return (int8_t)cpu_ldub_data(env, addr); -} - -uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_lduw_be_data_ra(env, addr, 0); -} - -int cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr) -{ - return (int16_t)cpu_lduw_be_data(env, addr); -} - -uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_ldl_be_data_ra(env, addr, 0); -} - -uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_ldq_be_data_ra(env, addr, 0); -} - -uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_lduw_le_data_ra(env, addr, 0); -} - -int cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr) -{ - return (int16_t)cpu_lduw_le_data(env, addr); -} - -uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_ldl_le_data_ra(env, addr, 0); -} - -uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr addr) -{ - return cpu_ldq_le_data_ra(env, addr, 0); -} - -void cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val) -{ - cpu_stb_data_ra(env, addr, val, 0); -} - -void cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val) -{ - cpu_stw_be_data_ra(env, addr, val, 0); -} - -void cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val) -{ - cpu_stl_be_data_ra(env, addr, val, 0); -} - -void cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val) -{ - cpu_stq_be_data_ra(env, addr, val, 0); -} - -void cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val) -{ - cpu_stw_le_data_ra(env, addr, val, 0); -} - -void cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val) -{ - cpu_stl_le_data_ra(env, addr, val, 0); -} - -void cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val) -{ - cpu_stq_le_data_ra(env, addr, val, 0); -} diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 2eda652a38..0054508eda 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -74,25 +74,6 @@ #include "user/guest-host.h" #endif /* CONFIG_USER_ONLY */ -uint32_t cpu_ldub_data(CPUArchState *env, abi_ptr ptr); -int cpu_ldsb_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_lduw_be_data(CPUArchState *env, abi_ptr ptr); -int cpu_ldsw_be_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_ldl_be_data(CPUArchState *env, abi_ptr ptr); -uint64_t cpu_ldq_be_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_lduw_le_data(CPUArchState *env, abi_ptr ptr); -int cpu_ldsw_le_data(CPUArchState *env, abi_ptr ptr); -uint32_t cpu_ldl_le_data(CPUArchState *env, abi_ptr ptr); -uint64_t cpu_ldq_le_data(CPUArchState *env, abi_ptr ptr); - -void cpu_stb_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stw_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stl_be_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stq_be_data(CPUArchState *env, abi_ptr ptr, uint64_t val); -void cpu_stw_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stl_le_data(CPUArchState *env, abi_ptr ptr, uint32_t val); -void cpu_stq_le_data(CPUArchState *env, abi_ptr ptr, uint64_t val); - static inline uint32_t cpu_ldub_mmuidx_ra(CPUArchState *env, abi_ptr addr, int mmu_idx, uintptr_t ra) { @@ -342,6 +323,110 @@ cpu_stq_le_data_ra(CPUArchState *env, abi_ptr addr, uint64_t val, uintptr_t ra) cpu_stq_le_mmuidx_ra(env, addr, val, mmu_index, ra); } +/*--------------------------*/ + +static inline uint32_t +cpu_ldub_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_ldub_data_ra(env, addr, 0); +} + +static inline int +cpu_ldsb_data(CPUArchState *env, abi_ptr addr) +{ + return (int8_t)cpu_ldub_data(env, addr); +} + +static inline uint32_t +cpu_lduw_be_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_lduw_be_data_ra(env, addr, 0); +} + +static inline int +cpu_ldsw_be_data(CPUArchState *env, abi_ptr addr) +{ + return (int16_t)cpu_lduw_be_data(env, addr); +} + +static inline uint32_t +cpu_ldl_be_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_ldl_be_data_ra(env, addr, 0); +} + +static inline uint64_t +cpu_ldq_be_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_ldq_be_data_ra(env, addr, 0); +} + +static inline uint32_t +cpu_lduw_le_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_lduw_le_data_ra(env, addr, 0); +} + +static inline int +cpu_ldsw_le_data(CPUArchState *env, abi_ptr addr) +{ + return (int16_t)cpu_lduw_le_data(env, addr); +} + +static inline uint32_t +cpu_ldl_le_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_ldl_le_data_ra(env, addr, 0); +} + +static inline uint64_t +cpu_ldq_le_data(CPUArchState *env, abi_ptr addr) +{ + return cpu_ldq_le_data_ra(env, addr, 0); +} + +static inline void +cpu_stb_data(CPUArchState *env, abi_ptr addr, uint32_t val) +{ + cpu_stb_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stw_be_data(CPUArchState *env, abi_ptr addr, uint32_t val) +{ + cpu_stw_be_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stl_be_data(CPUArchState *env, abi_ptr addr, uint32_t val) +{ + cpu_stl_be_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stq_be_data(CPUArchState *env, abi_ptr addr, uint64_t val) +{ + cpu_stq_be_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stw_le_data(CPUArchState *env, abi_ptr addr, uint32_t val) +{ + cpu_stw_le_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stl_le_data(CPUArchState *env, abi_ptr addr, uint32_t val) +{ + cpu_stl_le_data_ra(env, addr, val, 0); +} + +static inline void +cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val) +{ + cpu_stq_le_data_ra(env, addr, val, 0); +} + #if TARGET_BIG_ENDIAN # define cpu_lduw_data cpu_lduw_be_data # define cpu_ldsw_data cpu_ldsw_be_data From 4ba597c138306450e7fcc50d2dba3bfdad8478c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 14:34:28 -0700 Subject: [PATCH 0107/2760] include/exec: Inline *_code memory operations These need to be per-target for 'abi_ptr' and endianness. These expand inline to the *_mmu api with a lookup of the target's cpu_mmu_index() and ra == 0. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 28 ---------------------------- accel/tcg/user-exec.c | 40 ---------------------------------------- include/exec/cpu_ldst.h | 31 +++++++++++++++++++++++++++---- 3 files changed, 27 insertions(+), 72 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index b03998f926..2817c9dbdd 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2897,34 +2897,6 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, /* Code access functions. */ -uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) -{ - CPUState *cs = env_cpu(env); - MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(cs, true)); - return do_ld1_mmu(cs, addr, oi, 0, MMU_INST_FETCH); -} - -uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) -{ - CPUState *cs = env_cpu(env); - MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(cs, true)); - return do_ld2_mmu(cs, addr, oi, 0, MMU_INST_FETCH); -} - -uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) -{ - CPUState *cs = env_cpu(env); - MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(cs, true)); - return do_ld4_mmu(cs, addr, oi, 0, MMU_INST_FETCH); -} - -uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) -{ - CPUState *cs = env_cpu(env); - MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(cs, true)); - return do_ld8_mmu(cs, addr, oi, 0, MMU_INST_FETCH); -} - uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t retaddr) { diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index dec17435c5..ebc7c3ecf5 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1214,46 +1214,6 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, clear_helper_retaddr(); } -uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) -{ - uint32_t ret; - - set_helper_retaddr(1); - ret = ldub_p(g2h_untagged(ptr)); - clear_helper_retaddr(); - return ret; -} - -uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr) -{ - uint32_t ret; - - set_helper_retaddr(1); - ret = lduw_p(g2h_untagged(ptr)); - clear_helper_retaddr(); - return ret; -} - -uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr) -{ - uint32_t ret; - - set_helper_retaddr(1); - ret = ldl_p(g2h_untagged(ptr)); - clear_helper_retaddr(); - return ret; -} - -uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) -{ - uint64_t ret; - - set_helper_retaddr(1); - ret = ldq_p(g2h_untagged(ptr)); - clear_helper_retaddr(); - return ret; -} - uint8_t cpu_ldb_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra) { diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 0054508eda..77dc5ac61c 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -473,10 +473,33 @@ cpu_stq_le_data(CPUArchState *env, abi_ptr addr, uint64_t val) # define cpu_stq_mmuidx_ra cpu_stq_le_mmuidx_ra #endif -uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr); -uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr); -uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr); -uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr); +static inline uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr addr) +{ + CPUState *cs = env_cpu(env); + MemOpIdx oi = make_memop_idx(MO_UB, cpu_mmu_index(cs, true)); + return cpu_ldb_code_mmu(env, addr, oi, 0); +} + +static inline uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr addr) +{ + CPUState *cs = env_cpu(env); + MemOpIdx oi = make_memop_idx(MO_TEUW, cpu_mmu_index(cs, true)); + return cpu_ldw_code_mmu(env, addr, oi, 0); +} + +static inline uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr addr) +{ + CPUState *cs = env_cpu(env); + MemOpIdx oi = make_memop_idx(MO_TEUL, cpu_mmu_index(cs, true)); + return cpu_ldl_code_mmu(env, addr, oi, 0); +} + +static inline uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) +{ + CPUState *cs = env_cpu(env); + MemOpIdx oi = make_memop_idx(MO_TEUQ, cpu_mmu_index(cs, true)); + return cpu_ldq_code_mmu(env, addr, oi, 0); +} /** * tlb_vaddr_to_host: From 6a9dfe1984b0c593fb0ddb52d4e70832e6201dd6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 18:34:58 -0700 Subject: [PATCH 0108/2760] accel/tcg: Perform aligned atomic reads in translator_ld Perform aligned atomic reads in translator_ld, if possible. According to https://lore.kernel.org/qemu-devel/20240607101403.1109-1-jim.shu@sifive.com/ this is required for RISC-V Ziccif. Reviewed-by: Alistair Francis Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index ef1538b4fc..157be33bf6 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -265,12 +265,14 @@ static bool translator_ld(CPUArchState *env, DisasContextBase *db, if (likely(((base ^ last) & TARGET_PAGE_MASK) == 0)) { /* Entire read is from the first page. */ - memcpy(dest, host + (pc - base), len); - return true; + goto do_read; } if (unlikely(((base ^ pc) & TARGET_PAGE_MASK) == 0)) { - /* Read begins on the first page and extends to the second. */ + /* + * Read begins on the first page and extends to the second. + * The unaligned read is never atomic. + */ size_t len0 = -(pc | TARGET_PAGE_MASK); memcpy(dest, host + (pc - base), len0); pc += len0; @@ -329,7 +331,39 @@ static bool translator_ld(CPUArchState *env, DisasContextBase *db, host = db->host_addr[1]; } - memcpy(dest, host + (pc - base), len); + do_read: + /* + * Assume aligned reads should be atomic, if possible. + * We're not in a position to jump out with EXCP_ATOMIC. + */ + host += pc - base; + switch (len) { + case 2: + if (QEMU_IS_ALIGNED(pc, 2)) { + uint16_t t = qatomic_read((uint16_t *)host); + stw_he_p(dest, t); + return true; + } + break; + case 4: + if (QEMU_IS_ALIGNED(pc, 4)) { + uint32_t t = qatomic_read((uint32_t *)host); + stl_he_p(dest, t); + return true; + } + break; +#ifdef CONFIG_ATOMIC64 + case 8: + if (QEMU_IS_ALIGNED(pc, 8)) { + uint64_t t = qatomic_read__nocheck((uint64_t *)host); + stq_he_p(dest, t); + return true; + } + break; +#endif + } + /* Unaligned or partial read from the second page is not atomic. */ + memcpy(dest, host, len); return true; } From 028119c8baedb091e4f358a6176710507b4ce37d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Mar 2025 20:21:26 -0700 Subject: [PATCH 0109/2760] accel/tcg: Use cpu_ld*_code_mmu in translator.c Cache the mmu index in DisasContextBase. Perform the read on host endianness, which lets us share code with the translator_ld fast path. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 58 ++++++++++++++++++--------------------- include/exec/translator.h | 1 + 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 157be33bf6..4c320ab9c3 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -11,10 +11,10 @@ #include "qemu/log.h" #include "qemu/error-report.h" #include "exec/exec-all.h" +#include "exec/cpu-ldst-common.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/translator.h" -#include "exec/cpu_ldst.h" #include "exec/plugin-gen.h" -#include "exec/cpu_ldst.h" #include "exec/tswap.h" #include "tcg/tcg-op-common.h" #include "internal-target.h" @@ -142,6 +142,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns, db->host_addr[1] = NULL; db->record_start = 0; db->record_len = 0; + db->code_mmuidx = cpu_mmu_index(cpu, true); ops->init_disas_context(db, cpu); tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */ @@ -457,55 +458,50 @@ bool translator_st(const DisasContextBase *db, void *dest, uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc) { - uint8_t raw; + uint8_t val; - if (!translator_ld(env, db, &raw, pc, sizeof(raw))) { - raw = cpu_ldub_code(env, pc); - record_save(db, pc, &raw, sizeof(raw)); + if (!translator_ld(env, db, &val, pc, sizeof(val))) { + MemOpIdx oi = make_memop_idx(MO_UB, db->code_mmuidx); + val = cpu_ldb_code_mmu(env, pc, oi, 0); + record_save(db, pc, &val, sizeof(val)); } - return raw; + return val; } uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc) { - uint16_t raw, tgt; + uint16_t val; - if (translator_ld(env, db, &raw, pc, sizeof(raw))) { - tgt = tswap16(raw); - } else { - tgt = cpu_lduw_code(env, pc); - raw = tswap16(tgt); - record_save(db, pc, &raw, sizeof(raw)); + if (!translator_ld(env, db, &val, pc, sizeof(val))) { + MemOpIdx oi = make_memop_idx(MO_UW, db->code_mmuidx); + val = cpu_ldw_code_mmu(env, pc, oi, 0); + record_save(db, pc, &val, sizeof(val)); } - return tgt; + return tswap16(val); } uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc) { - uint32_t raw, tgt; + uint32_t val; - if (translator_ld(env, db, &raw, pc, sizeof(raw))) { - tgt = tswap32(raw); - } else { - tgt = cpu_ldl_code(env, pc); - raw = tswap32(tgt); - record_save(db, pc, &raw, sizeof(raw)); + if (!translator_ld(env, db, &val, pc, sizeof(val))) { + MemOpIdx oi = make_memop_idx(MO_UL, db->code_mmuidx); + val = cpu_ldl_code_mmu(env, pc, oi, 0); + record_save(db, pc, &val, sizeof(val)); } - return tgt; + return tswap32(val); } uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc) { - uint64_t raw, tgt; + uint64_t val; - if (translator_ld(env, db, &raw, pc, sizeof(raw))) { - tgt = tswap64(raw); - } else { - tgt = cpu_ldq_code(env, pc); - raw = tswap64(tgt); - record_save(db, pc, &raw, sizeof(raw)); + if (!translator_ld(env, db, &val, pc, sizeof(val))) { + MemOpIdx oi = make_memop_idx(MO_UQ, db->code_mmuidx); + val = cpu_ldq_code_mmu(env, pc, oi, 0); + record_save(db, pc, &val, sizeof(val)); } - return tgt; + return tswap64(val); } void translator_fake_ld(DisasContextBase *db, const void *data, size_t len) diff --git a/include/exec/translator.h b/include/exec/translator.h index d70942a10f..205dd85bba 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -73,6 +73,7 @@ struct DisasContextBase { int max_insns; bool plugin_enabled; bool fake_insn; + uint8_t code_mmuidx; struct TCGOp *insn_start; void *host_addr[2]; From 5c43a750b67d803588e0743e571ec055dbe6488f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 06:04:13 -0700 Subject: [PATCH 0110/2760] accel/tcg: Implement translator_ld*_end Add a new family of translator load functions which take an absolute endianness value in the form of MO_BE/MO_LE. Expand the other translator_ld* functions on top of this. Remove exec/tswap.h from translator.c. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 26 +++++++++++++++------ include/exec/translator.h | 49 ++++++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 26 deletions(-) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 4c320ab9c3..2ab081b95f 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -8,6 +8,7 @@ */ #include "qemu/osdep.h" +#include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/error-report.h" #include "exec/exec-all.h" @@ -15,7 +16,6 @@ #include "accel/tcg/cpu-mmu-index.h" #include "exec/translator.h" #include "exec/plugin-gen.h" -#include "exec/tswap.h" #include "tcg/tcg-op-common.h" #include "internal-target.h" #include "disas/disas.h" @@ -468,7 +468,8 @@ uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc) return val; } -uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc) +uint16_t translator_lduw_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian) { uint16_t val; @@ -477,10 +478,14 @@ uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc) val = cpu_ldw_code_mmu(env, pc, oi, 0); record_save(db, pc, &val, sizeof(val)); } - return tswap16(val); + if (endian & MO_BSWAP) { + val = bswap16(val); + } + return val; } -uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc) +uint32_t translator_ldl_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian) { uint32_t val; @@ -489,10 +494,14 @@ uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc) val = cpu_ldl_code_mmu(env, pc, oi, 0); record_save(db, pc, &val, sizeof(val)); } - return tswap32(val); + if (endian & MO_BSWAP) { + val = bswap32(val); + } + return val; } -uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc) +uint64_t translator_ldq_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian) { uint64_t val; @@ -501,7 +510,10 @@ uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc) val = cpu_ldq_code_mmu(env, pc, oi, 0); record_save(db, pc, &val, sizeof(val)); } - return tswap64(val); + if (endian & MO_BSWAP) { + val = bswap64(val); + } + return val; } void translator_fake_ld(DisasContextBase *db, const void *data, size_t len) diff --git a/include/exec/translator.h b/include/exec/translator.h index 205dd85bba..3c32655569 100644 --- a/include/exec/translator.h +++ b/include/exec/translator.h @@ -18,7 +18,7 @@ * member in your target-specific DisasContext. */ -#include "qemu/bswap.h" +#include "exec/memop.h" #include "exec/vaddr.h" /** @@ -181,42 +181,53 @@ bool translator_io_start(DisasContextBase *db); */ uint8_t translator_ldub(CPUArchState *env, DisasContextBase *db, vaddr pc); -uint16_t translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc); -uint32_t translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc); -uint64_t translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc); +uint16_t translator_lduw_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian); +uint32_t translator_ldl_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian); +uint64_t translator_ldq_end(CPUArchState *env, DisasContextBase *db, + vaddr pc, MemOp endian); + +#ifdef COMPILING_PER_TARGET +static inline uint16_t +translator_lduw(CPUArchState *env, DisasContextBase *db, vaddr pc) +{ + return translator_lduw_end(env, db, pc, MO_TE); +} + +static inline uint32_t +translator_ldl(CPUArchState *env, DisasContextBase *db, vaddr pc) +{ + return translator_ldl_end(env, db, pc, MO_TE); +} + +static inline uint64_t +translator_ldq(CPUArchState *env, DisasContextBase *db, vaddr pc) +{ + return translator_ldq_end(env, db, pc, MO_TE); +} static inline uint16_t translator_lduw_swap(CPUArchState *env, DisasContextBase *db, vaddr pc, bool do_swap) { - uint16_t ret = translator_lduw(env, db, pc); - if (do_swap) { - ret = bswap16(ret); - } - return ret; + return translator_lduw_end(env, db, pc, MO_TE ^ (do_swap * MO_BSWAP)); } static inline uint32_t translator_ldl_swap(CPUArchState *env, DisasContextBase *db, vaddr pc, bool do_swap) { - uint32_t ret = translator_ldl(env, db, pc); - if (do_swap) { - ret = bswap32(ret); - } - return ret; + return translator_ldl_end(env, db, pc, MO_TE ^ (do_swap * MO_BSWAP)); } static inline uint64_t translator_ldq_swap(CPUArchState *env, DisasContextBase *db, vaddr pc, bool do_swap) { - uint64_t ret = translator_ldq(env, db, pc); - if (do_swap) { - ret = bswap64(ret); - } - return ret; + return translator_ldq_end(env, db, pc, MO_TE ^ (do_swap * MO_BSWAP)); } +#endif /* COMPILING_PER_TARGET */ /** * translator_fake_ld - fake instruction load From 87f8eb1d30050d6df6cbd0c61eee6dc836451370 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 10:37:23 -0700 Subject: [PATCH 0111/2760] accel/tcg: Remove mmap_lock/unlock from watchpoint.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mmap_lock is user-only, whereas watchpoint.c is only compiled for system mode. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/watchpoint.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/accel/tcg/watchpoint.c b/accel/tcg/watchpoint.c index 65b21884ce..cfb37a49e7 100644 --- a/accel/tcg/watchpoint.c +++ b/accel/tcg/watchpoint.c @@ -124,17 +124,14 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, } cpu->watchpoint_hit = wp; - mmap_lock(); /* This call also restores vCPU state */ tb_check_watchpoint(cpu, ra); if (wp->flags & BP_STOP_BEFORE_ACCESS) { cpu->exception_index = EXCP_DEBUG; - mmap_unlock(); cpu_loop_exit(cpu); } else { /* Force execution of one insn next time. */ cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); - mmap_unlock(); cpu_loop_exit_noexc(cpu); } } else { From 4d3ad3c3ba1f1e9c217d0581e4913a59ef2ac15f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 10:36:39 -0700 Subject: [PATCH 0112/2760] include/exec: Split out mmap-lock.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split out mmap_lock, et al from page-protection.h to a new header. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + accel/tcg/internal-target.h | 1 + accel/tcg/tb-maint.c | 1 + accel/tcg/translate-all.c | 1 + bsd-user/bsd-mem.h | 1 + bsd-user/mmap.c | 1 + include/exec/mmap-lock.h | 33 +++++++++++++++++++++++++++++++++ include/exec/page-protection.h | 22 ---------------------- linux-user/arm/cpu_loop.c | 1 + linux-user/elfload.c | 1 + linux-user/flatload.c | 1 + linux-user/mmap.c | 1 + linux-user/syscall.c | 1 + target/arm/helper.c | 1 + 14 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 include/exec/mmap-lock.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index ef3d967e3a..372b876604 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -27,6 +27,7 @@ #include "disas/disas.h" #include "exec/cpu-common.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "exec/translation-block.h" #include "tcg/tcg.h" #include "qemu/atomic.h" diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 2cdf11c905..c88f007ffb 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -13,6 +13,7 @@ #include "exec/translation-block.h" #include "tb-internal.h" #include "tcg-target-mo.h" +#include "exec/mmap-lock.h" /* * Access to the various translations structures need to be serialised diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 3f1bebf6ab..d5899ad047 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -24,6 +24,7 @@ #include "exec/log.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "exec/tb-flush.h" #include "tb-internal.h" #include "system/tcg.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 82bc16bd53..16e5043597 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -45,6 +45,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "tb-internal.h" #include "exec/translator.h" #include "exec/tb-flush.h" diff --git a/bsd-user/bsd-mem.h b/bsd-user/bsd-mem.h index 90ca0e3377..1be906c591 100644 --- a/bsd-user/bsd-mem.h +++ b/bsd-user/bsd-mem.h @@ -56,6 +56,7 @@ #include #include "qemu-bsd.h" +#include "exec/mmap-lock.h" #include "exec/page-protection.h" #include "user/page-protection.h" diff --git a/bsd-user/mmap.c b/bsd-user/mmap.c index 3f0df79c37..47e317517c 100644 --- a/bsd-user/mmap.c +++ b/bsd-user/mmap.c @@ -17,6 +17,7 @@ * along with this program; if not, see . */ #include "qemu/osdep.h" +#include "exec/mmap-lock.h" #include "exec/page-protection.h" #include "user/page-protection.h" diff --git a/include/exec/mmap-lock.h b/include/exec/mmap-lock.h new file mode 100644 index 0000000000..50ffdab9c5 --- /dev/null +++ b/include/exec/mmap-lock.h @@ -0,0 +1,33 @@ +/* + * QEMU user-only mmap lock, with stubs for system mode + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#ifndef EXEC_MMAP_LOCK_H +#define EXEC_MMAP_LOCK_H + +#ifdef CONFIG_USER_ONLY + +void TSA_NO_TSA mmap_lock(void); +void TSA_NO_TSA mmap_unlock(void); +bool have_mmap_lock(void); + +static inline void mmap_unlock_guard(void *unused) +{ + mmap_unlock(); +} + +#define WITH_MMAP_LOCK_GUARD() \ + for (int _mmap_lock_iter __attribute__((cleanup(mmap_unlock_guard))) \ + = (mmap_lock(), 0); _mmap_lock_iter == 0; _mmap_lock_iter = 1) + +#else + +static inline void mmap_lock(void) {} +static inline void mmap_unlock(void) {} +#define WITH_MMAP_LOCK_GUARD() + +#endif /* CONFIG_USER_ONLY */ +#endif /* EXEC_MMAP_LOCK_H */ diff --git a/include/exec/page-protection.h b/include/exec/page-protection.h index 3e0a8a0333..c43231af8b 100644 --- a/include/exec/page-protection.h +++ b/include/exec/page-protection.h @@ -38,26 +38,4 @@ */ #define PAGE_PASSTHROUGH 0x0800 -#ifdef CONFIG_USER_ONLY - -void TSA_NO_TSA mmap_lock(void); -void TSA_NO_TSA mmap_unlock(void); -bool have_mmap_lock(void); - -static inline void mmap_unlock_guard(void *unused) -{ - mmap_unlock(); -} - -#define WITH_MMAP_LOCK_GUARD() \ - for (int _mmap_lock_iter __attribute__((cleanup(mmap_unlock_guard))) \ - = (mmap_lock(), 0); _mmap_lock_iter == 0; _mmap_lock_iter = 1) -#else - -static inline void mmap_lock(void) {} -static inline void mmap_unlock(void) {} -#define WITH_MMAP_LOCK_GUARD() - -#endif /* !CONFIG_USER_ONLY */ - #endif diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 7416e3216e..e8417d0406 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -25,6 +25,7 @@ #include "signal-common.h" #include "semihosting/common-semi.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "user/page-protection.h" #include "target/arm/syndrome.h" diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fa83d78667..99811af5e7 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -10,6 +10,7 @@ #include "user/tswap-target.h" #include "user/page-protection.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "exec/translation-block.h" #include "user/guest-base.h" #include "user-internals.h" diff --git a/linux-user/flatload.c b/linux-user/flatload.c index d5cb1830dd..4beb3ed1b9 100644 --- a/linux-user/flatload.c +++ b/linux-user/flatload.c @@ -35,6 +35,7 @@ #include "qemu.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "user-internals.h" #include "loader.h" #include "user-mmap.h" diff --git a/linux-user/mmap.c b/linux-user/mmap.c index d1f36e6f16..f88a80c31e 100644 --- a/linux-user/mmap.c +++ b/linux-user/mmap.c @@ -21,6 +21,7 @@ #include "trace.h" #include "exec/log.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "exec/tb-flush.h" #include "exec/translation-block.h" #include "qemu.h" diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 8bfe4912e1..5826ac3adb 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -26,6 +26,7 @@ #include "tcg/startup.h" #include "target_mman.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "exec/tb-flush.h" #include "exec/translation-block.h" #include diff --git a/target/arm/helper.c b/target/arm/helper.c index bb445e30cd..0454b06a6c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -14,6 +14,7 @@ #include "cpu-features.h" #include "exec/helper-proto.h" #include "exec/page-protection.h" +#include "exec/mmap-lock.h" #include "qemu/main-loop.h" #include "qemu/timer.h" #include "qemu/bitops.h" From 8be545ba5a315a9aaf7307f143a4a7926a6e605c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 12:11:21 -0700 Subject: [PATCH 0113/2760] include/system: Move exec/memory.h to system/memory.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing includes with sed -i ,exec/memory.h,system/memory.h,g Move the include within cpu-all.h into a !CONFIG_USER_ONLY block. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- MAINTAINERS | 2 +- accel/kvm/kvm-all.c | 2 +- accel/tcg/cputlb.c | 2 +- backends/tpm/tpm_util.c | 2 +- block/blkio.c | 4 ++-- disas/disas-mon.c | 2 +- docs/devel/memory.rst | 2 +- hw/acpi/erst.c | 2 +- hw/arm/strongarm.h | 2 +- hw/avr/atmega.c | 2 +- hw/block/fdc-sysbus.c | 2 +- hw/core/cpu-system.c | 2 +- hw/core/loader-fit.c | 2 +- hw/core/loader.c | 2 +- hw/display/apple-gfx.h | 2 +- hw/display/edid-region.c | 2 +- hw/display/framebuffer.h | 2 +- hw/display/vga_int.h | 2 +- hw/hyperv/hv-balloon-our_range_memslots.h | 2 +- hw/hyperv/hyperv.c | 2 +- hw/i386/acpi-common.c | 2 +- hw/i386/acpi-microvm.c | 2 +- hw/i386/pc_piix.c | 2 +- hw/intc/ioapic_internal.h | 2 +- hw/intc/mips_gic.c | 2 +- hw/intc/ompic.c | 2 +- hw/net/i82596.h | 2 +- hw/net/ne2000.c | 2 +- hw/net/pcnet.h | 2 +- hw/pci-bridge/pci_bridge_dev.c | 2 +- hw/pci-host/remote.c | 2 +- hw/ppc/pnv_homer.c | 2 +- hw/ppc/sam460ex.c | 2 +- hw/remote/iommu.c | 2 +- hw/remote/machine.c | 2 +- hw/remote/proxy-memory-listener.c | 2 +- hw/remote/vfio-user-obj.c | 2 +- hw/s390x/s390-pci-inst.c | 2 +- hw/timer/sh_timer.c | 2 +- hw/tpm/tpm_ppi.h | 2 +- hw/usb/hcd-uhci.h | 2 +- hw/vfio/common.c | 2 +- hw/vfio/container.c | 2 +- hw/vfio/pci.h | 2 +- hw/vfio/platform.c | 2 +- hw/virtio/vhost-iova-tree.h | 2 +- hw/xtensa/sim.c | 2 +- hw/xtensa/virt.c | 2 +- hw/xtensa/xtensa_memory.c | 2 +- hw/xtensa/xtfpga.c | 2 +- include/exec/cpu-all.h | 5 ++++- include/exec/ioport.h | 2 +- include/exec/ram_addr.h | 2 +- include/hw/acpi/acpi.h | 2 +- include/hw/acpi/ich9_tco.h | 2 +- include/hw/arm/fsl-imx25.h | 2 +- include/hw/arm/fsl-imx31.h | 2 +- include/hw/arm/fsl-imx6.h | 2 +- include/hw/arm/fsl-imx6ul.h | 2 +- include/hw/arm/omap.h | 2 +- include/hw/arm/stm32l4x5_soc.h | 2 +- include/hw/boards.h | 2 +- include/hw/char/parallel.h | 2 +- include/hw/char/riscv_htif.h | 2 +- include/hw/char/serial-mm.h | 2 +- include/hw/char/serial.h | 2 +- include/hw/display/macfb.h | 2 +- include/hw/fsi/aspeed_apb2opb.h | 2 +- include/hw/fsi/cfam.h | 2 +- include/hw/fsi/fsi-master.h | 2 +- include/hw/fsi/fsi.h | 2 +- include/hw/fsi/lbus.h | 2 +- include/hw/gpio/npcm7xx_gpio.h | 2 +- include/hw/i2c/npcm7xx_smbus.h | 2 +- include/hw/i2c/pm_smbus.h | 2 +- include/hw/i386/apic_internal.h | 2 +- include/hw/i386/x86.h | 2 +- include/hw/ide/ahci.h | 2 +- include/hw/ipmi/ipmi.h | 2 +- include/hw/isa/apm.h | 2 +- include/hw/isa/isa.h | 2 +- include/hw/m68k/q800.h | 2 +- include/hw/mem/npcm7xx_mc.h | 2 +- include/hw/mem/pc-dimm.h | 2 +- include/hw/mips/mips.h | 2 +- include/hw/misc/auxbus.h | 2 +- include/hw/misc/ivshmem-flat.h | 2 +- include/hw/misc/mac_via.h | 2 +- include/hw/misc/npcm7xx_mft.h | 2 +- include/hw/misc/npcm_clk.h | 2 +- include/hw/misc/npcm_gcr.h | 2 +- include/hw/misc/pvpanic.h | 2 +- include/hw/net/dp8393x.h | 2 +- include/hw/net/msf2-emac.h | 2 +- include/hw/nvram/mac_nvram.h | 2 +- include/hw/nvram/npcm7xx_otp.h | 2 +- include/hw/pci-host/fsl_imx8m_phy.h | 2 +- include/hw/pci-host/pam.h | 2 +- include/hw/pci-host/remote.h | 2 +- include/hw/pci/pci.h | 2 +- include/hw/pci/pcie_host.h | 2 +- include/hw/pci/shpc.h | 2 +- include/hw/ppc/mac_dbdma.h | 2 +- include/hw/ppc/pnv_lpc.h | 2 +- include/hw/ppc/pnv_occ.h | 2 +- include/hw/ppc/pnv_sbe.h | 2 +- include/hw/ppc/pnv_xscom.h | 2 +- include/hw/ppc/ppc4xx.h | 2 +- include/hw/ppc/vof.h | 2 +- include/hw/ppc/xics.h | 2 +- include/hw/register.h | 2 +- include/hw/remote/proxy-memory-listener.h | 2 +- include/hw/sh4/sh_intc.h | 2 +- include/hw/southbridge/ich9.h | 2 +- include/hw/sysbus.h | 2 +- include/hw/timer/npcm7xx_timer.h | 2 +- include/hw/tricore/tricore.h | 2 +- include/hw/usb.h | 2 +- include/hw/vfio/vfio-common.h | 2 +- include/hw/vfio/vfio-container-base.h | 2 +- include/hw/virtio/vhost-backend.h | 2 +- include/hw/virtio/vhost.h | 2 +- include/hw/virtio/virtio.h | 2 +- include/hw/xen/xen-pvh-common.h | 2 +- include/hw/xtensa/mx_pic.h | 2 +- include/qemu/iova-tree.h | 2 +- include/qemu/reserved-region.h | 2 +- include/system/dma.h | 2 +- include/system/hostmem.h | 2 +- include/system/kvm_int.h | 2 +- include/{exec => system}/memory.h | 8 ++------ include/system/vhost-user-backend.h | 2 +- migration/dirtyrate.c | 2 +- migration/rdma.c | 2 +- migration/rdma.h | 2 +- migration/savevm.c | 2 +- monitor/hmp-cmds-target.c | 2 +- rust/wrapper.h | 2 +- scripts/analyze-inclusions | 2 +- stubs/ram-block.c | 2 +- system/dirtylimit.c | 2 +- system/ioport.c | 2 +- system/memory.c | 2 +- system/memory_mapping.c | 2 +- system/physmem.c | 2 +- system/qtest.c | 2 +- target/avr/cpu.h | 2 +- target/loongarch/cpu.h | 2 +- target/mips/cpu.h | 2 +- target/xtensa/cpu.c | 2 +- tests/qtest/fuzz/generic_fuzz.c | 2 +- tests/qtest/fuzz/qos_fuzz.c | 2 +- tests/unit/test-resv-mem.c | 2 +- ui/console.c | 2 +- util/vfio-helpers.c | 2 +- 155 files changed, 160 insertions(+), 161 deletions(-) rename include/{exec => system}/memory.h (99%) diff --git a/MAINTAINERS b/MAINTAINERS index 04573e2934..5d391cfaa7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3120,7 +3120,7 @@ R: Philippe Mathieu-Daudé S: Supported F: include/exec/ioport.h F: include/exec/memop.h -F: include/exec/memory.h +F: include/system/memory.h F: include/exec/ram_addr.h F: include/exec/ramblock.h F: include/system/memory_mapping.h diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 951e8214e0..9e06a95f75 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -33,7 +33,7 @@ #include "system/cpus.h" #include "system/accel-blocker.h" #include "qemu/bswap.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ram_addr.h" #include "qemu/event_notifier.h" #include "qemu/main-loop.h" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 2817c9dbdd..6f0ea9067b 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -22,7 +22,7 @@ #include "accel/tcg/cpu-ops.h" #include "exec/exec-all.h" #include "exec/page-protection.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/cpu_ldst.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" diff --git a/backends/tpm/tpm_util.c b/backends/tpm/tpm_util.c index f07a2656ce..f2d1739e33 100644 --- a/backends/tpm/tpm_util.c +++ b/backends/tpm/tpm_util.c @@ -25,7 +25,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "tpm_int.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-properties.h" #include "system/tpm_backend.h" #include "system/tpm_util.h" diff --git a/block/blkio.c b/block/blkio.c index 5f4fce2b1b..4142673984 100644 --- a/block/blkio.c +++ b/block/blkio.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include #include "block/block_int.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/cpu-common.h" /* for qemu_ram_get_fd() */ #include "qemu/defer-call.h" #include "qapi/error.h" @@ -19,7 +19,7 @@ #include "qobject/qdict.h" #include "qemu/module.h" #include "system/block-backend.h" -#include "exec/memory.h" /* for ram_block_discard_disable() */ +#include "system/memory.h" /* for ram_block_discard_disable() */ #include "block/block-io.h" diff --git a/disas/disas-mon.c b/disas/disas-mon.c index 37bf16ac79..9c693618c2 100644 --- a/disas/disas-mon.c +++ b/disas/disas-mon.c @@ -7,7 +7,7 @@ #include "qemu/osdep.h" #include "disas-internal.h" #include "disas/disas.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/core/cpu.h" #include "monitor/monitor.h" diff --git a/docs/devel/memory.rst b/docs/devel/memory.rst index 69c5e3f914..57fb2aec76 100644 --- a/docs/devel/memory.rst +++ b/docs/devel/memory.rst @@ -369,4 +369,4 @@ callbacks are called: API Reference ------------- -.. kernel-doc:: include/exec/memory.h +.. kernel-doc:: include/system/memory.h diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index ec64f92893..5c4c1dc638 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "hw/qdev-core.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "hw/pci/pci_device.h" #include "qom/object_interfaces.h" diff --git a/hw/arm/strongarm.h b/hw/arm/strongarm.h index 192821f6aa..b11b3a3379 100644 --- a/hw/arm/strongarm.h +++ b/hw/arm/strongarm.h @@ -1,7 +1,7 @@ #ifndef STRONGARM_H #define STRONGARM_H -#include "exec/memory.h" +#include "system/memory.h" #include "target/arm/cpu-qom.h" #define SA_CS0 0x00000000 diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index 11fab184de..cb721c96b7 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -12,7 +12,7 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "system/system.h" #include "hw/qdev-properties.h" diff --git a/hw/block/fdc-sysbus.c b/hw/block/fdc-sysbus.c index 381b492aec..4955e478cd 100644 --- a/hw/block/fdc-sysbus.c +++ b/hw/block/fdc-sysbus.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qom/object.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" #include "hw/block/fdc.h" #include "migration/vmstate.h" diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index aed5076ec7..5ef8c24b5b 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -22,7 +22,7 @@ #include "qapi/error.h" #include "exec/address-spaces.h" #include "exec/cputlb.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/tb-flush.h" #include "exec/tswap.h" #include "hw/qdev-core.h" diff --git a/hw/core/loader-fit.c b/hw/core/loader-fit.c index 6eb66406b0..2dea485ae0 100644 --- a/hw/core/loader-fit.c +++ b/hw/core/loader-fit.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/units.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/loader.h" #include "hw/loader-fit.h" #include "qemu/cutils.h" diff --git a/hw/core/loader.c b/hw/core/loader.c index 2e35f0aa90..a3aa62d132 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -59,7 +59,7 @@ #include "uboot_image.h" #include "hw/loader.h" #include "hw/nvram/fw_cfg.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/boards.h" #include "qemu/cutils.h" #include "system/runstate.h" diff --git a/hw/display/apple-gfx.h b/hw/display/apple-gfx.h index 3900cdbabb..a8b1d1efc0 100644 --- a/hw/display/apple-gfx.h +++ b/hw/display/apple-gfx.h @@ -9,7 +9,7 @@ #define QEMU_APPLE_GFX_H #include "qemu/queue.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-properties.h" #include "ui/surface.h" diff --git a/hw/display/edid-region.c b/hw/display/edid-region.c index 675429dc18..f1596fba9a 100644 --- a/hw/display/edid-region.c +++ b/hw/display/edid-region.c @@ -1,5 +1,5 @@ #include "qemu/osdep.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/display/edid.h" static uint64_t edid_region_read(void *ptr, hwaddr addr, unsigned size) diff --git a/hw/display/framebuffer.h b/hw/display/framebuffer.h index 38fa0dcec6..29a828ce7a 100644 --- a/hw/display/framebuffer.h +++ b/hw/display/framebuffer.h @@ -1,7 +1,7 @@ #ifndef QEMU_FRAMEBUFFER_H #define QEMU_FRAMEBUFFER_H -#include "exec/memory.h" +#include "system/memory.h" /* Framebuffer device helper routines. */ diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index f77c1c1145..60ad26e03e 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -27,7 +27,7 @@ #include "ui/console.h" #include "exec/ioport.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/display/bochs-vbe.h" #include "hw/acpi/acpi_aml_interface.h" diff --git a/hw/hyperv/hv-balloon-our_range_memslots.h b/hw/hyperv/hv-balloon-our_range_memslots.h index df3b686bc7..b1f19d77da 100644 --- a/hw/hyperv/hv-balloon-our_range_memslots.h +++ b/hw/hyperv/hv-balloon-our_range_memslots.h @@ -11,7 +11,7 @@ #define HW_HYPERV_HV_BALLOON_OUR_RANGE_MEMSLOTS_H -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "hv-balloon-page_range_tree.h" diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 831e04f214..382c62d668 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -12,7 +12,7 @@ #include "qemu/module.h" #include "qapi/error.h" #include "exec/address-spaces.h" -#include "exec/memory.h" +#include "system/memory.h" #include "system/kvm.h" #include "qemu/bitops.h" #include "qemu/error-report.h" diff --git a/hw/i386/acpi-common.c b/hw/i386/acpi-common.c index 0cc2919bb8..7bd08067a7 100644 --- a/hw/i386/acpi-common.c +++ b/hw/i386/acpi-common.c @@ -23,7 +23,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/utils.h" diff --git a/hw/i386/acpi-microvm.c b/hw/i386/acpi-microvm.c index 279da6b4aa..bc6571778c 100644 --- a/hw/i386/acpi-microvm.c +++ b/hw/i386/acpi-microvm.c @@ -24,7 +24,7 @@ #include "qemu/cutils.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/acpi/acpi.h" #include "hw/acpi/acpi_aml_interface.h" #include "hw/acpi/aml-build.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index dbb59df64f..0dce512f18 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -47,7 +47,7 @@ #include "hw/i386/kvm/clock.h" #include "hw/sysbus.h" #include "hw/i2c/smbus_eeprom.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/acpi/acpi.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/hw/intc/ioapic_internal.h b/hw/intc/ioapic_internal.h index 37b8565539..51205767f4 100644 --- a/hw/intc/ioapic_internal.h +++ b/hw/intc/ioapic_internal.h @@ -22,7 +22,7 @@ #ifndef HW_INTC_IOAPIC_INTERNAL_H #define HW_INTC_IOAPIC_INTERNAL_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/intc/ioapic.h" #include "hw/sysbus.h" #include "qemu/notify.h" diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c index 5e3cbeabec..12d3908938 100644 --- a/hw/intc/mips_gic.c +++ b/hw/intc/mips_gic.c @@ -14,7 +14,7 @@ #include "qemu/module.h" #include "qapi/error.h" #include "hw/sysbus.h" -#include "exec/memory.h" +#include "system/memory.h" #include "system/kvm.h" #include "system/reset.h" #include "kvm_mips.h" diff --git a/hw/intc/ompic.c b/hw/intc/ompic.c index 42af4567c6..169baf2ded 100644 --- a/hw/intc/ompic.c +++ b/hw/intc/ompic.c @@ -13,7 +13,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" #include "migration/vmstate.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #define TYPE_OR1K_OMPIC "or1k-ompic" diff --git a/hw/net/i82596.h b/hw/net/i82596.h index f0bbe810eb..4bdfcaf856 100644 --- a/hw/net/i82596.h +++ b/hw/net/i82596.h @@ -3,7 +3,7 @@ #define I82596_IOPORT_SIZE 0x20 -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #define PORT_RESET 0x00 /* reset 82596 */ diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c index b482c5f3af..b1923c8c3e 100644 --- a/hw/net/ne2000.c +++ b/hw/net/ne2000.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "net/eth.h" #include "qemu/module.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/irq.h" #include "migration/vmstate.h" #include "ne2000.h" diff --git a/hw/net/pcnet.h b/hw/net/pcnet.h index eb7f46aab3..a94356ec30 100644 --- a/hw/net/pcnet.h +++ b/hw/net/pcnet.h @@ -7,7 +7,7 @@ #define PCNET_LOOPTEST_CRC 1 #define PCNET_LOOPTEST_NOCRC 2 -#include "exec/memory.h" +#include "system/memory.h" #include "hw/irq.h" /* BUS CONFIGURATION REGISTERS */ diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 0a91a8ae6c..4931ea24f6 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -28,7 +28,7 @@ #include "hw/pci/shpc.h" #include "hw/pci/slotid_cap.h" #include "hw/qdev-properties.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/pci/pci_bus.h" #include "hw/hotplug.h" #include "qom/object.h" diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c index bfb25ef6af..be077d075e 100644 --- a/hw/pci-host/remote.c +++ b/hw/pci-host/remote.c @@ -28,7 +28,7 @@ #include "hw/pci/pcie_host.h" #include "hw/qdev-properties.h" #include "hw/pci-host/remote.h" -#include "exec/memory.h" +#include "system/memory.h" static const char *remote_pcihost_root_bus_path(PCIHostState *host_bridge, PCIBus *rootbus) diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c index 18a53a80c1..0521f9a428 100644 --- a/hw/ppc/pnv_homer.c +++ b/hw/ppc/pnv_homer.c @@ -20,7 +20,7 @@ #include "qemu/log.h" #include "qapi/error.h" #include "exec/hwaddr.h" -#include "exec/memory.h" +#include "system/memory.h" #include "system/cpus.h" #include "hw/qdev-core.h" #include "hw/qdev-properties.h" diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index 7dc3b309c8..a070de23cf 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -24,7 +24,7 @@ #include "exec/page-protection.h" #include "hw/loader.h" #include "elf.h" -#include "exec/memory.h" +#include "system/memory.h" #include "ppc440.h" #include "hw/pci-host/ppc4xx.h" #include "hw/block/flash.h" diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c index 7c56aad0fc..ec845d1f58 100644 --- a/hw/remote/iommu.c +++ b/hw/remote/iommu.c @@ -13,7 +13,7 @@ #include "hw/remote/iommu.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "trace.h" diff --git a/hw/remote/machine.c b/hw/remote/machine.c index fdc6c441bb..d4616025e8 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "hw/remote/machine.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qapi/error.h" #include "hw/pci/pci_host.h" #include "hw/remote/iohub.h" diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index a926f61ebe..ce7f5b9bfb 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -10,7 +10,7 @@ #include "qemu/int128.h" #include "qemu/range.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/cpu-common.h" #include "exec/ram_addr.h" #include "qapi/error.h" diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index 6e51a92856..9bdd0a465b 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -57,7 +57,7 @@ #include "hw/qdev-core.h" #include "hw/pci/pci.h" #include "qemu/timer.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/remote/vfio-user-obj.h" diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 8cdeb6cb7f..b4e003c19c 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "exec/memop.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/error-report.h" #include "system/hw_accel.h" #include "hw/boards.h" diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index 7788939766..d4fa32c9d6 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/log.h" #include "hw/irq.h" #include "hw/sh4/sh.h" diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h index bf5d4a300f..88f316ee95 100644 --- a/hw/tpm/tpm_ppi.h +++ b/hw/tpm/tpm_ppi.h @@ -12,7 +12,7 @@ #ifndef TPM_TPM_PPI_H #define TPM_TPM_PPI_H -#include "exec/memory.h" +#include "system/memory.h" typedef struct TPMPPI { MemoryRegion ram; diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h index 6d26b94e92..d4664297cf 100644 --- a/hw/usb/hcd-uhci.h +++ b/hw/usb/hcd-uhci.h @@ -28,7 +28,7 @@ #ifndef HW_USB_HCD_UHCI_H #define HW_USB_HCD_UHCI_H -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/timer.h" #include "hw/pci/pci_device.h" #include "hw/usb.h" diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 1a0d9290f8..989c6ee83d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -28,7 +28,7 @@ #include "hw/vfio/vfio-common.h" #include "hw/vfio/pci.h" #include "exec/address-spaces.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ram_addr.h" #include "exec/target_page.h" #include "hw/hw.h" diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 7c57bdd27b..1d1c5f9a77 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -24,7 +24,7 @@ #include "hw/vfio/vfio-common.h" #include "exec/address-spaces.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ram_addr.h" #include "qemu/error-report.h" #include "qemu/range.h" diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index d94ecaba68..6c59300248 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -12,7 +12,7 @@ #ifndef HW_VFIO_VFIO_PCI_H #define HW_VFIO_VFIO_PCI_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/pci/pci_device.h" #include "hw/vfio/vfio-common.h" #include "qemu/event_notifier.h" diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 67bc57409c..96c6bf5654 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -28,7 +28,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/range.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "qemu/queue.h" #include "hw/sysbus.h" diff --git a/hw/virtio/vhost-iova-tree.h b/hw/virtio/vhost-iova-tree.h index 0c4ba5abd5..08f63b61cd 100644 --- a/hw/virtio/vhost-iova-tree.h +++ b/hw/virtio/vhost-iova-tree.h @@ -11,7 +11,7 @@ #define HW_VIRTIO_VHOST_IOVA_TREE_H #include "qemu/iova-tree.h" -#include "exec/memory.h" +#include "system/memory.h" typedef struct VhostIOVATree VhostIOVATree; diff --git a/hw/xtensa/sim.c b/hw/xtensa/sim.c index 1cea29c66d..49d17e7bb2 100644 --- a/hw/xtensa/sim.c +++ b/hw/xtensa/sim.c @@ -32,7 +32,7 @@ #include "hw/boards.h" #include "hw/loader.h" #include "elf.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/error-report.h" #include "xtensa_memory.h" #include "xtensa_sim.h" diff --git a/hw/xtensa/virt.c b/hw/xtensa/virt.c index b08404fc17..b10866ccd8 100644 --- a/hw/xtensa/virt.c +++ b/hw/xtensa/virt.c @@ -33,7 +33,7 @@ #include "hw/pci-host/gpex.h" #include "net/net.h" #include "elf.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/error-report.h" #include "xtensa_memory.h" #include "xtensa_sim.h" diff --git a/hw/xtensa/xtensa_memory.c b/hw/xtensa/xtensa_memory.c index 2c1095f017..13a6077d86 100644 --- a/hw/xtensa/xtensa_memory.c +++ b/hw/xtensa/xtensa_memory.c @@ -27,7 +27,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/error-report.h" #include "xtensa_memory.h" diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 3f3677f1c9..3bd0ef8268 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -34,7 +34,7 @@ #include "hw/loader.h" #include "hw/qdev-properties.h" #include "elf.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/tswap.h" #include "hw/char/serial-mm.h" #include "net/net.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 33b9dc81eb..4395fd08af 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -22,11 +22,14 @@ #include "exec/page-protection.h" #include "exec/cpu-common.h" #include "exec/cpu-interrupt.h" -#include "exec/memory.h" #include "exec/tswap.h" #include "hw/core/cpu.h" #include "exec/cpu-defs.h" #include "exec/target_page.h" +#ifndef CONFIG_USER_ONLY +#include "system/memory.h" +#endif + CPUArchState *cpu_copy(CPUArchState *env); diff --git a/include/exec/ioport.h b/include/exec/ioport.h index 4397f12f93..ecea3575bc 100644 --- a/include/exec/ioport.h +++ b/include/exec/ioport.h @@ -24,7 +24,7 @@ #ifndef IOPORT_H #define IOPORT_H -#include "exec/memory.h" +#include "system/memory.h" #define MAX_IOPORTS (64 * 1024) #define IOPORTS_MASK (MAX_IOPORTS - 1) diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h index 92e8708af7..8677761af5 100644 --- a/include/exec/ram_addr.h +++ b/include/exec/ram_addr.h @@ -26,7 +26,7 @@ #include "exec/ramlist.h" #include "exec/ramblock.h" #include "exec/exec-all.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/target_page.h" #include "qemu/rcu.h" diff --git a/include/hw/acpi/acpi.h b/include/hw/acpi/acpi.h index d1a4fa2af8..4b8ee094c4 100644 --- a/include/hw/acpi/acpi.h +++ b/include/hw/acpi/acpi.h @@ -21,7 +21,7 @@ */ #include "qemu/notify.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/acpi/acpi_dev_interface.h" /* diff --git a/include/hw/acpi/ich9_tco.h b/include/hw/acpi/ich9_tco.h index 2562a7cf39..b3c3f69451 100644 --- a/include/hw/acpi/ich9_tco.h +++ b/include/hw/acpi/ich9_tco.h @@ -10,7 +10,7 @@ #ifndef HW_ACPI_TCO_H #define HW_ACPI_TCO_H -#include "exec/memory.h" +#include "system/memory.h" #include "migration/vmstate.h" /* As per ICH9 spec, the internal timer has an error of ~0.6s on every tick */ diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h index df2f83980f..b68d4334a0 100644 --- a/include/hw/arm/fsl-imx25.h +++ b/include/hw/arm/fsl-imx25.h @@ -29,7 +29,7 @@ #include "hw/sd/sdhci.h" #include "hw/usb/chipidea.h" #include "hw/watchdog/wdt_imx2.h" -#include "exec/memory.h" +#include "system/memory.h" #include "target/arm/cpu.h" #include "qom/object.h" diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h index 40c593a5cf..41232a2237 100644 --- a/include/hw/arm/fsl-imx31.h +++ b/include/hw/arm/fsl-imx31.h @@ -25,7 +25,7 @@ #include "hw/i2c/imx_i2c.h" #include "hw/gpio/imx_gpio.h" #include "hw/watchdog/wdt_imx2.h" -#include "exec/memory.h" +#include "system/memory.h" #include "target/arm/cpu.h" #include "qom/object.h" diff --git a/include/hw/arm/fsl-imx6.h b/include/hw/arm/fsl-imx6.h index 9da32fc189..124bbd478f 100644 --- a/include/hw/arm/fsl-imx6.h +++ b/include/hw/arm/fsl-imx6.h @@ -34,7 +34,7 @@ #include "hw/usb/imx-usb-phy.h" #include "hw/pci-host/designware.h" #include "hw/or-irq.h" -#include "exec/memory.h" +#include "system/memory.h" #include "cpu.h" #include "qom/object.h" diff --git a/include/hw/arm/fsl-imx6ul.h b/include/hw/arm/fsl-imx6ul.h index 8277b0e8b2..4e3209b25b 100644 --- a/include/hw/arm/fsl-imx6ul.h +++ b/include/hw/arm/fsl-imx6ul.h @@ -33,7 +33,7 @@ #include "hw/net/imx_fec.h" #include "hw/usb/chipidea.h" #include "hw/usb/imx-usb-phy.h" -#include "exec/memory.h" +#include "system/memory.h" #include "cpu.h" #include "qom/object.h" #include "qemu/units.h" diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h index 7cb87ea89c..6185507373 100644 --- a/include/hw/arm/omap.h +++ b/include/hw/arm/omap.h @@ -20,7 +20,7 @@ #ifndef HW_ARM_OMAP_H #define HW_ARM_OMAP_H -#include "exec/memory.h" +#include "system/memory.h" #include "target/arm/cpu-qom.h" #include "qemu/log.h" #include "qom/object.h" diff --git a/include/hw/arm/stm32l4x5_soc.h b/include/hw/arm/stm32l4x5_soc.h index c243fb0e7f..c2fae6e23f 100644 --- a/include/hw/arm/stm32l4x5_soc.h +++ b/include/hw/arm/stm32l4x5_soc.h @@ -24,7 +24,7 @@ #ifndef HW_ARM_STM32L4x5_SOC_H #define HW_ARM_STM32L4x5_SOC_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/arm/armv7m.h" #include "hw/or-irq.h" #include "hw/misc/stm32l4x5_syscfg.h" diff --git a/include/hw/boards.h b/include/hw/boards.h index bfe8643a27..8556e01e21 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -3,7 +3,7 @@ #ifndef HW_BOARDS_H #define HW_BOARDS_H -#include "exec/memory.h" +#include "system/memory.h" #include "system/hostmem.h" #include "system/blockdev.h" #include "qapi/qapi-types-machine.h" diff --git a/include/hw/char/parallel.h b/include/hw/char/parallel.h index cfb97cc7cc..7b04478226 100644 --- a/include/hw/char/parallel.h +++ b/include/hw/char/parallel.h @@ -1,7 +1,7 @@ #ifndef HW_PARALLEL_H #define HW_PARALLEL_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/isa/isa.h" #include "hw/irq.h" #include "chardev/char-fe.h" diff --git a/include/hw/char/riscv_htif.h b/include/hw/char/riscv_htif.h index df493fdf6b..ee0ca29902 100644 --- a/include/hw/char/riscv_htif.h +++ b/include/hw/char/riscv_htif.h @@ -22,7 +22,7 @@ #include "chardev/char.h" #include "chardev/char-fe.h" -#include "exec/memory.h" +#include "system/memory.h" #define TYPE_HTIF_UART "riscv.htif.uart" diff --git a/include/hw/char/serial-mm.h b/include/hw/char/serial-mm.h index 62a8489d69..77abd098e0 100644 --- a/include/hw/char/serial-mm.h +++ b/include/hw/char/serial-mm.h @@ -27,7 +27,7 @@ #define HW_SERIAL_MM_H #include "hw/char/serial.h" -#include "exec/memory.h" +#include "system/memory.h" #include "chardev/char.h" #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/char/serial.h b/include/hw/char/serial.h index 942b372df6..4bf90a46f3 100644 --- a/include/hw/char/serial.h +++ b/include/hw/char/serial.h @@ -27,7 +27,7 @@ #define HW_SERIAL_H #include "chardev/char-fe.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/fifo8.h" #include "qom/object.h" diff --git a/include/hw/display/macfb.h b/include/hw/display/macfb.h index 27cebefc9e..0fae1f33a6 100644 --- a/include/hw/display/macfb.h +++ b/include/hw/display/macfb.h @@ -13,7 +13,7 @@ #ifndef MACFB_H #define MACFB_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/irq.h" #include "hw/nubus/nubus.h" #include "hw/sysbus.h" diff --git a/include/hw/fsi/aspeed_apb2opb.h b/include/hw/fsi/aspeed_apb2opb.h index f6a2387abf..878619eafa 100644 --- a/include/hw/fsi/aspeed_apb2opb.h +++ b/include/hw/fsi/aspeed_apb2opb.h @@ -8,7 +8,7 @@ #ifndef FSI_ASPEED_APB2OPB_H #define FSI_ASPEED_APB2OPB_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/fsi/fsi-master.h" #include "hw/sysbus.h" diff --git a/include/hw/fsi/cfam.h b/include/hw/fsi/cfam.h index 7abc3b287b..cceb4bd6f1 100644 --- a/include/hw/fsi/cfam.h +++ b/include/hw/fsi/cfam.h @@ -7,7 +7,7 @@ #ifndef FSI_CFAM_H #define FSI_CFAM_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/fsi/fsi.h" #include "hw/fsi/lbus.h" diff --git a/include/hw/fsi/fsi-master.h b/include/hw/fsi/fsi-master.h index 68e5f56db2..b634ecd393 100644 --- a/include/hw/fsi/fsi-master.h +++ b/include/hw/fsi/fsi-master.h @@ -7,7 +7,7 @@ #ifndef FSI_FSI_MASTER_H #define FSI_FSI_MASTER_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "hw/fsi/fsi.h" #include "hw/fsi/cfam.h" diff --git a/include/hw/fsi/fsi.h b/include/hw/fsi/fsi.h index e00f6ef078..f34765ed80 100644 --- a/include/hw/fsi/fsi.h +++ b/include/hw/fsi/fsi.h @@ -7,7 +7,7 @@ #ifndef FSI_FSI_H #define FSI_FSI_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "hw/fsi/lbus.h" #include "qemu/bitops.h" diff --git a/include/hw/fsi/lbus.h b/include/hw/fsi/lbus.h index 558268c013..12519073cd 100644 --- a/include/hw/fsi/lbus.h +++ b/include/hw/fsi/lbus.h @@ -9,7 +9,7 @@ #include "hw/qdev-core.h" #include "qemu/units.h" -#include "exec/memory.h" +#include "system/memory.h" #define TYPE_FSI_LBUS_DEVICE "fsi.lbus.device" OBJECT_DECLARE_SIMPLE_TYPE(FSILBusDevice, FSI_LBUS_DEVICE) diff --git a/include/hw/gpio/npcm7xx_gpio.h b/include/hw/gpio/npcm7xx_gpio.h index b1d771bd77..7c0bf61a96 100644 --- a/include/hw/gpio/npcm7xx_gpio.h +++ b/include/hw/gpio/npcm7xx_gpio.h @@ -15,7 +15,7 @@ #ifndef NPCM7XX_GPIO_H #define NPCM7XX_GPIO_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" /* Number of pins managed by each controller. */ diff --git a/include/hw/i2c/npcm7xx_smbus.h b/include/hw/i2c/npcm7xx_smbus.h index dc45963c0e..9c544c561b 100644 --- a/include/hw/i2c/npcm7xx_smbus.h +++ b/include/hw/i2c/npcm7xx_smbus.h @@ -16,7 +16,7 @@ #ifndef NPCM7XX_SMBUS_H #define NPCM7XX_SMBUS_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/i2c/i2c.h" #include "hw/irq.h" #include "hw/sysbus.h" diff --git a/include/hw/i2c/pm_smbus.h b/include/hw/i2c/pm_smbus.h index 0d74207efb..dafe0df4f6 100644 --- a/include/hw/i2c/pm_smbus.h +++ b/include/hw/i2c/pm_smbus.h @@ -1,7 +1,7 @@ #ifndef PM_SMBUS_H #define PM_SMBUS_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/i2c/smbus_master.h" #define PM_SMBUS_MAX_MSG_SIZE 32 diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h index d6e85833da..429278da61 100644 --- a/include/hw/i386/apic_internal.h +++ b/include/hw/i386/apic_internal.h @@ -22,7 +22,7 @@ #define QEMU_APIC_INTERNAL_H #include "cpu.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/timer.h" #include "target/i386/cpu-qom.h" #include "qom/object.h" diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index d43cb3908e..258b1343a1 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -18,7 +18,7 @@ #define HW_I386_X86_H #include "exec/hwaddr.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/boards.h" #include "hw/i386/topology.h" diff --git a/include/hw/ide/ahci.h b/include/hw/ide/ahci.h index ac0292c634..cd07b87811 100644 --- a/include/hw/ide/ahci.h +++ b/include/hw/ide/ahci.h @@ -24,7 +24,7 @@ #ifndef HW_IDE_AHCI_H #define HW_IDE_AHCI_H -#include "exec/memory.h" +#include "system/memory.h" typedef struct AHCIDevice AHCIDevice; diff --git a/include/hw/ipmi/ipmi.h b/include/hw/ipmi/ipmi.h index 802a2febb0..cd581aa134 100644 --- a/include/hw/ipmi/ipmi.h +++ b/include/hw/ipmi/ipmi.h @@ -25,7 +25,7 @@ #ifndef HW_IPMI_H #define HW_IPMI_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/hw/isa/apm.h b/include/hw/isa/apm.h index b6e070c00e..0834539045 100644 --- a/include/hw/isa/apm.h +++ b/include/hw/isa/apm.h @@ -1,7 +1,7 @@ #ifndef APM_H #define APM_H -#include "exec/memory.h" +#include "system/memory.h" #define APM_CNT_IOPORT 0xb2 #define ACPI_PORT_SMI_CMD APM_CNT_IOPORT diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 40d6224a4e..1d852011b3 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -3,7 +3,7 @@ /* ISA bus */ -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ioport.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/hw/m68k/q800.h b/include/hw/m68k/q800.h index 34365c9860..9caaed9692 100644 --- a/include/hw/m68k/q800.h +++ b/include/hw/m68k/q800.h @@ -26,7 +26,7 @@ #include "hw/boards.h" #include "qom/object.h" #include "target/m68k/cpu-qom.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/m68k/q800-glue.h" #include "hw/misc/mac_via.h" #include "hw/net/dp8393x.h" diff --git a/include/hw/mem/npcm7xx_mc.h b/include/hw/mem/npcm7xx_mc.h index 7ed38be243..568cc35fdd 100644 --- a/include/hw/mem/npcm7xx_mc.h +++ b/include/hw/mem/npcm7xx_mc.h @@ -16,7 +16,7 @@ #ifndef NPCM7XX_MC_H #define NPCM7XX_MC_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" /** diff --git a/include/hw/mem/pc-dimm.h b/include/hw/mem/pc-dimm.h index fe0f3ea963..e0dbdd43dc 100644 --- a/include/hw/mem/pc-dimm.h +++ b/include/hw/mem/pc-dimm.h @@ -16,7 +16,7 @@ #ifndef QEMU_PC_DIMM_H #define QEMU_PC_DIMM_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/hw/mips/mips.h b/include/hw/mips/mips.h index 101799f7d3..1f3672ba5f 100644 --- a/include/hw/mips/mips.h +++ b/include/hw/mips/mips.h @@ -7,7 +7,7 @@ /* Kernels can be configured with 64KB pages */ #define INITRD_PAGE_SIZE (64 * KiB) -#include "exec/memory.h" +#include "system/memory.h" /* bonito.c */ PCIBus *bonito_init(qemu_irq *pic); diff --git a/include/hw/misc/auxbus.h b/include/hw/misc/auxbus.h index 03cacdee42..ccd18ce209 100644 --- a/include/hw/misc/auxbus.h +++ b/include/hw/misc/auxbus.h @@ -25,7 +25,7 @@ #ifndef HW_MISC_AUXBUS_H #define HW_MISC_AUXBUS_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/hw/misc/ivshmem-flat.h b/include/hw/misc/ivshmem-flat.h index 0c2b015781..09bc3abcad 100644 --- a/include/hw/misc/ivshmem-flat.h +++ b/include/hw/misc/ivshmem-flat.h @@ -14,7 +14,7 @@ #include "qemu/queue.h" #include "qemu/event_notifier.h" #include "chardev/char-fe.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "hw/sysbus.h" diff --git a/include/hw/misc/mac_via.h b/include/hw/misc/mac_via.h index 63cdcf7c69..6a15228150 100644 --- a/include/hw/misc/mac_via.h +++ b/include/hw/misc/mac_via.h @@ -9,7 +9,7 @@ #ifndef HW_MISC_MAC_VIA_H #define HW_MISC_MAC_VIA_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" #include "hw/misc/mos6522.h" #include "hw/input/adb.h" diff --git a/include/hw/misc/npcm7xx_mft.h b/include/hw/misc/npcm7xx_mft.h index d6384382ce..e4b997a6ad 100644 --- a/include/hw/misc/npcm7xx_mft.h +++ b/include/hw/misc/npcm7xx_mft.h @@ -16,7 +16,7 @@ #ifndef NPCM7XX_MFT_H #define NPCM7XX_MFT_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/clock.h" #include "hw/irq.h" #include "hw/sysbus.h" diff --git a/include/hw/misc/npcm_clk.h b/include/hw/misc/npcm_clk.h index 8fa1e14bdd..52e972f460 100644 --- a/include/hw/misc/npcm_clk.h +++ b/include/hw/misc/npcm_clk.h @@ -16,7 +16,7 @@ #ifndef NPCM_CLK_H #define NPCM_CLK_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/clock.h" #include "hw/sysbus.h" diff --git a/include/hw/misc/npcm_gcr.h b/include/hw/misc/npcm_gcr.h index d81bb9afb2..702e7fddb1 100644 --- a/include/hw/misc/npcm_gcr.h +++ b/include/hw/misc/npcm_gcr.h @@ -16,7 +16,7 @@ #ifndef NPCM_GCR_H #define NPCM_GCR_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" #include "qom/object.h" diff --git a/include/hw/misc/pvpanic.h b/include/hw/misc/pvpanic.h index 049a94c112..5098693437 100644 --- a/include/hw/misc/pvpanic.h +++ b/include/hw/misc/pvpanic.h @@ -15,7 +15,7 @@ #ifndef HW_MISC_PVPANIC_H #define HW_MISC_PVPANIC_H -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "standard-headers/misc/pvpanic.h" diff --git a/include/hw/net/dp8393x.h b/include/hw/net/dp8393x.h index 4a3f7478be..24273dc1f4 100644 --- a/include/hw/net/dp8393x.h +++ b/include/hw/net/dp8393x.h @@ -22,7 +22,7 @@ #include "hw/sysbus.h" #include "net/net.h" -#include "exec/memory.h" +#include "system/memory.h" #define SONIC_REG_COUNT 0x40 diff --git a/include/hw/net/msf2-emac.h b/include/hw/net/msf2-emac.h index 846ba6e6dc..b5d9127e46 100644 --- a/include/hw/net/msf2-emac.h +++ b/include/hw/net/msf2-emac.h @@ -23,7 +23,7 @@ */ #include "hw/sysbus.h" -#include "exec/memory.h" +#include "system/memory.h" #include "net/net.h" #include "net/eth.h" #include "qom/object.h" diff --git a/include/hw/nvram/mac_nvram.h b/include/hw/nvram/mac_nvram.h index 0c4dfaeff6..e9d8398f84 100644 --- a/include/hw/nvram/mac_nvram.h +++ b/include/hw/nvram/mac_nvram.h @@ -26,7 +26,7 @@ #ifndef MAC_NVRAM_H #define MAC_NVRAM_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" #define MACIO_NVRAM_SIZE 0x2000 diff --git a/include/hw/nvram/npcm7xx_otp.h b/include/hw/nvram/npcm7xx_otp.h index ea4b5d0731..77b05f8b82 100644 --- a/include/hw/nvram/npcm7xx_otp.h +++ b/include/hw/nvram/npcm7xx_otp.h @@ -16,7 +16,7 @@ #ifndef NPCM7XX_OTP_H #define NPCM7XX_OTP_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" /* Each OTP module holds 8192 bits of one-time programmable storage */ diff --git a/include/hw/pci-host/fsl_imx8m_phy.h b/include/hw/pci-host/fsl_imx8m_phy.h index 4f4875b37d..5f1b212fd9 100644 --- a/include/hw/pci-host/fsl_imx8m_phy.h +++ b/include/hw/pci-host/fsl_imx8m_phy.h @@ -11,7 +11,7 @@ #include "hw/sysbus.h" #include "qom/object.h" -#include "exec/memory.h" +#include "system/memory.h" #define TYPE_FSL_IMX8M_PCIE_PHY "fsl-imx8m-pcie-phy" OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mPciePhyState, FSL_IMX8M_PCIE_PHY) diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h index 005916f826..44f3908160 100644 --- a/include/hw/pci-host/pam.h +++ b/include/hw/pci-host/pam.h @@ -50,7 +50,7 @@ * 0xf0000 - 0xfffff System BIOS Area Memory Segments */ -#include "exec/memory.h" +#include "system/memory.h" #define SMRAM_C_BASE 0xa0000 #define SMRAM_C_END 0xc0000 diff --git a/include/hw/pci-host/remote.h b/include/hw/pci-host/remote.h index 690a01f0fe..5264c35936 100644 --- a/include/hw/pci-host/remote.h +++ b/include/hw/pci-host/remote.h @@ -11,7 +11,7 @@ #ifndef PCI_HOST_REMOTE_H #define PCI_HOST_REMOTE_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/pci/pcie_host.h" #define TYPE_REMOTE_PCIHOST "remote-pcihost" diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 822fbacdf0..c2fe6caa2c 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -1,7 +1,7 @@ #ifndef QEMU_PCI_H #define QEMU_PCI_H -#include "exec/memory.h" +#include "system/memory.h" #include "system/dma.h" #include "system/host_iommu_device.h" diff --git a/include/hw/pci/pcie_host.h b/include/hw/pci/pcie_host.h index 82d92177da..f09de76bfe 100644 --- a/include/hw/pci/pcie_host.h +++ b/include/hw/pci/pcie_host.h @@ -22,7 +22,7 @@ #define PCIE_HOST_H #include "hw/pci/pci_host.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #define TYPE_PCIE_HOST_BRIDGE "pcie-host-bridge" diff --git a/include/hw/pci/shpc.h b/include/hw/pci/shpc.h index a0789df153..ad1089567a 100644 --- a/include/hw/pci/shpc.h +++ b/include/hw/pci/shpc.h @@ -1,7 +1,7 @@ #ifndef SHPC_H #define SHPC_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/hotplug.h" #include "hw/pci/pci_device.h" #include "migration/vmstate.h" diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h index 672c2be471..896ee4a2b1 100644 --- a/include/hw/ppc/mac_dbdma.h +++ b/include/hw/ppc/mac_dbdma.h @@ -23,7 +23,7 @@ #ifndef HW_MAC_DBDMA_H #define HW_MAC_DBDMA_H -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/iov.h" #include "system/dma.h" #include "hw/sysbus.h" diff --git a/include/hw/ppc/pnv_lpc.h b/include/hw/ppc/pnv_lpc.h index 174add4c53..266d56214f 100644 --- a/include/hw/ppc/pnv_lpc.h +++ b/include/hw/ppc/pnv_lpc.h @@ -20,7 +20,7 @@ #ifndef PPC_PNV_LPC_H #define PPC_PNV_LPC_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/ppc/pnv.h" #include "hw/qdev-core.h" #include "hw/isa/isa.h" /* For ISA_NUM_IRQS */ diff --git a/include/hw/ppc/pnv_occ.h b/include/hw/ppc/pnv_occ.h index 3ec42de0ff..013ea2e53e 100644 --- a/include/hw/ppc/pnv_occ.h +++ b/include/hw/ppc/pnv_occ.h @@ -20,7 +20,7 @@ #ifndef PPC_PNV_OCC_H #define PPC_PNV_OCC_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #define TYPE_PNV_OCC "pnv-occ" diff --git a/include/hw/ppc/pnv_sbe.h b/include/hw/ppc/pnv_sbe.h index b6b378ad14..48a8b86a80 100644 --- a/include/hw/ppc/pnv_sbe.h +++ b/include/hw/ppc/pnv_sbe.h @@ -20,7 +20,7 @@ #ifndef PPC_PNV_SBE_H #define PPC_PNV_SBE_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #define TYPE_PNV_SBE "pnv-sbe" diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index a927aea1c0..b14549db70 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -20,7 +20,7 @@ #ifndef PPC_PNV_XSCOM_H #define PPC_PNV_XSCOM_H -#include "exec/memory.h" +#include "system/memory.h" typedef struct PnvXScomInterface PnvXScomInterface; typedef struct PnvChip PnvChip; diff --git a/include/hw/ppc/ppc4xx.h b/include/hw/ppc/ppc4xx.h index 1bd9b8821b..2e94b00673 100644 --- a/include/hw/ppc/ppc4xx.h +++ b/include/hw/ppc/ppc4xx.h @@ -26,7 +26,7 @@ #define PPC4XX_H #include "hw/ppc/ppc.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" /* diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h index d3f293da8b..2918aaab12 100644 --- a/include/hw/ppc/vof.h +++ b/include/hw/ppc/vof.h @@ -8,7 +8,7 @@ #include "qom/object.h" #include "exec/address-spaces.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/cpu-defs.h" typedef struct Vof { diff --git a/include/hw/ppc/xics.h b/include/hw/ppc/xics.h index e94d53405f..097fcdf00f 100644 --- a/include/hw/ppc/xics.h +++ b/include/hw/ppc/xics.h @@ -28,7 +28,7 @@ #ifndef XICS_H #define XICS_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/hw/register.h b/include/hw/register.h index 6a076cfcdf..a913c52aee 100644 --- a/include/hw/register.h +++ b/include/hw/register.h @@ -12,7 +12,7 @@ #define REGISTER_H #include "hw/qdev-core.h" -#include "exec/memory.h" +#include "system/memory.h" #include "hw/registerfields.h" #include "qom/object.h" diff --git a/include/hw/remote/proxy-memory-listener.h b/include/hw/remote/proxy-memory-listener.h index c4f3efb928..ec516d8267 100644 --- a/include/hw/remote/proxy-memory-listener.h +++ b/include/hw/remote/proxy-memory-listener.h @@ -9,7 +9,7 @@ #ifndef PROXY_MEMORY_LISTENER_H #define PROXY_MEMORY_LISTENER_H -#include "exec/memory.h" +#include "system/memory.h" #include "io/channel.h" typedef struct ProxyMemoryListener { diff --git a/include/hw/sh4/sh_intc.h b/include/hw/sh4/sh_intc.h index f62d5c5e13..94f183121e 100644 --- a/include/hw/sh4/sh_intc.h +++ b/include/hw/sh4/sh_intc.h @@ -1,7 +1,7 @@ #ifndef SH_INTC_H #define SH_INTC_H -#include "exec/memory.h" +#include "system/memory.h" typedef unsigned char intc_enum; diff --git a/include/hw/southbridge/ich9.h b/include/hw/southbridge/ich9.h index 6c60017024..1e231e89c9 100644 --- a/include/hw/southbridge/ich9.h +++ b/include/hw/southbridge/ich9.h @@ -7,7 +7,7 @@ #include "hw/pci/pci.h" #include "hw/pci/pci_device.h" #include "hw/rtc/mc146818rtc.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/notify.h" #include "qom/object.h" diff --git a/include/hw/sysbus.h b/include/hw/sysbus.h index 81bbda10d3..7dc88aaa27 100644 --- a/include/hw/sysbus.h +++ b/include/hw/sysbus.h @@ -4,7 +4,7 @@ /* Devices attached directly to the main system bus. */ #include "hw/qdev-core.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #define QDEV_MAX_MMIO 32 diff --git a/include/hw/timer/npcm7xx_timer.h b/include/hw/timer/npcm7xx_timer.h index d45c051b56..e287375dce 100644 --- a/include/hw/timer/npcm7xx_timer.h +++ b/include/hw/timer/npcm7xx_timer.h @@ -16,7 +16,7 @@ #ifndef NPCM7XX_TIMER_H #define NPCM7XX_TIMER_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/sysbus.h" #include "qemu/timer.h" diff --git a/include/hw/tricore/tricore.h b/include/hw/tricore/tricore.h index c19ed3f013..4ffc0fe1d6 100644 --- a/include/hw/tricore/tricore.h +++ b/include/hw/tricore/tricore.h @@ -1,7 +1,7 @@ #ifndef HW_TRICORE_H #define HW_TRICORE_H -#include "exec/memory.h" +#include "system/memory.h" struct tricore_boot_info { uint64_t ram_size; diff --git a/include/hw/usb.h b/include/hw/usb.h index e410693d0c..26a9f3ecde 100644 --- a/include/hw/usb.h +++ b/include/hw/usb.h @@ -25,7 +25,7 @@ * THE SOFTWARE. */ -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "qemu/iov.h" #include "qemu/queue.h" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 04b123a6c9..f5b3f45a43 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -21,7 +21,7 @@ #ifndef HW_VFIO_VFIO_COMMON_H #define HW_VFIO_VFIO_COMMON_H -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/queue.h" #include "qemu/notify.h" #include "ui/console.h" diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 4cff9943ab..6aca02fb3d 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -13,7 +13,7 @@ #ifndef HW_VFIO_VFIO_CONTAINER_BASE_H #define HW_VFIO_VFIO_CONTAINER_BASE_H -#include "exec/memory.h" +#include "system/memory.h" typedef struct VFIODevice VFIODevice; typedef struct VFIOIOMMUClass VFIOIOMMUClass; diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h index 70c2e8ffee..d6df209a2f 100644 --- a/include/hw/virtio/vhost-backend.h +++ b/include/hw/virtio/vhost-backend.h @@ -11,7 +11,7 @@ #ifndef VHOST_BACKEND_H #define VHOST_BACKEND_H -#include "exec/memory.h" +#include "system/memory.h" typedef enum VhostBackendType { VHOST_BACKEND_TYPE_NONE = 0, diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index a9469d50bc..bb4b58e115 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -3,7 +3,7 @@ #include "hw/virtio/vhost-backend.h" #include "hw/virtio/virtio.h" -#include "exec/memory.h" +#include "system/memory.h" #define VHOST_F_DEVICE_IOTLB 63 #define VHOST_USER_F_PROTOCOL_FEATURES 30 diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 6386910280..7e0c471ea4 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -14,7 +14,7 @@ #ifndef QEMU_VIRTIO_H #define QEMU_VIRTIO_H -#include "exec/memory.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "net/net.h" #include "migration/vmstate.h" diff --git a/include/hw/xen/xen-pvh-common.h b/include/hw/xen/xen-pvh-common.h index 17c5a58a5a..5db83d88ec 100644 --- a/include/hw/xen/xen-pvh-common.h +++ b/include/hw/xen/xen-pvh-common.h @@ -9,7 +9,7 @@ #ifndef XEN_PVH_COMMON_H__ #define XEN_PVH_COMMON_H__ -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "hw/boards.h" #include "hw/pci-host/gpex.h" diff --git a/include/hw/xtensa/mx_pic.h b/include/hw/xtensa/mx_pic.h index 500424c8d3..cd316d86eb 100644 --- a/include/hw/xtensa/mx_pic.h +++ b/include/hw/xtensa/mx_pic.h @@ -28,7 +28,7 @@ #ifndef XTENSA_MX_PIC_H #define XTENSA_MX_PIC_H -#include "exec/memory.h" +#include "system/memory.h" struct XtensaMxPic; typedef struct XtensaMxPic XtensaMxPic; diff --git a/include/qemu/iova-tree.h b/include/qemu/iova-tree.h index 16d354a814..14e82a22d5 100644 --- a/include/qemu/iova-tree.h +++ b/include/qemu/iova-tree.h @@ -23,7 +23,7 @@ * for the thread safety issue. */ -#include "exec/memory.h" +#include "system/memory.h" #include "exec/hwaddr.h" #define IOVA_OK (0) diff --git a/include/qemu/reserved-region.h b/include/qemu/reserved-region.h index 8e6f0a97e2..9026cf08fd 100644 --- a/include/qemu/reserved-region.h +++ b/include/qemu/reserved-region.h @@ -20,7 +20,7 @@ #ifndef QEMU_RESERVED_REGION_H #define QEMU_RESERVED_REGION_H -#include "exec/memory.h" +#include "system/memory.h" /* * Insert a new region into a sorted list of reserved regions. In case diff --git a/include/system/dma.h b/include/system/dma.h index e142f7efa6..aaa03b9711 100644 --- a/include/system/dma.h +++ b/include/system/dma.h @@ -10,7 +10,7 @@ #ifndef DMA_H #define DMA_H -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "block/block.h" #include "block/accounting.h" diff --git a/include/system/hostmem.h b/include/system/hostmem.h index 62642e602c..88fa791ac7 100644 --- a/include/system/hostmem.h +++ b/include/system/hostmem.h @@ -16,7 +16,7 @@ #include "system/numa.h" #include "qapi/qapi-types-machine.h" #include "qom/object.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/bitmap.h" #include "qemu/thread-context.h" diff --git a/include/system/kvm_int.h b/include/system/kvm_int.h index 4de6106869..756a3c0a25 100644 --- a/include/system/kvm_int.h +++ b/include/system/kvm_int.h @@ -9,7 +9,7 @@ #ifndef QEMU_KVM_INT_H #define QEMU_KVM_INT_H -#include "exec/memory.h" +#include "system/memory.h" #include "qapi/qapi-types-common.h" #include "qemu/accel.h" #include "qemu/queue.h" diff --git a/include/exec/memory.h b/include/system/memory.h similarity index 99% rename from include/exec/memory.h rename to include/system/memory.h index 2f84a7cfed..fbbf4cf911 100644 --- a/include/exec/memory.h +++ b/include/system/memory.h @@ -11,10 +11,8 @@ * */ -#ifndef MEMORY_H -#define MEMORY_H - -#ifndef CONFIG_USER_ONLY +#ifndef SYSTEM_MEMORY_H +#define SYSTEM_MEMORY_H #include "exec/cpu-common.h" #include "exec/hwaddr.h" @@ -3197,5 +3195,3 @@ void ram_block_add_cpr_blocker(RAMBlock *rb, Error **errp); void ram_block_del_cpr_blocker(RAMBlock *rb); #endif - -#endif diff --git a/include/system/vhost-user-backend.h b/include/system/vhost-user-backend.h index 327b0b84f1..5ed953cd53 100644 --- a/include/system/vhost-user-backend.h +++ b/include/system/vhost-user-backend.h @@ -13,7 +13,7 @@ #define QEMU_VHOST_USER_BACKEND_H #include "qom/object.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/option.h" #include "qemu/bitmap.h" #include "hw/virtio/vhost.h" diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 4cd14779d6..09caf92f87 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -27,7 +27,7 @@ #include "qobject/qdict.h" #include "system/kvm.h" #include "system/runstate.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/xxhash.h" #include "migration.h" diff --git a/migration/rdma.c b/migration/rdma.c index 76fb034923..d9603ab603 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -30,7 +30,7 @@ #include "qemu/sockets.h" #include "qemu/bitmap.h" #include "qemu/coroutine.h" -#include "exec/memory.h" +#include "system/memory.h" #include #include #include diff --git a/migration/rdma.h b/migration/rdma.h index f55f28bbed..4d3386b84a 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -19,7 +19,7 @@ #ifndef QEMU_MIGRATION_RDMA_H #define QEMU_MIGRATION_RDMA_H -#include "exec/memory.h" +#include "system/memory.h" void rdma_start_outgoing_migration(void *opaque, InetSocketAddress *host_port, Error **errp); diff --git a/migration/savevm.c b/migration/savevm.c index ce158c3512..c33200a33f 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -48,7 +48,7 @@ #include "qapi/qapi-builtin-visit.h" #include "qemu/error-report.h" #include "system/cpus.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/target_page.h" #include "trace.h" #include "qemu/iov.h" diff --git a/monitor/hmp-cmds-target.c b/monitor/hmp-cmds-target.c index 239c2a61a4..6654d31406 100644 --- a/monitor/hmp-cmds-target.c +++ b/monitor/hmp-cmds-target.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "disas/disas.h" #include "exec/address-spaces.h" -#include "exec/memory.h" +#include "system/memory.h" #include "monitor/hmp-target.h" #include "monitor/monitor-internal.h" #include "qapi/error.h" diff --git a/rust/wrapper.h b/rust/wrapper.h index d4fec54657..94866b7e32 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -52,7 +52,7 @@ typedef enum memory_order { #include "qemu-io.h" #include "system/system.h" #include "hw/sysbus.h" -#include "exec/memory.h" +#include "system/memory.h" #include "chardev/char-fe.h" #include "hw/clock.h" #include "hw/qdev-clock.h" diff --git a/scripts/analyze-inclusions b/scripts/analyze-inclusions index b6280f25c8..d2c566667d 100644 --- a/scripts/analyze-inclusions +++ b/scripts/analyze-inclusions @@ -53,7 +53,7 @@ echo $(grep_include -F 'trace/generated-tracers.h') files include generated-trac echo $(grep_include -F 'qapi/error.h') files include qapi/error.h echo $(grep_include -F 'qom/object.h') files include qom/object.h echo $(grep_include -F 'block/aio.h') files include block/aio.h -echo $(grep_include -F 'exec/memory.h') files include exec/memory.h +echo $(grep_include -F 'system/memory.h') files include system/memory.h echo $(grep_include -F 'fpu/softfloat.h') files include fpu/softfloat.h echo $(grep_include -F 'qemu/bswap.h') files include qemu/bswap.h echo diff --git a/stubs/ram-block.c b/stubs/ram-block.c index 108197683b..e88fab31a5 100644 --- a/stubs/ram-block.c +++ b/stubs/ram-block.c @@ -1,7 +1,7 @@ #include "qemu/osdep.h" #include "exec/ramlist.h" #include "exec/cpu-common.h" -#include "exec/memory.h" +#include "system/memory.h" void *qemu_ram_get_host_addr(RAMBlock *rb) { diff --git a/system/dirtylimit.c b/system/dirtylimit.c index 7dedef8dd4..30cd09f3d1 100644 --- a/system/dirtylimit.c +++ b/system/dirtylimit.c @@ -19,7 +19,7 @@ #include "system/dirtylimit.h" #include "monitor/hmp.h" #include "monitor/monitor.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/target_page.h" #include "hw/boards.h" #include "system/kvm.h" diff --git a/system/ioport.c b/system/ioport.c index 89daae9d60..2291739039 100644 --- a/system/ioport.c +++ b/system/ioport.c @@ -27,7 +27,7 @@ #include "qemu/osdep.h" #include "exec/ioport.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "trace.h" diff --git a/system/memory.c b/system/memory.c index eddd21a6cd..2865d0deb1 100644 --- a/system/memory.c +++ b/system/memory.c @@ -16,7 +16,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qapi/visitor.h" #include "qemu/bitops.h" #include "qemu/error-report.h" diff --git a/system/memory_mapping.c b/system/memory_mapping.c index 37d3325f77..8538a8241e 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -16,7 +16,7 @@ #include "qapi/error.h" #include "system/memory_mapping.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/address-spaces.h" #include "hw/core/cpu.h" diff --git a/system/physmem.c b/system/physmem.c index 333a5eb94d..e61fea41b5 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -50,7 +50,7 @@ #include "qemu/log.h" #include "qemu/memalign.h" #include "qemu/memfd.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ioport.h" #include "system/dma.h" #include "system/hostmem.h" diff --git a/system/qtest.c b/system/qtest.c index 12152efbcd..5407289154 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -17,7 +17,7 @@ #include "system/runstate.h" #include "chardev/char-fe.h" #include "exec/ioport.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/tswap.h" #include "hw/qdev-core.h" #include "hw/irq.h" diff --git a/target/avr/cpu.h b/target/avr/cpu.h index 9862705c6a..b0518a1f60 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -23,7 +23,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" -#include "exec/memory.h" +#include "system/memory.h" #ifdef CONFIG_USER_ONLY #error "AVR 8-bit does not support user mode" diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 254e4fbdcd..02ef6ddecb 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -14,7 +14,7 @@ #include "hw/registerfields.h" #include "qemu/timer.h" #ifndef CONFIG_USER_ONLY -#include "exec/memory.h" +#include "system/memory.h" #endif #include "cpu-csr.h" #include "cpu-qom.h" diff --git a/target/mips/cpu.h b/target/mips/cpu.h index f6877ece8b..9ef72a95d7 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -4,7 +4,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" #ifndef CONFIG_USER_ONLY -#include "exec/memory.h" +#include "system/memory.h" #endif #include "fpu/softfloat-types.h" #include "hw/clock.h" diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 7663b62d01..ec6a0a8b66 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -36,7 +36,7 @@ #include "migration/vmstate.h" #include "hw/qdev-clock.h" #ifndef CONFIG_USER_ONLY -#include "exec/memory.h" +#include "system/memory.h" #endif diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index d107a496da..239be9372d 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -20,7 +20,7 @@ #include "tests/qtest/libqos/pci-pc.h" #include "fuzz.h" #include "string.h" -#include "exec/memory.h" +#include "system/memory.h" #include "exec/ramblock.h" #include "hw/qdev-core.h" #include "hw/pci/pci.h" diff --git a/tests/qtest/fuzz/qos_fuzz.c b/tests/qtest/fuzz/qos_fuzz.c index d3839bf999..9afe8bf6d8 100644 --- a/tests/qtest/fuzz/qos_fuzz.c +++ b/tests/qtest/fuzz/qos_fuzz.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/main-loop.h" #include "tests/qtest/libqtest.h" diff --git a/tests/unit/test-resv-mem.c b/tests/unit/test-resv-mem.c index cd8f7318cc..4de2d042d1 100644 --- a/tests/unit/test-resv-mem.c +++ b/tests/unit/test-resv-mem.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "qemu/range.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qemu/reserved-region.h" #define DEBUG 0 diff --git a/ui/console.c b/ui/console.c index 6456e8dd90..6cd122cf40 100644 --- a/ui/console.c +++ b/ui/console.c @@ -35,7 +35,7 @@ #include "qemu/option.h" #include "chardev/char.h" #include "trace.h" -#include "exec/memory.h" +#include "system/memory.h" #include "qom/object.h" #include "qemu/memfd.h" diff --git a/util/vfio-helpers.c b/util/vfio-helpers.c index f8bab46c68..fdff042ab4 100644 --- a/util/vfio-helpers.c +++ b/util/vfio-helpers.c @@ -16,7 +16,7 @@ #include "qapi/error.h" #include "exec/ramlist.h" #include "exec/cpu-common.h" -#include "exec/memory.h" +#include "system/memory.h" #include "trace.h" #include "qemu/error-report.h" #include "standard-headers/linux/pci_regs.h" From dfc56946a70052136126f6a207f237af8032d74a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 12:31:54 -0700 Subject: [PATCH 0114/2760] include/system: Move exec/address-spaces.h to system/address-spaces.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing includes with sed. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/hvf/hvf-accel-ops.c | 2 +- hw/acpi/erst.c | 2 +- hw/arm/aspeed_ast10x0.c | 2 +- hw/arm/bananapi_m2u.c | 2 +- hw/arm/collie.c | 2 +- hw/arm/exynos4_boards.c | 2 +- hw/arm/fsl-imx31.c | 2 +- hw/arm/fsl-imx8mp.c | 2 +- hw/arm/imx8mp-evk.c | 2 +- hw/arm/integratorcp.c | 2 +- hw/arm/kzm.c | 2 +- hw/arm/microbit.c | 2 +- hw/arm/mps2-tz.c | 2 +- hw/arm/mps2.c | 2 +- hw/arm/mps3r.c | 2 +- hw/arm/msf2-soc.c | 2 +- hw/arm/msf2-som.c | 2 +- hw/arm/musca.c | 2 +- hw/arm/omap1.c | 2 +- hw/arm/omap_sx1.c | 2 +- hw/arm/orangepi.c | 2 +- hw/arm/stellaris.c | 2 +- hw/arm/stm32f100_soc.c | 2 +- hw/arm/stm32f205_soc.c | 2 +- hw/arm/stm32f405_soc.c | 2 +- hw/arm/stm32l4x5_soc.c | 2 +- hw/avr/atmega.c | 2 +- hw/char/goldfish_tty.c | 2 +- hw/char/omap_uart.c | 2 +- hw/char/riscv_htif.c | 2 +- hw/core/cpu-system.c | 2 +- hw/core/null-machine.c | 2 +- hw/core/sysbus.c | 2 +- hw/display/apple-gfx.m | 2 +- hw/dma/rc4030.c | 2 +- hw/hyperv/hv-balloon.c | 2 +- hw/hyperv/hyperv.c | 2 +- hw/i386/kvm/xen_evtchn.c | 2 +- hw/i386/kvm/xen_gnttab.c | 2 +- hw/i386/kvm/xen_overlay.c | 2 +- hw/i386/sgx-epc.c | 2 +- hw/i386/sgx.c | 2 +- hw/i386/vapic.c | 2 +- hw/ide/ahci-sysbus.c | 2 +- hw/input/lasips2.c | 2 +- hw/intc/loongarch_extioi.c | 2 +- hw/intc/riscv_aplic.c | 2 +- hw/intc/riscv_imsic.c | 2 +- hw/loongarch/virt.c | 2 +- hw/mem/memory-device.c | 2 +- hw/microblaze/petalogix_ml605_mmu.c | 2 +- hw/microblaze/petalogix_s3adsp1800_mmu.c | 2 +- hw/microblaze/xlnx-zynqmp-pmu.c | 2 +- hw/mips/mipssim.c | 2 +- hw/misc/allwinner-h3-dramc.c | 2 +- hw/misc/allwinner-r40-dramc.c | 2 +- hw/misc/ivshmem-flat.c | 2 +- hw/misc/mac_via.c | 2 +- hw/net/i82596.c | 2 +- hw/net/i82596.h | 2 +- hw/nvram/fw_cfg.c | 2 +- hw/openrisc/openrisc_sim.c | 2 +- hw/openrisc/virt.c | 2 +- hw/pci-host/mv64361.c | 2 +- hw/ppc/pegasos2.c | 2 +- hw/ppc/pnv_psi.c | 2 +- hw/ppc/ppc4xx_sdram.c | 2 +- hw/ppc/prep_systemio.c | 2 +- hw/ppc/rs6000_mc.c | 2 +- hw/ppc/spapr_ovec.c | 2 +- hw/ppc/vof.c | 2 +- hw/remote/iommu.c | 2 +- hw/riscv/microblaze-v-generic.c | 2 +- hw/riscv/opentitan.c | 2 +- hw/riscv/shakti_c.c | 2 +- hw/s390x/css.c | 2 +- hw/s390x/ipl.h | 2 +- hw/s390x/s390-skeys.c | 2 +- hw/s390x/virtio-ccw.c | 2 +- hw/sparc/sun4m_iommu.c | 2 +- hw/sparc64/sun4u_iommu.c | 2 +- hw/timer/hpet.c | 2 +- hw/tpm/tpm_crb.c | 2 +- hw/vfio/ap.c | 2 +- hw/vfio/ccw.c | 2 +- hw/vfio/common.c | 2 +- hw/vfio/container.c | 2 +- hw/vfio/platform.c | 2 +- hw/vfio/spapr.c | 2 +- hw/virtio/vhost-vdpa.c | 2 +- hw/virtio/virtio-balloon.c | 2 +- hw/virtio/virtio-bus.c | 2 +- include/hw/misc/lasi.h | 2 +- include/hw/nubus/nubus.h | 2 +- include/hw/ppc/vof.h | 2 +- include/hw/tricore/triboard.h | 2 +- include/{exec => system}/address-spaces.h | 8 ++------ include/system/dma.h | 2 +- monitor/hmp-cmds-target.c | 2 +- monitor/hmp-cmds.c | 2 +- rust/wrapper.h | 2 +- system/ioport.c | 2 +- system/memory.c | 2 +- system/memory_mapping.c | 2 +- target/arm/hvf/hvf.c | 2 +- target/arm/kvm.c | 2 +- target/avr/cpu.c | 2 +- target/i386/cpu-apic.c | 2 +- target/i386/cpu.c | 2 +- target/i386/hvf/vmx.h | 2 +- target/i386/kvm/xen-emu.c | 2 +- target/i386/nvmm/nvmm-all.c | 2 +- target/i386/sev.c | 2 +- target/i386/tcg/system/misc_helper.c | 2 +- target/i386/tcg/system/tcg-cpu.c | 2 +- target/i386/whpx/whpx-all.c | 2 +- target/loongarch/kvm/kvm.c | 2 +- target/riscv/kvm/kvm-cpu.c | 2 +- target/s390x/mmu_helper.c | 2 +- target/s390x/sigp.c | 2 +- target/s390x/tcg/excp_helper.c | 2 +- target/xtensa/dbg_helper.c | 2 +- 122 files changed, 123 insertions(+), 127 deletions(-) rename include/{exec => system}/address-spaces.h (89%) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 12fc30c276..601c3bc0ac 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -50,7 +50,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/exec-all.h" #include "gdbstub/enums.h" #include "hw/boards.h" diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index 5c4c1dc638..2e49b551f2 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -23,7 +23,7 @@ #include "hw/acpi/acpi-defs.h" #include "hw/acpi/aml-build.h" #include "hw/acpi/bios-linker-loader.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/hostmem.h" #include "hw/acpi/erst.h" #include "trace.h" diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index ec329f4991..21ffab10f3 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/qdev-clock.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/bananapi_m2u.c b/hw/arm/bananapi_m2u.c index 4d84d10d24..b750a575f7 100644 --- a/hw/arm/bananapi_m2u.c +++ b/hw/arm/bananapi_m2u.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/boards.h" diff --git a/hw/arm/collie.c b/hw/arm/collie.c index eaa5c52d45..e83aee58c6 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -16,7 +16,7 @@ #include "strongarm.h" #include "hw/arm/boot.h" #include "hw/block/flash.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #include "qemu/error-report.h" diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 43dc89d902..2d8f2d7326 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -28,7 +28,7 @@ #include "hw/sysbus.h" #include "net/net.h" #include "hw/arm/boot.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/exynos4210.h" #include "hw/net/lan9118.h" #include "hw/qdev-properties.h" diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 9de0f2148f..2a8ffb15f7 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -23,7 +23,7 @@ #include "qapi/error.h" #include "hw/arm/fsl-imx31.h" #include "system/system.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "chardev/char.h" #include "target/arm/cpu-qom.h" diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c index 82edf61082..af7a7e6745 100644 --- a/hw/arm/fsl-imx8mp.c +++ b/hw/arm/fsl-imx8mp.c @@ -9,7 +9,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/bsa.h" #include "hw/arm/fsl-imx8mp.h" #include "hw/intc/arm_gicv3.h" diff --git a/hw/arm/imx8mp-evk.c b/hw/arm/imx8mp-evk.c index b5aec06ec5..b3082fa60d 100644 --- a/hw/arm/imx8mp-evk.c +++ b/hw/arm/imx8mp-evk.c @@ -7,7 +7,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/boot.h" #include "hw/arm/fsl-imx8mp.h" #include "hw/boards.h" diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index 8aa2e6e98e..ac0c6c6096 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -16,7 +16,7 @@ #include "hw/misc/arm_integrator_debug.h" #include "hw/net/smc91c111.h" #include "net/net.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/runstate.h" #include "system/system.h" #include "qemu/log.h" diff --git a/hw/arm/kzm.c b/hw/arm/kzm.c index 08d2b3025c..362c145409 100644 --- a/hw/arm/kzm.c +++ b/hw/arm/kzm.c @@ -19,7 +19,7 @@ #include "hw/arm/boot.h" #include "hw/boards.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "net/net.h" #include "hw/net/lan9118.h" #include "hw/char/serial-mm.h" diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index 3f56fb45ce..ade363daaa 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -13,7 +13,7 @@ #include "hw/boards.h" #include "hw/arm/boot.h" #include "system/system.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/nrf51_soc.h" #include "hw/i2c/microbit_i2c.h" diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 13ed868b6b..b0633a5a69 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -54,7 +54,7 @@ #include "hw/arm/armv7m.h" #include "hw/or-irq.h" #include "hw/boards.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "system/reset.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 3f8db0cab6..6958485a66 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -33,7 +33,7 @@ #include "hw/arm/armv7m.h" #include "hw/or-irq.h" #include "hw/boards.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/qdev-properties.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/mps3r.c b/hw/arm/mps3r.c index 1bddb5e822..4dd1e8a718 100644 --- a/hw/arm/mps3r.c +++ b/hw/arm/mps3r.c @@ -28,7 +28,7 @@ #include "qemu/units.h" #include "qapi/error.h" #include "qobject/qlist.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "cpu.h" #include "system/system.h" #include "hw/boards.h" diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index e8a5b231ba..bc9b419e37 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/char/serial-mm.h" #include "hw/arm/msf2-soc.h" #include "hw/misc/unimp.h" diff --git a/hw/arm/msf2-som.c b/hw/arm/msf2-som.c index 9b20f1e2c9..29c76c6860 100644 --- a/hw/arm/msf2-som.c +++ b/hw/arm/msf2-som.c @@ -33,7 +33,7 @@ #include "hw/qdev-properties.h" #include "hw/arm/boot.h" #include "hw/qdev-clock.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/msf2-soc.h" #define DDR_BASE_ADDRESS 0xA0000000 diff --git a/hw/arm/musca.c b/hw/arm/musca.c index e9c092abc3..a4f43f1992 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -22,7 +22,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/arm/boot.h" #include "hw/arm/armsse.h" diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 3ee10b4777..91d7e3f04b 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -23,7 +23,7 @@ #include "qemu/main-loop.h" #include "qapi/error.h" #include "cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/hw.h" #include "hw/irq.h" #include "hw/qdev-properties.h" diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 24b4043183..aa1e96b3ad 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -34,7 +34,7 @@ #include "hw/arm/boot.h" #include "hw/block/flash.h" #include "system/qtest.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/cutils.h" #include "qemu/error-report.h" diff --git a/hw/arm/orangepi.c b/hw/arm/orangepi.c index 634af9b0a1..e0956880d1 100644 --- a/hw/arm/orangepi.c +++ b/hw/arm/orangepi.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/boards.h" diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index 3361111360..cbe914c93e 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -20,7 +20,7 @@ #include "net/net.h" #include "hw/boards.h" #include "qemu/log.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/arm/armv7m.h" #include "hw/char/pl011.h" diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c index 53b5636452..0eabaf8d9b 100644 --- a/hw/arm/stm32f100_soc.c +++ b/hw/arm/stm32f100_soc.c @@ -27,7 +27,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "hw/arm/boot.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/stm32f100_soc.h" #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 47a54e592b..32e96912f0 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "hw/arm/boot.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/arm/stm32f205_soc.h" #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index 18d8824f29..bba9060daf 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/arm/stm32f405_soc.h" #include "hw/qdev-clock.h" diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c index dbf75329f7..6278d354c8 100644 --- a/hw/arm/stm32l4x5_soc.c +++ b/hw/arm/stm32l4x5_soc.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/or-irq.h" #include "hw/arm/stm32l4x5_soc.h" diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index cb721c96b7..2e8b8e8c67 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -13,7 +13,7 @@ #include "qemu/units.h" #include "qapi/error.h" #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/system.h" #include "hw/qdev-properties.h" #include "hw/sysbus.h" diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c index 7374561141..f0891ffa4d 100644 --- a/hw/char/goldfish_tty.c +++ b/hw/char/goldfish_tty.c @@ -15,7 +15,7 @@ #include "chardev/char-fe.h" #include "qemu/log.h" #include "trace.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/dma.h" #include "hw/char/goldfish_tty.h" diff --git a/hw/char/omap_uart.c b/hw/char/omap_uart.c index 07fb868965..8cbf6ce803 100644 --- a/hw/char/omap_uart.c +++ b/hw/char/omap_uart.c @@ -21,7 +21,7 @@ #include "chardev/char.h" #include "hw/arm/omap.h" #include "hw/char/serial-mm.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" /* UARTs */ struct omap_uart_s { diff --git a/hw/char/riscv_htif.c b/hw/char/riscv_htif.c index ec5db5a597..c884be5d75 100644 --- a/hw/char/riscv_htif.c +++ b/hw/char/riscv_htif.c @@ -28,7 +28,7 @@ #include "chardev/char-fe.h" #include "qemu/timer.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/tswap.h" #include "system/dma.h" #include "system/runstate.h" diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 5ef8c24b5b..82b68b8927 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/cputlb.h" #include "system/memory.h" #include "exec/tb-flush.h" diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c index 7f1fb562be..a6e477a2d8 100644 --- a/hw/core/null-machine.c +++ b/hw/core/null-machine.c @@ -14,7 +14,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "hw/boards.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/core/cpu.h" static void machine_none_init(MachineState *mch) diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 98819d5dc6..6eb4c0f15a 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -21,7 +21,7 @@ #include "qapi/error.h" #include "hw/sysbus.h" #include "monitor/monitor.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *sysbus_get_fw_dev_path(DeviceState *dev); diff --git a/hw/display/apple-gfx.m b/hw/display/apple-gfx.m index c4323574e1..2ff1c90df7 100644 --- a/hw/display/apple-gfx.m +++ b/hw/display/apple-gfx.m @@ -18,7 +18,7 @@ #include "qapi/visitor.h" #include "qapi/error.h" #include "block/aio-wait.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/dma.h" #include "migration/blocker.h" #include "ui/console.h" diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 5bf54347ed..6842e7d491 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -32,7 +32,7 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "qemu/module.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c index 6f33c3e741..0b1da723c8 100644 --- a/hw/hyperv/hv-balloon.c +++ b/hw/hyperv/hv-balloon.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "hv-balloon-internal.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/cpu-common.h" #include "exec/ramblock.h" #include "hw/boards.h" diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 382c62d668..d21e428eae 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -11,7 +11,7 @@ #include "qemu/main-loop.h" #include "qemu/module.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/memory.h" #include "system/kvm.h" #include "qemu/bitops.h" diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index 9b8b092bc2..f9223ef1a1 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -23,7 +23,7 @@ #include "qobject/qdict.h" #include "qom/object.h" #include "exec/target_page.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/vmstate.h" #include "trace.h" diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c index 7b843a72b1..430ba62896 100644 --- a/hw/i386/kvm/xen_gnttab.c +++ b/hw/i386/kvm/xen_gnttab.c @@ -17,7 +17,7 @@ #include "qapi/error.h" #include "qom/object.h" #include "exec/target_page.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/vmstate.h" #include "hw/sysbus.h" diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c index db9aa7942d..a2b26e9906 100644 --- a/hw/i386/kvm/xen_overlay.c +++ b/hw/i386/kvm/xen_overlay.c @@ -16,7 +16,7 @@ #include "qapi/error.h" #include "qom/object.h" #include "exec/target_page.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/vmstate.h" #include "hw/sysbus.h" diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c index 875e1c5c33..00b220d4d6 100644 --- a/hw/i386/sgx-epc.c +++ b/hw/i386/sgx-epc.c @@ -17,7 +17,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "target/i386/cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" static const Property sgx_epc_properties[] = { DEFINE_PROP_UINT64(SGX_EPC_ADDR_PROP, SGXEPCDevice, addr, 0), diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index e665e2111c..5685c4fb80 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -20,7 +20,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qapi/qapi-commands-misc-target.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/hw_accel.h" #include "system/reset.h" #include diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c index 14de9b7a82..26aae64e5d 100644 --- a/hw/i386/vapic.c +++ b/hw/i386/vapic.c @@ -16,7 +16,7 @@ #include "system/hw_accel.h" #include "system/kvm.h" #include "system/runstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/i386/apic_internal.h" #include "hw/sysbus.h" #include "hw/boards.h" diff --git a/hw/ide/ahci-sysbus.c b/hw/ide/ahci-sysbus.c index 03a5bd42d0..3c1935d81c 100644 --- a/hw/ide/ahci-sysbus.c +++ b/hw/ide/ahci-sysbus.c @@ -22,7 +22,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index d9f8c36778..987034efd3 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -29,7 +29,7 @@ #include "hw/input/lasips2.h" #include "exec/hwaddr.h" #include "trace.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/vmstate.h" #include "hw/irq.h" #include "qapi/error.h" diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index a51a215e6e..a558c50185 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -11,7 +11,7 @@ #include "qapi/error.h" #include "hw/irq.h" #include "hw/loongarch/virt.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/intc/loongarch_extioi.h" #include "trace.h" diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index 5964cde7e0..789c4a4d6e 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -22,7 +22,7 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "qemu/bswap.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/sysbus.h" #include "hw/pci/msi.h" #include "hw/boards.h" diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index 241b12fef0..852f413e5a 100644 --- a/hw/intc/riscv_imsic.c +++ b/hw/intc/riscv_imsic.c @@ -22,7 +22,7 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "qemu/bswap.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/sysbus.h" #include "hw/pci/msi.h" #include "hw/boards.h" diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 65c9027feb..f1eb42c2c1 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -18,7 +18,7 @@ #include "system/reset.h" #include "system/rtc.h" #include "hw/loongarch/virt.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/irq.h" #include "net/net.h" #include "hw/loader.h" diff --git a/hw/mem/memory-device.c b/hw/mem/memory-device.c index 1de8dfec7d..1a432e9bd2 100644 --- a/hw/mem/memory-device.c +++ b/hw/mem/memory-device.c @@ -17,7 +17,7 @@ #include "qemu/range.h" #include "hw/virtio/vhost.h" #include "system/kvm.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" static bool memory_device_is_empty(const MemoryDeviceState *md) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index 21ad215e44..c887c7a99e 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -36,7 +36,7 @@ #include "hw/boards.h" #include "hw/char/serial-mm.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/ssi/ssi.h" #include "boot.h" diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index bdba2006b7..f976c90bd2 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -33,7 +33,7 @@ #include "system/system.h" #include "hw/boards.h" #include "hw/misc/unimp.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/char/xilinx_uartlite.h" #include "boot.h" diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index bdbf7328bf..0922c65295 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "cpu.h" #include "boot.h" diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index c530688e76..b6dabf2893 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -28,7 +28,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/datadir.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/clock.h" #include "hw/mips/mips.h" #include "hw/char/serial-mm.h" diff --git a/hw/misc/allwinner-h3-dramc.c b/hw/misc/allwinner-h3-dramc.c index c4f3eb9274..74ff71b753 100644 --- a/hw/misc/allwinner-h3-dramc.c +++ b/hw/misc/allwinner-h3-dramc.c @@ -24,7 +24,7 @@ #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "hw/misc/allwinner-h3-dramc.h" diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 96e1848c21..5908a059e8 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -24,7 +24,7 @@ #include "migration/vmstate.h" #include "qemu/log.h" #include "qemu/module.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "qapi/error.h" #include "qemu/bitops.h" diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c index 40309a8ff3..076c4b42de 100644 --- a/hw/misc/ivshmem-flat.c +++ b/hw/misc/ivshmem-flat.c @@ -17,7 +17,7 @@ #include "hw/qdev-properties-system.h" #include "hw/sysbus.h" #include "chardev/char-fe.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" #include "hw/misc/ivshmem-flat.h" diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 03b1feda50..3c0819c58a 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -16,7 +16,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/vmstate.h" #include "hw/sysbus.h" #include "hw/irq.h" diff --git a/hw/net/i82596.c b/hw/net/i82596.c index ee919dab3c..64ed3c8390 100644 --- a/hw/net/i82596.c +++ b/hw/net/i82596.c @@ -15,7 +15,7 @@ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/module.h" #include "trace.h" #include "i82596.h" diff --git a/hw/net/i82596.h b/hw/net/i82596.h index 4bdfcaf856..dc1fa1a1dc 100644 --- a/hw/net/i82596.h +++ b/hw/net/i82596.h @@ -4,7 +4,7 @@ #define I82596_IOPORT_SIZE 0x20 #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #define PORT_RESET 0x00 /* reset 82596 */ #define PORT_SELFTEST 0x01 /* selftest */ diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index a757939cfb..cbfb2b5303 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -27,7 +27,7 @@ #include "system/system.h" #include "system/dma.h" #include "system/reset.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "hw/nvram/fw_cfg.h" #include "hw/qdev-properties.h" diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index 83d7c2a8af..c2284a7d41 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -28,7 +28,7 @@ #include "net/net.h" #include "hw/openrisc/boot.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/device_tree.h" #include "system/system.h" #include "hw/sysbus.h" diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 3055306783..0d1c1f103c 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -11,7 +11,7 @@ #include "qemu/guest-random.h" #include "qapi/error.h" #include "cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/irq.h" #include "hw/boards.h" #include "hw/char/serial-mm.h" diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index 9c41c155fb..a297318c6e 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -17,7 +17,7 @@ #include "hw/irq.h" #include "hw/intc/i8259.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/log.h" #include "qemu/error-report.h" #include "trace.h" diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 246d6d633b..7b2dc6985c 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -31,7 +31,7 @@ #include "qemu/error-report.h" #include "system/kvm.h" #include "kvm_ppc.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/qom-qobject.h" #include "qobject/qdict.h" #include "trace.h" diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 1fe11dde50..f832ee61e8 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -18,7 +18,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/irq.h" #include "target/ppc/cpu.h" #include "qemu/log.h" diff --git a/hw/ppc/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c index 562bff8d53..bf0faad9e7 100644 --- a/hw/ppc/ppc4xx_sdram.c +++ b/hw/ppc/ppc4xx_sdram.c @@ -34,7 +34,7 @@ #include "qapi/error.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" /* get_system_memory() */ +#include "system/address-spaces.h" /* get_system_memory() */ #include "hw/irq.h" #include "hw/qdev-properties.h" #include "hw/ppc/ppc4xx.h" diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c index b1f2e130f0..08f29e72e4 100644 --- a/hw/ppc/prep_systemio.c +++ b/hw/ppc/prep_systemio.c @@ -28,7 +28,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #include "qemu/error-report.h" /* for error_report() */ #include "qemu/module.h" diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c index 0e5d53b8b6..27f1c90f06 100644 --- a/hw/ppc/rs6000_mc.c +++ b/hw/ppc/rs6000_mc.c @@ -24,7 +24,7 @@ #include "hw/isa/isa.h" #include "hw/qdev-properties.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qapi/error.h" #include "trace.h" #include "qom/object.h" diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c index 88e29536aa..6d6eaf67cb 100644 --- a/hw/ppc/spapr_ovec.c +++ b/hw/ppc/spapr_ovec.c @@ -15,7 +15,7 @@ #include "hw/ppc/spapr_ovec.h" #include "migration/vmstate.h" #include "qemu/bitmap.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/error-report.h" #include "trace.h" #include diff --git a/hw/ppc/vof.c b/hw/ppc/vof.c index 09cb77de93..f14efa3a7c 100644 --- a/hw/ppc/vof.c +++ b/hw/ppc/vof.c @@ -15,7 +15,7 @@ #include "qemu/units.h" #include "qemu/log.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/ppc/vof.h" #include "hw/ppc/fdt.h" #include "system/runstate.h" diff --git a/hw/remote/iommu.c b/hw/remote/iommu.c index ec845d1f58..3e0758a21e 100644 --- a/hw/remote/iommu.c +++ b/hw/remote/iommu.c @@ -14,7 +14,7 @@ #include "hw/pci/pci_bus.h" #include "hw/pci/pci.h" #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" /** diff --git a/hw/riscv/microblaze-v-generic.c b/hw/riscv/microblaze-v-generic.c index d8e67906d2..e863c50cbc 100644 --- a/hw/riscv/microblaze-v-generic.c +++ b/hw/riscv/microblaze-v-generic.c @@ -22,7 +22,7 @@ #include "net/net.h" #include "hw/boards.h" #include "hw/char/serial-mm.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/char/xilinx_uartlite.h" #include "hw/misc/unimp.h" diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 98a67fe52a..019d6b3986 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -28,7 +28,7 @@ #include "hw/riscv/boot.h" #include "qemu/units.h" #include "system/system.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" /* * This version of the OpenTitan machine currently supports diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index e2242b97d0..17c5c72102 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -25,7 +25,7 @@ #include "hw/intc/riscv_aclint.h" #include "system/system.h" #include "hw/qdev-properties.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/riscv/boot.h" static const struct MemmapEntry { diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 17afcbb2cd..53444f6828 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -14,7 +14,7 @@ #include "qapi/visitor.h" #include "qemu/bitops.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/s390x/ioinst.h" #include "hw/qdev-properties.h" #include "hw/s390x/css.h" diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 8e3882d506..c6ecb3433c 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -14,7 +14,7 @@ #define HW_S390_IPL_H #include "cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-core.h" #include "hw/s390x/ipl/qipl.h" #include "qom/object.h" diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 067ea03726..0bb90fed04 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -20,7 +20,7 @@ #include "qobject/qdict.h" #include "qemu/error-report.h" #include "system/memory_mapping.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/kvm.h" #include "migration/qemu-file-types.h" #include "migration/register.h" diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 43f3b162c8..e8ecb90826 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/kvm.h" #include "net/net.h" #include "hw/virtio/virtio.h" diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c index 5a4c1f5e3b..4a542b18d2 100644 --- a/hw/sparc/sun4m_iommu.c +++ b/hw/sparc/sun4m_iommu.c @@ -29,7 +29,7 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/module.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" /* diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index eba811af0c..533fcae1fb 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -27,7 +27,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/sparc/sun4u_iommu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index ccb97b6806..ea82472105 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -36,7 +36,7 @@ #include "hw/rtc/mc146818rtc_regs.h" #include "migration/vmstate.h" #include "hw/timer/i8254.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #include "trace.h" diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 6cdeb72df0..b668aee97a 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -18,7 +18,7 @@ #include "qemu/module.h" #include "qapi/error.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "hw/pci/pci_ids.h" #include "hw/acpi/tpm.h" diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index c7ab4ff57a..d6575d7c44 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -28,7 +28,7 @@ #include "migration/vmstate.h" #include "hw/qdev-properties.h" #include "hw/s390x/ap-bridge.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #define TYPE_VFIO_AP_DEVICE "vfio-ap" diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index e5e0d9e3e7..29e804e122 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -27,7 +27,7 @@ #include "hw/s390x/vfio-ccw.h" #include "hw/qdev-properties.h" #include "hw/s390x/ccw-device.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "qemu/module.h" diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 989c6ee83d..98832af88d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -27,7 +27,7 @@ #include "hw/vfio/vfio-common.h" #include "hw/vfio/pci.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/memory.h" #include "exec/ram_addr.h" #include "exec/target_page.h" diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 1d1c5f9a77..2e993c7e73 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -23,7 +23,7 @@ #include #include "hw/vfio/vfio-common.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/memory.h" #include "exec/ram_addr.h" #include "qemu/error-report.h" diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 96c6bf5654..c6edbdd4ae 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -29,7 +29,7 @@ #include "qemu/module.h" #include "qemu/range.h" #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/queue.h" #include "hw/sysbus.h" #include "trace.h" diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 1a5d1611f2..c9a7dd8d68 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -13,7 +13,7 @@ #include #include "system/kvm.h" #include "system/hostmem.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/vfio/vfio-common.h" #include "hw/hw.h" diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 7efbde3d4c..1e0336df1d 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -20,7 +20,7 @@ #include "hw/virtio/virtio-net.h" #include "hw/virtio/vhost-shadow-virtqueue.h" #include "hw/virtio/vhost-vdpa.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "migration/blocker.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 2eb5a14fa2..0d0603c674 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -24,7 +24,7 @@ #include "hw/boards.h" #include "system/balloon.h" #include "hw/virtio/virtio-balloon.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qapi/error.h" #include "qapi/qapi-events-machine.h" #include "qapi/visitor.h" diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index 896feb37a1..d1c79c567b 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -28,7 +28,7 @@ #include "qapi/error.h" #include "hw/virtio/virtio-bus.h" #include "hw/virtio/virtio.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" /* #define DEBUG_VIRTIO_BUS */ diff --git a/include/hw/misc/lasi.h b/include/hw/misc/lasi.h index f01c0f680a..0bdfb11b50 100644 --- a/include/hw/misc/lasi.h +++ b/include/hw/misc/lasi.h @@ -12,7 +12,7 @@ #ifndef LASI_H #define LASI_H -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/pci/pci_host.h" #include "hw/boards.h" diff --git a/include/hw/nubus/nubus.h b/include/hw/nubus/nubus.h index fee79b71d1..7825840dca 100644 --- a/include/hw/nubus/nubus.h +++ b/include/hw/nubus/nubus.h @@ -11,7 +11,7 @@ #include "hw/qdev-properties.h" #include "hw/sysbus.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #include "qemu/units.h" diff --git a/include/hw/ppc/vof.h b/include/hw/ppc/vof.h index 2918aaab12..3a0fbffe54 100644 --- a/include/hw/ppc/vof.h +++ b/include/hw/ppc/vof.h @@ -7,7 +7,7 @@ #define HW_VOF_H #include "qom/object.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/memory.h" #include "exec/cpu-defs.h" diff --git a/include/hw/tricore/triboard.h b/include/hw/tricore/triboard.h index 8250470643..ca49a0c752 100644 --- a/include/hw/tricore/triboard.h +++ b/include/hw/tricore/triboard.h @@ -21,7 +21,7 @@ #include "qapi/error.h" #include "hw/boards.h" #include "system/system.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qom/object.h" #include "hw/tricore/tc27x_soc.h" diff --git a/include/exec/address-spaces.h b/include/system/address-spaces.h similarity index 89% rename from include/exec/address-spaces.h rename to include/system/address-spaces.h index 0d0aa61d68..72d17afb0f 100644 --- a/include/exec/address-spaces.h +++ b/include/system/address-spaces.h @@ -11,16 +11,14 @@ * */ -#ifndef EXEC_ADDRESS_SPACES_H -#define EXEC_ADDRESS_SPACES_H +#ifndef SYSTEM_ADDRESS_SPACES_H +#define SYSTEM_ADDRESS_SPACES_H /* * Internal interfaces between memory.c/exec.c/vl.c. Do not #include unless * you're one of them. */ -#ifndef CONFIG_USER_ONLY - /* Get the root memory region. This interface should only be used temporarily * until a proper bus interface is available. */ @@ -35,5 +33,3 @@ extern AddressSpace address_space_memory; extern AddressSpace address_space_io; #endif - -#endif diff --git a/include/system/dma.h b/include/system/dma.h index aaa03b9711..82e7ad5437 100644 --- a/include/system/dma.h +++ b/include/system/dma.h @@ -11,7 +11,7 @@ #define DMA_H #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "block/block.h" #include "block/accounting.h" diff --git a/monitor/hmp-cmds-target.c b/monitor/hmp-cmds-target.c index 6654d31406..011a367357 100644 --- a/monitor/hmp-cmds-target.c +++ b/monitor/hmp-cmds-target.c @@ -24,7 +24,7 @@ #include "qemu/osdep.h" #include "disas/disas.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "system/memory.h" #include "monitor/hmp-target.h" #include "monitor/monitor-internal.h" diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 7ded3378cf..8ddcdd76c1 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -14,7 +14,7 @@ */ #include "qemu/osdep.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/ioport.h" #include "exec/gdbstub.h" #include "gdbstub/enums.h" diff --git a/rust/wrapper.h b/rust/wrapper.h index 94866b7e32..beddd9aab2 100644 --- a/rust/wrapper.h +++ b/rust/wrapper.h @@ -64,5 +64,5 @@ typedef enum memory_order { #include "chardev/char-serial.h" #include "exec/memattrs.h" #include "qemu/timer.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/char/pl011.h" diff --git a/system/ioport.c b/system/ioport.c index 2291739039..5300716464 100644 --- a/system/ioport.c +++ b/system/ioport.c @@ -28,7 +28,7 @@ #include "qemu/osdep.h" #include "exec/ioport.h" #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "trace.h" struct MemoryRegionPortioList { diff --git a/system/memory.c b/system/memory.c index 2865d0deb1..a4185ea353 100644 --- a/system/memory.c +++ b/system/memory.c @@ -33,7 +33,7 @@ #include "qemu/accel.h" #include "hw/boards.h" #include "migration/vmstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" //#define DEBUG_UNASSIGNED diff --git a/system/memory_mapping.c b/system/memory_mapping.c index 8538a8241e..da708a08ab 100644 --- a/system/memory_mapping.c +++ b/system/memory_mapping.c @@ -17,7 +17,7 @@ #include "system/memory_mapping.h" #include "system/memory.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/core/cpu.h" //#define DEBUG_GUEST_PHYS_REGION_ADD diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 2439af63a0..93a3f9b53d 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -22,7 +22,7 @@ #include -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "hw/irq.h" #include "qemu/main-loop.h" diff --git a/target/arm/kvm.c b/target/arm/kvm.c index da30bdbb23..97de8c7e93 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -30,7 +30,7 @@ #include "internals.h" #include "hw/pci/pci.h" #include "exec/memattrs.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "gdbstub/enums.h" #include "hw/boards.h" #include "hw/irq.h" diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 0b14b36c17..1121822470 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -23,7 +23,7 @@ #include "qemu/qemu-print.h" #include "exec/exec-all.h" #include "exec/translation-block.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "cpu.h" #include "disas/dis-asm.h" #include "tcg/debug-assert.h" diff --git a/target/i386/cpu-apic.c b/target/i386/cpu-apic.c index c1708b04bb..242a05fdbe 100644 --- a/target/i386/cpu-apic.c +++ b/target/i386/cpu-apic.c @@ -14,7 +14,7 @@ #include "system/hw_accel.h" #include "system/kvm.h" #include "system/xen.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/qdev-properties.h" #include "hw/i386/apic_internal.h" #include "cpu-internal.h" diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 3fb1ec62da..5c9f80b4cc 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -38,7 +38,7 @@ #ifndef CONFIG_USER_ONLY #include "system/reset.h" #include "qapi/qapi-commands-machine-target.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "hw/i386/sgx-epc.h" #endif diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 3c56afc9d3..029516e5c0 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -33,7 +33,7 @@ #include "system/hvf.h" #include "system/hvf_int.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" static inline uint64_t rreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg) { diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c index e81a245881..b23010374f 100644 --- a/target/i386/kvm/xen-emu.c +++ b/target/i386/kvm/xen-emu.c @@ -17,7 +17,7 @@ #include "system/kvm_int.h" #include "system/kvm_xen.h" #include "kvm/kvm_i386.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "xen-emu.h" #include "trace.h" #include "system/runstate.h" diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 04e5f7e637..91f0e32366 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -9,7 +9,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/ioport.h" #include "qemu/accel.h" #include "system/nvmm.h" diff --git a/target/i386/sev.c b/target/i386/sev.c index 0e1dbb6959..ba88976e9f 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -39,7 +39,7 @@ #include "qapi/qapi-commands-misc-target.h" #include "confidential-guest.h" #include "hw/i386/pc.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "qemu/queue.h" OBJECT_DECLARE_TYPE(SevCommonState, SevCommonStateClass, SEV_COMMON) diff --git a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/misc_helper.c index ce18c75b9f..0555cf2604 100644 --- a/target/i386/tcg/system/misc_helper.c +++ b/target/i386/tcg/system/misc_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/cputlb.h" #include "tcg/helper-tcg.h" #include "hw/i386/apic.h" diff --git a/target/i386/tcg/system/tcg-cpu.c b/target/i386/tcg/system/tcg-cpu.c index 13a3507863..ab1f3c7c59 100644 --- a/target/i386/tcg/system/tcg-cpu.c +++ b/target/i386/tcg/system/tcg-cpu.c @@ -23,7 +23,7 @@ #include "system/system.h" #include "qemu/units.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "tcg/tcg-cpu.h" diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 41fb8c5a4e..d58cb11cee 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/ioport.h" #include "gdbstub/helpers.h" #include "qemu/accel.h" diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index f0e3cfef03..1bda570482 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -18,7 +18,7 @@ #include "system/kvm_int.h" #include "hw/pci/pci.h" #include "exec/memattrs.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "hw/irq.h" #include "hw/loongarch/virt.h" diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 0f4997a918..5315134e08 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -35,7 +35,7 @@ #include "accel/accel-cpu-target.h" #include "hw/pci/pci.h" #include "exec/memattrs.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/boards.h" #include "hw/irq.h" #include "hw/intc/riscv_imsic.h" diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index d8f483898d..b079d120db 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -17,7 +17,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "cpu.h" #include "s390x-internal.h" #include "kvm/kvm_s390x.h" diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c index 6a4d9c5081..a3347f1236 100644 --- a/target/s390x/sigp.c +++ b/target/s390x/sigp.c @@ -14,7 +14,7 @@ #include "hw/boards.h" #include "system/hw_accel.h" #include "system/runstate.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "exec/cputlb.h" #include "exec/exec-all.h" #include "system/tcg.h" diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index f969850f87..ac733f407f 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -28,7 +28,7 @@ #include "tcg_s390x.h" #ifndef CONFIG_USER_ONLY #include "qemu/timer.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" #include "hw/s390x/ioinst.h" #include "hw/s390x/s390_flic.h" #include "hw/boards.h" diff --git a/target/xtensa/dbg_helper.c b/target/xtensa/dbg_helper.c index 5546c82ecd..163a1ffc7b 100644 --- a/target/xtensa/dbg_helper.c +++ b/target/xtensa/dbg_helper.c @@ -31,7 +31,7 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" -#include "exec/address-spaces.h" +#include "system/address-spaces.h" void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) { From 91a853837da22e35d140471058e5d73dbfa87707 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 12:49:38 -0700 Subject: [PATCH 0115/2760] include/system: Move exec/ioport.h to system/ioport.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing includes with sed. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- MAINTAINERS | 2 +- hw/block/fdc-isa.c | 2 +- hw/display/vga_int.h | 2 +- include/hw/char/parallel-isa.h | 2 +- include/hw/dma/i8257.h | 2 +- include/hw/ide/ide-bus.h | 2 +- include/hw/isa/isa.h | 2 +- include/{exec => system}/ioport.h | 6 ++---- monitor/hmp-cmds.c | 2 +- system/ioport.c | 2 +- system/physmem.c | 2 +- system/qtest.c | 2 +- target/i386/nvmm/nvmm-all.c | 2 +- target/i386/whpx/whpx-all.c | 2 +- tests/qtest/fuzz/qtest_wrappers.c | 2 +- 15 files changed, 16 insertions(+), 18 deletions(-) rename include/{exec => system}/ioport.h (97%) diff --git a/MAINTAINERS b/MAINTAINERS index 5d391cfaa7..9a96cc1b5e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3118,7 +3118,7 @@ M: Peter Xu M: David Hildenbrand R: Philippe Mathieu-Daudé S: Supported -F: include/exec/ioport.h +F: include/system/ioport.h F: include/exec/memop.h F: include/system/memory.h F: include/exec/ram_addr.h diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c index a10c24aab1..561cfa47c1 100644 --- a/hw/block/fdc-isa.c +++ b/hw/block/fdc-isa.c @@ -42,7 +42,7 @@ #include "system/block-backend.h" #include "system/blockdev.h" #include "system/system.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/module.h" diff --git a/hw/display/vga_int.h b/hw/display/vga_int.h index 60ad26e03e..747b5cc6cf 100644 --- a/hw/display/vga_int.h +++ b/hw/display/vga_int.h @@ -26,7 +26,7 @@ #define HW_VGA_INT_H #include "ui/console.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "system/memory.h" #include "hw/display/bochs-vbe.h" diff --git a/include/hw/char/parallel-isa.h b/include/hw/char/parallel-isa.h index 5284b2ffec..3edaf9dbe4 100644 --- a/include/hw/char/parallel-isa.h +++ b/include/hw/char/parallel-isa.h @@ -12,7 +12,7 @@ #include "parallel.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "hw/isa/isa.h" #include "qom/object.h" diff --git a/include/hw/dma/i8257.h b/include/hw/dma/i8257.h index 4342e4a91e..33b6286d5a 100644 --- a/include/hw/dma/i8257.h +++ b/include/hw/dma/i8257.h @@ -2,7 +2,7 @@ #define HW_I8257_H #include "hw/isa/isa.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "qom/object.h" #define TYPE_I8257 "i8257" diff --git a/include/hw/ide/ide-bus.h b/include/hw/ide/ide-bus.h index 4841a7dcd6..121b455fcd 100644 --- a/include/hw/ide/ide-bus.h +++ b/include/hw/ide/ide-bus.h @@ -1,7 +1,7 @@ #ifndef HW_IDE_BUS_H #define HW_IDE_BUS_H -#include "exec/ioport.h" +#include "system/ioport.h" #include "hw/ide/ide-dev.h" #include "hw/ide/ide-dma.h" diff --git a/include/hw/isa/isa.h b/include/hw/isa/isa.h index 1d852011b3..a82c5f1004 100644 --- a/include/hw/isa/isa.h +++ b/include/hw/isa/isa.h @@ -4,7 +4,7 @@ /* ISA bus */ #include "system/memory.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "hw/qdev-core.h" #include "qom/object.h" diff --git a/include/exec/ioport.h b/include/system/ioport.h similarity index 97% rename from include/exec/ioport.h rename to include/system/ioport.h index ecea3575bc..780ea5a676 100644 --- a/include/exec/ioport.h +++ b/include/system/ioport.h @@ -21,8 +21,8 @@ * IO ports API */ -#ifndef IOPORT_H -#define IOPORT_H +#ifndef SYSTEM_IOPORT_H +#define SYSTEM_IOPORT_H #include "system/memory.h" @@ -39,9 +39,7 @@ typedef struct MemoryRegionPortio { #define PORTIO_END_OF_LIST() { } -#ifndef CONFIG_USER_ONLY extern const MemoryRegionOps unassigned_io_ops; -#endif void cpu_outb(uint32_t addr, uint8_t val); void cpu_outw(uint32_t addr, uint16_t val); diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c index 8ddcdd76c1..74a0f56566 100644 --- a/monitor/hmp-cmds.c +++ b/monitor/hmp-cmds.c @@ -15,7 +15,7 @@ #include "qemu/osdep.h" #include "system/address-spaces.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "exec/gdbstub.h" #include "gdbstub/enums.h" #include "monitor/hmp.h" diff --git a/system/ioport.c b/system/ioport.c index 5300716464..4f96e9119f 100644 --- a/system/ioport.c +++ b/system/ioport.c @@ -26,7 +26,7 @@ */ #include "qemu/osdep.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "system/memory.h" #include "system/address-spaces.h" #include "trace.h" diff --git a/system/physmem.c b/system/physmem.c index e61fea41b5..234e489199 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -51,7 +51,7 @@ #include "qemu/memalign.h" #include "qemu/memfd.h" #include "system/memory.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "system/dma.h" #include "system/hostmem.h" #include "system/hw_accel.h" diff --git a/system/qtest.c b/system/qtest.c index 5407289154..523a047995 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -16,7 +16,7 @@ #include "system/qtest.h" #include "system/runstate.h" #include "chardev/char-fe.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "system/memory.h" #include "exec/tswap.h" #include "hw/qdev-core.h" diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 91f0e32366..17394d073d 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -10,7 +10,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "system/address-spaces.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "qemu/accel.h" #include "system/nvmm.h" #include "system/cpus.h" diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index d58cb11cee..b64852e13e 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "system/address-spaces.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "gdbstub/helpers.h" #include "qemu/accel.h" #include "system/whpx.h" diff --git a/tests/qtest/fuzz/qtest_wrappers.c b/tests/qtest/fuzz/qtest_wrappers.c index 0580f8df86..d7adcbe3fd 100644 --- a/tests/qtest/fuzz/qtest_wrappers.c +++ b/tests/qtest/fuzz/qtest_wrappers.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "hw/core/cpu.h" -#include "exec/ioport.h" +#include "system/ioport.h" #include "fuzz.h" From 4705a71db5909ac5586e87397b2dece132b9e330 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 17:42:03 -0700 Subject: [PATCH 0116/2760] include/system: Move exec/ram_addr.h to system/ram_addr.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing includes with sed. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- MAINTAINERS | 2 +- accel/kvm/kvm-all.c | 2 +- accel/tcg/cputlb.c | 2 +- accel/tcg/translate-all.c | 2 +- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_caps.c | 2 +- hw/ppc/spapr_pci.c | 2 +- hw/remote/memory.c | 2 +- hw/remote/proxy-memory-listener.c | 2 +- hw/s390x/s390-stattrib-kvm.c | 2 +- hw/s390x/s390-stattrib.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- hw/vfio/common.c | 3 +-- hw/vfio/container.c | 2 +- hw/vfio/spapr.c | 2 +- hw/virtio/virtio-mem.c | 2 +- include/{exec => system}/ram_addr.h | 7 +++---- migration/ram.c | 2 +- system/memory.c | 2 +- system/physmem.c | 2 +- target/arm/tcg/mte_helper.c | 2 +- target/ppc/kvm.c | 2 +- target/s390x/kvm/kvm.c | 2 +- 23 files changed, 25 insertions(+), 27 deletions(-) rename include/{exec => system}/ram_addr.h (99%) diff --git a/MAINTAINERS b/MAINTAINERS index 9a96cc1b5e..b1ac3ff7d2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3121,7 +3121,7 @@ S: Supported F: include/system/ioport.h F: include/exec/memop.h F: include/system/memory.h -F: include/exec/ram_addr.h +F: include/system/ram_addr.h F: include/exec/ramblock.h F: include/system/memory_mapping.h F: system/dma-helpers.c diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 9e06a95f75..a30b19f455 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -34,7 +34,7 @@ #include "system/accel-blocker.h" #include "qemu/bswap.h" #include "system/memory.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qemu/event_notifier.h" #include "qemu/main-loop.h" #include "trace.h" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 6f0ea9067b..134e523cab 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -27,7 +27,7 @@ #include "exec/cputlb.h" #include "exec/tb-flush.h" #include "exec/memory-internal.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "exec/mmu-access-type.h" #include "exec/tlb-common.h" #include "exec/vaddr.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 16e5043597..167535bcb1 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -40,7 +40,7 @@ #endif #endif #else -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #endif #include "exec/cputlb.h" diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 6fef1d167a..c1a7ac3536 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -77,7 +77,7 @@ #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/vhost-scsi-common.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "system/confidential-guest-support.h" #include "hw/usb.h" #include "qemu/config-file.h" diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 815c94ed2f..f2f5722d8a 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -27,7 +27,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "system/hw_accel.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "target/ppc/cpu.h" #include "target/ppc/mmu-hash64.h" #include "cpu-models.h" diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index e0a9d50edc..384269b831 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -34,7 +34,7 @@ #include "hw/pci/pci_host.h" #include "hw/ppc/spapr.h" #include "hw/pci-host/spapr.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include #include "trace.h" #include "qemu/error-report.h" diff --git a/hw/remote/memory.c b/hw/remote/memory.c index 6d60da91e0..00193a552f 100644 --- a/hw/remote/memory.c +++ b/hw/remote/memory.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "hw/remote/memory.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qapi/error.h" static void remote_sysmem_reset(void) diff --git a/hw/remote/proxy-memory-listener.c b/hw/remote/proxy-memory-listener.c index ce7f5b9bfb..30ac74961d 100644 --- a/hw/remote/proxy-memory-listener.c +++ b/hw/remote/proxy-memory-listener.c @@ -12,7 +12,7 @@ #include "qemu/range.h" #include "system/memory.h" #include "exec/cpu-common.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/remote/mpqemu-link.h" diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c index d0ff04364d..ebcd56368f 100644 --- a/hw/s390x/s390-stattrib-kvm.c +++ b/hw/s390x/s390-stattrib-kvm.c @@ -16,7 +16,7 @@ #include "qemu/error-report.h" #include "system/kvm.h" #include "system/memory_mapping.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "kvm/kvm_s390x.h" #include "qapi/error.h" diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index 35bf697ef0..a86002be6a 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -16,7 +16,7 @@ #include "hw/qdev-properties.h" #include "hw/s390x/storage-attributes.h" #include "qemu/error-report.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qapi/error.h" #include "qobject/qdict.h" #include "cpu.h" diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 5af3c4f547..52c273b3de 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "system/confidential-guest-support.h" #include "hw/boards.h" #include "hw/s390x/sclp.h" diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 98832af88d..bae0633c3d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -29,8 +29,7 @@ #include "hw/vfio/pci.h" #include "system/address-spaces.h" #include "system/memory.h" -#include "exec/ram_addr.h" -#include "exec/target_page.h" +#include "system/ram_addr.h" #include "hw/hw.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 2e993c7e73..812d5edbcf 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -25,7 +25,7 @@ #include "hw/vfio/vfio-common.h" #include "system/address-spaces.h" #include "system/memory.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qemu/error-report.h" #include "qemu/range.h" #include "system/reset.h" diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index c9a7dd8d68..66a2d2bb0d 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -17,7 +17,7 @@ #include "hw/vfio/vfio-common.h" #include "hw/hw.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "trace.h" diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 5f57eccbb6..c7968ee0c6 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -24,7 +24,7 @@ #include "hw/virtio/virtio-mem.h" #include "qapi/error.h" #include "qapi/visitor.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "migration/misc.h" #include "hw/boards.h" #include "hw/qdev-properties.h" diff --git a/include/exec/ram_addr.h b/include/system/ram_addr.h similarity index 99% rename from include/exec/ram_addr.h rename to include/system/ram_addr.h index 8677761af5..3b81c3091f 100644 --- a/include/exec/ram_addr.h +++ b/include/system/ram_addr.h @@ -16,10 +16,9 @@ * The functions declared here will be removed soon. */ -#ifndef RAM_ADDR_H -#define RAM_ADDR_H +#ifndef SYSTEM_RAM_ADDR_H +#define SYSTEM_RAM_ADDR_H -#ifndef CONFIG_USER_ONLY #include "system/xen.h" #include "system/tcg.h" #include "exec/cputlb.h" @@ -559,5 +558,5 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb, return num_dirty; } -#endif + #endif diff --git a/migration/ram.c b/migration/ram.c index 424df6d9f1..6295f675df 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -48,7 +48,7 @@ #include "qapi/qapi-commands-migration.h" #include "qapi/qmp/qerror.h" #include "trace.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "exec/target_page.h" #include "qemu/rcu_queue.h" #include "migration/colo.h" diff --git a/system/memory.c b/system/memory.c index a4185ea353..6a5d853071 100644 --- a/system/memory.c +++ b/system/memory.c @@ -26,7 +26,7 @@ #include "trace.h" #include "exec/memory-internal.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "system/kvm.h" #include "system/runstate.h" #include "system/tcg.h" diff --git a/system/physmem.c b/system/physmem.c index 234e489199..307d0764b6 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -67,7 +67,7 @@ #include "system/replay.h" #include "exec/memory-internal.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "qemu/pmem.h" diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 5d6d8a17ae..80164a8050 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -27,7 +27,7 @@ #include "user/cpu_loop.h" #include "user/page-protection.h" #else -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #endif #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 992356cb75..8b12b8e7d2 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -41,7 +41,7 @@ #include "trace.h" #include "gdbstub/enums.h" #include "exec/memattrs.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "system/hostmem.h" #include "qemu/cutils.h" #include "qemu/main-loop.h" diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 4d56e653dd..b9f1422197 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -41,7 +41,7 @@ #include "system/runstate.h" #include "system/device_tree.h" #include "gdbstub/enums.h" -#include "exec/ram_addr.h" +#include "system/ram_addr.h" #include "trace.h" #include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-bus.h" From 548a01650c9be153b352406cd4afb86cb350788e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 19:03:02 -0700 Subject: [PATCH 0117/2760] include/system: Move exec/ramblock.h to system/ramblock.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert the existing includes with sed. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- MAINTAINERS | 2 +- hw/display/virtio-gpu-udmabuf.c | 2 +- hw/hyperv/hv-balloon.c | 2 +- hw/virtio/vhost-user.c | 2 +- include/system/ram_addr.h | 2 +- include/{exec => system}/ramblock.h | 9 ++++----- migration/dirtyrate.c | 2 +- migration/file.c | 2 +- migration/multifd-nocomp.c | 2 +- migration/multifd-qatzip.c | 2 +- migration/multifd-qpl.c | 2 +- migration/multifd-uadk.c | 2 +- migration/multifd-zero-page.c | 2 +- migration/multifd-zlib.c | 2 +- migration/multifd-zstd.c | 2 +- migration/multifd.c | 2 +- migration/postcopy-ram.c | 2 +- tests/qtest/fuzz/generic_fuzz.c | 2 +- 18 files changed, 21 insertions(+), 22 deletions(-) rename include/{exec => system}/ramblock.h (96%) diff --git a/MAINTAINERS b/MAINTAINERS index b1ac3ff7d2..ba885010c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3122,7 +3122,7 @@ F: include/system/ioport.h F: include/exec/memop.h F: include/system/memory.h F: include/system/ram_addr.h -F: include/exec/ramblock.h +F: include/system/ramblock.h F: include/system/memory_mapping.h F: system/dma-helpers.c F: system/ioport.c diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 85ca23cb32..0510577475 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -19,7 +19,7 @@ #include "hw/virtio/virtio-gpu.h" #include "hw/virtio/virtio-gpu-pixman.h" #include "trace.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "system/hostmem.h" #include #include diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c index 0b1da723c8..acabff2c4a 100644 --- a/hw/hyperv/hv-balloon.c +++ b/hw/hyperv/hv-balloon.c @@ -12,7 +12,7 @@ #include "system/address-spaces.h" #include "exec/cpu-common.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "hw/boards.h" #include "hw/hyperv/dynmem-proto.h" #include "hw/hyperv/hv-balloon.h" diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 267b612587..48561d3c74 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -28,7 +28,7 @@ #include "system/cryptodev.h" #include "migration/postcopy-ram.h" #include "trace.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include #include diff --git a/include/system/ram_addr.h b/include/system/ram_addr.h index 3b81c3091f..b4e4425acb 100644 --- a/include/system/ram_addr.h +++ b/include/system/ram_addr.h @@ -23,7 +23,7 @@ #include "system/tcg.h" #include "exec/cputlb.h" #include "exec/ramlist.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "exec/exec-all.h" #include "system/memory.h" #include "exec/target_page.h" diff --git a/include/exec/ramblock.h b/include/system/ramblock.h similarity index 96% rename from include/exec/ramblock.h rename to include/system/ramblock.h index 64484cd821..d8a116ba99 100644 --- a/include/exec/ramblock.h +++ b/include/system/ramblock.h @@ -16,11 +16,10 @@ * The functions declared here will be removed soon. */ -#ifndef QEMU_EXEC_RAMBLOCK_H -#define QEMU_EXEC_RAMBLOCK_H +#ifndef SYSTEM_RAMBLOCK_H +#define SYSTEM_RAMBLOCK_H -#ifndef CONFIG_USER_ONLY -#include "cpu-common.h" +#include "exec/cpu-common.h" #include "qemu/rcu.h" #include "exec/ramlist.h" @@ -91,5 +90,5 @@ struct RAMBlock { */ ram_addr_t postcopy_length; }; -#endif + #endif diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c index 09caf92f87..986624c79a 100644 --- a/migration/dirtyrate.c +++ b/migration/dirtyrate.c @@ -14,7 +14,7 @@ #include "qemu/error-report.h" #include "hw/core/cpu.h" #include "qapi/error.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "exec/target_page.h" #include "qemu/rcu_queue.h" #include "qemu/main-loop.h" diff --git a/migration/file.c b/migration/file.c index 7f11e26f5c..bb8031e3c7 100644 --- a/migration/file.c +++ b/migration/file.c @@ -6,7 +6,7 @@ */ #include "qemu/osdep.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "qemu/cutils.h" #include "qemu/error-report.h" #include "qapi/error.h" diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c index ffe75256c9..94f248e8a2 100644 --- a/migration/multifd-nocomp.c +++ b/migration/multifd-nocomp.c @@ -11,7 +11,7 @@ */ #include "qemu/osdep.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "exec/target_page.h" #include "file.h" #include "migration-stats.h" diff --git a/migration/multifd-qatzip.c b/migration/multifd-qatzip.c index 6a0e989fae..7419e5dc0d 100644 --- a/migration/multifd-qatzip.c +++ b/migration/multifd-qatzip.c @@ -13,7 +13,7 @@ */ #include "qemu/osdep.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qapi/qapi-types-migration.h" diff --git a/migration/multifd-qpl.c b/migration/multifd-qpl.c index 88e2344af2..52902eb00c 100644 --- a/migration/multifd-qpl.c +++ b/migration/multifd-qpl.c @@ -14,7 +14,7 @@ #include "qemu/module.h" #include "qapi/error.h" #include "qapi/qapi-types-migration.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "multifd.h" #include "qpl/qpl.h" diff --git a/migration/multifd-uadk.c b/migration/multifd-uadk.c index 6895c1f65a..fd7cd9b5e8 100644 --- a/migration/multifd-uadk.c +++ b/migration/multifd-uadk.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qapi/error.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "migration.h" #include "multifd.h" #include "options.h" diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c index f1e988a959..dbc1184921 100644 --- a/migration/multifd-zero-page.c +++ b/migration/multifd-zero-page.c @@ -12,7 +12,7 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "migration.h" #include "migration-stats.h" #include "multifd.h" diff --git a/migration/multifd-zlib.c b/migration/multifd-zlib.c index 8cf8a26bb4..8820b2a787 100644 --- a/migration/multifd-zlib.c +++ b/migration/multifd-zlib.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include #include "qemu/rcu.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "exec/target_page.h" #include "qapi/error.h" #include "migration.h" diff --git a/migration/multifd-zstd.c b/migration/multifd-zstd.c index abed140855..3c2dcf76b0 100644 --- a/migration/multifd-zstd.c +++ b/migration/multifd-zstd.c @@ -13,7 +13,7 @@ #include "qemu/osdep.h" #include #include "qemu/rcu.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "exec/target_page.h" #include "qapi/error.h" #include "migration.h" diff --git a/migration/multifd.c b/migration/multifd.c index dfb5189f0e..86c83e43c0 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -16,7 +16,7 @@ #include "qemu/rcu.h" #include "exec/target_page.h" #include "system/system.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "file.h" diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c index 5d3edfcfec..995614b38c 100644 --- a/migration/postcopy-ram.c +++ b/migration/postcopy-ram.c @@ -31,7 +31,7 @@ #include "qemu/error-report.h" #include "trace.h" #include "hw/boards.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "socket.h" #include "yank_functions.h" #include "tls.h" diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index 239be9372d..507de74806 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -21,7 +21,7 @@ #include "fuzz.h" #include "string.h" #include "system/memory.h" -#include "exec/ramblock.h" +#include "system/ramblock.h" #include "hw/qdev-core.h" #include "hw/pci/pci.h" #include "hw/pci/pci_device.h" From 261a0303ae4770cadaf02ec21da9b5e60076cd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Mar 2025 17:13:28 +0100 Subject: [PATCH 0118/2760] accel/tcg: Remove unnecesary inclusion of memory-internal.h in cputlb.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At some point cputlb.c stopped depending on the "exec/memory-internal.h" header. Clean that now. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson Message-ID: <20250317161329.40300-2-philmd@linaro.org> --- accel/tcg/cputlb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 134e523cab..613f919fff 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -26,7 +26,6 @@ #include "exec/cpu_ldst.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" -#include "exec/memory-internal.h" #include "system/ram_addr.h" #include "exec/mmu-access-type.h" #include "exec/tlb-common.h" From d4c9cab37fa440807a4f2bf87efd0511d5694b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 17 Mar 2025 17:13:29 +0100 Subject: [PATCH 0119/2760] exec: Restrict memory-internal.h to system/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only file units within the system/ directory need access to "memory-internal.h". Restrict its scope by moving it there. The comment from commit 9d70618c684 ("memory-internal.h: Remove obsolete claim that header is obsolete") is now obsolete, remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Signed-off-by: Richard Henderson Message-ID: <20250317161329.40300-3-philmd@linaro.org> --- MAINTAINERS | 2 +- {include/exec => system}/memory-internal.h | 6 ------ system/memory.c | 4 ++-- system/physmem.c | 3 ++- 4 files changed, 5 insertions(+), 10 deletions(-) rename {include/exec => system}/memory-internal.h (88%) diff --git a/MAINTAINERS b/MAINTAINERS index ba885010c5..661a47db5a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3129,7 +3129,7 @@ F: system/ioport.c F: system/memory.c F: system/memory_mapping.c F: system/physmem.c -F: include/exec/memory-internal.h +F: system/memory-internal.h F: scripts/coccinelle/memory-region-housekeeping.cocci Memory devices diff --git a/include/exec/memory-internal.h b/system/memory-internal.h similarity index 88% rename from include/exec/memory-internal.h rename to system/memory-internal.h index c75178a3d6..085e81a9fe 100644 --- a/include/exec/memory-internal.h +++ b/system/memory-internal.h @@ -11,12 +11,6 @@ * */ -/* - * This header is for use by exec.c, memory.c and accel/tcg/cputlb.c ONLY, - * for declarations which are shared between the memory subsystem's - * internals and the TCG TLB code. Do not include it from elsewhere. - */ - #ifndef MEMORY_INTERNAL_H #define MEMORY_INTERNAL_H diff --git a/system/memory.c b/system/memory.c index 6a5d853071..7e2f16f4e9 100644 --- a/system/memory.c +++ b/system/memory.c @@ -24,8 +24,6 @@ #include "qemu/qemu-print.h" #include "qom/object.h" #include "trace.h" - -#include "exec/memory-internal.h" #include "system/ram_addr.h" #include "system/kvm.h" #include "system/runstate.h" @@ -35,6 +33,8 @@ #include "migration/vmstate.h" #include "system/address-spaces.h" +#include "memory-internal.h" + //#define DEBUG_UNASSIGNED static unsigned memory_region_transaction_depth; diff --git a/system/physmem.c b/system/physmem.c index 307d0764b6..16cf557d1a 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -66,7 +66,6 @@ #include "qemu/main-loop.h" #include "system/replay.h" -#include "exec/memory-internal.h" #include "system/ram_addr.h" #include "qemu/pmem.h" @@ -88,6 +87,8 @@ #include #endif +#include "memory-internal.h" + //#define DEBUG_SUBPAGE /* ram_list is read under rcu_read_lock()/rcu_read_unlock(). Writes From 5983a20a0bca7d54846abbb36fb59c7d9b1f226b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 14:33:07 -0700 Subject: [PATCH 0120/2760] meson: Introduce top-level libuser_ss and libsystem_ss We already have two subdirectories for which we need to build files twice, for user vs system modes. Move this handling to the top level. This cannot be combined with user_ss or system_ss, because the formulation has not been extended to support configuration symbols. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- gdbstub/meson.build | 32 ++++++++------------------------ meson.build | 22 ++++++++++++++++++++++ tcg/meson.build | 23 ++--------------------- 3 files changed, 32 insertions(+), 45 deletions(-) diff --git a/gdbstub/meson.build b/gdbstub/meson.build index dff741ddd4..0e8099ae9c 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -4,32 +4,16 @@ # types such as hwaddr. # -# We need to build the core gdb code via a library to be able to tweak -# cflags so: - -gdb_user_ss = ss.source_set() -gdb_system_ss = ss.source_set() - # We build two versions of gdbstub, one for each mode -gdb_user_ss.add(files('gdbstub.c', 'user.c')) -gdb_system_ss.add(files('gdbstub.c', 'system.c')) +libuser_ss.add(files( + 'gdbstub.c', + 'user.c' +)) -gdb_user_ss = gdb_user_ss.apply({}) -gdb_system_ss = gdb_system_ss.apply({}) - -libgdb_user = static_library('gdb_user', - gdb_user_ss.sources() + genh, - c_args: '-DCONFIG_USER_ONLY', - build_by_default: false) - -libgdb_system = static_library('gdb_system', - gdb_system_ss.sources() + genh, - build_by_default: false) - -gdb_user = declare_dependency(objects: libgdb_user.extract_all_objects(recursive: false)) -user_ss.add(gdb_user) -gdb_system = declare_dependency(objects: libgdb_system.extract_all_objects(recursive: false)) -system_ss.add(gdb_system) +libsystem_ss.add(files( + 'gdbstub.c', + 'system.c' +)) common_ss.add(files('syscalls.c')) diff --git a/meson.build b/meson.build index 41f68d3806..7e22afe135 100644 --- a/meson.build +++ b/meson.build @@ -3662,12 +3662,14 @@ io_ss = ss.source_set() qmp_ss = ss.source_set() qom_ss = ss.source_set() system_ss = ss.source_set() +libsystem_ss = ss.source_set() specific_fuzz_ss = ss.source_set() specific_ss = ss.source_set() rust_devices_ss = ss.source_set() stub_ss = ss.source_set() trace_ss = ss.source_set() user_ss = ss.source_set() +libuser_ss = ss.source_set() util_ss = ss.source_set() # accel modules @@ -4045,6 +4047,26 @@ common_ss.add(qom, qemuutil) common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss]) common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) +libuser_ss = libuser_ss.apply({}) +libuser = static_library('user', + libuser_ss.sources() + genh, + c_args: '-DCONFIG_USER_ONLY', + dependencies: libuser_ss.dependencies(), + build_by_default: false) +libuser = declare_dependency(objects: libuser.extract_all_objects(recursive: false), + dependencies: libuser_ss.dependencies()) +common_ss.add(when: 'CONFIG_USER_ONLY', if_true: libuser) + +libsystem_ss = libsystem_ss.apply({}) +libsystem = static_library('system', + libsystem_ss.sources() + genh, + c_args: '-DCONFIG_SOFTMMU', + dependencies: libsystem_ss.dependencies(), + build_by_default: false) +libsystem = declare_dependency(objects: libsystem.extract_all_objects(recursive: false), + dependencies: libsystem_ss.dependencies()) +common_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: libsystem) + # Note that this library is never used directly (only through extract_objects) # and is not built by default; therefore, source files not used by the build # configuration will be in build.ninja, but are never built by default. diff --git a/tcg/meson.build b/tcg/meson.build index 69ebb4908a..7df378d773 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -27,24 +27,5 @@ if host_os == 'linux' tcg_ss.add(files('perf.c')) endif -tcg_ss = tcg_ss.apply({}) - -libtcg_user = static_library('tcg_user', - tcg_ss.sources() + genh, - dependencies: tcg_ss.dependencies(), - c_args: '-DCONFIG_USER_ONLY', - build_by_default: false) - -tcg_user = declare_dependency(objects: libtcg_user.extract_all_objects(recursive: false), - dependencies: tcg_ss.dependencies()) -user_ss.add(tcg_user) - -libtcg_system = static_library('tcg_system', - tcg_ss.sources() + genh, - dependencies: tcg_ss.dependencies(), - c_args: '-DCONFIG_SOFTMMU', - build_by_default: false) - -tcg_system = declare_dependency(objects: libtcg_system.extract_all_objects(recursive: false), - dependencies: tcg_ss.dependencies()) -system_ss.add(tcg_system) +libuser_ss.add_all(tcg_ss) +libsystem_ss.add_all(tcg_ss) From 7ed79a9adbeff0ff8a8b6c76d3d10b2fe0f68c63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 14:37:07 -0700 Subject: [PATCH 0121/2760] gdbstub: Move syscalls.c out of common_ss Copy to libuser_ss and libsystem_ss. This file uses semihosting/semihost.h, which has separate implementations with and without CONFIG_USER_ONLY. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- gdbstub/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gdbstub/meson.build b/gdbstub/meson.build index 0e8099ae9c..b25db86767 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -7,15 +7,15 @@ # We build two versions of gdbstub, one for each mode libuser_ss.add(files( 'gdbstub.c', + 'syscalls.c', 'user.c' )) libsystem_ss.add(files( 'gdbstub.c', + 'syscalls.c', 'system.c' )) -common_ss.add(files('syscalls.c')) - # The user-target is specialised by the guest specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-target.c')) From 1a1567b1747ef46fca2dfa8c22c2262a2e8f6d6c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 14:55:21 -0700 Subject: [PATCH 0122/2760] accel/tcg: Use libuser_ss and libsystem_ss While some of these files are built exactly once, due to being in only libuser_ss or libsystem_ss, some of the includes that they depend on require CONFIG_USER_ONLY. So make use of the common infrastructure to allow that. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 185830d0f5..72d4acfe5e 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -1,12 +1,21 @@ -common_ss.add(when: 'CONFIG_TCG', if_true: files( +if not get_option('tcg').allowed() + subdir_done() +endif + +tcg_ss = ss.source_set() + +tcg_ss.add(files( 'cpu-exec-common.c', 'tcg-runtime.c', 'tcg-runtime-gvec.c', )) if get_option('plugins') - common_ss.add(when: 'CONFIG_TCG', if_true: files('plugin-gen.c')) + tcg_ss.add(files('plugin-gen.c')) endif +libuser_ss.add_all(tcg_ss) +libsystem_ss.add_all(tcg_ss) + tcg_specific_ss = ss.source_set() tcg_specific_ss.add(files( 'tcg-all.c', @@ -22,11 +31,11 @@ specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( 'cputlb.c', )) -user_ss.add(when: ['CONFIG_TCG'], if_true: files( +libuser_ss.add(files( 'user-exec-stub.c', )) -system_ss.add(when: ['CONFIG_TCG'], if_true: files( +libsystem_ss.add(files( 'icount-common.c', 'monitor.c', 'tcg-accel-ops.c', From 695e7f6026c4ed8a1a50cd26d3199fc4f4d9b3a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 16 Mar 2025 15:48:07 -0700 Subject: [PATCH 0123/2760] target/mips: Restrict semihosting tests to system mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do not set CONFIG_SEMIHOSTING in configs/targets/mips*-linux-user.mak. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/mips/cpu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index b207106dd7..47df563e12 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -32,8 +32,10 @@ #include "exec/exec-all.h" #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" -#include "semihosting/semihost.h" #include "fpu_helper.h" +#ifndef CONFIG_USER_ONLY +#include "semihosting/semihost.h" +#endif const char regnames[32][3] = { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", @@ -415,12 +417,11 @@ static void mips_cpu_reset_hold(Object *obj, ResetType type) restore_pamask(env); cs->exception_index = EXCP_NONE; +#ifndef CONFIG_USER_ONLY if (semihosting_get_argc()) { /* UHI interface can be used to obtain argc and argv */ env->active_tc.gpr[4] = -1; } - -#ifndef CONFIG_USER_ONLY if (kvm_enabled()) { kvm_mips_reset_vcpu(cpu); } From 690793e005e004f749aa963ea0040f18e067c98e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 17 Mar 2025 09:36:32 -0700 Subject: [PATCH 0124/2760] target/xtensa: Restrict semihosting tests to system mode We do not set CONFIG_SEMIHOSTING in configs/targets/xtensa*-linux-user.mak. Do not raise SIGILL for user-only unconditionally. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/xtensa/translate.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 4f02cefde3..cb817b3119 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -35,14 +35,14 @@ #include "tcg/tcg-op.h" #include "qemu/log.h" #include "qemu/qemu-print.h" -#include "semihosting/semihost.h" #include "exec/translator.h" #include "exec/translation-block.h" - #include "exec/helper-proto.h" #include "exec/helper-gen.h" - #include "exec/log.h" +#ifndef CONFIG_USER_ONLY +#include "semihosting/semihost.h" +#endif #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" @@ -2241,17 +2241,15 @@ static uint32_t test_exceptions_simcall(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { - bool is_semi = semihosting_enabled(dc->cring != 0); -#ifdef CONFIG_USER_ONLY - bool ill = true; -#else - /* Between RE.2 and RE.3 simcall opcode's become nop for the hardware. */ - bool ill = dc->config->hw_version <= 250002 && !is_semi; -#endif - if (ill || !is_semi) { - qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); +#ifndef CONFIG_USER_ONLY + if (semihosting_enabled(dc->cring != 0)) { + return 0; } - return ill ? XTENSA_OP_ILL : 0; +#endif + qemu_log_mask(LOG_GUEST_ERROR, "SIMCALL but semihosting is disabled\n"); + + /* Between RE.2 and RE.3 simcall opcode's become nop for the hardware. */ + return dc->config->hw_version <= 250002 ? XTENSA_OP_ILL : 0; } static void translate_simcall(DisasContext *dc, const OpcodeArg arg[], From d0b4cfa62937ce59bd88de5928ada687329be194 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 17:16:05 -0700 Subject: [PATCH 0125/2760] semihosting: Move user-only implementation out-of-line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid testing CONFIG_USER_ONLY in semihost.h. The only function that's required is semihosting_enabled. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/semihosting/semihost.h | 29 ++--------------------------- semihosting/meson.build | 5 +++-- semihosting/stubs-all.c | 6 ++++++ semihosting/stubs-system.c | 6 ------ semihosting/user.c | 20 ++++++++++++++++++++ 5 files changed, 31 insertions(+), 35 deletions(-) create mode 100644 semihosting/user.c diff --git a/include/semihosting/semihost.h b/include/semihosting/semihost.h index 97d2a2ba99..b03e637578 100644 --- a/include/semihosting/semihost.h +++ b/include/semihosting/semihost.h @@ -26,32 +26,6 @@ typedef enum SemihostingTarget { SEMIHOSTING_TARGET_GDB } SemihostingTarget; -#ifdef CONFIG_USER_ONLY -static inline bool semihosting_enabled(bool is_user) -{ - return true; -} - -static inline SemihostingTarget semihosting_get_target(void) -{ - return SEMIHOSTING_TARGET_AUTO; -} - -static inline const char *semihosting_get_arg(int i) -{ - return NULL; -} - -static inline int semihosting_get_argc(void) -{ - return 0; -} - -static inline const char *semihosting_get_cmdline(void) -{ - return NULL; -} -#else /* !CONFIG_USER_ONLY */ /** * semihosting_enabled: * @is_user: true if guest code is in usermode (i.e. not privileged) @@ -59,17 +33,18 @@ static inline const char *semihosting_get_cmdline(void) * Return true if guest code is allowed to make semihosting calls. */ bool semihosting_enabled(bool is_user); + SemihostingTarget semihosting_get_target(void); const char *semihosting_get_arg(int i); int semihosting_get_argc(void); const char *semihosting_get_cmdline(void); void semihosting_arg_fallback(const char *file, const char *cmd); + /* for vl.c hooks */ void qemu_semihosting_enable(void); int qemu_semihosting_config_options(const char *optstr); void qemu_semihosting_chardev_init(void); void qemu_semihosting_console_init(Chardev *); -#endif /* CONFIG_USER_ONLY */ void qemu_semihosting_guestfd_init(void); #endif /* SEMIHOST_H */ diff --git a/semihosting/meson.build b/semihosting/meson.build index 86f5004bed..f3d38dda91 100644 --- a/semihosting/meson.build +++ b/semihosting/meson.build @@ -7,8 +7,9 @@ specific_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SYSTEM_ONLY'], if_true: fil 'uaccess.c', )) -common_ss.add(when: ['CONFIG_SEMIHOSTING', 'CONFIG_SYSTEM_ONLY'], if_false: files('stubs-all.c')) -system_ss.add(when: ['CONFIG_SEMIHOSTING'], if_true: files( +common_ss.add(when: 'CONFIG_SEMIHOSTING', if_false: files('stubs-all.c')) +user_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files('user.c')) +system_ss.add(when: 'CONFIG_SEMIHOSTING', if_true: files( 'config.c', 'console.c', ), if_false: files( diff --git a/semihosting/stubs-all.c b/semihosting/stubs-all.c index a2a1fc9c6f..c001c84574 100644 --- a/semihosting/stubs-all.c +++ b/semihosting/stubs-all.c @@ -11,6 +11,12 @@ #include "qemu/osdep.h" #include "semihosting/semihost.h" +/* Queries to config status default to off */ +bool semihosting_enabled(bool is_user) +{ + return false; +} + SemihostingTarget semihosting_get_target(void) { return SEMIHOSTING_TARGET_AUTO; diff --git a/semihosting/stubs-system.c b/semihosting/stubs-system.c index f26cbb7c25..989789f373 100644 --- a/semihosting/stubs-system.c +++ b/semihosting/stubs-system.c @@ -22,12 +22,6 @@ QemuOptsList qemu_semihosting_config_opts = { }, }; -/* Queries to config status default to off */ -bool semihosting_enabled(bool is_user) -{ - return false; -} - /* * All the rest are empty subs. We could g_assert_not_reached() but * that adds extra weight to the final binary. Waste not want not. diff --git a/semihosting/user.c b/semihosting/user.c new file mode 100644 index 0000000000..515de3d2c0 --- /dev/null +++ b/semihosting/user.c @@ -0,0 +1,20 @@ +/* + * Semihosting for user emulation + * + * Copyright (c) 2019 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "semihosting/semihost.h" + +bool semihosting_enabled(bool is_user) +{ + return true; +} + +SemihostingTarget semihosting_get_target(void) +{ + return SEMIHOSTING_TARGET_AUTO; +} From 17a71e89693e17d60f73a00b4cea6963073152e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 20 Mar 2025 16:09:51 -0700 Subject: [PATCH 0126/2760] semihosting: Assert is_user in user-only semihosting_enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Suggested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- semihosting/user.c | 1 + 1 file changed, 1 insertion(+) diff --git a/semihosting/user.c b/semihosting/user.c index 515de3d2c0..98c144cb45 100644 --- a/semihosting/user.c +++ b/semihosting/user.c @@ -11,6 +11,7 @@ bool semihosting_enabled(bool is_user) { + assert(is_user); return true; } From 3e57baa22ea6892d1b8c212253b2859be30f45ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Mar 2025 10:39:19 -0700 Subject: [PATCH 0127/2760] include/exec: Split out watchpoint.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relatively few objects in qemu care about watchpoints, so split out to a new header. Removes an instance of CONFIG_USER_ONLY from hw/core/cpu.h. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tcg-accel-ops.c | 1 + include/exec/watchpoint.h | 41 +++++++++++++++++++++++++++++ include/hw/core/cpu.h | 30 --------------------- system/watchpoint.c | 1 + target/arm/debug_helper.c | 1 + target/i386/cpu.c | 1 + target/i386/machine.c | 2 +- target/i386/tcg/system/bpt_helper.c | 1 + target/ppc/cpu.c | 1 + target/ppc/cpu_init.c | 2 +- target/riscv/debug.c | 1 + target/s390x/helper.c | 1 + target/s390x/tcg/excp_helper.c | 1 + target/xtensa/dbg_helper.c | 1 + 14 files changed, 53 insertions(+), 32 deletions(-) create mode 100644 include/exec/watchpoint.h diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index d9b662efe3..5c88056157 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -37,6 +37,7 @@ #include "exec/hwaddr.h" #include "exec/tb-flush.h" #include "exec/translation-block.h" +#include "exec/watchpoint.h" #include "gdbstub/enums.h" #include "hw/core/cpu.h" diff --git a/include/exec/watchpoint.h b/include/exec/watchpoint.h new file mode 100644 index 0000000000..4b6668826c --- /dev/null +++ b/include/exec/watchpoint.h @@ -0,0 +1,41 @@ +/* + * CPU watchpoints + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef EXEC_WATCHPOINT_H +#define EXEC_WATCHPOINT_H + +#if defined(CONFIG_USER_ONLY) +static inline int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, + int flags, CPUWatchpoint **watchpoint) +{ + return -ENOSYS; +} + +static inline int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, + vaddr len, int flags) +{ + return -ENOSYS; +} + +static inline void cpu_watchpoint_remove_by_ref(CPUState *cpu, + CPUWatchpoint *wp) +{ +} + +static inline void cpu_watchpoint_remove_all(CPUState *cpu, int mask) +{ +} +#else +int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, + int flags, CPUWatchpoint **watchpoint); +int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, + vaddr len, int flags); +void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint); +void cpu_watchpoint_remove_all(CPUState *cpu, int mask); +#endif + +#endif /* EXEC_WATCHPOINT_H */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index abd8764e83..37cb7d1531 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1109,36 +1109,6 @@ static inline bool cpu_breakpoint_test(CPUState *cpu, vaddr pc, int mask) return false; } -#if defined(CONFIG_USER_ONLY) -static inline int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, - int flags, CPUWatchpoint **watchpoint) -{ - return -ENOSYS; -} - -static inline int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, - vaddr len, int flags) -{ - return -ENOSYS; -} - -static inline void cpu_watchpoint_remove_by_ref(CPUState *cpu, - CPUWatchpoint *wp) -{ -} - -static inline void cpu_watchpoint_remove_all(CPUState *cpu, int mask) -{ -} -#else -int cpu_watchpoint_insert(CPUState *cpu, vaddr addr, vaddr len, - int flags, CPUWatchpoint **watchpoint); -int cpu_watchpoint_remove(CPUState *cpu, vaddr addr, - vaddr len, int flags); -void cpu_watchpoint_remove_by_ref(CPUState *cpu, CPUWatchpoint *watchpoint); -void cpu_watchpoint_remove_all(CPUState *cpu, int mask); -#endif - /** * cpu_get_address_space: * @cpu: CPU to get address space from diff --git a/system/watchpoint.c b/system/watchpoint.c index 08dbd8483d..21d0bb36ca 100644 --- a/system/watchpoint.c +++ b/system/watchpoint.c @@ -21,6 +21,7 @@ #include "qemu/error-report.h" #include "exec/cputlb.h" #include "exec/target_page.h" +#include "exec/watchpoint.h" #include "hw/core/cpu.h" /* Add a watchpoint. */ diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index a9a619ba6b..473ee2af38 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -13,6 +13,7 @@ #include "cpregs.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exec/watchpoint.h" #include "system/tcg.h" #ifdef CONFIG_TCG diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5c9f80b4cc..c596e2174d 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -35,6 +35,7 @@ #include "standard-headers/asm-x86/kvm_para.h" #include "hw/qdev-properties.h" #include "hw/i386/topology.h" +#include "exec/watchpoint.h" #ifndef CONFIG_USER_ONLY #include "system/reset.h" #include "qapi/qapi-commands-machine-target.h" diff --git a/target/i386/machine.c b/target/i386/machine.c index 70f632a36f..6cb561c632 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -7,7 +7,7 @@ #include "hw/i386/x86.h" #include "kvm/kvm_i386.h" #include "hw/xen/xen.h" - +#include "exec/watchpoint.h" #include "system/kvm.h" #include "system/kvm_xen.h" #include "system/tcg.h" diff --git a/target/i386/tcg/system/bpt_helper.c b/target/i386/tcg/system/bpt_helper.c index be232c1ca9..08ccd3f5e6 100644 --- a/target/i386/tcg/system/bpt_helper.c +++ b/target/i386/tcg/system/bpt_helper.c @@ -21,6 +21,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exec/watchpoint.h" #include "tcg/helper-tcg.h" diff --git a/target/ppc/cpu.c b/target/ppc/cpu.c index bfcc695de7..4d8faaddee 100644 --- a/target/ppc/cpu.c +++ b/target/ppc/cpu.c @@ -22,6 +22,7 @@ #include "cpu-models.h" #include "cpu-qom.h" #include "exec/log.h" +#include "exec/watchpoint.h" #include "fpu/softfloat-helpers.h" #include "mmu-hash64.h" #include "helper_regs.h" diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index f81cb680fc..17f0f3d3ff 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -40,7 +40,7 @@ #include "qemu/cutils.h" #include "disas/capstone.h" #include "fpu/softfloat.h" - +#include "exec/watchpoint.h" #include "helper_regs.h" #include "internal.h" #include "spr_common.h" diff --git a/target/riscv/debug.c b/target/riscv/debug.c index 9db4048523..fea989afe9 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -30,6 +30,7 @@ #include "trace.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" +#include "exec/watchpoint.h" #include "system/cpu-timers.h" /* diff --git a/target/s390x/helper.c b/target/s390x/helper.c index c689e11b46..e660c69f60 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -27,6 +27,7 @@ #include "target/s390x/kvm/pv.h" #include "system/hw_accel.h" #include "system/runstate.h" +#include "exec/watchpoint.h" void s390x_tod_timer(void *opaque) { diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index ac733f407f..1d51043e88 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "exec/cputlb.h" #include "exec/exec-all.h" +#include "exec/watchpoint.h" #include "s390x-internal.h" #include "tcg_s390x.h" #ifndef CONFIG_USER_ONLY diff --git a/target/xtensa/dbg_helper.c b/target/xtensa/dbg_helper.c index 163a1ffc7b..c4f4298a50 100644 --- a/target/xtensa/dbg_helper.c +++ b/target/xtensa/dbg_helper.c @@ -31,6 +31,7 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" +#include "exec/watchpoint.h" #include "system/address-spaces.h" void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) From 53d2354cec1df5a364600ab5dcf4462266a84b63 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 19:45:02 -0700 Subject: [PATCH 0128/2760] hw/core: Move unconditional files to libsystem_ss, libuser_ss Many of the headers used by these require CONFIG_USER_ONLY. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- hw/core/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/core/meson.build b/hw/core/meson.build index b5a545a0ed..547de6527c 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -26,7 +26,7 @@ system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls]) -system_ss.add(files( +libsystem_ss.add(files( 'cpu-system.c', 'fw-path-provider.c', 'gpio.c', @@ -46,7 +46,7 @@ system_ss.add(files( 'vm-change-state-handler.c', 'clock-vmstate.c', )) -user_ss.add(files( +libuser_ss.add(files( 'cpu-user.c', 'qdev-user.c', )) From 7c2f3580e51f3a1d74d78b88267be22650b518ac Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 19:45:50 -0700 Subject: [PATCH 0129/2760] system: Move most files to libsystem_ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the headers used require CONFIG_USER_ONLY. Do not move vl.c, because it has other include dependencies that are present in system_ss. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- system/meson.build | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/system/meson.build b/system/meson.build index 063301c3ad..c2f0082766 100644 --- a/system/meson.build +++ b/system/meson.build @@ -4,6 +4,10 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( )]) system_ss.add(files( + 'vl.c', +), sdl, libpmem, libdaxctl) + +libsystem_ss.add(files( 'balloon.c', 'bootdevice.c', 'cpus.c', @@ -23,9 +27,8 @@ system_ss.add(files( 'runstate-hmp-cmds.c', 'runstate.c', 'tpm-hmp-cmds.c', - 'vl.c', 'watchpoint.c', -), sdl, libpmem, libdaxctl) +)) if have_tpm system_ss.add(files('tpm.c')) From 6c1ae457a17a9462fb89ef1f30ad7da5266bfea6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 19:46:44 -0700 Subject: [PATCH 0130/2760] plugins: Move api.c, core.c to libuser_ss, libsystem_ss Headers used by these files require CONFIG_USER_ONLY. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- plugins/meson.build | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/meson.build b/plugins/meson.build index 3be8245a69..5383c7b88b 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -61,5 +61,8 @@ endif user_ss.add(files('user.c', 'api-user.c')) system_ss.add(files('system.c', 'api-system.c')) -common_ss.add(files('loader.c', 'api.c', 'core.c')) +libuser_ss.add(files('api.c', 'core.c')) +libsystem_ss.add(files('api.c', 'core.c')) + +common_ss.add(files('loader.c')) From 1596f1206f1d7d9ab9abfb7e010f3d3775c51202 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:08:44 -0700 Subject: [PATCH 0131/2760] include/exec: Drop ifndef CONFIG_USER_ONLY from cpu-common.h We were hiding a number of declarations from user-only, although it hurts nothing to allow them. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/cpu-common.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index be032e1a49..9b83fd7ac8 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -9,9 +9,7 @@ #define CPU_COMMON_H #include "exec/vaddr.h" -#ifndef CONFIG_USER_ONLY #include "exec/hwaddr.h" -#endif #include "hw/core/cpu.h" #include "tcg/debug-assert.h" #include "exec/page-protection.h" @@ -40,8 +38,6 @@ int cpu_get_free_index(void); void tcg_iommu_init_notifier_list(CPUState *cpu); void tcg_iommu_free_notifier_list(CPUState *cpu); -#if !defined(CONFIG_USER_ONLY) - enum device_endian { DEVICE_NATIVE_ENDIAN, DEVICE_BIG_ENDIAN, @@ -176,8 +172,6 @@ int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length); int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start, size_t length); -#endif - /* Returns: 0 on success, -1 on error */ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, void *ptr, size_t len, bool is_write); From bcd6d0d60c5c5edf324af4427039d50693731e46 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:10:02 -0700 Subject: [PATCH 0132/2760] include/hw/core: Drop ifndef CONFIG_USER_ONLY from cpu.h We were hiding a number of declarations from user-only, although it hurts nothing to allow them. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/hw/core/cpu.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 37cb7d1531..6dcee5d0ba 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -614,8 +614,6 @@ extern bool mttcg_enabled; */ bool cpu_paging_enabled(const CPUState *cpu); -#if !defined(CONFIG_USER_ONLY) - /** * cpu_get_memory_mapping: * @cpu: The CPU whose memory mappings are to be obtained. @@ -676,8 +674,6 @@ int cpu_write_elf32_qemunote(WriteCoreDumpFunction f, CPUState *cpu, */ GuestPanicInformation *cpu_get_crash_info(CPUState *cpu); -#endif /* !CONFIG_USER_ONLY */ - /** * CPUDumpFlags: * @CPU_DUMP_CODE: @@ -701,7 +697,6 @@ enum CPUDumpFlags { */ void cpu_dump_state(CPUState *cpu, FILE *f, int flags); -#ifndef CONFIG_USER_ONLY /** * cpu_get_phys_page_attrs_debug: * @cpu: The CPU to obtain the physical page address for. @@ -758,8 +753,6 @@ bool cpu_virtio_is_big_endian(CPUState *cpu); */ bool cpu_has_work(CPUState *cpu); -#endif /* CONFIG_USER_ONLY */ - /** * cpu_list_add: * @cpu: The CPU to be added to the list of CPUs. @@ -1136,8 +1129,6 @@ const char *target_name(void); #ifdef COMPILING_PER_TARGET -#ifndef CONFIG_USER_ONLY - extern const VMStateDescription vmstate_cpu_common; #define VMSTATE_CPU() { \ @@ -1147,7 +1138,6 @@ extern const VMStateDescription vmstate_cpu_common; .flags = VMS_STRUCT, \ .offset = 0, \ } -#endif /* !CONFIG_USER_ONLY */ #endif /* COMPILING_PER_TARGET */ From a771605798ba929fa18da2bcdd316c463c387462 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:11:41 -0700 Subject: [PATCH 0133/2760] include/hw/intc: Remove ifndef CONFIG_USER_ONLY from armv7m_nvic.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We were hiding a number of declarations from user-only, although it hurts nothing to allow them. The inlines for user-only are unused. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/hw/intc/armv7m_nvic.h | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/include/hw/intc/armv7m_nvic.h b/include/hw/intc/armv7m_nvic.h index 89fe8aedaa..7b9964fe7e 100644 --- a/include/hw/intc/armv7m_nvic.h +++ b/include/hw/intc/armv7m_nvic.h @@ -189,21 +189,7 @@ int armv7m_nvic_raw_execution_priority(NVICState *s); * @secure: the security state to test * This corresponds to the pseudocode IsReqExecPriNeg(). */ -#ifndef CONFIG_USER_ONLY bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure); -#else -static inline bool armv7m_nvic_neg_prio_requested(NVICState *s, bool secure) -{ - return false; -} -#endif -#ifndef CONFIG_USER_ONLY bool armv7m_nvic_can_take_pending_exception(NVICState *s); -#else -static inline bool armv7m_nvic_can_take_pending_exception(NVICState *s) -{ - return true; -} -#endif #endif From 31030cf0ff7c72584663a5fe9a9318fc843210ef Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:12:17 -0700 Subject: [PATCH 0134/2760] include/hw/s390x: Remove ifndef CONFIG_USER_ONLY in css.h We were hiding a number of declarations from user-only, although it hurts nothing to allow them. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/hw/s390x/css.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index dbf919bdd2..0b0400a9d4 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -238,7 +238,6 @@ uint32_t css_get_adapter_id(CssIoAdapterType type, uint8_t isc); void css_register_io_adapters(CssIoAdapterType type, bool swap, bool maskable, uint8_t flags, Error **errp); -#ifndef CONFIG_USER_ONLY SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid); bool css_subch_visible(SubchDev *sch); @@ -262,7 +261,6 @@ int css_enable_mss(void); IOInstEnding css_do_rsch(SubchDev *sch); int css_do_rchp(uint8_t cssid, uint8_t chpid); bool css_present(uint8_t cssid); -#endif extern const PropertyInfo css_devid_ro_propinfo; From 161f5bc8e965fa8255db435683e6b52042037bb7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Mar 2025 12:57:31 -0700 Subject: [PATCH 0135/2760] include/exec: Split out icount.h Split icount stuff from system/cpu-timers.h. There are 17 files which only require icount.h, 7 that only require cpu-timers.h, and 7 that require both. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 2 +- accel/tcg/icount-common.c | 2 +- accel/tcg/monitor.c | 1 + accel/tcg/tcg-accel-ops-icount.c | 2 +- accel/tcg/tcg-accel-ops-mttcg.c | 2 +- accel/tcg/tcg-accel-ops-rr.c | 2 +- accel/tcg/tcg-accel-ops.c | 2 +- accel/tcg/tcg-all.c | 2 +- accel/tcg/translate-all.c | 2 +- hw/core/ptimer.c | 2 +- include/exec/icount.h | 68 ++++++++++++++++++++++++++++++++ include/system/cpu-timers.h | 58 --------------------------- replay/replay.c | 2 +- stubs/icount.c | 2 +- system/cpu-timers.c | 1 + system/dma-helpers.c | 2 +- system/vl.c | 1 + target/arm/helper.c | 1 + target/riscv/cpu_helper.c | 2 +- target/riscv/csr.c | 2 +- target/riscv/debug.c | 1 + target/riscv/machine.c | 2 +- target/riscv/pmu.c | 2 +- util/async.c | 2 +- util/main-loop.c | 1 + util/qemu-timer.c | 1 + 26 files changed, 92 insertions(+), 75 deletions(-) create mode 100644 include/exec/icount.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 372b876604..034c2ded6b 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -35,7 +35,7 @@ #include "exec/log.h" #include "qemu/main-loop.h" #include "exec/cpu-all.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "exec/replay-core.h" #include "system/tcg.h" #include "exec/helper-proto-common.h" diff --git a/accel/tcg/icount-common.c b/accel/tcg/icount-common.c index 402d3e3f4e..d6471174a3 100644 --- a/accel/tcg/icount-common.c +++ b/accel/tcg/icount-common.c @@ -35,7 +35,7 @@ #include "system/replay.h" #include "system/runstate.h" #include "hw/core/cpu.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/cpu-timers-internal.h" /* diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c index eeb38a4d9c..1c182b6bfb 100644 --- a/accel/tcg/monitor.c +++ b/accel/tcg/monitor.c @@ -14,6 +14,7 @@ #include "qapi/qapi-commands-machine.h" #include "monitor/monitor.h" #include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/tcg.h" #include "tcg/tcg.h" #include "internal-common.h" diff --git a/accel/tcg/tcg-accel-ops-icount.c b/accel/tcg/tcg-accel-ops-icount.c index 27cf1044c7..d0f7b410fa 100644 --- a/accel/tcg/tcg-accel-ops-icount.c +++ b/accel/tcg/tcg-accel-ops-icount.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "system/replay.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "hw/core/cpu.h" diff --git a/accel/tcg/tcg-accel-ops-mttcg.c b/accel/tcg/tcg-accel-ops-mttcg.c index bdcc385ae9..dfcee30947 100644 --- a/accel/tcg/tcg-accel-ops-mttcg.c +++ b/accel/tcg/tcg-accel-ops-mttcg.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "system/tcg.h" #include "system/replay.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/main-loop.h" #include "qemu/notify.h" #include "qemu/guest-random.h" diff --git a/accel/tcg/tcg-accel-ops-rr.c b/accel/tcg/tcg-accel-ops-rr.c index f62cf24e1d..6eec5c9eee 100644 --- a/accel/tcg/tcg-accel-ops-rr.c +++ b/accel/tcg/tcg-accel-ops-rr.c @@ -27,7 +27,7 @@ #include "qemu/lockable.h" #include "system/tcg.h" #include "system/replay.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/main-loop.h" #include "qemu/notify.h" #include "qemu/guest-random.h" diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index 5c88056157..ccdb781eef 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -29,7 +29,7 @@ #include "system/accel-ops.h" #include "system/tcg.h" #include "system/replay.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/main-loop.h" #include "qemu/guest-random.h" #include "qemu/timer.h" diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index c1a30b0121..7a5b810b88 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -26,7 +26,7 @@ #include "qemu/osdep.h" #include "system/tcg.h" #include "exec/replay-core.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "tcg/startup.h" #include "qapi/error.h" #include "qemu/error-report.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 167535bcb1..bb161ae61a 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -55,7 +55,7 @@ #include "qemu/cacheinfo.h" #include "qemu/timer.h" #include "exec/log.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/tcg.h" #include "qapi/error.h" #include "accel/tcg/cpu-ops.h" diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 7f63d17ca1..0aeb10fb53 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -11,7 +11,7 @@ #include "migration/vmstate.h" #include "qemu/host-utils.h" #include "exec/replay-core.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/qtest.h" #include "block/aio.h" #include "hw/clock.h" diff --git a/include/exec/icount.h b/include/exec/icount.h new file mode 100644 index 0000000000..4964987ae4 --- /dev/null +++ b/include/exec/icount.h @@ -0,0 +1,68 @@ +/* + * icount - Instruction Counter API + * CPU timers state API + * + * Copyright 2020 SUSE LLC + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef EXEC_ICOUNT_H +#define EXEC_ICOUNT_H + +/** + * ICountMode: icount enablement state: + * + * @ICOUNT_DISABLED: Disabled - Do not count executed instructions. + * @ICOUNT_PRECISE: Enabled - Fixed conversion of insn to ns via "shift" option + * @ICOUNT_ADAPTATIVE: Enabled - Runtime adaptive algorithm to compute shift + */ +typedef enum { + ICOUNT_DISABLED = 0, + ICOUNT_PRECISE, + ICOUNT_ADAPTATIVE, +} ICountMode; + +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) +extern ICountMode use_icount; +#define icount_enabled() (use_icount) +#else +#define icount_enabled() ICOUNT_DISABLED +#endif + +/* + * Update the icount with the executed instructions. Called by + * cpus-tcg vCPU thread so the main-loop can see time has moved forward. + */ +void icount_update(CPUState *cpu); + +/* get raw icount value */ +int64_t icount_get_raw(void); + +/* return the virtual CPU time in ns, based on the instruction counter. */ +int64_t icount_get(void); +/* + * convert an instruction counter value to ns, based on the icount shift. + * This shift is set as a fixed value with the icount "shift" option + * (precise mode), or it is constantly approximated and corrected at + * runtime in adaptive mode. + */ +int64_t icount_to_ns(int64_t icount); + +/** + * icount_configure: configure the icount options, including "shift" + * @opts: Options to parse + * @errp: pointer to a NULL-initialized error object + * + * Return: true on success, else false setting @errp with error + */ +bool icount_configure(QemuOpts *opts, Error **errp); + +/* used by tcg vcpu thread to calc icount budget */ +int64_t icount_round(int64_t count); + +/* if the CPUs are idle, start accounting real time to virtual clock. */ +void icount_start_warp_timer(void); +void icount_account_warp_timer(void); +void icount_notify_exit(void); + +#endif /* EXEC_ICOUNT_H */ diff --git a/include/system/cpu-timers.h b/include/system/cpu-timers.h index 64ae54f6d6..a1abed0d7a 100644 --- a/include/system/cpu-timers.h +++ b/include/system/cpu-timers.h @@ -15,64 +15,6 @@ /* init the whole cpu timers API, including icount, ticks, and cpu_throttle */ void cpu_timers_init(void); -/* icount - Instruction Counter API */ - -/** - * ICountMode: icount enablement state: - * - * @ICOUNT_DISABLED: Disabled - Do not count executed instructions. - * @ICOUNT_PRECISE: Enabled - Fixed conversion of insn to ns via "shift" option - * @ICOUNT_ADAPTATIVE: Enabled - Runtime adaptive algorithm to compute shift - */ -typedef enum { - ICOUNT_DISABLED = 0, - ICOUNT_PRECISE, - ICOUNT_ADAPTATIVE, -} ICountMode; - -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) -extern ICountMode use_icount; -#define icount_enabled() (use_icount) -#else -#define icount_enabled() ICOUNT_DISABLED -#endif - -/* - * Update the icount with the executed instructions. Called by - * cpus-tcg vCPU thread so the main-loop can see time has moved forward. - */ -void icount_update(CPUState *cpu); - -/* get raw icount value */ -int64_t icount_get_raw(void); - -/* return the virtual CPU time in ns, based on the instruction counter. */ -int64_t icount_get(void); -/* - * convert an instruction counter value to ns, based on the icount shift. - * This shift is set as a fixed value with the icount "shift" option - * (precise mode), or it is constantly approximated and corrected at - * runtime in adaptive mode. - */ -int64_t icount_to_ns(int64_t icount); - -/** - * icount_configure: configure the icount options, including "shift" - * @opts: Options to parse - * @errp: pointer to a NULL-initialized error object - * - * Return: true on success, else false setting @errp with error - */ -bool icount_configure(QemuOpts *opts, Error **errp); - -/* used by tcg vcpu thread to calc icount budget */ -int64_t icount_round(int64_t count); - -/* if the CPUs are idle, start accounting real time to virtual clock. */ -void icount_start_warp_timer(void); -void icount_account_warp_timer(void); -void icount_notify_exit(void); - /* * CPU Ticks and Clock */ diff --git a/replay/replay.c b/replay/replay.c index 3adc387b3d..a3e24c967a 100644 --- a/replay/replay.c +++ b/replay/replay.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/replay.h" #include "system/runstate.h" #include "replay-internal.h" diff --git a/stubs/icount.c b/stubs/icount.c index edbf60cbfa..ceb73b4fc2 100644 --- a/stubs/icount.c +++ b/stubs/icount.c @@ -1,6 +1,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" /* icount - Instruction Counter API */ diff --git a/system/cpu-timers.c b/system/cpu-timers.c index 23dd82b465..cb35fa62b8 100644 --- a/system/cpu-timers.c +++ b/system/cpu-timers.c @@ -36,6 +36,7 @@ #include "hw/core/cpu.h" #include "system/cpu-timers.h" #include "system/cpu-timers-internal.h" +#include "exec/icount.h" /* clock and ticks */ diff --git a/system/dma-helpers.c b/system/dma-helpers.c index 6bad75876f..0d592f6468 100644 --- a/system/dma-helpers.c +++ b/system/dma-helpers.c @@ -13,7 +13,7 @@ #include "trace.h" #include "qemu/thread.h" #include "qemu/main-loop.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/range.h" /* #define DEBUG_IOMMU */ diff --git a/system/vl.c b/system/vl.c index ec93988a03..c17945c493 100644 --- a/system/vl.c +++ b/system/vl.c @@ -89,6 +89,7 @@ #include "audio/audio.h" #include "system/cpus.h" #include "system/cpu-timers.h" +#include "exec/icount.h" #include "migration/colo.h" #include "migration/postcopy-ram.h" #include "system/kvm.h" diff --git a/target/arm/helper.c b/target/arm/helper.c index 0454b06a6c..becbbbd0d8 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -24,6 +24,7 @@ #include "exec/translation-block.h" #include "hw/irq.h" #include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/kvm.h" #include "system/tcg.h" #include "qapi/error.h" diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 6c4391d96b..0dd8645994 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -31,7 +31,7 @@ #include "accel/tcg/cpu-ops.h" #include "trace.h" #include "semihosting/common-semi.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "cpu_bits.h" #include "debug.h" #include "pmp.h" diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 7948188356..c52c87faae 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -27,7 +27,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "qemu/guest-random.h" #include "qapi/error.h" #include diff --git a/target/riscv/debug.c b/target/riscv/debug.c index fea989afe9..7fc9e121e1 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -32,6 +32,7 @@ #include "exec/helper-proto.h" #include "exec/watchpoint.h" #include "system/cpu-timers.h" +#include "exec/icount.h" /* * The following M-mode trigger CSRs are implemented: diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 889e2b6570..a1f70cc955 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -21,7 +21,7 @@ #include "qemu/error-report.h" #include "system/kvm.h" #include "migration/cpu.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "debug.h" static bool pmp_needed(void *opaque) diff --git a/target/riscv/pmu.c b/target/riscv/pmu.c index 0408f96e6a..a68809eef3 100644 --- a/target/riscv/pmu.c +++ b/target/riscv/pmu.c @@ -22,7 +22,7 @@ #include "qemu/timer.h" #include "cpu.h" #include "pmu.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/device_tree.h" #define RISCV_TIMEBASE_FREQ 1000000000 /* 1Ghz */ diff --git a/util/async.c b/util/async.c index 863416dee9..2719c629ae 100644 --- a/util/async.c +++ b/util/async.c @@ -35,7 +35,7 @@ #include "block/raw-aio.h" #include "qemu/coroutine_int.h" #include "qemu/coroutine-tls.h" -#include "system/cpu-timers.h" +#include "exec/icount.h" #include "trace.h" /***********************************************************/ diff --git a/util/main-loop.c b/util/main-loop.c index acad8c2e6c..42bd75c193 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -27,6 +27,7 @@ #include "qemu/cutils.h" #include "qemu/timer.h" #include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/replay.h" #include "qemu/main-loop.h" #include "block/aio.h" diff --git a/util/qemu-timer.c b/util/qemu-timer.c index 788466fe22..1fb48be281 100644 --- a/util/qemu-timer.c +++ b/util/qemu-timer.c @@ -27,6 +27,7 @@ #include "qemu/timer.h" #include "qemu/lockable.h" #include "system/cpu-timers.h" +#include "exec/icount.h" #include "system/replay.h" #include "system/cpus.h" From 1751889b5a63f7b246525fad4cfd6902e674dcc4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 14 Mar 2025 13:15:07 -0700 Subject: [PATCH 0136/2760] include/exec: Protect icount_enabled from poisoned symbols Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/icount.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/exec/icount.h b/include/exec/icount.h index 4964987ae4..7a26b40084 100644 --- a/include/exec/icount.h +++ b/include/exec/icount.h @@ -22,13 +22,21 @@ typedef enum { ICOUNT_ADAPTATIVE, } ICountMode; -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) +#ifdef CONFIG_TCG extern ICountMode use_icount; #define icount_enabled() (use_icount) #else #define icount_enabled() ICOUNT_DISABLED #endif +/* Protect the CONFIG_USER_ONLY test vs poisoning. */ +#if defined(COMPILING_PER_TARGET) || defined(COMPILING_SYSTEM_VS_USER) +# ifdef CONFIG_USER_ONLY +# undef icount_enabled +# define icount_enabled() ICOUNT_DISABLED +# endif +#endif + /* * Update the icount with the executed instructions. Called by * cpus-tcg vCPU thread so the main-loop can see time has moved forward. From 4d9baad7dc1d57cc3fe7d71d16431ccff203dfbb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:15:41 -0700 Subject: [PATCH 0137/2760] include/system: Remove ifndef CONFIG_USER_ONLY in qtest.h This is include/system, so CONFIG_USER_ONLY will never be true. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/system/qtest.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/system/qtest.h b/include/system/qtest.h index 6ddddc501b..84b1f8c6ee 100644 --- a/include/system/qtest.h +++ b/include/system/qtest.h @@ -23,7 +23,6 @@ static inline bool qtest_enabled(void) return qtest_allowed; } -#ifndef CONFIG_USER_ONLY void G_GNUC_PRINTF(2, 3) qtest_sendf(CharBackend *chr, const char *fmt, ...); void qtest_set_command_cb(bool (*pc_cb)(CharBackend *chr, gchar **words)); bool qtest_driver(void); @@ -33,6 +32,5 @@ void qtest_server_init(const char *qtest_chrdev, const char *qtest_log, Error ** void qtest_server_set_send_handler(void (*send)(void *, const char *), void *opaque); void qtest_server_inproc_recv(void *opaque, const char *buf); -#endif #endif From c09a2edce0b0764698f61073e968288820b0941c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:18:08 -0700 Subject: [PATCH 0138/2760] include/qemu: Remove ifndef CONFIG_USER_ONLY from accel.h While setup_post and has_memory will not be used for CONFIG_USER_ONLY, let the struct have constant layout. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/qemu/accel.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/include/qemu/accel.h b/include/qemu/accel.h index 972a849a2b..fbd3d897fe 100644 --- a/include/qemu/accel.h +++ b/include/qemu/accel.h @@ -38,13 +38,13 @@ typedef struct AccelClass { const char *name; int (*init_machine)(MachineState *ms); -#ifndef CONFIG_USER_ONLY + bool (*cpu_common_realize)(CPUState *cpu, Error **errp); + void (*cpu_common_unrealize)(CPUState *cpu); + + /* system related hooks */ void (*setup_post)(MachineState *ms, AccelState *accel); bool (*has_memory)(MachineState *ms, AddressSpace *as, hwaddr start_addr, hwaddr size); -#endif - bool (*cpu_common_realize)(CPUState *cpu, Error **errp); - void (*cpu_common_unrealize)(CPUState *cpu); /* gdbstub related hooks */ int (*gdbstub_supported_sstep_flags)(void); @@ -78,12 +78,10 @@ const char *current_accel_name(void); void accel_init_interfaces(AccelClass *ac); -#ifndef CONFIG_USER_ONLY int accel_init_machine(AccelState *accel, MachineState *ms); /* Called just before os_setup_post (ie just before drop OS privs) */ void accel_setup_post(MachineState *ms); -#endif /* !CONFIG_USER_ONLY */ /** * accel_cpu_instance_init: From e4610f38095a3ae01177fe67fd70e4d66b683259 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:23:18 -0700 Subject: [PATCH 0139/2760] target/riscv: Remove ifndef CONFIG_USER_ONLY from cpu_cfg.h While RISCVCPUConfig.satp_mode is unused for user-only, this header is used from disas/riscv.h, whose users are only built once. The savings of 4 bytes isn't worth it. Reviewed-by: Alistair Francis Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/riscv/cpu_cfg.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 8a843482cc..cfe371b829 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -196,9 +196,7 @@ struct RISCVCPUConfig { bool short_isa_string; -#ifndef CONFIG_USER_ONLY RISCVSATPMap satp_mode; -#endif }; typedef struct RISCVCPUConfig RISCVCPUConfig; From 8916c373a3fd56938f1b7d57010491a0b9662b1e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Mar 2025 20:24:44 -0700 Subject: [PATCH 0140/2760] meson: Only allow CONFIG_USER_ONLY from certain source sets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Poison CONFIG_USER_ONLY and CONFIG_SOFTMMU unless the compilation unit is in specific_ss, libuser_ss, or libsystem_ss. This is intended to prevent files being incorrectly added to common_ss. Remove #ifndef CONFIG_USER_ONLY / #error / #endif blocks. All they do is trigger the poison error. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/poison.h | 5 +++++ include/hw/hw.h | 4 ---- include/system/confidential-guest-support.h | 4 ---- include/system/replay.h | 4 ---- include/system/xen.h | 4 ---- meson.build | 6 ++++-- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/include/exec/poison.h b/include/exec/poison.h index 2c151fd1e0..4180a5a489 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -66,4 +66,9 @@ #pragma GCC poison CONFIG_WHPX #pragma GCC poison CONFIG_XEN +#ifndef COMPILING_SYSTEM_VS_USER +#pragma GCC poison CONFIG_USER_ONLY +#pragma GCC poison CONFIG_SOFTMMU +#endif + #endif diff --git a/include/hw/hw.h b/include/hw/hw.h index 045c1c8b09..1b33d12b7f 100644 --- a/include/hw/hw.h +++ b/include/hw/hw.h @@ -1,10 +1,6 @@ #ifndef QEMU_HW_H #define QEMU_HW_H -#ifdef CONFIG_USER_ONLY -#error Cannot include hw/hw.h from user emulation -#endif - G_NORETURN void hw_error(const char *fmt, ...) G_GNUC_PRINTF(1, 2); #endif diff --git a/include/system/confidential-guest-support.h b/include/system/confidential-guest-support.h index b68c4bebbc..ea46b50c56 100644 --- a/include/system/confidential-guest-support.h +++ b/include/system/confidential-guest-support.h @@ -18,10 +18,6 @@ #ifndef QEMU_CONFIDENTIAL_GUEST_SUPPORT_H #define QEMU_CONFIDENTIAL_GUEST_SUPPORT_H -#ifdef CONFIG_USER_ONLY -#error Cannot include system/confidential-guest-support.h from user emulation -#endif - #include "qom/object.h" #define TYPE_CONFIDENTIAL_GUEST_SUPPORT "confidential-guest-support" diff --git a/include/system/replay.h b/include/system/replay.h index 8926d8cf4b..1c87c97fdd 100644 --- a/include/system/replay.h +++ b/include/system/replay.h @@ -11,10 +11,6 @@ #ifndef SYSTEM_REPLAY_H #define SYSTEM_REPLAY_H -#ifdef CONFIG_USER_ONLY -#error Cannot include this header from user emulation -#endif - #include "exec/replay-core.h" #include "qapi/qapi-types-misc.h" #include "qapi/qapi-types-run-state.h" diff --git a/include/system/xen.h b/include/system/xen.h index 5f41915732..c2f283d1c2 100644 --- a/include/system/xen.h +++ b/include/system/xen.h @@ -10,10 +10,6 @@ #ifndef SYSTEM_XEN_H #define SYSTEM_XEN_H -#ifdef CONFIG_USER_ONLY -#error Cannot include system/xen.h from user emulation -#endif - #include "exec/cpu-common.h" #ifdef COMPILING_PER_TARGET diff --git a/meson.build b/meson.build index 7e22afe135..657949326b 100644 --- a/meson.build +++ b/meson.build @@ -4050,7 +4050,8 @@ common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) libuser_ss = libuser_ss.apply({}) libuser = static_library('user', libuser_ss.sources() + genh, - c_args: '-DCONFIG_USER_ONLY', + c_args: ['-DCONFIG_USER_ONLY', + '-DCOMPILING_SYSTEM_VS_USER'], dependencies: libuser_ss.dependencies(), build_by_default: false) libuser = declare_dependency(objects: libuser.extract_all_objects(recursive: false), @@ -4060,7 +4061,8 @@ common_ss.add(when: 'CONFIG_USER_ONLY', if_true: libuser) libsystem_ss = libsystem_ss.apply({}) libsystem = static_library('system', libsystem_ss.sources() + genh, - c_args: '-DCONFIG_SOFTMMU', + c_args: ['-DCONFIG_SOFTMMU', + '-DCOMPILING_SYSTEM_VS_USER'], dependencies: libsystem_ss.dependencies(), build_by_default: false) libsystem = declare_dependency(objects: libsystem.extract_all_objects(recursive: false), From 4d43552abe5c20ab414c054dd591bb6777832355 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 20 Mar 2025 15:29:34 -0700 Subject: [PATCH 0141/2760] exec/cpu-all: extract tlb flags defines to exec/tlb-flags.h Signed-off-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250320223002.2915728-3-pierrick.bouvier@linaro.org> --- accel/tcg/cputlb.c | 1 + accel/tcg/user-exec.c | 1 + include/exec/cpu-all.h | 63 -------------------- include/exec/tlb-flags.h | 89 ++++++++++++++++++++++++++++ semihosting/uaccess.c | 1 + target/arm/ptw.c | 1 + target/arm/tcg/helper-a64.c | 1 + target/arm/tcg/mte_helper.c | 1 + target/arm/tcg/sve_helper.c | 1 + target/i386/tcg/system/excp_helper.c | 1 + target/riscv/op_helper.c | 1 + target/riscv/vector_helper.c | 1 + target/s390x/tcg/mem_helper.c | 1 + target/sparc/mmu_helper.c | 1 + 14 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 include/exec/tlb-flags.h diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 613f919fff..b2db49e305 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -34,6 +34,7 @@ #include "qemu/error-report.h" #include "exec/log.h" #include "exec/helper-proto-common.h" +#include "exec/tlb-flags.h" #include "qemu/atomic.h" #include "qemu/atomic128.h" #include "tb-internal.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index ebc7c3ecf5..667c5e0354 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -21,6 +21,7 @@ #include "disas/disas.h" #include "exec/vaddr.h" #include "exec/exec-all.h" +#include "exec/tlb-flags.h" #include "tcg/tcg.h" #include "qemu/bitops.h" #include "qemu/rcu.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 4395fd08af..5c4379f0d0 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -35,69 +35,6 @@ CPUArchState *cpu_copy(CPUArchState *env); #include "cpu.h" -#ifdef CONFIG_USER_ONLY - -/* - * Allow some level of source compatibility with softmmu. We do not - * support any of the more exotic features, so only invalid pages may - * be signaled by probe_access_flags(). - */ -#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) -#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2)) -#define TLB_WATCHPOINT 0 - -#else - -/* - * Flags stored in the low bits of the TLB virtual address. - * These are defined so that fast path ram access is all zeros. - * The flags all must be between TARGET_PAGE_BITS and - * maximum address alignment bit. - * - * Use TARGET_PAGE_BITS_MIN so that these bits are constant - * when TARGET_PAGE_BITS_VARY is in effect. - * - * The count, if not the placement of these bits is known - * to tcg/tcg-op-ldst.c, check_max_alignment(). - */ -/* Zero if TLB entry is valid. */ -#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) -/* Set if TLB entry references a clean RAM page. The iotlb entry will - contain the page physical address. */ -#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2)) -/* Set if TLB entry is an IO callback. */ -#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3)) -/* Set if TLB entry writes ignored. */ -#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 4)) -/* Set if the slow path must be used; more flags in CPUTLBEntryFull. */ -#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5)) - -/* - * Use this mask to check interception with an alignment mask - * in a TCG backend. - */ -#define TLB_FLAGS_MASK \ - (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ - | TLB_FORCE_SLOW | TLB_DISCARD_WRITE) - -/* - * Flags stored in CPUTLBEntryFull.slow_flags[x]. - * TLB_FORCE_SLOW must be set in CPUTLBEntry.addr_idx[x]. - */ -/* Set if TLB entry requires byte swap. */ -#define TLB_BSWAP (1 << 0) -/* Set if TLB entry contains a watchpoint. */ -#define TLB_WATCHPOINT (1 << 1) -/* Set if TLB entry requires aligned accesses. */ -#define TLB_CHECK_ALIGNED (1 << 2) - -#define TLB_SLOW_FLAGS_MASK (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED) - -/* The two sets of flags must not overlap. */ -QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); - -#endif /* !CONFIG_USER_ONLY */ - /* Validate correct placement of CPUArchState. */ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); diff --git a/include/exec/tlb-flags.h b/include/exec/tlb-flags.h new file mode 100644 index 0000000000..a0e51a4b37 --- /dev/null +++ b/include/exec/tlb-flags.h @@ -0,0 +1,89 @@ +/* + * TLB flags definition + * + * Copyright (c) 2003 Fabrice Bellard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ +#ifndef TLB_FLAGS_H +#define TLB_FLAGS_H + +#include "exec/cpu-defs.h" + +#ifdef CONFIG_USER_ONLY + +/* + * Allow some level of source compatibility with softmmu. We do not + * support any of the more exotic features, so only invalid pages may + * be signaled by probe_access_flags(). + */ +#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) +#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2)) +#define TLB_WATCHPOINT 0 + +#else + +/* + * Flags stored in the low bits of the TLB virtual address. + * These are defined so that fast path ram access is all zeros. + * The flags all must be between TARGET_PAGE_BITS and + * maximum address alignment bit. + * + * Use TARGET_PAGE_BITS_MIN so that these bits are constant + * when TARGET_PAGE_BITS_VARY is in effect. + * + * The count, if not the placement of these bits is known + * to tcg/tcg-op-ldst.c, check_max_alignment(). + */ +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) +/* + * Set if TLB entry references a clean RAM page. The iotlb entry will + * contain the page physical address. + */ +#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2)) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3)) +/* Set if TLB entry writes ignored. */ +#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 4)) +/* Set if the slow path must be used; more flags in CPUTLBEntryFull. */ +#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5)) + +/* + * Use this mask to check interception with an alignment mask + * in a TCG backend. + */ +#define TLB_FLAGS_MASK \ + (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ + | TLB_FORCE_SLOW | TLB_DISCARD_WRITE) + +/* + * Flags stored in CPUTLBEntryFull.slow_flags[x]. + * TLB_FORCE_SLOW must be set in CPUTLBEntry.addr_idx[x]. + */ +/* Set if TLB entry requires byte swap. */ +#define TLB_BSWAP (1 << 0) +/* Set if TLB entry contains a watchpoint. */ +#define TLB_WATCHPOINT (1 << 1) +/* Set if TLB entry requires aligned accesses. */ +#define TLB_CHECK_ALIGNED (1 << 2) + +#define TLB_SLOW_FLAGS_MASK (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED) + +/* The two sets of flags must not overlap. */ +QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); + +#endif /* !CONFIG_USER_ONLY */ + +#endif /* TLB_FLAGS_H */ diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index 2e33596428..ccb0c96070 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -11,6 +11,7 @@ #include "exec/cpu-all.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" +#include "exec/tlb-flags.h" #include "semihosting/uaccess.h" void *uaccess_lock_user(CPUArchState *env, target_ulong addr, diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 4330900348..8d4e9e07a9 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -12,6 +12,7 @@ #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/tlb-flags.h" #include "cpu.h" #include "internals.h" #include "cpu-features.h" diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 9244848efe..fa79d19425 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -31,6 +31,7 @@ #include "exec/cpu-common.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "exec/tlb-flags.h" #include "qemu/int128.h" #include "qemu/atomic128.h" #include "fpu/softfloat.h" diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 80164a8050..888c670754 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -31,6 +31,7 @@ #endif #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" +#include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" #include "qapi/error.h" #include "qemu/guest-random.h" diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index d786b4b111..e3bed77b48 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" +#include "exec/tlb-flags.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" #include "tcg/tcg.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index 6876329de2..b0b74df72f 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -22,6 +22,7 @@ #include "exec/cpu_ldst.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/tlb-flags.h" #include "tcg/helper-tcg.h" typedef struct TranslateParams { diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 72dc48e58d..f3d26b6b95 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -25,6 +25,7 @@ #include "exec/cputlb.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" +#include "exec/tlb-flags.h" #include "trace.h" /* Exceptions processing helpers */ diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 67b3bafebb..83978be060 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -25,6 +25,7 @@ #include "exec/cpu_ldst.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" +#include "exec/tlb-flags.h" #include "fpu/softfloat.h" #include "tcg/tcg-gvec-desc.h" #include "internals.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 8187b917ba..0ff2e10d81 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -29,6 +29,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/cpu_ldst.h" +#include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" #include "qemu/int128.h" #include "qemu/atomic128.h" diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 78cb24a8e2..249b1f6c4c 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/tlb-flags.h" #include "qemu/qemu-print.h" #include "trace.h" From 31d399ff385498816e597bcc72de0f6efc36051e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 19:47:32 -0700 Subject: [PATCH 0142/2760] accel/tcg: Fix argument types of tlb_reset_dirty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The arguments to tlb_reset_dirty are host pointers. The conversion from ram_addr_t was done in the sole caller, tlb_reset_dirty_range_all. Fixes: e554861766d ("exec: prepare for splitting") Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 6 +++--- include/exec/cputlb.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index b2db49e305..10090067f7 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -912,7 +912,7 @@ static inline void copy_tlb_helper_locked(CPUTLBEntry *d, const CPUTLBEntry *s) * We must take tlb_c.lock to avoid racing with another vCPU update. The only * thing actually updated is the target TLB entry ->addr_write flags. */ -void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) +void tlb_reset_dirty(CPUState *cpu, uintptr_t start, uintptr_t length) { int mmu_idx; @@ -923,12 +923,12 @@ void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length) for (i = 0; i < n; i++) { tlb_reset_dirty_range_locked(&cpu->neg.tlb.f[mmu_idx].table[i], - start1, length); + start, length); } for (i = 0; i < CPU_VTLB_SIZE; i++) { tlb_reset_dirty_range_locked(&cpu->neg.tlb.d[mmu_idx].vtable[i], - start1, length); + start, length); } } qemu_spin_unlock(&cpu->neg.tlb.c.lock); diff --git a/include/exec/cputlb.h b/include/exec/cputlb.h index 8125f6809c..03ed7e2165 100644 --- a/include/exec/cputlb.h +++ b/include/exec/cputlb.h @@ -31,7 +31,7 @@ void tlb_unprotect_code(ram_addr_t ram_addr); #endif #ifndef CONFIG_USER_ONLY -void tlb_reset_dirty(CPUState *cpu, ram_addr_t start1, ram_addr_t length); +void tlb_reset_dirty(CPUState *cpu, uintptr_t start, uintptr_t length); void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length); #endif From 970354edc09a0ede505cea117b92e71330f1ed53 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 20:10:42 -0700 Subject: [PATCH 0143/2760] accel/tcg: Pass CPUTLBEntryFull to tlb_reset_dirty_range_locked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While we're renaming things, don't modify addr; save it for reuse in the qatomic_set. Compute the host address into a new local variable. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 10090067f7..5df98d93d0 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -882,18 +882,16 @@ void tlb_unprotect_code(ram_addr_t ram_addr) * * Called with tlb_c.lock held. */ -static void tlb_reset_dirty_range_locked(CPUTLBEntry *tlb_entry, +static void tlb_reset_dirty_range_locked(CPUTLBEntryFull *full, CPUTLBEntry *ent, uintptr_t start, uintptr_t length) { - uintptr_t addr = tlb_entry->addr_write; + const uintptr_t addr = ent->addr_write; if ((addr & (TLB_INVALID_MASK | TLB_MMIO | TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { - addr &= TARGET_PAGE_MASK; - addr += tlb_entry->addend; - if ((addr - start) < length) { - qatomic_set(&tlb_entry->addr_write, - tlb_entry->addr_write | TLB_NOTDIRTY); + uintptr_t host = (addr & TARGET_PAGE_MASK) + ent->addend; + if ((host - start) < length) { + qatomic_set(&ent->addr_write, addr | TLB_NOTDIRTY); } } } @@ -918,16 +916,18 @@ void tlb_reset_dirty(CPUState *cpu, uintptr_t start, uintptr_t length) qemu_spin_lock(&cpu->neg.tlb.c.lock); for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { + CPUTLBDesc *desc = &cpu->neg.tlb.d[mmu_idx]; + CPUTLBDescFast *fast = &cpu->neg.tlb.f[mmu_idx]; + unsigned int n = tlb_n_entries(fast); unsigned int i; - unsigned int n = tlb_n_entries(&cpu->neg.tlb.f[mmu_idx]); for (i = 0; i < n; i++) { - tlb_reset_dirty_range_locked(&cpu->neg.tlb.f[mmu_idx].table[i], + tlb_reset_dirty_range_locked(&desc->fulltlb[i], &fast->table[i], start, length); } for (i = 0; i < CPU_VTLB_SIZE; i++) { - tlb_reset_dirty_range_locked(&cpu->neg.tlb.d[mmu_idx].vtable[i], + tlb_reset_dirty_range_locked(&desc->vfulltlb[i], &desc->vtable[i], start, length); } } From f05d251906a335465a5c5b3a6ffcdce96eca54f4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 20:21:23 -0700 Subject: [PATCH 0144/2760] accel/tcg: Rebuild full flags in tlb_reset_dirty_range_locked Undo the split between inline and slow flags before masking. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 5df98d93d0..28c47d4872 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -886,9 +886,10 @@ static void tlb_reset_dirty_range_locked(CPUTLBEntryFull *full, CPUTLBEntry *ent uintptr_t start, uintptr_t length) { const uintptr_t addr = ent->addr_write; + int flags = addr | full->slow_flags[MMU_DATA_STORE]; - if ((addr & (TLB_INVALID_MASK | TLB_MMIO | - TLB_DISCARD_WRITE | TLB_NOTDIRTY)) == 0) { + flags &= TLB_INVALID_MASK | TLB_MMIO | TLB_DISCARD_WRITE | TLB_NOTDIRTY; + if (flags == 0) { uintptr_t host = (addr & TARGET_PAGE_MASK) + ent->addend; if ((host - start) < length) { qatomic_set(&ent->addr_write, addr | TLB_NOTDIRTY); From 24b5e0fdb543a09c26d6d77051b17055288bef8e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 25 Mar 2025 20:22:14 -0700 Subject: [PATCH 0145/2760] include/exec: Move TLB_MMIO, TLB_DISCARD_WRITE to slow flags Recover two bits from the inline flags. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/tlb-flags.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/exec/tlb-flags.h b/include/exec/tlb-flags.h index a0e51a4b37..54a6bae768 100644 --- a/include/exec/tlb-flags.h +++ b/include/exec/tlb-flags.h @@ -53,20 +53,15 @@ * contain the page physical address. */ #define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2)) -/* Set if TLB entry is an IO callback. */ -#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 3)) -/* Set if TLB entry writes ignored. */ -#define TLB_DISCARD_WRITE (1 << (TARGET_PAGE_BITS_MIN - 4)) /* Set if the slow path must be used; more flags in CPUTLBEntryFull. */ -#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 5)) +#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 3)) /* * Use this mask to check interception with an alignment mask * in a TCG backend. */ #define TLB_FLAGS_MASK \ - (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_MMIO \ - | TLB_FORCE_SLOW | TLB_DISCARD_WRITE) + (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_FORCE_SLOW) /* * Flags stored in CPUTLBEntryFull.slow_flags[x]. @@ -78,8 +73,14 @@ #define TLB_WATCHPOINT (1 << 1) /* Set if TLB entry requires aligned accesses. */ #define TLB_CHECK_ALIGNED (1 << 2) +/* Set if TLB entry writes ignored. */ +#define TLB_DISCARD_WRITE (1 << 3) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << 4) -#define TLB_SLOW_FLAGS_MASK (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED) +#define TLB_SLOW_FLAGS_MASK \ + (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED | \ + TLB_DISCARD_WRITE | TLB_MMIO) /* The two sets of flags must not overlap. */ QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); From a456c72695e59589d88100ca7b3448817a6fa953 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 16:11:09 -0500 Subject: [PATCH 0146/2760] include/exec: Move tb_{,set_}page_addr[01] to translation-block.h Move the accessor functions for TranslationBlock into the header related to the structure. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/exec-all.h | 49 ------------------------------- include/exec/translation-block.h | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 19b0eda44a..fcad3446fe 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -123,55 +123,6 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif /* !CONFIG_USER_ONLY */ #endif /* CONFIG_TCG */ -static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb) -{ -#ifdef CONFIG_USER_ONLY - return tb->itree.start; -#else - return tb->page_addr[0]; -#endif -} - -static inline tb_page_addr_t tb_page_addr1(const TranslationBlock *tb) -{ -#ifdef CONFIG_USER_ONLY - tb_page_addr_t next = tb->itree.last & TARGET_PAGE_MASK; - return next == (tb->itree.start & TARGET_PAGE_MASK) ? -1 : next; -#else - return tb->page_addr[1]; -#endif -} - -static inline void tb_set_page_addr0(TranslationBlock *tb, - tb_page_addr_t addr) -{ -#ifdef CONFIG_USER_ONLY - tb->itree.start = addr; - /* - * To begin, we record an interval of one byte. When the translation - * loop encounters a second page, the interval will be extended to - * include the first byte of the second page, which is sufficient to - * allow tb_page_addr1() above to work properly. The final corrected - * interval will be set by tb_page_add() from tb->size before the - * node is added to the interval tree. - */ - tb->itree.last = addr; -#else - tb->page_addr[0] = addr; -#endif -} - -static inline void tb_set_page_addr1(TranslationBlock *tb, - tb_page_addr_t addr) -{ -#ifdef CONFIG_USER_ONLY - /* Extend the interval to the first byte of the second page. See above. */ - tb->itree.last = addr; -#else - tb->page_addr[1] = addr; -#endif -} - /* TranslationBlock invalidate API */ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last); diff --git a/include/exec/translation-block.h b/include/exec/translation-block.h index 3c69bc71a9..8b8e730561 100644 --- a/include/exec/translation-block.h +++ b/include/exec/translation-block.h @@ -13,6 +13,7 @@ #include "exec/vaddr.h" #ifdef CONFIG_USER_ONLY #include "qemu/interval-tree.h" +#include "exec/target_page.h" #endif /* @@ -157,4 +158,53 @@ static inline uint32_t tb_cflags(const TranslationBlock *tb) bool tcg_cflags_has(CPUState *cpu, uint32_t flags); void tcg_cflags_set(CPUState *cpu, uint32_t flags); +static inline tb_page_addr_t tb_page_addr0(const TranslationBlock *tb) +{ +#ifdef CONFIG_USER_ONLY + return tb->itree.start; +#else + return tb->page_addr[0]; +#endif +} + +static inline tb_page_addr_t tb_page_addr1(const TranslationBlock *tb) +{ +#ifdef CONFIG_USER_ONLY + tb_page_addr_t next = tb->itree.last & TARGET_PAGE_MASK; + return next == (tb->itree.start & TARGET_PAGE_MASK) ? -1 : next; +#else + return tb->page_addr[1]; +#endif +} + +static inline void tb_set_page_addr0(TranslationBlock *tb, + tb_page_addr_t addr) +{ +#ifdef CONFIG_USER_ONLY + tb->itree.start = addr; + /* + * To begin, we record an interval of one byte. When the translation + * loop encounters a second page, the interval will be extended to + * include the first byte of the second page, which is sufficient to + * allow tb_page_addr1() above to work properly. The final corrected + * interval will be set by tb_page_add() from tb->size before the + * node is added to the interval tree. + */ + tb->itree.last = addr; +#else + tb->page_addr[0] = addr; +#endif +} + +static inline void tb_set_page_addr1(TranslationBlock *tb, + tb_page_addr_t addr) +{ +#ifdef CONFIG_USER_ONLY + /* Extend the interval to the first byte of the second page. See above. */ + tb->itree.last = addr; +#else + tb->page_addr[1] = addr; +#endif +} + #endif /* EXEC_TRANSLATION_BLOCK_H */ From aa6f138abada97176598c89a9e4e3a7c3d47cb1e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 16:28:08 -0500 Subject: [PATCH 0147/2760] accel/tcg: Move get_page_addr_code* declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the declarations from exec/exec-all.h to the private accel/tcg/internal-common.h. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/internal-common.h | 34 ++++++++++++++++++++++++++++++++++ accel/tcg/translator.c | 1 + include/exec/exec-all.h | 34 ---------------------------------- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 9b6ab3a8cc..2f00560d10 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -74,4 +74,38 @@ uint32_t curr_cflags(CPUState *cpu); void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr); +/** + * get_page_addr_code_hostp() + * @env: CPUArchState + * @addr: guest virtual address of guest code + * + * See get_page_addr_code() (full-system version) for documentation on the + * return value. + * + * Sets *@hostp (when @hostp is non-NULL) as follows. + * If the return value is -1, sets *@hostp to NULL. Otherwise, sets *@hostp + * to the host address where @addr's content is kept. + * + * Note: this function can trigger an exception. + */ +tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, + void **hostp); + +/** + * get_page_addr_code() + * @env: CPUArchState + * @addr: guest virtual address of guest code + * + * If we cannot translate and execute from the entire RAM page, or if + * the region is not backed by RAM, returns -1. Otherwise, returns the + * ram_addr_t corresponding to the guest code at @addr. + * + * Note: this function can trigger an exception. + */ +static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, + vaddr addr) +{ + return get_page_addr_code_hostp(env, addr, NULL); +} + #endif diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 2ab081b95f..5f0aa9d56a 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -17,6 +17,7 @@ #include "exec/translator.h" #include "exec/plugin-gen.h" #include "tcg/tcg-op-common.h" +#include "internal-common.h" #include "internal-target.h" #include "disas/disas.h" #include "tb-internal.h" diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index fcad3446fe..f52a680f42 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -143,40 +143,6 @@ struct MemoryRegionSection *iotlb_to_section(CPUState *cpu, hwaddr index, MemTxAttrs attrs); #endif -/** - * get_page_addr_code_hostp() - * @env: CPUArchState - * @addr: guest virtual address of guest code - * - * See get_page_addr_code() (full-system version) for documentation on the - * return value. - * - * Sets *@hostp (when @hostp is non-NULL) as follows. - * If the return value is -1, sets *@hostp to NULL. Otherwise, sets *@hostp - * to the host address where @addr's content is kept. - * - * Note: this function can trigger an exception. - */ -tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, - void **hostp); - -/** - * get_page_addr_code() - * @env: CPUArchState - * @addr: guest virtual address of guest code - * - * If we cannot translate and execute from the entire RAM page, or if - * the region is not backed by RAM, returns -1. Otherwise, returns the - * ram_addr_t corresponding to the guest code at @addr. - * - * Note: this function can trigger an exception. - */ -static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, - vaddr addr) -{ - return get_page_addr_code_hostp(env, addr, NULL); -} - #if !defined(CONFIG_USER_ONLY) MemoryRegionSection * From b103cc6e74ac92f070a0e004bd84334e845c20b5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 16:48:09 -0500 Subject: [PATCH 0148/2760] accel/tcg: Remove page_protect Merge the user-only page_protect function with the user-only implementation of tb_lock_page0. This avoids pulling page-protection.h into tb-internal.h. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-internal.h | 11 +++-------- accel/tcg/user-exec.c | 2 +- include/user/page-protection.h | 1 - 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/accel/tcg/tb-internal.h b/accel/tcg/tb-internal.h index 68aa8d17f4..f7c2073e29 100644 --- a/accel/tcg/tb-internal.h +++ b/accel/tcg/tb-internal.h @@ -51,28 +51,23 @@ #endif /* CONFIG_SOFTMMU */ +void tb_lock_page0(tb_page_addr_t); + #ifdef CONFIG_USER_ONLY -#include "user/page-protection.h" /* * For user-only, page_protect sets the page read-only. * Since most execution is already on read-only pages, and we'd need to * account for other TBs on the same page, defer undoing any page protection * until we receive the write fault. */ -static inline void tb_lock_page0(tb_page_addr_t p0) -{ - page_protect(p0); -} - static inline void tb_lock_page1(tb_page_addr_t p0, tb_page_addr_t p1) { - page_protect(p1); + tb_lock_page0(p1); } static inline void tb_unlock_page1(tb_page_addr_t p0, tb_page_addr_t p1) { } static inline void tb_unlock_pages(TranslationBlock *tb) { } #else -void tb_lock_page0(tb_page_addr_t); void tb_lock_page1(tb_page_addr_t, tb_page_addr_t); void tb_unlock_page1(tb_page_addr_t, tb_page_addr_t); void tb_unlock_pages(TranslationBlock *); diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 667c5e0354..72a9809c2d 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -657,7 +657,7 @@ target_ulong page_find_range_empty(target_ulong min, target_ulong max, } } -void page_protect(tb_page_addr_t address) +void tb_lock_page0(tb_page_addr_t address) { PageFlagsNode *p; target_ulong start, last; diff --git a/include/user/page-protection.h b/include/user/page-protection.h index 51daa18648..d5c8748d49 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -16,7 +16,6 @@ #include "exec/target_long.h" #include "exec/translation-block.h" -void page_protect(tb_page_addr_t page_addr); int page_unprotect(tb_page_addr_t address, uintptr_t pc); int page_get_flags(target_ulong address); From 7b18e3a727f46771f41eb764c2b40cebca81c3de Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 17:07:09 -0500 Subject: [PATCH 0149/2760] accel/tcg: Remove cpu-all.h, exec-all.h from tb-internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used by tb-internal.h, but add an include for target_page.h in tb-maint.c. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-internal.h | 2 -- accel/tcg/tb-maint.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/accel/tcg/tb-internal.h b/accel/tcg/tb-internal.h index f7c2073e29..f9a06bcbab 100644 --- a/accel/tcg/tb-internal.h +++ b/accel/tcg/tb-internal.h @@ -9,8 +9,6 @@ #ifndef ACCEL_TCG_TB_INTERNAL_TARGET_H #define ACCEL_TCG_TB_INTERNAL_TARGET_H -#include "exec/cpu-all.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" /* diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index d5899ad047..df3438e190 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -26,6 +26,7 @@ #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "exec/tb-flush.h" +#include "exec/target_page.h" #include "tb-internal.h" #include "system/tcg.h" #include "tcg/tcg.h" From f3ad026e359971729539c6af799859b003f81b9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 09:20:52 +0200 Subject: [PATCH 0150/2760] target/rx: Fix copy/paste typo (riscv -> rx) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename riscv_cpu_mmu_index() -> rx_cpu_mmu_index(). Fixes: ef5cc166da1 ("target/rx: Populate CPUClass.mmu_index") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401072052.25892-1-philmd@linaro.org> --- target/rx/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 0ba0d55ab5..a240b3b3ce 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -66,7 +66,7 @@ static bool rx_cpu_has_work(CPUState *cs) (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIR); } -static int riscv_cpu_mmu_index(CPUState *cs, bool ifunc) +static int rx_cpu_mmu_index(CPUState *cs, bool ifunc) { return 0; } @@ -227,7 +227,7 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data) &rcc->parent_phases); cc->class_by_name = rx_cpu_class_by_name; - cc->mmu_index = riscv_cpu_mmu_index; + cc->mmu_index = rx_cpu_mmu_index; cc->dump_state = rx_cpu_dump_state; cc->set_pc = rx_cpu_set_pc; cc->get_pc = rx_cpu_get_pc; From 6ca6310699f5a295115e090c489d411fd219dcf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:14 +0200 Subject: [PATCH 0151/2760] hw/core/cpu: Update CPUClass::mmu_index docstring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commits 32a8ea12fab..90b7022e698 (target: "Split out TARGET_env_mmu_index"), target's memory_rw_debug() callbacks use the target's TARGET_env_mmu_index(), not the generic CPUClass::mmu_index() callback. Update the documentation. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-2-philmd@linaro.org> --- include/hw/core/cpu.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 6dcee5d0ba..29f6419050 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -104,8 +104,7 @@ struct SysemuCPUOps; * instantiatable CPU type. * @parse_features: Callback to parse command line arguments. * @reset_dump_flags: #CPUDumpFlags to use for reset logging. - * @mmu_index: Callback for choosing softmmu mmu index; - * may be used internally by memory_rw_debug without TCG. + * @mmu_index: Callback for choosing softmmu mmu index. * @memory_rw_debug: Callback for GDB memory access. * @dump_state: Callback for dumping state. * @query_cpu_fast: From 17fa8b6f039d79e91884ecc1af65a3e771536ca3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:15 +0200 Subject: [PATCH 0152/2760] accel/tcg: Introduce TCGCPUOps::mmu_index() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'll move CPUClass::mmu_index() to TCGCPUOps::mmu_index(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-3-philmd@linaro.org> --- include/accel/tcg/cpu-mmu-index.h | 5 ++++- include/accel/tcg/cpu-ops.h | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/accel/tcg/cpu-mmu-index.h b/include/accel/tcg/cpu-mmu-index.h index 8d1cb53bfa..f1ca385d3c 100644 --- a/include/accel/tcg/cpu-mmu-index.h +++ b/include/accel/tcg/cpu-mmu-index.h @@ -10,6 +10,7 @@ #define ACCEL_TCG_CPU_MMU_INDEX_H #include "hw/core/cpu.h" +#include "accel/tcg/cpu-ops.h" #include "tcg/debug-assert.h" #ifdef COMPILING_PER_TARGET # ifdef CONFIG_USER_ONLY @@ -33,7 +34,9 @@ static inline int cpu_mmu_index(CPUState *cs, bool ifetch) # endif #endif - int ret = cs->cc->mmu_index(cs, ifetch); + const TCGCPUOps *tcg_ops = cs->cc->tcg_ops; + int ret = tcg_ops->mmu_index ? tcg_ops->mmu_index(cs, ifetch) + : cs->cc->mmu_index(cs, ifetch); tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES); return ret; } diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index f60e5303f2..106a0688da 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -67,6 +67,9 @@ struct TCGCPUOps { /** @debug_excp_handler: Callback for handling debug exceptions */ void (*debug_excp_handler)(CPUState *cpu); + /** @mmu_index: Callback for choosing softmmu mmu index */ + int (*mmu_index)(CPUState *cpu, bool ifetch); + #ifdef CONFIG_USER_ONLY /** * @fake_user_interrupt: Callback for 'fake exception' handling. From 6ea8bce7ee60e3f6fd14a959effe2cc6f3be7d94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:16 +0200 Subject: [PATCH 0153/2760] target/alpha: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-4-philmd@linaro.org> --- target/alpha/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 584c2aa76b..56c96b1c4d 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -238,6 +238,7 @@ static const TCGCPUOps alpha_tcg_ops = { .translate_code = alpha_translate_code, .synchronize_from_tb = alpha_cpu_synchronize_from_tb, .restore_state_to_opc = alpha_restore_state_to_opc, + .mmu_index = alpha_cpu_mmu_index, #ifdef CONFIG_USER_ONLY .record_sigsegv = alpha_cpu_record_sigsegv, @@ -262,7 +263,6 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) &acc->parent_realize); cc->class_by_name = alpha_cpu_class_by_name; - cc->mmu_index = alpha_cpu_mmu_index; cc->dump_state = alpha_cpu_dump_state; cc->set_pc = alpha_cpu_set_pc; cc->get_pc = alpha_cpu_get_pc; From 61dc4d0da8ae2c7dc46f5d69ef063b64726f841f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:17 +0200 Subject: [PATCH 0154/2760] target/arm: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move arm_cpu_mmu_index() within CONFIG_TCG #ifdef'ry, convert CPUClass::mmu_index() to TCGCPUOps::mmu_index(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-5-philmd@linaro.org> --- target/arm/cpu.c | 13 +++++++------ target/arm/internals.h | 1 + target/arm/tcg/cpu-v7m.c | 1 + 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 01786ac787..21e8cf1400 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -121,6 +121,12 @@ void arm_restore_state_to_opc(CPUState *cs, env->exception.syndrome = data[2] << ARM_INSN_START_WORD2_SHIFT; } } + +int arm_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + return arm_env_mmu_index(cpu_env(cs)); +} + #endif /* CONFIG_TCG */ #ifndef CONFIG_USER_ONLY @@ -144,11 +150,6 @@ static bool arm_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -static int arm_cpu_mmu_index(CPUState *cs, bool ifetch) -{ - return arm_env_mmu_index(cpu_env(cs)); -} - void arm_register_pre_el_change_hook(ARMCPU *cpu, ARMELChangeHookFn *hook, void *opaque) { @@ -2674,6 +2675,7 @@ static const TCGCPUOps arm_tcg_ops = { .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, .restore_state_to_opc = arm_restore_state_to_opc, + .mmu_index = arm_cpu_mmu_index, #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, @@ -2708,7 +2710,6 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) &acc->parent_phases); cc->class_by_name = arm_cpu_class_by_name; - cc->mmu_index = arm_cpu_mmu_index; cc->dump_state = arm_cpu_dump_state; cc->set_pc = arm_cpu_set_pc; cc->get_pc = arm_cpu_get_pc; diff --git a/target/arm/internals.h b/target/arm/internals.h index 28585c0755..8756c24c08 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -373,6 +373,7 @@ void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); /* Our implementation of TCGCPUOps::cpu_exec_halt */ bool arm_cpu_exec_halt(CPUState *cs); +int arm_cpu_mmu_index(CPUState *cs, bool ifetch); #endif /* CONFIG_TCG */ typedef enum ARMFPRounding { diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index c4dd309272..1a913faa50 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -237,6 +237,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = { .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, .restore_state_to_opc = arm_restore_state_to_opc, + .mmu_index = arm_cpu_mmu_index, #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, From 364f4633b7bc917ef9b2ecd307b42276a6582fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:18 +0200 Subject: [PATCH 0155/2760] target/avr: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-6-philmd@linaro.org> --- target/avr/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 1121822470..feb73e722b 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -228,6 +228,7 @@ static const TCGCPUOps avr_tcg_ops = { .translate_code = avr_cpu_translate_code, .synchronize_from_tb = avr_cpu_synchronize_from_tb, .restore_state_to_opc = avr_restore_state_to_opc, + .mmu_index = avr_cpu_mmu_index, .cpu_exec_interrupt = avr_cpu_exec_interrupt, .cpu_exec_halt = avr_cpu_has_work, .tlb_fill = avr_cpu_tlb_fill, @@ -250,7 +251,6 @@ static void avr_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = avr_cpu_class_by_name; - cc->mmu_index = avr_cpu_mmu_index; cc->dump_state = avr_cpu_dump_state; cc->set_pc = avr_cpu_set_pc; cc->get_pc = avr_cpu_get_pc; From 7856232a93aa9b768d3dd09882192f8fbbc4d708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:19 +0200 Subject: [PATCH 0156/2760] target/hppa: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-7-philmd@linaro.org> --- target/hppa/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 2a85495d02..09a6aaa3dd 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -256,6 +256,7 @@ static const TCGCPUOps hppa_tcg_ops = { .translate_code = hppa_translate_code, .synchronize_from_tb = hppa_cpu_synchronize_from_tb, .restore_state_to_opc = hppa_restore_state_to_opc, + .mmu_index = hppa_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill_align = hppa_cpu_tlb_fill_align, @@ -281,7 +282,6 @@ static void hppa_cpu_class_init(ObjectClass *oc, void *data) &acc->parent_phases); cc->class_by_name = hppa_cpu_class_by_name; - cc->mmu_index = hppa_cpu_mmu_index; cc->dump_state = hppa_cpu_dump_state; cc->set_pc = hppa_cpu_set_pc; cc->get_pc = hppa_cpu_get_pc; From c8db986959942edd7bbc2f3d193cacd7f85c145b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:20 +0200 Subject: [PATCH 0157/2760] target/i386: Remove unused cpu_(ldub, stb)_kernel macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-8-philmd@linaro.org> --- target/i386/tcg/seg_helper.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/i386/tcg/seg_helper.h b/target/i386/tcg/seg_helper.h index ebf1035277..6b8606cd6d 100644 --- a/target/i386/tcg/seg_helper.h +++ b/target/i386/tcg/seg_helper.h @@ -35,8 +35,6 @@ * TODO: Convert callers to compute cpu_mmu_index_kernel once * and use *_mmuidx_ra directly. */ -#define cpu_ldub_kernel_ra(e, p, r) \ - cpu_ldub_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) #define cpu_lduw_kernel_ra(e, p, r) \ cpu_lduw_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) #define cpu_ldl_kernel_ra(e, p, r) \ @@ -44,8 +42,6 @@ #define cpu_ldq_kernel_ra(e, p, r) \ cpu_ldq_mmuidx_ra(e, p, cpu_mmu_index_kernel(e), r) -#define cpu_stb_kernel_ra(e, p, v, r) \ - cpu_stb_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) #define cpu_stw_kernel_ra(e, p, v, r) \ cpu_stw_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) #define cpu_stl_kernel_ra(e, p, v, r) \ @@ -53,12 +49,10 @@ #define cpu_stq_kernel_ra(e, p, v, r) \ cpu_stq_mmuidx_ra(e, p, v, cpu_mmu_index_kernel(e), r) -#define cpu_ldub_kernel(e, p) cpu_ldub_kernel_ra(e, p, 0) #define cpu_lduw_kernel(e, p) cpu_lduw_kernel_ra(e, p, 0) #define cpu_ldl_kernel(e, p) cpu_ldl_kernel_ra(e, p, 0) #define cpu_ldq_kernel(e, p) cpu_ldq_kernel_ra(e, p, 0) -#define cpu_stb_kernel(e, p, v) cpu_stb_kernel_ra(e, p, v, 0) #define cpu_stw_kernel(e, p, v) cpu_stw_kernel_ra(e, p, v, 0) #define cpu_stl_kernel(e, p, v) cpu_stl_kernel_ra(e, p, v, 0) #define cpu_stq_kernel(e, p, v) cpu_stq_kernel_ra(e, p, v, 0) From 611c34a745ee7ab98733175458378f94e03c23d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:21 +0200 Subject: [PATCH 0158/2760] target/i386: Restrict cpu_mmu_index_kernel() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move cpu_mmu_index_kernel() to seg_helper.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-9-philmd@linaro.org> --- target/i386/cpu.c | 16 ---------------- target/i386/cpu.h | 1 - target/i386/tcg/seg_helper.c | 16 ++++++++++++++++ target/i386/tcg/seg_helper.h | 4 ++++ 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index c596e2174d..fd85663833 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -8681,22 +8681,6 @@ static int x86_cpu_mmu_index(CPUState *cs, bool ifetch) return x86_mmu_index_pl(env, env->hflags & HF_CPL_MASK); } -static int x86_mmu_index_kernel_pl(CPUX86State *env, unsigned pl) -{ - int mmu_index_32 = (env->hflags & HF_LMA_MASK) ? 0 : 1; - int mmu_index_base = - !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : - (pl < 3 && (env->eflags & AC_MASK) - ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX); - - return mmu_index_base + mmu_index_32; -} - -int cpu_mmu_index_kernel(CPUX86State *env) -{ - return x86_mmu_index_kernel_pl(env, env->hflags & HF_CPL_MASK); -} - static void x86_disas_set_info(CPUState *cs, disassemble_info *info) { X86CPU *cpu = X86_CPU(cs); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 119efc6c60..c9f39e99d3 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2598,7 +2598,6 @@ static inline bool is_mmu_index_32(int mmu_index) } int x86_mmu_index_pl(CPUX86State *env, unsigned pl); -int cpu_mmu_index_kernel(CPUX86State *env); #define CC_DST (env->cc_dst) #define CC_SRC (env->cc_src) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 71962113fb..f4370202fe 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -128,6 +128,22 @@ int get_pg_mode(CPUX86State *env) return pg_mode; } +static int x86_mmu_index_kernel_pl(CPUX86State *env, unsigned pl) +{ + int mmu_index_32 = (env->hflags & HF_LMA_MASK) ? 0 : 1; + int mmu_index_base = + !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : + (pl < 3 && (env->eflags & AC_MASK) + ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX); + + return mmu_index_base + mmu_index_32; +} + +int cpu_mmu_index_kernel(CPUX86State *env) +{ + return x86_mmu_index_kernel_pl(env, env->hflags & HF_CPL_MASK); +} + /* return non zero if error */ static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr, uint32_t *e2_ptr, int selector, diff --git a/target/i386/tcg/seg_helper.h b/target/i386/tcg/seg_helper.h index 6b8606cd6d..ea98e1a98e 100644 --- a/target/i386/tcg/seg_helper.h +++ b/target/i386/tcg/seg_helper.h @@ -20,6 +20,8 @@ #ifndef SEG_HELPER_H #define SEG_HELPER_H +#include "cpu.h" + //#define DEBUG_PCALL #ifdef DEBUG_PCALL @@ -31,6 +33,8 @@ # define LOG_PCALL_STATE(cpu) do { } while (0) #endif +int cpu_mmu_index_kernel(CPUX86State *env); + /* * TODO: Convert callers to compute cpu_mmu_index_kernel once * and use *_mmuidx_ra directly. From 8480f7c7454de9527e14eaa2430835684eb03bbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:22 +0200 Subject: [PATCH 0159/2760] target/i386: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move x86_cpu_mmu_index() to tcg-cpu.c, convert CPUClass::mmu_index() to TCGCPUOps::mmu_index(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-10-philmd@linaro.org> --- target/i386/cpu.c | 18 ------------------ target/i386/cpu.h | 2 -- target/i386/tcg/seg_helper.c | 1 + target/i386/tcg/tcg-cpu.c | 18 ++++++++++++++++++ target/i386/tcg/tcg-cpu.h | 2 ++ 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index fd85663833..57f62cc869 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -8664,23 +8664,6 @@ static bool x86_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -int x86_mmu_index_pl(CPUX86State *env, unsigned pl) -{ - int mmu_index_32 = (env->hflags & HF_CS64_MASK) ? 0 : 1; - int mmu_index_base = - pl == 3 ? MMU_USER64_IDX : - !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : - (env->eflags & AC_MASK) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX; - - return mmu_index_base + mmu_index_32; -} - -static int x86_cpu_mmu_index(CPUState *cs, bool ifetch) -{ - CPUX86State *env = cpu_env(cs); - return x86_mmu_index_pl(env, env->hflags & HF_CPL_MASK); -} - static void x86_disas_set_info(CPUState *cs, disassemble_info *info) { X86CPU *cpu = X86_CPU(cs); @@ -8922,7 +8905,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->class_by_name = x86_cpu_class_by_name; cc->parse_features = x86_cpu_parse_featurestr; - cc->mmu_index = x86_cpu_mmu_index; cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; cc->get_pc = x86_cpu_get_pc; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c9f39e99d3..0ad67fe0fd 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2597,8 +2597,6 @@ static inline bool is_mmu_index_32(int mmu_index) return mmu_index & 1; } -int x86_mmu_index_pl(CPUX86State *env, unsigned pl); - #define CC_DST (env->cc_dst) #define CC_SRC (env->cc_src) #define CC_SRC2 (env->cc_src2) diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index f4370202fe..9dfbc4208c 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -28,6 +28,7 @@ #include "helper-tcg.h" #include "seg_helper.h" #include "access.h" +#include "tcg-cpu.h" #ifdef TARGET_X86_64 #define SET_ESP(val, sp_mask) \ diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index b8aff825ee..818653ee6d 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -94,6 +94,23 @@ static void x86_restore_state_to_opc(CPUState *cs, } } +int x86_mmu_index_pl(CPUX86State *env, unsigned pl) +{ + int mmu_index_32 = (env->hflags & HF_CS64_MASK) ? 0 : 1; + int mmu_index_base = + pl == 3 ? MMU_USER64_IDX : + !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP64_IDX : + (env->eflags & AC_MASK) ? MMU_KNOSMAP64_IDX : MMU_KSMAP64_IDX; + + return mmu_index_base + mmu_index_32; +} + +static int x86_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + CPUX86State *env = cpu_env(cs); + return x86_mmu_index_pl(env, env->hflags & HF_CPL_MASK); +} + #ifndef CONFIG_USER_ONLY static bool x86_debug_check_breakpoint(CPUState *cs) { @@ -112,6 +129,7 @@ static const TCGCPUOps x86_tcg_ops = { .translate_code = x86_translate_code, .synchronize_from_tb = x86_cpu_synchronize_from_tb, .restore_state_to_opc = x86_restore_state_to_opc, + .mmu_index = x86_cpu_mmu_index, .cpu_exec_enter = x86_cpu_exec_enter, .cpu_exec_exit = x86_cpu_exec_exit, #ifdef CONFIG_USER_ONLY diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h index 53a8494455..7580f8afb4 100644 --- a/target/i386/tcg/tcg-cpu.h +++ b/target/i386/tcg/tcg-cpu.h @@ -78,4 +78,6 @@ QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, pkru_state) != XSAVE_PKRU_OFFSET); bool tcg_cpu_realizefn(CPUState *cs, Error **errp); +int x86_mmu_index_pl(CPUX86State *env, unsigned pl); + #endif /* TCG_CPU_H */ From 3076af3441034a8050f660d5c294d26b2e2943b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:23 +0200 Subject: [PATCH 0160/2760] target/loongarch: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-11-philmd@linaro.org> --- target/loongarch/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index ea1665e270..cb96b17911 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -868,6 +868,7 @@ static const TCGCPUOps loongarch_tcg_ops = { .translate_code = loongarch_translate_code, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .restore_state_to_opc = loongarch_restore_state_to_opc, + .mmu_index = loongarch_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = loongarch_cpu_tlb_fill, @@ -919,7 +920,6 @@ static void loongarch_cpu_class_init(ObjectClass *c, void *data) &lacc->parent_phases); cc->class_by_name = loongarch_cpu_class_by_name; - cc->mmu_index = loongarch_cpu_mmu_index; cc->dump_state = loongarch_cpu_dump_state; cc->set_pc = loongarch_cpu_set_pc; cc->get_pc = loongarch_cpu_get_pc; From cc944932ecef3b7a56ae62d89dd92fb9e56c5cc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:24 +0200 Subject: [PATCH 0161/2760] target/m68k: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-12-philmd@linaro.org> --- target/m68k/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 0065e1c1ca..4409d8941c 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -592,6 +592,7 @@ static const TCGCPUOps m68k_tcg_ops = { .initialize = m68k_tcg_init, .translate_code = m68k_translate_code, .restore_state_to_opc = m68k_restore_state_to_opc, + .mmu_index = m68k_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = m68k_cpu_tlb_fill, @@ -615,7 +616,6 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) &mcc->parent_phases); cc->class_by_name = m68k_cpu_class_by_name; - cc->mmu_index = m68k_cpu_mmu_index; cc->dump_state = m68k_cpu_dump_state; cc->set_pc = m68k_cpu_set_pc; cc->get_pc = m68k_cpu_get_pc; From 2b08170ffeca77cb0f02a365f536a341dd857a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:25 +0200 Subject: [PATCH 0162/2760] target/microblaze: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-13-philmd@linaro.org> --- target/microblaze/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index f3bebea856..88baeb6807 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -431,6 +431,7 @@ static const TCGCPUOps mb_tcg_ops = { .translate_code = mb_translate_code, .synchronize_from_tb = mb_cpu_synchronize_from_tb, .restore_state_to_opc = mb_restore_state_to_opc, + .mmu_index = mb_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = mb_cpu_tlb_fill, @@ -455,7 +456,6 @@ static void mb_cpu_class_init(ObjectClass *oc, void *data) &mcc->parent_phases); cc->class_by_name = mb_cpu_class_by_name; - cc->mmu_index = mb_cpu_mmu_index; cc->dump_state = mb_cpu_dump_state; cc->set_pc = mb_cpu_set_pc; cc->get_pc = mb_cpu_get_pc; From a433b2194ff32d80e4374f340673c5357984f9a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:26 +0200 Subject: [PATCH 0163/2760] target/mips: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-14-philmd@linaro.org> --- target/mips/cpu.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 47df563e12..cb0d6dde0e 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -182,11 +182,6 @@ static bool mips_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) -{ - return mips_env_mmu_index(cpu_env(cs)); -} - #include "cpu-defs.c.inc" static void mips_cpu_reset_hold(Object *obj, ResetType type) @@ -549,11 +544,18 @@ static const Property mips_cpu_properties[] = { #ifdef CONFIG_TCG #include "accel/tcg/cpu-ops.h" + +static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) +{ + return mips_env_mmu_index(cpu_env(cs)); +} + static const TCGCPUOps mips_tcg_ops = { .initialize = mips_tcg_init, .translate_code = mips_translate_code, .synchronize_from_tb = mips_cpu_synchronize_from_tb, .restore_state_to_opc = mips_restore_state_to_opc, + .mmu_index = mips_cpu_mmu_index, #if !defined(CONFIG_USER_ONLY) .tlb_fill = mips_cpu_tlb_fill, @@ -581,7 +583,6 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) &mcc->parent_phases); cc->class_by_name = mips_cpu_class_by_name; - cc->mmu_index = mips_cpu_mmu_index; cc->dump_state = mips_cpu_dump_state; cc->set_pc = mips_cpu_set_pc; cc->get_pc = mips_cpu_get_pc; From a53066a9d660ee187a06062c1c44639714195a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:27 +0200 Subject: [PATCH 0164/2760] target/openrisc: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-15-philmd@linaro.org> --- target/openrisc/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index e8abf1f8b5..dc55594a7d 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -247,6 +247,7 @@ static const TCGCPUOps openrisc_tcg_ops = { .translate_code = openrisc_translate_code, .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, .restore_state_to_opc = openrisc_restore_state_to_opc, + .mmu_index = openrisc_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, @@ -269,7 +270,6 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data) &occ->parent_phases); cc->class_by_name = openrisc_cpu_class_by_name; - cc->mmu_index = openrisc_cpu_mmu_index; cc->dump_state = openrisc_cpu_dump_state; cc->set_pc = openrisc_cpu_set_pc; cc->get_pc = openrisc_cpu_get_pc; From 853f9378a325dbeec78afe3478dea277be369a3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:28 +0200 Subject: [PATCH 0165/2760] target/ppc: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert CPUClass::mmu_index() to TCGCPUOps::mmu_index(), restricting ppc_cpu_mmu_index() to TCG #ifdef. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-16-philmd@linaro.org> --- target/ppc/cpu_init.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 17f0f3d3ff..fd8c42069e 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7216,6 +7216,11 @@ static void ppc_restore_state_to_opc(CPUState *cs, cpu->env.nip = data[0]; } + +static int ppc_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + return ppc_env_mmu_index(cpu_env(cs), ifetch); +} #endif /* CONFIG_TCG */ #ifndef CONFIG_USER_ONLY @@ -7225,11 +7230,6 @@ static bool ppc_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -static int ppc_cpu_mmu_index(CPUState *cs, bool ifetch) -{ - return ppc_env_mmu_index(cpu_env(cs), ifetch); -} - static void ppc_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -7482,6 +7482,7 @@ static const TCGCPUOps ppc_tcg_ops = { .initialize = ppc_translate_init, .translate_code = ppc_translate_code, .restore_state_to_opc = ppc_restore_state_to_opc, + .mmu_index = ppc_cpu_mmu_index, #ifdef CONFIG_USER_ONLY .record_sigsegv = ppc_cpu_record_sigsegv, @@ -7518,7 +7519,6 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) &pcc->parent_phases); cc->class_by_name = ppc_cpu_class_by_name; - cc->mmu_index = ppc_cpu_mmu_index; cc->dump_state = ppc_cpu_dump_state; cc->set_pc = ppc_cpu_set_pc; cc->get_pc = ppc_cpu_get_pc; From bf8dc33bbca3d84251d40bd81fa1d832b3171ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:29 +0200 Subject: [PATCH 0166/2760] target/riscv: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move riscv_cpu_mmu_index() to the TCG-specific file, convert CPUClass::mmu_index() to TCGCPUOps::mmu_index(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-17-philmd@linaro.org> --- target/riscv/cpu.c | 6 ------ target/riscv/tcg/tcg-cpu.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 09ded6829a..430b02d2a5 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1021,11 +1021,6 @@ bool riscv_cpu_has_work(CPUState *cs) } #endif /* !CONFIG_USER_ONLY */ -static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch) -{ - return riscv_env_mmu_index(cpu_env(cs), ifetch); -} - static void riscv_cpu_reset_hold(Object *obj, ResetType type) { #ifndef CONFIG_USER_ONLY @@ -3049,7 +3044,6 @@ static void riscv_cpu_common_class_init(ObjectClass *c, void *data) &mcc->parent_phases); cc->class_by_name = riscv_cpu_class_by_name; - cc->mmu_index = riscv_cpu_mmu_index; cc->dump_state = riscv_cpu_dump_state; cc->set_pc = riscv_cpu_set_pc; cc->get_pc = riscv_cpu_get_pc; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 5aef9eef36..bee7dfd803 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -91,6 +91,11 @@ static const char *cpu_priv_ver_to_str(int priv_ver) return priv_spec_str; } +static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + return riscv_env_mmu_index(cpu_env(cs), ifetch); +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -138,6 +143,7 @@ static const TCGCPUOps riscv_tcg_ops = { .translate_code = riscv_translate_code, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, .restore_state_to_opc = riscv_restore_state_to_opc, + .mmu_index = riscv_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = riscv_cpu_tlb_fill, From f1a1c2b9586f6402fa1447c611c9f2d77e648ce9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:30 +0200 Subject: [PATCH 0167/2760] target/rx: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-18-philmd@linaro.org> --- target/rx/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/rx/cpu.c b/target/rx/cpu.c index a240b3b3ce..51743020d4 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -207,6 +207,7 @@ static const TCGCPUOps rx_tcg_ops = { .translate_code = rx_translate_code, .synchronize_from_tb = rx_cpu_synchronize_from_tb, .restore_state_to_opc = rx_restore_state_to_opc, + .mmu_index = rx_cpu_mmu_index, .tlb_fill = rx_cpu_tlb_fill, .cpu_exec_interrupt = rx_cpu_exec_interrupt, @@ -227,7 +228,6 @@ static void rx_cpu_class_init(ObjectClass *klass, void *data) &rcc->parent_phases); cc->class_by_name = rx_cpu_class_by_name; - cc->mmu_index = rx_cpu_mmu_index; cc->dump_state = rx_cpu_dump_state; cc->set_pc = rx_cpu_set_pc; cc->get_pc = rx_cpu_get_pc; From 96a786ed038f015c4f6293e2b3a641941a0e9f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:31 +0200 Subject: [PATCH 0168/2760] target/s390x: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert CPUClass::mmu_index() to TCGCPUOps::mmu_index(), restricting s390x_cpu_mmu_index() to TCG #ifdef. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-19-philmd@linaro.org> --- target/s390x/cpu.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 1f75629ddc..d15b1943e0 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -126,11 +126,6 @@ static vaddr s390_cpu_get_pc(CPUState *cs) return cpu->env.psw.addr; } -static int s390x_cpu_mmu_index(CPUState *cs, bool ifetch) -{ - return s390x_env_mmu_index(cpu_env(cs), ifetch); -} - static void s390_query_cpu_fast(CPUState *cpu, CpuInfoFast *value) { S390CPU *s390_cpu = S390_CPU(cpu); @@ -308,6 +303,11 @@ static const Property s390x_cpu_properties[] = { #ifdef CONFIG_TCG #include "accel/tcg/cpu-ops.h" +static int s390x_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + return s390x_env_mmu_index(cpu_env(cs), ifetch); +} + void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, uint64_t *cs_base, uint32_t *pflags) { @@ -348,6 +348,7 @@ static const TCGCPUOps s390_tcg_ops = { .initialize = s390x_translate_init, .translate_code = s390x_translate_code, .restore_state_to_opc = s390x_restore_state_to_opc, + .mmu_index = s390x_cpu_mmu_index, #ifdef CONFIG_USER_ONLY .record_sigsegv = s390_cpu_record_sigsegv, @@ -378,7 +379,6 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) &scc->parent_phases); cc->class_by_name = s390_cpu_class_by_name; - cc->mmu_index = s390x_cpu_mmu_index; cc->dump_state = s390_cpu_dump_state; cc->query_cpu_fast = s390_query_cpu_fast; cc->set_pc = s390_cpu_set_pc; From 32a84b306fe216986d8c78f60571a073f224e4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:32 +0200 Subject: [PATCH 0169/2760] target/sh4: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-20-philmd@linaro.org> --- target/sh4/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index ce84bdf539..df093988cb 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -266,6 +266,7 @@ static const TCGCPUOps superh_tcg_ops = { .translate_code = sh4_translate_code, .synchronize_from_tb = superh_cpu_synchronize_from_tb, .restore_state_to_opc = superh_restore_state_to_opc, + .mmu_index = sh4_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = superh_cpu_tlb_fill, @@ -291,7 +292,6 @@ static void superh_cpu_class_init(ObjectClass *oc, void *data) &scc->parent_phases); cc->class_by_name = superh_cpu_class_by_name; - cc->mmu_index = sh4_cpu_mmu_index; cc->dump_state = superh_cpu_dump_state; cc->set_pc = superh_cpu_set_pc; cc->get_pc = superh_cpu_get_pc; From f34769a536c80753442f14f40387e2a4c936fd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:33 +0200 Subject: [PATCH 0170/2760] target/sparc: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-21-philmd@linaro.org> --- target/sparc/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 57fbf16ad2..af3cec43e7 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1005,6 +1005,7 @@ static const TCGCPUOps sparc_tcg_ops = { .translate_code = sparc_translate_code, .synchronize_from_tb = sparc_cpu_synchronize_from_tb, .restore_state_to_opc = sparc_restore_state_to_opc, + .mmu_index = sparc_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = sparc_cpu_tlb_fill, @@ -1033,7 +1034,6 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) cc->class_by_name = sparc_cpu_class_by_name; cc->parse_features = sparc_cpu_parse_features; - cc->mmu_index = sparc_cpu_mmu_index; cc->dump_state = sparc_cpu_dump_state; #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) cc->memory_rw_debug = sparc_cpu_memory_rw_debug; From 46708ccec1cd4bb2c022bf97a67affb5a4bea6f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:34 +0200 Subject: [PATCH 0171/2760] target/tricore: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-22-philmd@linaro.org> --- target/tricore/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 16acc4ecb9..833a93d37a 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -176,6 +176,7 @@ static const TCGCPUOps tricore_tcg_ops = { .translate_code = tricore_translate_code, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, .restore_state_to_opc = tricore_restore_state_to_opc, + .mmu_index = tricore_cpu_mmu_index, .tlb_fill = tricore_cpu_tlb_fill, .cpu_exec_interrupt = tricore_cpu_exec_interrupt, .cpu_exec_halt = tricore_cpu_has_work, @@ -194,7 +195,6 @@ static void tricore_cpu_class_init(ObjectClass *c, void *data) resettable_class_set_parent_phases(rc, NULL, tricore_cpu_reset_hold, NULL, &mcc->parent_phases); cc->class_by_name = tricore_cpu_class_by_name; - cc->mmu_index = tricore_cpu_mmu_index; cc->gdb_read_register = tricore_cpu_gdb_read_register; cc->gdb_write_register = tricore_cpu_gdb_write_register; From befb31d349e1761855a24023f21aab4207ce5392 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:35 +0200 Subject: [PATCH 0172/2760] target/xtensa: Restrict SoftMMU mmu_index() to TCG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-23-philmd@linaro.org> --- target/xtensa/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index ec6a0a8b66..51f9ee9e89 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -236,6 +236,7 @@ static const TCGCPUOps xtensa_tcg_ops = { .translate_code = xtensa_translate_code, .debug_excp_handler = xtensa_breakpoint_handler, .restore_state_to_opc = xtensa_restore_state_to_opc, + .mmu_index = xtensa_cpu_mmu_index, #ifndef CONFIG_USER_ONLY .tlb_fill = xtensa_cpu_tlb_fill, @@ -262,7 +263,6 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) &xcc->parent_phases); cc->class_by_name = xtensa_cpu_class_by_name; - cc->mmu_index = xtensa_cpu_mmu_index; cc->dump_state = xtensa_cpu_dump_state; cc->set_pc = xtensa_cpu_set_pc; cc->get_pc = xtensa_cpu_get_pc; From 43d6a56a0574775c1b5ce5c5ad0c7f9dded83c87 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 3 Apr 2025 08:44:13 -0700 Subject: [PATCH 0173/2760] target/hexagon: Implement TCGCPUOps.mmu_index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This hook is about to become mandatory. Since hexagon is still user-only, the implementation is trivial. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Brian Cain Signed-off-by: Richard Henderson --- target/hexagon/cpu.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 766b678651..ad1f303fbc 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -313,6 +313,11 @@ static void hexagon_cpu_realize(DeviceState *dev, Error **errp) mcc->parent_realize(dev, errp); } +static int hexagon_cpu_mmu_index(CPUState *cs, bool ifetch) +{ + return MMU_USER_IDX; +} + static void hexagon_cpu_init(Object *obj) { } @@ -324,6 +329,7 @@ static const TCGCPUOps hexagon_tcg_ops = { .translate_code = hexagon_translate_code, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, .restore_state_to_opc = hexagon_restore_state_to_opc, + .mmu_index = hexagon_cpu_mmu_index, }; static void hexagon_cpu_class_init(ObjectClass *c, void *data) From 42fec1bbf58a288e86314e495716d609928712df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:09:36 +0200 Subject: [PATCH 0174/2760] hw/core/cpu: Remove CPUClass::mmu_index() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All targets have been converted to TCGCPUOps::mmu_index(), remove the now unused CPUClass::mmu_index(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250401080938.32278-24-philmd@linaro.org> --- accel/tcg/cpu-exec.c | 1 + include/accel/tcg/cpu-mmu-index.h | 4 +--- include/hw/core/cpu.h | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 034c2ded6b..9e15105533 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -1075,6 +1075,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp) assert(tcg_ops->cpu_exec_interrupt); #endif /* !CONFIG_USER_ONLY */ assert(tcg_ops->translate_code); + assert(tcg_ops->mmu_index); tcg_ops->initialize(); tcg_target_initialized = true; } diff --git a/include/accel/tcg/cpu-mmu-index.h b/include/accel/tcg/cpu-mmu-index.h index f1ca385d3c..e681a90844 100644 --- a/include/accel/tcg/cpu-mmu-index.h +++ b/include/accel/tcg/cpu-mmu-index.h @@ -34,9 +34,7 @@ static inline int cpu_mmu_index(CPUState *cs, bool ifetch) # endif #endif - const TCGCPUOps *tcg_ops = cs->cc->tcg_ops; - int ret = tcg_ops->mmu_index ? tcg_ops->mmu_index(cs, ifetch) - : cs->cc->mmu_index(cs, ifetch); + int ret = cs->cc->tcg_ops->mmu_index(cs, ifetch); tcg_debug_assert(ret >= 0 && ret < NB_MMU_MODES); return ret; } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 29f6419050..28bd27b8ed 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -104,7 +104,6 @@ struct SysemuCPUOps; * instantiatable CPU type. * @parse_features: Callback to parse command line arguments. * @reset_dump_flags: #CPUDumpFlags to use for reset logging. - * @mmu_index: Callback for choosing softmmu mmu index. * @memory_rw_debug: Callback for GDB memory access. * @dump_state: Callback for dumping state. * @query_cpu_fast: @@ -151,7 +150,6 @@ struct CPUClass { ObjectClass *(*class_by_name)(const char *cpu_model); void (*parse_features)(const char *typename, char *str, Error **errp); - int (*mmu_index)(CPUState *cpu, bool ifetch); int (*memory_rw_debug)(CPUState *cpu, vaddr addr, uint8_t *buf, size_t len, bool is_write); void (*dump_state)(CPUState *cpu, FILE *, int flags); From 41fed3c99288451f0528752709151cef5822bd7e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 17:11:05 -0500 Subject: [PATCH 0175/2760] accel/tcg: Build translator.c twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop some unnecessary includes. Change the offsetof expressions to be based on CPUState instead of ArchCPU. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 2 +- accel/tcg/translator.c | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 72d4acfe5e..047afa49a2 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -8,6 +8,7 @@ tcg_ss.add(files( 'cpu-exec-common.c', 'tcg-runtime.c', 'tcg-runtime-gvec.c', + 'translator.c', )) if get_option('plugins') tcg_ss.add(files('plugin-gen.c')) @@ -22,7 +23,6 @@ tcg_specific_ss.add(files( 'cpu-exec.c', 'tb-maint.c', 'translate-all.c', - 'translator.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index 5f0aa9d56a..c53bbdef99 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -11,14 +11,13 @@ #include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "exec/exec-all.h" #include "exec/cpu-ldst-common.h" #include "accel/tcg/cpu-mmu-index.h" +#include "exec/target_page.h" #include "exec/translator.h" #include "exec/plugin-gen.h" #include "tcg/tcg-op-common.h" #include "internal-common.h" -#include "internal-target.h" #include "disas/disas.h" #include "tb-internal.h" @@ -26,8 +25,7 @@ static void set_can_do_io(DisasContextBase *db, bool val) { QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1); tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env, - offsetof(ArchCPU, parent_obj.neg.can_do_io) - - offsetof(ArchCPU, env)); + offsetof(CPUState, neg.can_do_io) - sizeof(CPUState)); } bool translator_io_start(DisasContextBase *db) @@ -50,8 +48,8 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) if ((cflags & CF_USE_ICOUNT) || !(cflags & CF_NOIRQ)) { count = tcg_temp_new_i32(); tcg_gen_ld_i32(count, tcg_env, - offsetof(ArchCPU, parent_obj.neg.icount_decr.u32) - - offsetof(ArchCPU, env)); + offsetof(CPUState, neg.icount_decr.u32) - + sizeof(CPUState)); } if (cflags & CF_USE_ICOUNT) { @@ -80,8 +78,8 @@ static TCGOp *gen_tb_start(DisasContextBase *db, uint32_t cflags) if (cflags & CF_USE_ICOUNT) { tcg_gen_st16_i32(count, tcg_env, - offsetof(ArchCPU, parent_obj.neg.icount_decr.u16.low) - - offsetof(ArchCPU, env)); + offsetof(CPUState, neg.icount_decr.u16.low) - + sizeof(CPUState)); } return icount_start_insn; From 33646c72c75637fb3a4c5b225dea5d44ed2e4d44 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 15:48:11 -0500 Subject: [PATCH 0176/2760] accel/tcg: Split out tlb-bounds.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CPU_TLB_DYN_{MIN,MAX}_BITS definitions are not required outside of cputlb.c and translate-all.c. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 1 + accel/tcg/tb-internal.h | 27 --------------------------- accel/tcg/tlb-bounds.h | 32 ++++++++++++++++++++++++++++++++ accel/tcg/translate-all.c | 1 + 4 files changed, 34 insertions(+), 27 deletions(-) create mode 100644 accel/tcg/tlb-bounds.h diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 28c47d4872..a717f357d5 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -41,6 +41,7 @@ #include "trace.h" #include "tb-hash.h" #include "tb-internal.h" +#include "tlb-bounds.h" #include "internal-common.h" #include "internal-target.h" #ifdef CONFIG_PLUGIN diff --git a/accel/tcg/tb-internal.h b/accel/tcg/tb-internal.h index f9a06bcbab..08538e2896 100644 --- a/accel/tcg/tb-internal.h +++ b/accel/tcg/tb-internal.h @@ -22,33 +22,6 @@ */ #define GETPC_ADJ 2 -#ifdef CONFIG_SOFTMMU - -#define CPU_TLB_DYN_MIN_BITS 6 -#define CPU_TLB_DYN_DEFAULT_BITS 8 - -# if HOST_LONG_BITS == 32 -/* Make sure we do not require a double-word shift for the TLB load */ -# define CPU_TLB_DYN_MAX_BITS (32 - TARGET_PAGE_BITS) -# else /* HOST_LONG_BITS == 64 */ -/* - * Assuming TARGET_PAGE_BITS==12, with 2**22 entries we can cover 2**(22+12) == - * 2**34 == 16G of address space. This is roughly what one would expect a - * TLB to cover in a modern (as of 2018) x86_64 CPU. For instance, Intel - * Skylake's Level-2 STLB has 16 1G entries. - * Also, make sure we do not size the TLB past the guest's address space. - */ -# ifdef TARGET_PAGE_BITS_VARY -# define CPU_TLB_DYN_MAX_BITS \ - MIN(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) -# else -# define CPU_TLB_DYN_MAX_BITS \ - MIN_CONST(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) -# endif -# endif - -#endif /* CONFIG_SOFTMMU */ - void tb_lock_page0(tb_page_addr_t); #ifdef CONFIG_USER_ONLY diff --git a/accel/tcg/tlb-bounds.h b/accel/tcg/tlb-bounds.h new file mode 100644 index 0000000000..efd34d4793 --- /dev/null +++ b/accel/tcg/tlb-bounds.h @@ -0,0 +1,32 @@ +/* + * softmmu size bounds + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_TLB_BOUNDS_H +#define ACCEL_TCG_TLB_BOUNDS_H + +#define CPU_TLB_DYN_MIN_BITS 6 +#define CPU_TLB_DYN_DEFAULT_BITS 8 + +# if HOST_LONG_BITS == 32 +/* Make sure we do not require a double-word shift for the TLB load */ +# define CPU_TLB_DYN_MAX_BITS (32 - TARGET_PAGE_BITS) +# else /* HOST_LONG_BITS == 64 */ +/* + * Assuming TARGET_PAGE_BITS==12, with 2**22 entries we can cover 2**(22+12) == + * 2**34 == 16G of address space. This is roughly what one would expect a + * TLB to cover in a modern (as of 2018) x86_64 CPU. For instance, Intel + * Skylake's Level-2 STLB has 16 1G entries. + * Also, make sure we do not size the TLB past the guest's address space. + */ +# ifdef TARGET_PAGE_BITS_VARY +# define CPU_TLB_DYN_MAX_BITS \ + MIN(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) +# else +# define CPU_TLB_DYN_MAX_BITS \ + MIN_CONST(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) +# endif +# endif + +#endif /* ACCEL_TCG_TLB_BOUNDS_H */ diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index bb161ae61a..87fb6c51d3 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -47,6 +47,7 @@ #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "tb-internal.h" +#include "tlb-bounds.h" #include "exec/translator.h" #include "exec/tb-flush.h" #include "qemu/bitmap.h" From 6effa87475986093007e3f2dcfd1f781de0993b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 15:05:12 -0500 Subject: [PATCH 0177/2760] include/exec: Redefine tlb-flags with absolute values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don't base the values on TARGET_PAGE_BITS_MIN, but do verify that TLB_FLAGS_MASK does not overlap minimum page size. All targets now have the same placement for these flags, simplifying mmu management when we enable heterogeneous systems. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 2 ++ include/exec/tlb-flags.h | 68 +++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index a717f357d5..39314e86f3 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -49,6 +49,8 @@ #endif #include "tcg/tcg-ldst.h" +QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & ((1u < TARGET_PAGE_BITS_MIN) - 1)); + /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ /* #define DEBUG_TLB */ /* #define DEBUG_TLB_LOG */ diff --git a/include/exec/tlb-flags.h b/include/exec/tlb-flags.h index 54a6bae768..357e79095c 100644 --- a/include/exec/tlb-flags.h +++ b/include/exec/tlb-flags.h @@ -19,54 +19,29 @@ #ifndef TLB_FLAGS_H #define TLB_FLAGS_H -#include "exec/cpu-defs.h" +/* + * Flags returned for lookup of a TLB virtual address. + */ #ifdef CONFIG_USER_ONLY /* - * Allow some level of source compatibility with softmmu. We do not - * support any of the more exotic features, so only invalid pages may - * be signaled by probe_access_flags(). + * Allow some level of source compatibility with softmmu. + * Invalid is set when the page does not have requested permissions. + * MMIO is set when we want the target helper to use the functional + * interface for load/store so that plugins see the access. */ -#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) -#define TLB_MMIO (1 << (TARGET_PAGE_BITS_MIN - 2)) -#define TLB_WATCHPOINT 0 +#define TLB_INVALID_MASK (1 << 0) +#define TLB_MMIO (1 << 1) +#define TLB_WATCHPOINT 0 #else -/* - * Flags stored in the low bits of the TLB virtual address. - * These are defined so that fast path ram access is all zeros. - * The flags all must be between TARGET_PAGE_BITS and - * maximum address alignment bit. - * - * Use TARGET_PAGE_BITS_MIN so that these bits are constant - * when TARGET_PAGE_BITS_VARY is in effect. - * - * The count, if not the placement of these bits is known - * to tcg/tcg-op-ldst.c, check_max_alignment(). - */ -/* Zero if TLB entry is valid. */ -#define TLB_INVALID_MASK (1 << (TARGET_PAGE_BITS_MIN - 1)) -/* - * Set if TLB entry references a clean RAM page. The iotlb entry will - * contain the page physical address. - */ -#define TLB_NOTDIRTY (1 << (TARGET_PAGE_BITS_MIN - 2)) -/* Set if the slow path must be used; more flags in CPUTLBEntryFull. */ -#define TLB_FORCE_SLOW (1 << (TARGET_PAGE_BITS_MIN - 3)) - -/* - * Use this mask to check interception with an alignment mask - * in a TCG backend. - */ -#define TLB_FLAGS_MASK \ - (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_FORCE_SLOW) - /* * Flags stored in CPUTLBEntryFull.slow_flags[x]. * TLB_FORCE_SLOW must be set in CPUTLBEntry.addr_idx[x]. */ + /* Set if TLB entry requires byte swap. */ #define TLB_BSWAP (1 << 0) /* Set if TLB entry contains a watchpoint. */ @@ -82,6 +57,27 @@ (TLB_BSWAP | TLB_WATCHPOINT | TLB_CHECK_ALIGNED | \ TLB_DISCARD_WRITE | TLB_MMIO) +/* + * Flags stored in CPUTLBEntry.addr_idx[x]. + * These must be above the largest alignment (64 bytes), + * and below the smallest page size (1024 bytes). + * This leaves bits [9:6] available for use. + */ + +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << 6) +/* Set if TLB entry references a clean RAM page. */ +#define TLB_NOTDIRTY (1 << 7) +/* Set if the slow path must be used; more flags in CPUTLBEntryFull. */ +#define TLB_FORCE_SLOW (1 << 8) + +/* + * Use this mask to check interception with an alignment mask + * in a TCG backend. + */ +#define TLB_FLAGS_MASK \ + (TLB_INVALID_MASK | TLB_NOTDIRTY | TLB_FORCE_SLOW) + /* The two sets of flags must not overlap. */ QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & TLB_SLOW_FLAGS_MASK); From 12eeb04ab4dd98f802ffc503f0da948a8c843086 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 27 Mar 2025 18:52:13 -0500 Subject: [PATCH 0178/2760] page-vary: Move and rename qemu_target_page_bits_min Rename to migration_legacy_page_bits, to make it clear that we cannot change the value without causing a migration break. Move to page-vary.h and page-vary-target.c. Define via TARGET_PAGE_BITS if not TARGET_PAGE_BITS_VARY. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/exec/page-vary.h | 9 +++++++++ include/exec/target_page.h | 1 - migration/savevm.c | 6 +++--- page-target.c | 5 ----- page-vary-target.c | 9 +++++++++ 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/exec/page-vary.h b/include/exec/page-vary.h index 54ddde308a..101c25911c 100644 --- a/include/exec/page-vary.h +++ b/include/exec/page-vary.h @@ -49,4 +49,13 @@ bool set_preferred_target_page_bits(int bits); */ void finalize_target_page_bits(void); +/** + * migration_legacy_page_bits + * + * For migration compatibility with qemu v2.9, prior to the introduction + * of the configuration/target-page-bits section, return the value of + * TARGET_PAGE_BITS that the target had then. + */ +int migration_legacy_page_bits(void); + #endif /* EXEC_PAGE_VARY_H */ diff --git a/include/exec/target_page.h b/include/exec/target_page.h index 8e89e5cbe6..e4bd7f7767 100644 --- a/include/exec/target_page.h +++ b/include/exec/target_page.h @@ -63,7 +63,6 @@ static inline int qemu_target_page_bits(void) return TARGET_PAGE_BITS; } -int qemu_target_page_bits_min(void); size_t qemu_target_pages_to_MiB(size_t pages); #endif diff --git a/migration/savevm.c b/migration/savevm.c index c33200a33f..0c12e373b4 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -50,6 +50,7 @@ #include "system/cpus.h" #include "system/memory.h" #include "exec/target_page.h" +#include "exec/page-vary.h" #include "trace.h" #include "qemu/iov.h" #include "qemu/job.h" @@ -339,7 +340,7 @@ static int configuration_pre_load(void *opaque) * predates the variable-target-page-bits support and is using the * minimum possible value for this CPU. */ - state->target_page_bits = qemu_target_page_bits_min(); + state->target_page_bits = migration_legacy_page_bits(); return 0; } @@ -462,8 +463,7 @@ static const VMStateInfo vmstate_info_capability = { */ static bool vmstate_target_page_bits_needed(void *opaque) { - return qemu_target_page_bits() - > qemu_target_page_bits_min(); + return qemu_target_page_bits() > migration_legacy_page_bits(); } static const VMStateDescription vmstate_target_page_bits = { diff --git a/page-target.c b/page-target.c index 321e43d06f..8fcd5443b5 100644 --- a/page-target.c +++ b/page-target.c @@ -9,11 +9,6 @@ #include "qemu/osdep.h" #include "exec/target_page.h" -int qemu_target_page_bits_min(void) -{ - return TARGET_PAGE_BITS_MIN; -} - /* Convert target pages to MiB (2**20). */ size_t qemu_target_pages_to_MiB(size_t pages) { diff --git a/page-vary-target.c b/page-vary-target.c index 84ddeb7c26..6251d948cf 100644 --- a/page-vary-target.c +++ b/page-vary-target.c @@ -23,6 +23,15 @@ #include "exec/page-vary.h" #include "exec/target_page.h" +int migration_legacy_page_bits(void) +{ +#ifdef TARGET_PAGE_BITS_VARY + return TARGET_PAGE_BITS_MIN; +#else + return TARGET_PAGE_BITS; +#endif +} + bool set_preferred_target_page_bits(int bits) { #ifdef TARGET_PAGE_BITS_VARY From d11bf649d587dec050b6ba900a8f9baea1fe157d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 28 Mar 2025 14:28:06 -0500 Subject: [PATCH 0179/2760] page-vary: Restrict scope of TARGET_PAGE_BITS_MIN The only place we really need to know the minimum is within page-vary-target.c. Rename the target/arm TARGET_PAGE_BITS_MIN to TARGET_PAGE_BITS_LEGACY to emphasize what it really means. Move the assertions related to minimum page size as well. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 1 - include/exec/cpu-defs.h | 10 ++-------- include/exec/target_page.h | 1 - page-vary-target.c | 39 +++++++++++++++++++++++++++++++++++--- target/alpha/cpu-param.h | 1 - target/arm/cpu-param.h | 3 +-- target/ppc/cpu-param.h | 1 - 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 39314e86f3..0de46903dd 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -49,7 +49,6 @@ #endif #include "tcg/tcg-ldst.h" -QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & ((1u < TARGET_PAGE_BITS_MIN) - 1)); /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ /* #define DEBUG_TLB */ diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h index 9f955f53fd..e01acb7c90 100644 --- a/include/exec/cpu-defs.h +++ b/include/exec/cpu-defs.h @@ -34,14 +34,8 @@ #ifndef TARGET_VIRT_ADDR_SPACE_BITS # error TARGET_VIRT_ADDR_SPACE_BITS must be defined in cpu-param.h #endif -#ifndef TARGET_PAGE_BITS -# ifdef TARGET_PAGE_BITS_VARY -# ifndef TARGET_PAGE_BITS_MIN -# error TARGET_PAGE_BITS_MIN must be defined in cpu-param.h -# endif -# else -# error TARGET_PAGE_BITS must be defined in cpu-param.h -# endif +#if !defined(TARGET_PAGE_BITS) && !defined(TARGET_PAGE_BITS_VARY) +# error TARGET_PAGE_BITS must be defined in cpu-param.h #endif #include "exec/target_long.h" diff --git a/include/exec/target_page.h b/include/exec/target_page.h index e4bd7f7767..ca0ebbc8bb 100644 --- a/include/exec/target_page.h +++ b/include/exec/target_page.h @@ -41,7 +41,6 @@ extern const TargetPageBits target_page; # endif # define TARGET_PAGE_SIZE (-(int)TARGET_PAGE_MASK) #else -# define TARGET_PAGE_BITS_MIN TARGET_PAGE_BITS # define TARGET_PAGE_SIZE (1 << TARGET_PAGE_BITS) # define TARGET_PAGE_MASK ((TARGET_PAGE_TYPE)-1 << TARGET_PAGE_BITS) #endif diff --git a/page-vary-target.c b/page-vary-target.c index 6251d948cf..49a32b4fe5 100644 --- a/page-vary-target.c +++ b/page-vary-target.c @@ -23,19 +23,45 @@ #include "exec/page-vary.h" #include "exec/target_page.h" + +/* + * For system mode, the minimum comes from the number of bits + * required for maximum alignment (6) and the number of bits + * required for TLB_FLAGS_MASK (3). + * + * For user mode, TARGET_PAGE_BITS_VARY is a hack to allow the target + * page size to match the host page size. Mostly, this reduces the + * ordinary target page size to run on a host with 4KiB pages (i.e. x86). + * There is no true minimum required by the implementation, but keep the + * same minimum as for system mode for sanity. + * See linux-user/mmap.c, mmap_h_lt_g and mmap_h_gt_g. + */ +#define TARGET_PAGE_BITS_MIN 9 + +#ifndef TARGET_PAGE_BITS_VARY +QEMU_BUILD_BUG_ON(TARGET_PAGE_BITS < TARGET_PAGE_BITS_MIN); +#endif + +#ifndef CONFIG_USER_ONLY +#include "exec/tlb-flags.h" + +QEMU_BUILD_BUG_ON(TLB_FLAGS_MASK & ((1u < TARGET_PAGE_BITS_MIN) - 1)); + int migration_legacy_page_bits(void) { #ifdef TARGET_PAGE_BITS_VARY - return TARGET_PAGE_BITS_MIN; + QEMU_BUILD_BUG_ON(TARGET_PAGE_BITS_LEGACY < TARGET_PAGE_BITS_MIN); + return TARGET_PAGE_BITS_LEGACY; #else return TARGET_PAGE_BITS; #endif } +#endif bool set_preferred_target_page_bits(int bits) { -#ifdef TARGET_PAGE_BITS_VARY assert(bits >= TARGET_PAGE_BITS_MIN); +#ifdef TARGET_PAGE_BITS_VARY return set_preferred_target_page_bits_common(bits); #else return true; @@ -44,5 +70,12 @@ bool set_preferred_target_page_bits(int bits) void finalize_target_page_bits(void) { - finalize_target_page_bits_common(TARGET_PAGE_BITS_MIN); +#ifndef TARGET_PAGE_BITS_VARY + finalize_target_page_bits_common(TARGET_PAGE_BITS); +#elif defined(CONFIG_USER_ONLY) + assert(target_page.bits != 0); + finalize_target_page_bits_common(target_page.bits); +#else + finalize_target_page_bits_common(TARGET_PAGE_BITS_LEGACY); +#endif } diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index ff06e41497..63989e71c0 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -18,7 +18,6 @@ * a 4k minimum to match x86 host, which can minimize emulation issues. */ # define TARGET_PAGE_BITS_VARY -# define TARGET_PAGE_BITS_MIN 12 # define TARGET_VIRT_ADDR_SPACE_BITS 63 #else # define TARGET_PAGE_BITS 13 diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 896b35bd6d..a7ae42d17d 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -24,7 +24,6 @@ # else /* Allow user-only to vary page size from 4k */ # define TARGET_PAGE_BITS_VARY -# define TARGET_PAGE_BITS_MIN 12 # endif # else # define TARGET_PAGE_BITS 12 @@ -35,7 +34,7 @@ * have to support 1K tiny pages. */ # define TARGET_PAGE_BITS_VARY -# define TARGET_PAGE_BITS_MIN 10 +# define TARGET_PAGE_BITS_LEGACY 10 #endif /* !CONFIG_USER_ONLY */ /* ARM processors have a weak memory model */ diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h index 6c4525fdf3..553ad2f4c6 100644 --- a/target/ppc/cpu-param.h +++ b/target/ppc/cpu-param.h @@ -33,7 +33,6 @@ #ifdef CONFIG_USER_ONLY /* Allow user-only to vary page size from 4k */ # define TARGET_PAGE_BITS_VARY -# define TARGET_PAGE_BITS_MIN 12 #else # define TARGET_PAGE_BITS 12 #endif From 33d2cca32b6822767c1f388f0b05b8a046aa556f Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:47 -0700 Subject: [PATCH 0180/2760] exec/cpu-all: move cpu_copy to linux-user/qemu.h Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-3-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 2 -- linux-user/qemu.h | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 5c4379f0d0..2aaaf0548d 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -31,8 +31,6 @@ #endif -CPUArchState *cpu_copy(CPUArchState *env); - #include "cpu.h" /* Validate correct placement of CPUArchState. */ diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 5f00750151..948de8431a 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -362,4 +362,7 @@ void *lock_user_string(abi_ulong guest_addr); #define unlock_user_struct(host_ptr, guest_addr, copy) \ unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0) +/* Clone cpu state */ +CPUArchState *cpu_copy(CPUArchState *env); + #endif /* QEMU_H */ From 8d535c312ca5944622b3b74177eb12d8f6b7a7fa Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:48 -0700 Subject: [PATCH 0181/2760] include/exec/cpu-all: move compile time check for CPUArchState to cpu-target.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Philippe Mathieu-Daudé Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-4-pierrick.bouvier@linaro.org> --- cpu-target.c | 5 +++++ include/exec/cpu-all.h | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index 519b0f8900..7f3b244ed1 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "cpu.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" @@ -29,6 +30,10 @@ #include "accel/accel-cpu-target.h" #include "trace/trace-root.h" +/* Validate correct placement of CPUArchState. */ +QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); +QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); + char *cpu_model_from_type(const char *typename) { const char *suffix = "-" CPU_RESOLVING_TYPE; diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 2aaaf0548d..be462c4410 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -33,8 +33,4 @@ #include "cpu.h" -/* Validate correct placement of CPUArchState. */ -QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); -QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); - #endif /* CPU_ALL_H */ From 342e313d6c1a8e6da758bd642777b85af1a0fc37 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:49 -0700 Subject: [PATCH 0182/2760] exec/cpu-all: remove system/memory include We include this header where needed. When includes set already have ifdef CONFIG_USER_ONLY, we add it here, else, we don't condition the include. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-5-pierrick.bouvier@linaro.org> --- hw/ppc/spapr_ovec.c | 1 + hw/s390x/ipl.h | 1 + include/exec/cpu-all.h | 5 ----- target/alpha/helper.c | 1 + target/arm/hvf/hvf.c | 1 + target/arm/internals.h | 1 + target/hppa/cpu.h | 1 + target/i386/arch_memory_mapping.c | 1 + target/i386/helper.c | 1 + target/i386/hvf/vmx.h | 1 + target/i386/tcg/system/misc_helper.c | 1 + target/i386/tcg/system/tcg-cpu.c | 1 + target/m68k/helper.c | 1 + target/ppc/excp_helper.c | 1 + target/ppc/mmu-book3s-v3.c | 1 + target/ppc/mmu-hash32.h | 2 ++ target/ppc/mmu-hash64.c | 1 + target/ppc/mmu-radix64.c | 1 + target/riscv/cpu_helper.c | 1 + target/sparc/ldst_helper.c | 1 + target/sparc/mmu_helper.c | 1 + target/xtensa/mmu_helper.c | 1 + target/xtensa/op_helper.c | 1 + 23 files changed, 23 insertions(+), 5 deletions(-) diff --git a/hw/ppc/spapr_ovec.c b/hw/ppc/spapr_ovec.c index 6d6eaf67cb..75ab4fe262 100644 --- a/hw/ppc/spapr_ovec.c +++ b/hw/ppc/spapr_ovec.c @@ -16,6 +16,7 @@ #include "migration/vmstate.h" #include "qemu/bitmap.h" #include "system/address-spaces.h" +#include "system/memory.h" #include "qemu/error-report.h" #include "trace.h" #include diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index c6ecb3433c..6557ac3be5 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -15,6 +15,7 @@ #include "cpu.h" #include "system/address-spaces.h" +#include "system/memory.h" #include "hw/qdev-core.h" #include "hw/s390x/ipl/qipl.h" #include "qom/object.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index be462c4410..399fcbb9d1 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -26,11 +26,6 @@ #include "hw/core/cpu.h" #include "exec/cpu-defs.h" #include "exec/target_page.h" -#ifndef CONFIG_USER_ONLY -#include "system/memory.h" -#endif - - #include "cpu.h" #endif /* CPU_ALL_H */ diff --git a/target/alpha/helper.c b/target/alpha/helper.c index 57cefcba14..f6261a3a53 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -25,6 +25,7 @@ #include "fpu/softfloat-types.h" #include "exec/helper-proto.h" #include "qemu/qemu-print.h" +#include "system/memory.h" #define CONVERT_BIT(X, SRC, DST) \ diff --git a/target/arm/hvf/hvf.c b/target/arm/hvf/hvf.c index 93a3f9b53d..34ca36fab5 100644 --- a/target/arm/hvf/hvf.c +++ b/target/arm/hvf/hvf.c @@ -23,6 +23,7 @@ #include #include "system/address-spaces.h" +#include "system/memory.h" #include "hw/boards.h" #include "hw/irq.h" #include "qemu/main-loop.h" diff --git a/target/arm/internals.h b/target/arm/internals.h index 8756c24c08..01408e40a3 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -28,6 +28,7 @@ #include "exec/breakpoint.h" #include "hw/registerfields.h" #include "tcg/tcg-gvec-desc.h" +#include "system/memory.h" #include "syndrome.h" #include "cpu-features.h" diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 8b36642b59..f6bf068776 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "system/memory.h" #include "qemu/cpu-float.h" #include "qemu/interval-tree.h" #include "hw/registerfields.h" diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index ced199862d..a2398c2173 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "system/memory_mapping.h" +#include "system/memory.h" /* PAE Paging or IA-32e Paging */ static void walk_pte(MemoryMappingList *list, AddressSpace *as, diff --git a/target/i386/helper.c b/target/i386/helper.c index c07b1b16ea..64d9e8ab9c 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -25,6 +25,7 @@ #include "system/runstate.h" #ifndef CONFIG_USER_ONLY #include "system/hw_accel.h" +#include "system/memory.h" #include "monitor/monitor.h" #include "kvm/kvm_i386.h" #endif diff --git a/target/i386/hvf/vmx.h b/target/i386/hvf/vmx.h index 029516e5c0..26d6029fa5 100644 --- a/target/i386/hvf/vmx.h +++ b/target/i386/hvf/vmx.h @@ -34,6 +34,7 @@ #include "system/hvf_int.h" #include "system/address-spaces.h" +#include "system/memory.h" static inline uint64_t rreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg) { diff --git a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/misc_helper.c index 0555cf2604..67896c8c87 100644 --- a/target/i386/tcg/system/misc_helper.c +++ b/target/i386/tcg/system/misc_helper.c @@ -23,6 +23,7 @@ #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #include "system/address-spaces.h" +#include "system/memory.h" #include "exec/cputlb.h" #include "tcg/helper-tcg.h" #include "hw/i386/apic.h" diff --git a/target/i386/tcg/system/tcg-cpu.c b/target/i386/tcg/system/tcg-cpu.c index ab1f3c7c59..0538a4fd51 100644 --- a/target/i386/tcg/system/tcg-cpu.c +++ b/target/i386/tcg/system/tcg-cpu.c @@ -24,6 +24,7 @@ #include "system/system.h" #include "qemu/units.h" #include "system/address-spaces.h" +#include "system/memory.h" #include "tcg/tcg-cpu.h" diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 0bf574830f..8251272219 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -25,6 +25,7 @@ #include "exec/page-protection.h" #include "exec/gdbstub.h" #include "exec/helper-proto.h" +#include "system/memory.h" #include "gdbstub/helpers.h" #include "fpu/softfloat.h" #include "qemu/qemu-print.h" diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index c941c89806..da8b525a41 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "qemu/log.h" +#include "system/memory.h" #include "system/tcg.h" #include "system/system.h" #include "system/runstate.h" diff --git a/target/ppc/mmu-book3s-v3.c b/target/ppc/mmu-book3s-v3.c index a812cb5113..3865556310 100644 --- a/target/ppc/mmu-book3s-v3.c +++ b/target/ppc/mmu-book3s-v3.c @@ -18,6 +18,7 @@ */ #include "qemu/osdep.h" +#include "system/memory.h" #include "cpu.h" #include "mmu-hash64.h" #include "mmu-book3s-v3.h" diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h index 2838de031c..04c23ea75e 100644 --- a/target/ppc/mmu-hash32.h +++ b/target/ppc/mmu-hash32.h @@ -3,6 +3,8 @@ #ifndef CONFIG_USER_ONLY +#include "system/memory.h" + bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type, hwaddr *raddrp, int *psizep, int *protp, int mmu_idx, bool guest_visible); diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 5ca4faee2a..3ba4810497 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -25,6 +25,7 @@ #include "qemu/error-report.h" #include "qemu/qemu-print.h" #include "system/hw_accel.h" +#include "system/memory.h" #include "kvm_ppc.h" #include "mmu-hash64.h" #include "exec/log.h" diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 461eda4a3d..4ab5f3bb92 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -23,6 +23,7 @@ #include "exec/page-protection.h" #include "qemu/error-report.h" #include "system/kvm.h" +#include "system/memory.h" #include "kvm_ppc.h" #include "exec/log.h" #include "internal.h" diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 0dd8645994..ca58094fb5 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -26,6 +26,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "system/memory.h" #include "instmap.h" #include "tcg/tcg-op.h" #include "accel/tcg/cpu-ops.h" diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 45882e25db..8890d2b119 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -27,6 +27,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/cpu_ldst.h" +#include "system/memory.h" #ifdef CONFIG_USER_ONLY #include "user/page-protection.h" #endif diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index 249b1f6c4c..c5d82a0854 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -24,6 +24,7 @@ #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" #include "exec/tlb-flags.h" +#include "system/memory.h" #include "qemu/qemu-print.h" #include "trace.h" diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 40b02f0a2c..1ce125794d 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -36,6 +36,7 @@ #include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "system/memory.h" #define XTENSA_MPU_SEGMENT_MASK 0x0000001f #define XTENSA_MPU_ACC_RIGHTS_MASK 0x00000f00 diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index 028d4e0a1c..c125fa4946 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -31,6 +31,7 @@ #include "exec/page-protection.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" +#include "system/memory.h" #include "qemu/atomic.h" #include "qemu/timer.h" From e33865f0484cf8f65e12e864d8dc825456174ddc Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:50 -0700 Subject: [PATCH 0183/2760] exec/cpu-all: remove exec/page-protection include Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-6-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 399fcbb9d1..957c86886e 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -19,7 +19,6 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -#include "exec/page-protection.h" #include "exec/cpu-common.h" #include "exec/cpu-interrupt.h" #include "exec/tswap.h" From 4533af18b2ed5a6852ffb2dc024784d243f64ba4 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:51 -0700 Subject: [PATCH 0184/2760] exec/cpu-all: remove tswap include Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-7-pierrick.bouvier@linaro.org> --- include/exec/cpu-all.h | 1 - target/i386/tcg/system/excp_helper.c | 1 + target/i386/xsave_helper.c | 1 + target/ppc/mmu-hash64.h | 2 ++ target/riscv/vector_helper.c | 1 + 5 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 957c86886e..bfa039ab76 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -21,7 +21,6 @@ #include "exec/cpu-common.h" #include "exec/cpu-interrupt.h" -#include "exec/tswap.h" #include "hw/core/cpu.h" #include "exec/cpu-defs.h" #include "exec/target_page.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index b0b74df72f..4badd73943 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/tlb-flags.h" +#include "exec/tswap.h" #include "tcg/helper-tcg.h" typedef struct TranslateParams { diff --git a/target/i386/xsave_helper.c b/target/i386/xsave_helper.c index 996e9f3bfe..24ab7be8e9 100644 --- a/target/i386/xsave_helper.c +++ b/target/i386/xsave_helper.c @@ -5,6 +5,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/tswap.h" void x86_cpu_xsave_all_areas(X86CPU *cpu, void *buf, uint32_t buflen) { diff --git a/target/ppc/mmu-hash64.h b/target/ppc/mmu-hash64.h index ae8d4b37ae..b8fb12a970 100644 --- a/target/ppc/mmu-hash64.h +++ b/target/ppc/mmu-hash64.h @@ -1,6 +1,8 @@ #ifndef MMU_HASH64_H #define MMU_HASH64_H +#include "exec/tswap.h" + #ifndef CONFIG_USER_ONLY #ifdef TARGET_PPC64 diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 83978be060..7fffa23bc8 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -26,6 +26,7 @@ #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" +#include "exec/tswap.h" #include "fpu/softfloat.h" #include "tcg/tcg-gvec-desc.h" #include "internals.h" From 22a7c2f239229b2ee9fcbac03cb598d9aebb9196 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:52 -0700 Subject: [PATCH 0185/2760] exec/cpu-all: remove exec/cpu-interrupt include Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-8-pierrick.bouvier@linaro.org> --- accel/tcg/cpu-exec.c | 1 + hw/alpha/typhoon.c | 1 + hw/m68k/next-cube.c | 1 + hw/ppc/ppc.c | 1 + hw/xtensa/pic_cpu.c | 1 + include/exec/cpu-all.h | 1 - target/alpha/cpu.h | 1 + target/arm/cpu.h | 1 + target/avr/cpu.h | 1 + target/hppa/cpu.h | 1 + target/i386/cpu.h | 1 + target/loongarch/cpu.h | 1 + target/m68k/cpu.h | 1 + target/microblaze/cpu.h | 1 + target/mips/cpu.h | 1 + target/openrisc/cpu.h | 1 + target/ppc/cpu.h | 1 + target/riscv/cpu.h | 1 + target/rx/cpu.h | 1 + target/s390x/cpu.h | 1 + target/sh4/cpu.h | 1 + target/sparc/cpu.h | 1 + target/xtensa/cpu.h | 1 + 23 files changed, 22 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 9e15105533..d388be83d0 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -26,6 +26,7 @@ #include "trace.h" #include "disas/disas.h" #include "exec/cpu-common.h" +#include "exec/cpu-interrupt.h" #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "exec/translation-block.h" diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index e8711ae16a..9718e1a579 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" #include "qemu/units.h" +#include "exec/cpu-interrupt.h" #include "qapi/error.h" #include "hw/pci/pci_host.h" #include "cpu.h" diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 0570e4a76f..4ae5668331 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "exec/hwaddr.h" +#include "exec/cpu-interrupt.h" #include "system/system.h" #include "system/qtest.h" #include "hw/irq.h" diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index 3a80931538..43d0d0e755 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -27,6 +27,7 @@ #include "hw/ppc/ppc.h" #include "hw/ppc/ppc_e500.h" #include "qemu/timer.h" +#include "exec/cpu-interrupt.h" #include "system/cpus.h" #include "qemu/log.h" #include "qemu/main-loop.h" diff --git a/hw/xtensa/pic_cpu.c b/hw/xtensa/pic_cpu.c index 8cef88c61b..e388531610 100644 --- a/hw/xtensa/pic_cpu.c +++ b/hw/xtensa/pic_cpu.c @@ -27,6 +27,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/cpu-interrupt.h" #include "hw/irq.h" #include "qemu/log.h" #include "qemu/timer.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index bfa039ab76..7b712b2556 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -20,7 +20,6 @@ #define CPU_ALL_H #include "exec/cpu-common.h" -#include "exec/cpu-interrupt.h" #include "hw/core/cpu.h" #include "exec/cpu-defs.h" #include "exec/target_page.h" diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 80562adfb5..42788a6a0b 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #define ICACHE_LINE_SIZE 32 diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a8177c6c2e..958a921490 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -25,6 +25,7 @@ #include "hw/registerfields.h" #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "exec/gdbstub.h" #include "exec/page-protection.h" #include "qapi/qapi-types-common.h" diff --git a/target/avr/cpu.h b/target/avr/cpu.h index b0518a1f60..c2cc2daa66 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -23,6 +23,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "system/memory.h" #ifdef CONFIG_USER_ONLY diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index f6bf068776..dab58c227f 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "system/memory.h" #include "qemu/cpu-float.h" #include "qemu/interval-tree.h" diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 0ad67fe0fd..778dfd9637 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -24,6 +24,7 @@ #include "cpu-qom.h" #include "kvm/hyperv-proto.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "exec/memop.h" #include "hw/i386/topology.h" #include "qapi/qapi-types-common.h" diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 02ef6ddecb..a924aa01d7 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -10,6 +10,7 @@ #include "qemu/int128.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "fpu/softfloat-types.h" #include "hw/registerfields.h" #include "qemu/timer.h" diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index ddb0f29f4a..451644a05a 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -22,6 +22,7 @@ #define M68K_CPU_H #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #include "cpu-qom.h" diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index e44ddd5307..d29681abed 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -23,6 +23,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" +#include "exec/cpu-interrupt.h" typedef struct CPUArchState CPUMBState; #if !defined(CONFIG_USER_ONLY) diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 9ef72a95d7..29362498ec 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -3,6 +3,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #ifndef CONFIG_USER_ONLY #include "system/memory.h" #endif diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index b97d2ffdd2..c153823b62 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "fpu/softfloat-types.h" /** diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 3ee83517dc..7489ba9564 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -23,6 +23,7 @@ #include "qemu/int128.h" #include "qemu/cpu-float.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "cpu-qom.h" #include "qom/object.h" #include "hw/registerfields.h" diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 51e49e03de..556eda57e9 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -24,6 +24,7 @@ #include "hw/registerfields.h" #include "hw/qdev-properties.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "exec/gdbstub.h" #include "qemu/cpu-float.h" #include "qom/object.h" diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 349d61c4e4..5f2fcb6656 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -24,6 +24,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #ifdef CONFIG_USER_ONLY diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 5b7992deda..0a32ad4c61 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -28,6 +28,7 @@ #include "cpu-qom.h" #include "cpu_models.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #include "qapi/qapi-types-machine-common.h" diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index d536d5d715..18557d8c38 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" /* CPU Subtypes */ diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 68f8c21e7c..c0aab69b61 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -4,6 +4,7 @@ #include "qemu/bswap.h" #include "cpu-qom.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" #if !defined(TARGET_SPARC64) diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 8d70bfc0cd..6684631478 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -31,6 +31,7 @@ #include "cpu-qom.h" #include "qemu/cpu-float.h" #include "exec/cpu-defs.h" +#include "exec/cpu-interrupt.h" #include "hw/clock.h" #include "xtensa-isa.h" From 98c7c1469880e5430e709fd20c5d5daed6b3ad75 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:56 -0700 Subject: [PATCH 0186/2760] accel/tcg: fix missing includes for TCG_GUEST_DEFAULT_MO We prepare to remove cpu.h from cpu-all.h, which will transitively remove it from accel/tcg/tb-internal.h, and thus from most of tcg compilation units. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-12-pierrick.bouvier@linaro.org> --- accel/tcg/internal-target.h | 1 + accel/tcg/translate-all.c | 1 + include/exec/poison.h | 1 + 3 files changed, 3 insertions(+) diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index c88f007ffb..05abaeb8e0 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -9,6 +9,7 @@ #ifndef ACCEL_TCG_INTERNAL_TARGET_H #define ACCEL_TCG_INTERNAL_TARGET_H +#include "cpu-param.h" #include "exec/exec-all.h" #include "exec/translation-block.h" #include "tb-internal.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 87fb6c51d3..ed41fc5d0c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -43,6 +43,7 @@ #include "system/ram_addr.h" #endif +#include "cpu-param.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/mmap-lock.h" diff --git a/include/exec/poison.h b/include/exec/poison.h index 4180a5a489..8ec02b40e8 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -37,6 +37,7 @@ #pragma GCC poison TARGET_NAME #pragma GCC poison TARGET_SUPPORTS_MTTCG #pragma GCC poison TARGET_BIG_ENDIAN +#pragma GCC poison TCG_GUEST_DEFAULT_MO #pragma GCC poison TARGET_LONG_BITS #pragma GCC poison TARGET_FMT_lx From 4fadca8d649a2aeef8070b973b2a1d5da75dfefb Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:57 -0700 Subject: [PATCH 0187/2760] accel/tcg: fix missing includes for TARGET_HAS_PRECISE_SMC We prepare to remove cpu.h from cpu-all.h, which will transitively remove it from accel/tcg/tb-internal.h, and thus from most of tcg compilation units. Note: this was caught by a test regression for s390x-softmmu. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-13-pierrick.bouvier@linaro.org> --- accel/tcg/tb-maint.c | 1 + accel/tcg/user-exec.c | 1 + include/exec/poison.h | 1 + 3 files changed, 3 insertions(+) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index df3438e190..d479f53ae0 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/interval-tree.h" #include "qemu/qtree.h" +#include "cpu.h" #include "exec/cputlb.h" #include "exec/log.h" #include "exec/exec-all.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 72a9809c2d..7f57d8f1af 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "accel/tcg/cpu-ops.h" #include "disas/disas.h" +#include "cpu.h" #include "exec/vaddr.h" #include "exec/exec-all.h" #include "exec/tlb-flags.h" diff --git a/include/exec/poison.h b/include/exec/poison.h index 8ec02b40e8..f267da6083 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -38,6 +38,7 @@ #pragma GCC poison TARGET_SUPPORTS_MTTCG #pragma GCC poison TARGET_BIG_ENDIAN #pragma GCC poison TCG_GUEST_DEFAULT_MO +#pragma GCC poison TARGET_HAS_PRECISE_SMC #pragma GCC poison TARGET_LONG_BITS #pragma GCC poison TARGET_FMT_lx From e9659a4da2e5d75b6d100007efe315150a943146 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:58 -0700 Subject: [PATCH 0188/2760] exec/cpu-all: remove cpu include Now we made sure important defines are included using their direct path, we can remove cpu.h from cpu-all.h. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-14-pierrick.bouvier@linaro.org> --- accel/tcg/cpu-exec.c | 1 + include/exec/cpu-all.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index d388be83d0..8d2b957a3b 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -36,6 +36,7 @@ #include "exec/log.h" #include "qemu/main-loop.h" #include "exec/cpu-all.h" +#include "cpu.h" #include "exec/icount.h" #include "exec/replay-core.h" #include "system/tcg.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index 7b712b2556..dae4fbcea8 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -23,6 +23,5 @@ #include "hw/core/cpu.h" #include "exec/cpu-defs.h" #include "exec/target_page.h" -#include "cpu.h" #endif /* CPU_ALL_H */ From 9c2ff9cdc9b33472333e9431cbf4417f5f228883 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 31 Mar 2025 16:40:55 -0500 Subject: [PATCH 0189/2760] exec/cpu-all: remove exec/target_page include Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-hash.h | 1 + hw/alpha/dp264.c | 1 + hw/arm/boot.c | 1 + hw/arm/smmuv3.c | 1 + hw/avr/atmega.c | 1 + hw/hppa/machine.c | 1 + hw/hyperv/hyperv.c | 1 + hw/hyperv/syndbg.c | 1 + hw/hyperv/vmbus.c | 1 + hw/i386/multiboot.c | 1 + hw/i386/pc.c | 1 + hw/i386/pc_sysfw_ovmf.c | 1 + hw/i386/vapic.c | 1 + hw/loongarch/virt.c | 1 + hw/m68k/q800.c | 1 + hw/m68k/virt.c | 1 + hw/openrisc/boot.c | 1 + hw/pci-host/astro.c | 1 + hw/ppc/e500.c | 1 + hw/ppc/mac_newworld.c | 1 + hw/ppc/mac_oldworld.c | 1 + hw/ppc/ppc_booke.c | 1 + hw/ppc/prep.c | 1 + hw/ppc/spapr_hcall.c | 1 + hw/riscv/riscv-iommu-pci.c | 1 + hw/riscv/riscv-iommu.c | 1 + hw/s390x/ipl.h | 1 + hw/s390x/s390-pci-bus.c | 1 + hw/s390x/s390-pci-inst.c | 1 + hw/s390x/s390-skeys.c | 1 + hw/sparc/sun4m.c | 1 + hw/sparc64/sun4u.c | 1 + include/exec/cpu-all.h | 1 - monitor/hmp-cmds-target.c | 1 + semihosting/uaccess.c | 1 + target/alpha/cpu.c | 1 + target/alpha/helper.c | 1 + target/alpha/translate.c | 1 + target/arm/cpu.c | 1 + target/arm/gdbstub64.c | 1 + target/arm/ptw.c | 1 + target/arm/tcg/helper-a64.c | 1 + target/arm/tcg/op_helper.c | 1 + target/arm/tcg/sve_helper.c | 1 + target/arm/tcg/tlb-insns.c | 1 + target/arm/tcg/translate-a64.c | 2 +- target/arm/tcg/translate.c | 1 + target/avr/helper.c | 1 + target/avr/translate.c | 1 + target/hppa/cpu.c | 1 + target/hppa/mem_helper.c | 1 + target/hppa/translate.c | 1 + target/i386/helper.c | 1 + target/i386/kvm/hyperv.c | 1 + target/i386/kvm/kvm.c | 1 + target/i386/kvm/xen-emu.c | 1 + target/i386/sev.c | 1 + target/i386/tcg/access.c | 1 + target/i386/tcg/mpx_helper.c | 1 + target/i386/tcg/system/excp_helper.c | 1 + target/i386/tcg/tcg-cpu.c | 2 +- target/i386/tcg/translate.c | 1 + target/loongarch/cpu_helper.c | 1 + target/loongarch/tcg/tlb_helper.c | 1 + target/loongarch/tcg/translate.c | 1 + target/m68k/helper.c | 1 + target/m68k/translate.c | 1 + target/microblaze/helper.c | 1 + target/microblaze/mmu.c | 1 + target/microblaze/translate.c | 1 + target/mips/tcg/msa_helper.c | 1 + target/mips/tcg/system/cp0_helper.c | 1 + target/mips/tcg/system/tlb_helper.c | 1 + target/mips/tcg/translate.c | 1 + target/openrisc/mmu.c | 1 + target/openrisc/sys_helper.c | 1 + target/openrisc/translate.c | 2 +- target/ppc/mem_helper.c | 1 + target/ppc/mmu-hash32.c | 1 + target/ppc/mmu_common.c | 1 + target/ppc/mmu_helper.c | 1 + target/ppc/translate.c | 1 + target/riscv/cpu_helper.c | 1 + target/riscv/pmp.c | 1 + target/riscv/tcg/tcg-cpu.c | 1 + target/riscv/translate.c | 2 +- target/riscv/vector_helper.c | 1 + target/rx/cpu.c | 1 + target/s390x/helper.c | 1 + target/s390x/ioinst.c | 1 + target/s390x/mmu_helper.c | 1 + target/s390x/tcg/excp_helper.c | 1 + target/s390x/tcg/mem_helper.c | 1 + target/s390x/tcg/misc_helper.c | 1 + target/sh4/helper.c | 1 + target/sh4/translate.c | 1 + target/sparc/ldst_helper.c | 1 + target/sparc/mmu_helper.c | 1 + target/sparc/translate.c | 1 + target/tricore/helper.c | 1 + target/tricore/translate.c | 1 + target/xtensa/helper.c | 1 + target/xtensa/mmu_helper.c | 1 + target/xtensa/translate.c | 1 + target/xtensa/xtensa-semi.c | 1 + 105 files changed, 104 insertions(+), 5 deletions(-) diff --git a/accel/tcg/tb-hash.h b/accel/tcg/tb-hash.h index a5382f460d..3bc5042d9d 100644 --- a/accel/tcg/tb-hash.h +++ b/accel/tcg/tb-hash.h @@ -22,6 +22,7 @@ #include "exec/cpu-defs.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "exec/translation-block.h" #include "qemu/xxhash.h" #include "tb-jmp-cache.h" diff --git a/hw/alpha/dp264.c b/hw/alpha/dp264.c index 570ea9edf2..19562b5967 100644 --- a/hw/alpha/dp264.c +++ b/hw/alpha/dp264.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/target_page.h" #include "elf.h" #include "hw/loader.h" #include "alpha_sys.h" diff --git a/hw/arm/boot.c b/hw/arm/boot.c index e296b62fa1..d3811b896f 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -14,6 +14,7 @@ #include #include "hw/arm/boot.h" #include "hw/arm/linux-boot-if.h" +#include "exec/target_page.h" #include "system/kvm.h" #include "system/tcg.h" #include "system/system.h" diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 1a96287ba9..4362ae6aa1 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -25,6 +25,7 @@ #include "hw/qdev-core.h" #include "hw/pci/pci.h" #include "cpu.h" +#include "exec/target_page.h" #include "trace.h" #include "qemu/log.h" #include "qemu/error-report.h" diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index 2e8b8e8c67..c105d2a97c 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -12,6 +12,7 @@ #include "qemu/module.h" #include "qemu/units.h" #include "qapi/error.h" +#include "exec/target_page.h" #include "system/memory.h" #include "system/address-spaces.h" #include "system/system.h" diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index c5f247633e..c430bf28dd 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -11,6 +11,7 @@ #include "elf.h" #include "hw/loader.h" #include "qemu/error-report.h" +#include "exec/target_page.h" #include "system/reset.h" #include "system/system.h" #include "system/qtest.h" diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index d21e428eae..c487f13e2f 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -25,6 +25,7 @@ #include "target/i386/kvm/hyperv-proto.h" #include "target/i386/cpu.h" #include "exec/cpu-all.h" +#include "exec/target_page.h" struct SynICState { DeviceState parent_obj; diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c index d3e3917077..a410b55b9a 100644 --- a/hw/hyperv/syndbg.c +++ b/hw/hyperv/syndbg.c @@ -15,6 +15,7 @@ #include "hw/qdev-properties.h" #include "hw/loader.h" #include "cpu.h" +#include "exec/target_page.h" #include "hw/hyperv/hyperv.h" #include "hw/hyperv/vmbus-bridge.h" #include "hw/hyperv/hyperv-proto.h" diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 12a7dc4312..06649b2a2e 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/main-loop.h" +#include "exec/target_page.h" #include "qapi/error.h" #include "migration/vmstate.h" #include "hw/qdev-properties.h" diff --git a/hw/i386/multiboot.c b/hw/i386/multiboot.c index cd07a05861..6e6b96bc34 100644 --- a/hw/i386/multiboot.c +++ b/hw/i386/multiboot.c @@ -29,6 +29,7 @@ #include "multiboot.h" #include "hw/loader.h" #include "elf.h" +#include "exec/target_page.h" #include "system/system.h" #include "qemu/error-report.h" diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 1b5d55e96d..5481fe40be 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "exec/target_page.h" #include "hw/i386/pc.h" #include "hw/char/serial-isa.h" #include "hw/char/parallel.h" diff --git a/hw/i386/pc_sysfw_ovmf.c b/hw/i386/pc_sysfw_ovmf.c index 07a4c267fa..da947c3ca4 100644 --- a/hw/i386/pc_sysfw_ovmf.c +++ b/hw/i386/pc_sysfw_ovmf.c @@ -26,6 +26,7 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "hw/i386/pc.h" +#include "exec/target_page.h" #include "cpu.h" #define OVMF_TABLE_FOOTER_GUID "96b582de-1fb2-45f7-baea-a366c55a082d" diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c index 26aae64e5d..347431eeef 100644 --- a/hw/i386/vapic.c +++ b/hw/i386/vapic.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/module.h" +#include "exec/target_page.h" #include "system/system.h" #include "system/cpus.h" #include "system/hw_accel.h" diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index f1eb42c2c1..39ea5cadd6 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -8,6 +8,7 @@ #include "qemu/units.h" #include "qemu/datadir.h" #include "qapi/error.h" +#include "exec/target_page.h" #include "hw/boards.h" #include "hw/char/serial-mm.h" #include "system/kvm.h" diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index aeed4c8ddb..c2e365a820 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -24,6 +24,7 @@ #include "qemu/units.h" #include "qemu/datadir.h" #include "qemu/guest-random.h" +#include "exec/target_page.h" #include "system/system.h" #include "cpu.h" #include "hw/boards.h" diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index 295a614e16..e74d709a18 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -10,6 +10,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "qemu/guest-random.h" +#include "exec/target_page.h" #include "system/system.h" #include "cpu.h" #include "hw/boards.h" diff --git a/hw/openrisc/boot.c b/hw/openrisc/boot.c index 0a5881be31..c81efe8138 100644 --- a/hw/openrisc/boot.c +++ b/hw/openrisc/boot.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/cpu-defs.h" +#include "exec/target_page.h" #include "elf.h" #include "hw/loader.h" #include "hw/openrisc/boot.h" diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c index 039cc3ad01..c6f2d4f494 100644 --- a/hw/pci-host/astro.c +++ b/hw/pci-host/astro.c @@ -35,6 +35,7 @@ #include "target/hppa/cpu.h" #include "trace.h" #include "qom/object.h" +#include "exec/target_page.h" /* * Helper functions diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 69269aa24c..809078a2c3 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -18,6 +18,7 @@ #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/guest-random.h" +#include "exec/target_page.h" #include "qapi/error.h" #include "e500.h" #include "e500-ccsr.h" diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2d5309d6f5..21b2fc569a 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -50,6 +50,7 @@ #include "qemu/datadir.h" #include "qemu/units.h" #include "qapi/error.h" +#include "exec/target_page.h" #include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" #include "hw/nvram/mac_nvram.h" diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index b5814690f5..0d34e6bfda 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -28,6 +28,7 @@ #include "qemu/datadir.h" #include "qemu/units.h" #include "qapi/error.h" +#include "exec/target_page.h" #include "hw/ppc/ppc.h" #include "hw/qdev-properties.h" #include "hw/boards.h" diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index 925e670ba0..3872ae2822 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -24,6 +24,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/target_page.h" #include "hw/ppc/ppc.h" #include "qemu/timer.h" #include "system/reset.h" diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c index 3e68d8e6e2..739526335c 100644 --- a/hw/ppc/prep.c +++ b/hw/ppc/prep.c @@ -39,6 +39,7 @@ #include "hw/rtc/mc146818rtc.h" #include "hw/isa/pc87312.h" #include "hw/qdev-properties.h" +#include "exec/target_page.h" #include "system/kvm.h" #include "system/reset.h" #include "trace.h" diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 406aea4ecb..a4f399c4ff 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -9,6 +9,7 @@ #include "qemu/module.h" #include "qemu/error-report.h" #include "exec/tb-flush.h" +#include "exec/target_page.h" #include "helper_regs.h" #include "hw/ppc/ppc.h" #include "hw/ppc/spapr.h" diff --git a/hw/riscv/riscv-iommu-pci.c b/hw/riscv/riscv-iommu-pci.c index 12451869e4..a795464803 100644 --- a/hw/riscv/riscv-iommu-pci.c +++ b/hw/riscv/riscv-iommu-pci.c @@ -17,6 +17,7 @@ */ #include "qemu/osdep.h" +#include "exec/target_page.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" #include "hw/pci/pci_bus.h" diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index 76e0fcd873..65411b3e4c 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -18,6 +18,7 @@ #include "qemu/osdep.h" #include "qom/object.h" +#include "exec/target_page.h" #include "hw/pci/pci_bus.h" #include "hw/pci/pci_device.h" #include "hw/qdev-properties.h" diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index 6557ac3be5..cb55101f06 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -14,6 +14,7 @@ #define HW_S390_IPL_H #include "cpu.h" +#include "exec/target_page.h" #include "system/address-spaces.h" #include "system/memory.h" #include "hw/qdev-core.h" diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 2591ee49c1..4365f8ed1e 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/visitor.h" +#include "exec/target_page.h" #include "hw/s390x/s390-pci-bus.h" #include "hw/s390x/s390-pci-inst.h" #include "hw/s390x/s390-pci-kvm.h" diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index b4e003c19c..b5dddb22b8 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "exec/memop.h" +#include "exec/target_page.h" #include "system/memory.h" #include "qemu/error-report.h" #include "system/hw_accel.h" diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index 0bb90fed04..d437fe070d 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "qemu/units.h" +#include "exec/target_page.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/qdev-properties.h" #include "hw/s390x/storage-keys.h" diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 5aaafb40da..edbf19d958 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -27,6 +27,7 @@ #include "qapi/error.h" #include "qemu/datadir.h" #include "cpu.h" +#include "exec/target_page.h" #include "hw/sysbus.h" #include "qemu/error-report.h" #include "qemu/timer.h" diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index d3cb7270ff..becdf3ea98 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -28,6 +28,7 @@ #include "qapi/error.h" #include "qemu/datadir.h" #include "cpu.h" +#include "exec/target_page.h" #include "hw/irq.h" #include "hw/pci/pci.h" #include "hw/pci/pci_bridge.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index dae4fbcea8..e7c8b8672f 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -22,6 +22,5 @@ #include "exec/cpu-common.h" #include "hw/core/cpu.h" #include "exec/cpu-defs.h" -#include "exec/target_page.h" #endif /* CPU_ALL_H */ diff --git a/monitor/hmp-cmds-target.c b/monitor/hmp-cmds-target.c index 011a367357..8eaf70d9c9 100644 --- a/monitor/hmp-cmds-target.c +++ b/monitor/hmp-cmds-target.c @@ -31,6 +31,7 @@ #include "qapi/error.h" #include "qobject/qdict.h" #include "system/hw_accel.h" +#include "exec/target_page.h" /* Set the current CPU defined by the user. Callers must hold BQL. */ int monitor_set_cpu(Monitor *mon, int cpu_index) diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index ccb0c96070..f51a253626 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -11,6 +11,7 @@ #include "exec/cpu-all.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "semihosting/uaccess.h" diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 56c96b1c4d..99d839a279 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -25,6 +25,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "fpu/softfloat.h" diff --git a/target/alpha/helper.c b/target/alpha/helper.c index f6261a3a53..096eac3445 100644 --- a/target/alpha/helper.c +++ b/target/alpha/helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "fpu/softfloat-types.h" #include "exec/helper-proto.h" #include "qemu/qemu-print.h" diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 2156c02214..7f3195a5dc 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -27,6 +27,7 @@ #include "exec/helper-gen.h" #include "exec/translator.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "exec/log.h" #define HELPER_H "helper.h" diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 21e8cf1400..c9e043bc9b 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -34,6 +34,7 @@ #include "internals.h" #include "cpu-features.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "hw/qdev-properties.h" #if !defined(CONFIG_USER_ONLY) #include "hw/loader.h" diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index be38016fc7..64ee9b3b56 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -29,6 +29,7 @@ #endif #ifdef CONFIG_TCG #include "accel/tcg/cpu-mmu-index.h" +#include "exec/target_page.h" #endif int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 8d4e9e07a9..e0e82ae507 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -12,6 +12,7 @@ #include "qemu/main-loop.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "cpu.h" #include "internals.h" diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index fa79d19425..507dbc1a44 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -31,6 +31,7 @@ #include "exec/cpu-common.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "qemu/int128.h" #include "qemu/atomic128.h" diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index 30786fd1ff..71ba406782 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -20,6 +20,7 @@ #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" +#include "exec/target_page.h" #include "internals.h" #include "cpu-features.h" #include "exec/exec-all.h" diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index e3bed77b48..9b0d40c9e1 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c index 630a481f0f..0407ad5542 100644 --- a/target/arm/tcg/tlb-insns.c +++ b/target/arm/tcg/tlb-insns.c @@ -8,6 +8,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "exec/cputlb.h" +#include "exec/target_page.h" #include "cpu.h" #include "internals.h" #include "cpu-features.h" diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 39014325df..43408c71bb 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -17,8 +17,8 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" - #include "exec/exec-all.h" +#include "exec/target_page.h" #include "translate.h" #include "translate-a64.h" #include "qemu/log.h" diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index d280018138..273b860d57 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -27,6 +27,7 @@ #include "semihosting/semihost.h" #include "cpregs.h" #include "exec/helper-proto.h" +#include "exec/target_page.h" #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" diff --git a/target/avr/helper.c b/target/avr/helper.c index f23fa3e8ba..32cbf17919 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -26,6 +26,7 @@ #include "accel/tcg/getpc.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" diff --git a/target/avr/translate.c b/target/avr/translate.c index 0490936cd5..b9c592c899 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -29,6 +29,7 @@ #include "exec/helper-gen.h" #include "exec/log.h" #include "exec/translator.h" +#include "exec/target_page.h" #define HELPER_H "helper.h" #include "exec/helper-info.c.inc" diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 09a6aaa3dd..51bff0c5d6 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -26,6 +26,7 @@ #include "qemu/module.h" #include "exec/exec-all.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "fpu/softfloat.h" #include "tcg/tcg.h" #include "hw/hppa/hppa_hardware.h" diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index a1ade9079e..554d7bf4d1 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -24,6 +24,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/helper-proto.h" #include "hw/core/cpu.h" #include "trace.h" diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 0d0d1bc99b..14f3833322 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -28,6 +28,7 @@ #include "exec/helper-gen.h" #include "exec/translator.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "exec/log.h" #define HELPER_H "helper.h" diff --git a/target/i386/helper.c b/target/i386/helper.c index 64d9e8ab9c..197fdac7dd 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/cputlb.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "system/runstate.h" #ifndef CONFIG_USER_ONLY #include "system/hw_accel.h" diff --git a/target/i386/kvm/hyperv.c b/target/i386/kvm/hyperv.c index 70b89cacf9..9865120cc4 100644 --- a/target/i386/kvm/hyperv.c +++ b/target/i386/kvm/hyperv.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" +#include "exec/target_page.h" #include "hyperv.h" #include "hw/hyperv/hyperv.h" #include "hyperv-proto.h" diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 6c749d4ee8..c9a3c02e3e 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -67,6 +67,7 @@ #include "hw/pci/msix.h" #include "migration/blocker.h" #include "exec/memattrs.h" +#include "exec/target_page.h" #include "trace.h" #include CONFIG_DEVICES diff --git a/target/i386/kvm/xen-emu.c b/target/i386/kvm/xen-emu.c index b23010374f..284c5ef6f6 100644 --- a/target/i386/kvm/xen-emu.c +++ b/target/i386/kvm/xen-emu.c @@ -13,6 +13,7 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/error-report.h" +#include "exec/target_page.h" #include "hw/xen/xen.h" #include "system/kvm_int.h" #include "system/kvm_xen.h" diff --git a/target/i386/sev.c b/target/i386/sev.c index ba88976e9f..878dd20f2c 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -26,6 +26,7 @@ #include "qemu/uuid.h" #include "qemu/error-report.h" #include "crypto/hash.h" +#include "exec/target_page.h" #include "system/kvm.h" #include "kvm/kvm_i386.h" #include "sev.h" diff --git a/target/i386/tcg/access.c b/target/i386/tcg/access.c index e68b73a24b..5a4721dcee 100644 --- a/target/i386/tcg/access.c +++ b/target/i386/tcg/access.c @@ -5,6 +5,7 @@ #include "cpu.h" #include "exec/cpu_ldst.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "access.h" diff --git a/target/i386/tcg/mpx_helper.c b/target/i386/tcg/mpx_helper.c index 22423eedcd..b942665adc 100644 --- a/target/i386/tcg/mpx_helper.c +++ b/target/i386/tcg/mpx_helper.c @@ -22,6 +22,7 @@ #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "helper-tcg.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index 4badd73943..a563c9b35e 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -22,6 +22,7 @@ #include "exec/cpu_ldst.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "exec/tswap.h" #include "tcg/helper-tcg.h" diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 818653ee6d..35b17f2b18 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -23,7 +23,7 @@ #include "qemu/accel.h" #include "accel/accel-cpu-target.h" #include "exec/translation-block.h" - +#include "exec/target_page.h" #include "tcg-cpu.h" /* Frob eflags into and out of the CPU temporary format. */ diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 6418d4bb03..1dcc35f5df 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -26,6 +26,7 @@ #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" #include "exec/translator.h" +#include "exec/target_page.h" #include "fpu/softfloat.h" #include "exec/helper-proto.h" diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index f8965cd155..bb343078bf 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "accel/tcg/cpu-mmu-index.h" +#include "exec/target_page.h" #include "internals.h" #include "cpu-csr.h" diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index 70d1b5cf99..0d6c9844a6 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -15,6 +15,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/cpu_ldst.h" #include "exec/log.h" #include "cpu-csr.h" diff --git a/target/loongarch/tcg/translate.c b/target/loongarch/tcg/translate.c index e59e4ed25b..53a0b4c3ce 100644 --- a/target/loongarch/tcg/translate.c +++ b/target/loongarch/tcg/translate.c @@ -11,6 +11,7 @@ #include "tcg/tcg-op-gvec.h" #include "exec/translation-block.h" #include "exec/translator.h" +#include "exec/target_page.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "exec/log.h" diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 8251272219..f73e0def23 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/gdbstub.h" #include "exec/helper-proto.h" #include "system/memory.h" diff --git a/target/m68k/translate.c b/target/m68k/translate.c index dec2967fce..b1266a7875 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "tcg/tcg-op.h" #include "qemu/log.h" #include "qemu/qemu-print.h" diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 022c98f0c3..9203192483 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "qemu/host-utils.h" #include "exec/log.h" diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 2d18659b99..95a12e16f8 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -24,6 +24,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/target_page.h" static unsigned int tlb_decode_size(unsigned int f) { diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index b54e5ac4b2..4bb867c969 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -27,6 +27,7 @@ #include "exec/helper-gen.h" #include "exec/translator.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "qemu/qemu-print.h" #include "exec/log.h" diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index 74fb80cc25..969dd34b3e 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -25,6 +25,7 @@ #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "exec/memop.h" +#include "exec/target_page.h" #include "fpu/softfloat.h" #include "fpu_helper.h" diff --git a/target/mips/tcg/system/cp0_helper.c b/target/mips/tcg/system/cp0_helper.c index 78e422b0ca..101b1e65fd 100644 --- a/target/mips/tcg/system/cp0_helper.c +++ b/target/mips/tcg/system/cp0_helper.c @@ -28,6 +28,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/cputlb.h" +#include "exec/target_page.h" /* SMP helpers. */ diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c index df80301a41..d239fa9353 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -24,6 +24,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/cpu_ldst.h" #include "exec/log.h" #include "exec/helper-proto.h" diff --git a/target/mips/tcg/translate.c b/target/mips/tcg/translate.c index 78b848a6d9..8658315f93 100644 --- a/target/mips/tcg/translate.c +++ b/target/mips/tcg/translate.c @@ -27,6 +27,7 @@ #include "internal.h" #include "exec/helper-proto.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "semihosting/semihost.h" #include "trace.h" #include "fpu_helper.h" diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c index 47ac783c52..acea50c41e 100644 --- a/target/openrisc/mmu.c +++ b/target/openrisc/mmu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "gdbstub/helpers.h" #include "qemu/host-utils.h" #include "hw/loader.h" diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 21bc137ccc..92badf017f 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/cputlb.h" +#include "exec/target_page.h" #include "exec/helper-proto.h" #include "exception.h" #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index da033bffff..d4ce60188b 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -28,7 +28,7 @@ #include "qemu/qemu-print.h" #include "exec/translator.h" #include "exec/translation-block.h" - +#include "exec/target_page.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 51b137febd..0967624afe 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "helper_regs.h" diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 1f791a7f2f..5bd3efe70e 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "system/kvm.h" #include "kvm_ppc.h" #include "internal.h" diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index fb62b947f1..394a0c9bb6 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -26,6 +26,7 @@ #include "mmu-hash32.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/log.h" #include "helper_regs.h" #include "qemu/error-report.h" diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index ad9ba8294c..c90ceb7d60 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -27,6 +27,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/log.h" #include "helper_regs.h" #include "qemu/error-report.h" diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a52cbc869a..399107d319 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -22,6 +22,7 @@ #include "cpu.h" #include "internal.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" #include "qemu/host-utils.h" diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index ca58094fb5..619c76cc00 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -26,6 +26,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "system/memory.h" #include "instmap.h" #include "tcg/tcg-op.h" diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index b0841d44f4..c13a117e3f 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -26,6 +26,7 @@ #include "trace.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index, uint8_t val); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index bee7dfd803..710449d17e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -22,6 +22,7 @@ #include "exec/translation-block.h" #include "tcg-cpu.h" #include "cpu.h" +#include "exec/target_page.h" #include "internals.h" #include "pmu.h" #include "time_helper.h" diff --git a/target/riscv/translate.c b/target/riscv/translate.c index d6651f244f..cef61b5b29 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -23,7 +23,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" - +#include "exec/target_page.h" #include "exec/translator.h" #include "exec/translation-block.h" #include "exec/log.h" diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7fffa23bc8..7de6cbae5c 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -26,6 +26,7 @@ #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" +#include "exec/target_page.h" #include "exec/tswap.h" #include "fpu/softfloat.h" #include "tcg/tcg-gvec-desc.h" diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 51743020d4..e14d9cbef9 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -24,6 +24,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "hw/loader.h" #include "fpu/softfloat.h" #include "tcg/debug-assert.h" diff --git a/target/s390x/helper.c b/target/s390x/helper.c index e660c69f60..3c57c32e47 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -27,6 +27,7 @@ #include "target/s390x/kvm/pv.h" #include "system/hw_accel.h" #include "system/runstate.h" +#include "exec/target_page.h" #include "exec/watchpoint.h" void s390x_tod_timer(void *opaque) diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index a944f16c25..fe62ba5b06 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "exec/target_page.h" #include "s390x-internal.h" #include "hw/s390x/ioinst.h" #include "trace.h" diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index b079d120db..0e133cb9a5 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -25,6 +25,7 @@ #include "system/tcg.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "hw/hw.h" #include "hw/s390x/storage-keys.h" #include "hw/boards.h" diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index 1d51043e88..6cd813e1ab 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "exec/cputlb.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "exec/watchpoint.h" #include "s390x-internal.h" #include "tcg_s390x.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 0ff2e10d81..d5eece4384 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -29,6 +29,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/cpu_ldst.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" #include "qemu/int128.h" diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index 31266aeda4..e02f443850 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -29,6 +29,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/cpu_ldst.h" +#include "exec/target_page.h" #include "qapi/error.h" #include "tcg_s390x.h" #include "s390-tod.h" diff --git a/target/sh4/helper.c b/target/sh4/helper.c index 7567e6c8b6..b41d14d5d7 100644 --- a/target/sh4/helper.c +++ b/target/sh4/helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/log.h" #if !defined(CONFIG_USER_ONLY) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index bcdd558818..5ce477d0ad 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -25,6 +25,7 @@ #include "exec/helper-gen.h" #include "exec/translation-block.h" #include "exec/translator.h" +#include "exec/target_page.h" #include "exec/log.h" #include "qemu/qemu-print.h" diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 8890d2b119..3fa5e78816 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -26,6 +26,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/cpu_ldst.h" #include "system/memory.h" #ifdef CONFIG_USER_ONLY diff --git a/target/sparc/mmu_helper.c b/target/sparc/mmu_helper.c index c5d82a0854..217580a4d8 100644 --- a/target/sparc/mmu_helper.c +++ b/target/sparc/mmu_helper.c @@ -23,6 +23,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "exec/tlb-flags.h" #include "system/memory.h" #include "qemu/qemu-print.h" diff --git a/target/sparc/translate.c b/target/sparc/translate.c index bfe63649db..adebddf27b 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" +#include "exec/target_page.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" #include "exec/helper-gen.h" diff --git a/target/tricore/helper.c b/target/tricore/helper.c index b1ee126112..e4c53d453d 100644 --- a/target/tricore/helper.c +++ b/target/tricore/helper.c @@ -22,6 +22,7 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "fpu/softfloat-helpers.h" #include "qemu/qemu-print.h" diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 6819b77668..5c7ed395ca 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -31,6 +31,7 @@ #include "tricore-opcodes.h" #include "exec/translator.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "exec/log.h" #define HELPER_H "helper.h" diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index 4824b97e37..d02d16f9ec 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -29,6 +29,7 @@ #include "qemu/log.h" #include "cpu.h" #include "exec/cputlb.h" +#include "exec/target_page.h" #include "gdbstub/helpers.h" #include "exec/helper-proto.h" #include "qemu/error-report.h" diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 1ce125794d..a7dd810055 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -36,6 +36,7 @@ #include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/page-protection.h" +#include "exec/target_page.h" #include "system/memory.h" #define XTENSA_MPU_SEGMENT_MASK 0x0000001f diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index cb817b3119..5ebd4a512c 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -37,6 +37,7 @@ #include "qemu/qemu-print.h" #include "exec/translator.h" #include "exec/translation-block.h" +#include "exec/target_page.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "exec/log.h" diff --git a/target/xtensa/xtensa-semi.c b/target/xtensa/xtensa-semi.c index 2ded8e5634..636f421da2 100644 --- a/target/xtensa/xtensa-semi.c +++ b/target/xtensa/xtensa-semi.c @@ -29,6 +29,7 @@ #include "cpu.h" #include "chardev/char-fe.h" #include "exec/helper-proto.h" +#include "exec/target_page.h" #include "semihosting/semihost.h" #include "semihosting/uaccess.h" #include "qapi/error.h" From d97c3b06de5bdd885f0ee3d8153326acd3db480e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:58:59 -0700 Subject: [PATCH 0190/2760] exec/cpu-all: transfer exec/cpu-common include to cpu.h headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-15-pierrick.bouvier@linaro.org> --- cpu-target.c | 1 + include/exec/cpu-all.h | 1 - include/exec/cpu_ldst.h | 1 + target/alpha/cpu.h | 1 + target/arm/cpu.h | 1 + target/avr/cpu.h | 1 + target/hexagon/cpu.h | 1 + target/hppa/cpu.h | 1 + target/i386/cpu.h | 1 + target/loongarch/cpu.h | 1 + target/m68k/cpu.h | 1 + target/microblaze/cpu.h | 1 + target/mips/cpu.h | 1 + target/openrisc/cpu.h | 1 + target/ppc/cpu.h | 1 + target/riscv/cpu.h | 1 + target/rx/cpu.h | 1 + target/s390x/cpu.h | 1 + target/sh4/cpu.h | 1 + target/sparc/cpu.h | 1 + target/tricore/cpu.h | 1 + target/xtensa/cpu.h | 1 + 22 files changed, 21 insertions(+), 1 deletion(-) diff --git a/cpu-target.c b/cpu-target.c index 7f3b244ed1..14cd623bff 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -24,6 +24,7 @@ #include "qemu/qemu-print.h" #include "system/accel-ops.h" #include "system/cpus.h" +#include "exec/cpu-common.h" #include "exec/tswap.h" #include "exec/replay-core.h" #include "exec/log.h" diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h index e7c8b8672f..5122fdbee3 100644 --- a/include/exec/cpu-all.h +++ b/include/exec/cpu-all.h @@ -19,7 +19,6 @@ #ifndef CPU_ALL_H #define CPU_ALL_H -#include "exec/cpu-common.h" #include "hw/core/cpu.h" #include "exec/cpu-defs.h" diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 77dc5ac61c..63847f6e61 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -66,6 +66,7 @@ #error Can only include this header with TCG #endif +#include "exec/cpu-common.h" #include "exec/cpu-ldst-common.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/abi_ptr.h" diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 42788a6a0b..fb1d63527e 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -21,6 +21,7 @@ #define ALPHA_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 958a921490..ee92476814 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -24,6 +24,7 @@ #include "qemu/cpu-float.h" #include "hw/registerfields.h" #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "exec/gdbstub.h" diff --git a/target/avr/cpu.h b/target/avr/cpu.h index c2cc2daa66..a0fb40141a 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -22,6 +22,7 @@ #define QEMU_AVR_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "system/memory.h" diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index f78c8f9c2a..e4fc35b112 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -21,6 +21,7 @@ #include "fpu/softfloat-types.h" #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "hex_regs.h" #include "mmvec/mmvec.h" diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index dab58c227f..4e72ab025b 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -21,6 +21,7 @@ #define HPPA_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "system/memory.h" diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 778dfd9637..02ea87347a 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -23,6 +23,7 @@ #include "system/tcg.h" #include "cpu-qom.h" #include "kvm/hyperv-proto.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "exec/memop.h" diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index a924aa01d7..69117c602a 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -9,6 +9,7 @@ #define LOONGARCH_CPU_H #include "qemu/int128.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "fpu/softfloat-types.h" diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 451644a05a..5347fbe397 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -21,6 +21,7 @@ #ifndef M68K_CPU_H #define M68K_CPU_H +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index d29681abed..90d820b90c 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -21,6 +21,7 @@ #define MICROBLAZE_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" #include "exec/cpu-interrupt.h" diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 29362498ec..79f8041ced 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -2,6 +2,7 @@ #define MIPS_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index c153823b62..f16a070ef6 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -21,6 +21,7 @@ #define OPENRISC_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "fpu/softfloat-types.h" diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 7489ba9564..aa5df47bda 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -22,6 +22,7 @@ #include "qemu/int128.h" #include "qemu/cpu-float.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "cpu-qom.h" diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 556eda57e9..14a6779b4c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -23,6 +23,7 @@ #include "hw/core/cpu.h" #include "hw/registerfields.h" #include "hw/qdev-properties.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "exec/gdbstub.h" diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 5f2fcb6656..e2ec78835e 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -23,6 +23,7 @@ #include "hw/registerfields.h" #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 0a32ad4c61..83d01d5c4e 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -27,6 +27,7 @@ #include "cpu-qom.h" #include "cpu_models.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 18557d8c38..7581f5eecb 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -21,6 +21,7 @@ #define SH4_CPU_H #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index c0aab69b61..b87351a666 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -3,6 +3,7 @@ #include "qemu/bswap.h" #include "cpu-qom.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "qemu/cpu-float.h" diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index cf9dbc6df8..abb9cba136 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -22,6 +22,7 @@ #include "cpu-qom.h" #include "hw/registerfields.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "qemu/cpu-float.h" #include "tricore-defs.h" diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index 6684631478..c5d2042de1 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -30,6 +30,7 @@ #include "cpu-qom.h" #include "qemu/cpu-float.h" +#include "exec/cpu-common.h" #include "exec/cpu-defs.h" #include "exec/cpu-interrupt.h" #include "hw/clock.h" From 0df783b2fbeca9aa3cc19adafb9a4ec7f97e3a6d Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:00 -0700 Subject: [PATCH 0191/2760] exec/cpu-all: remove this header Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-16-pierrick.bouvier@linaro.org> --- accel/tcg/cpu-exec.c | 1 - hw/hyperv/hyperv.c | 1 - include/exec/cpu-all.h | 25 ------------------------- include/hw/core/cpu.h | 2 +- include/qemu/bswap.h | 3 --- semihosting/uaccess.c | 1 - target/alpha/cpu.h | 2 -- target/arm/cpu.h | 2 -- target/avr/cpu.h | 2 -- target/hexagon/cpu.h | 2 -- target/hppa/cpu.h | 2 -- target/i386/cpu.h | 1 - target/loongarch/cpu.h | 2 -- target/m68k/cpu.h | 2 -- target/microblaze/cpu.h | 2 -- target/mips/cpu.h | 2 -- target/openrisc/cpu.h | 2 -- target/ppc/cpu.h | 2 -- target/riscv/cpu.h | 2 -- target/rx/cpu.h | 2 -- target/s390x/cpu.h | 2 -- target/sh4/cpu.h | 2 -- target/sparc/cpu.h | 2 -- target/tricore/cpu.h | 2 -- target/xtensa/cpu.h | 2 -- tcg/tcg-op-ldst.c | 2 +- 26 files changed, 2 insertions(+), 70 deletions(-) delete mode 100644 include/exec/cpu-all.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8d2b957a3b..5ced3879ac 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -35,7 +35,6 @@ #include "qemu/rcu.h" #include "exec/log.h" #include "qemu/main-loop.h" -#include "exec/cpu-all.h" #include "cpu.h" #include "exec/icount.h" #include "exec/replay-core.h" diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index c487f13e2f..8f193fd0bd 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -24,7 +24,6 @@ #include "qom/object.h" #include "target/i386/kvm/hyperv-proto.h" #include "target/i386/cpu.h" -#include "exec/cpu-all.h" #include "exec/target_page.h" struct SynICState { diff --git a/include/exec/cpu-all.h b/include/exec/cpu-all.h deleted file mode 100644 index 5122fdbee3..0000000000 --- a/include/exec/cpu-all.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * defines common to all virtual CPUs - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ -#ifndef CPU_ALL_H -#define CPU_ALL_H - -#include "hw/core/cpu.h" -#include "exec/cpu-defs.h" - -#endif /* CPU_ALL_H */ diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 28bd27b8ed..10b6b25b34 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -579,7 +579,7 @@ QEMU_BUILD_BUG_ON(offsetof(CPUState, neg) != static inline CPUArchState *cpu_env(CPUState *cpu) { - /* We validate that CPUArchState follows CPUState in cpu-all.h. */ + /* We validate that CPUArchState follows CPUState in cpu-target.c */ return (CPUArchState *)(cpu + 1); } diff --git a/include/qemu/bswap.h b/include/qemu/bswap.h index b915835bea..9a11764536 100644 --- a/include/qemu/bswap.h +++ b/include/qemu/bswap.h @@ -205,9 +205,6 @@ CPU_CONVERT(le, 64, uint64_t) * te : target endian * (except for byte accesses, which have no endian infix). * - * The target endian accessors are obviously only available to source - * files which are built per-target; they are defined in cpu-all.h. - * * In all cases these functions take a host pointer. * For accessors that take a guest address rather than a * host address, see the cpu_{ld,st}_* accessors defined in diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index f51a253626..81ffecaaba 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -8,7 +8,6 @@ */ #include "qemu/osdep.h" -#include "exec/cpu-all.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/exec-all.h" #include "exec/target_page.h" diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index fb1d63527e..849f673489 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -289,8 +289,6 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags); int alpha_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int alpha_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -#include "exec/cpu-all.h" - enum { FEATURE_ASN = 0x00000001, FEATURE_SPS = 0x00000002, diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ee92476814..ea9956395c 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -2968,8 +2968,6 @@ static inline bool arm_sctlr_b(CPUARMState *env) uint64_t arm_sctlr(CPUARMState *env, int el); -#include "exec/cpu-all.h" - /* * We have more than 32-bits worth of state per TB, so we split the data * between tb->flags and tb->cs_base, which is otherwise unused for ARM. diff --git a/target/avr/cpu.h b/target/avr/cpu.h index a0fb40141a..d6666175a9 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -259,6 +259,4 @@ bool avr_cpu_tlb_fill(CPUState *cs, vaddr address, int size, extern const MemoryRegionOps avr_cpu_reg1; extern const MemoryRegionOps avr_cpu_reg2; -#include "exec/cpu-all.h" - #endif /* QEMU_AVR_CPU_H */ diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index e4fc35b112..c065fa8ddc 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -158,6 +158,4 @@ void hexagon_translate_init(void); void hexagon_translate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); -#include "exec/cpu-all.h" - #endif /* HEXAGON_CPU_H */ diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index 4e72ab025b..da5f8adcd5 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -306,8 +306,6 @@ struct HPPACPUClass { ResettablePhases parent_phases; }; -#include "exec/cpu-all.h" - static inline bool hppa_is_pa20(const CPUHPPAState *env) { return env->is_pa20; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 02ea87347a..bd63036334 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2604,7 +2604,6 @@ static inline bool is_mmu_index_32(int mmu_index) #define CC_SRC2 (env->cc_src2) #define CC_OP (env->cc_op) -#include "exec/cpu-all.h" #include "svm.h" #if !defined(CONFIG_USER_ONLY) diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 69117c602a..ad8b0ed235 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -504,8 +504,6 @@ static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, *flags |= is_va32(env) * HW_FLAGS_VA32; } -#include "exec/cpu-all.h" - #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU void loongarch_cpu_post_init(Object *obj); diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 5347fbe397..0b70e8c6ab 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -596,8 +596,6 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, MemTxResult response, uintptr_t retaddr); #endif -#include "exec/cpu-all.h" - /* TB flags */ #define TB_FLAGS_MACSR 0x0f #define TB_FLAGS_MSR_S_BIT 13 diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 90d820b90c..2bfa396c96 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -411,8 +411,6 @@ void mb_translate_code(CPUState *cs, TranslationBlock *tb, #define MMU_USER_IDX 2 /* See NB_MMU_MODES in cpu-defs.h. */ -#include "exec/cpu-all.h" - /* Ensure there is no overlap between the two masks. */ QEMU_BUILD_BUG_ON(MSR_TB_MASK & IFLAGS_TB_MASK); diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 79f8041ced..20f31370bc 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1258,8 +1258,6 @@ static inline int mips_env_mmu_index(CPUMIPSState *env) return hflags_mmu_index(env->hflags); } -#include "exec/cpu-all.h" - /* Exceptions */ enum { EXCP_NONE = -1, diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index f16a070ef6..19ee85ff5a 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -334,8 +334,6 @@ void cpu_openrisc_count_stop(OpenRISCCPU *cpu); #define CPU_RESOLVING_TYPE TYPE_OPENRISC_CPU -#include "exec/cpu-all.h" - #define TB_FLAGS_SM SR_SM #define TB_FLAGS_DME SR_DME #define TB_FLAGS_IME SR_IME diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index aa5df47bda..3c02f7f7d4 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1704,8 +1704,6 @@ void ppc_compat_add_property(Object *obj, const char *name, uint32_t *compat_pvr, const char *basedesc); #endif /* defined(TARGET_PPC64) */ -#include "exec/cpu-all.h" - /*****************************************************************************/ /* CRF definitions */ #define CRF_LT_BIT 3 diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 14a6779b4c..867e539b53 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -634,8 +634,6 @@ G_NORETURN void riscv_raise_exception(CPURISCVState *env, target_ulong riscv_cpu_get_fflags(CPURISCVState *env); void riscv_cpu_set_fflags(CPURISCVState *env, target_ulong); -#include "exec/cpu-all.h" - FIELD(TB_FLAGS, MEM_IDX, 0, 3) FIELD(TB_FLAGS, FS, 3, 2) /* Vector flags */ diff --git a/target/rx/cpu.h b/target/rx/cpu.h index e2ec78835e..5c19c83219 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -147,8 +147,6 @@ void rx_translate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte); -#include "exec/cpu-all.h" - #define CPU_INTERRUPT_SOFT CPU_INTERRUPT_TGT_INT_0 #define CPU_INTERRUPT_FIR CPU_INTERRUPT_TGT_INT_1 diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 83d01d5c4e..940eda8dd1 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -948,6 +948,4 @@ uint64_t s390_cpu_get_psw_mask(CPUS390XState *env); /* outside of target/s390x/ */ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); -#include "exec/cpu-all.h" - #endif diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 7581f5eecb..7752a0c2e1 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -288,8 +288,6 @@ void cpu_load_tlb(CPUSH4State * env); /* MMU modes definitions */ #define MMU_USER_IDX 1 -#include "exec/cpu-all.h" - /* MMU control register */ #define MMUCR 0x1F000010 #define MMUCR_AT (1<<0) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index b87351a666..734dfdb1d3 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -729,8 +729,6 @@ static inline int cpu_pil_allowed(CPUSPARCState *env1, int pil) #endif } -#include "exec/cpu-all.h" - #ifdef TARGET_SPARC64 /* sun4u.c */ void cpu_tick_set_count(CPUTimer *timer, uint64_t count); diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index abb9cba136..c76e65f818 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -251,8 +251,6 @@ void fpu_set_state(CPUTriCoreState *env); #define MMU_USER_IDX 2 -#include "exec/cpu-all.h" - FIELD(TB_FLAGS, PRIV, 0, 2) void cpu_state_reset(CPUTriCoreState *s); diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index c5d2042de1..c03ed71c94 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -733,8 +733,6 @@ static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) #define XTENSA_CSBASE_LBEG_OFF_MASK 0x00ff0000 #define XTENSA_CSBASE_LBEG_OFF_SHIFT 16 -#include "exec/cpu-all.h" - static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) { diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index 73838e2701..3b073b4ce0 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -37,7 +37,7 @@ static void check_max_alignment(unsigned a_bits) { /* * The requested alignment cannot overlap the TLB flags. - * FIXME: Must keep the count up-to-date with "exec/cpu-all.h". + * FIXME: Must keep the count up-to-date with "exec/tlb-flags.h". */ if (tcg_use_softmmu) { tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits); From f1d2a8e95383090c8b3a57138f742fbd9aedf678 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:02 -0700 Subject: [PATCH 0192/2760] accel/kvm: move KVM_HAVE_MCE_INJECTION define to kvm-all.c This define is used only in accel/kvm/kvm-all.c, so we push directly the definition there. Add more visibility to kvm_arch_on_sigbus_vcpu() to allow removing this define from any header. The architectures defining KVM_HAVE_MCE_INJECTION are i386, x86_64 and aarch64. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-18-pierrick.bouvier@linaro.org> --- accel/kvm/kvm-all.c | 5 +++++ include/system/kvm.h | 2 -- target/arm/cpu.h | 4 ---- target/i386/cpu.h | 2 -- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index a30b19f455..cba9c78d2f 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -57,6 +57,11 @@ #include #endif +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) +# define KVM_HAVE_MCE_INJECTION 1 +#endif + + /* KVM uses PAGE_SIZE in its definition of KVM_COALESCED_MMIO_MAX. We * need to use the real host PAGE_SIZE, as that's what KVM will use. */ diff --git a/include/system/kvm.h b/include/system/kvm.h index 21da3b8b05..18811cad6f 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -390,9 +390,7 @@ bool kvm_vcpu_id_is_valid(int vcpu_id); /* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */ unsigned long kvm_arch_vcpu_id(CPUState *cpu); -#ifdef KVM_HAVE_MCE_INJECTION void kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); -#endif void kvm_arch_init_irq_routing(KVMState *s); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ea9956395c..a8a1a8faf6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -33,10 +33,6 @@ #include "target/arm/multiprocessing.h" #include "target/arm/gtimer.h" -#ifdef TARGET_AARCH64 -#define KVM_HAVE_MCE_INJECTION 1 -#endif - #define EXCP_UDEF 1 /* undefined instruction */ #define EXCP_SWI 2 /* software interrupt */ #define EXCP_PREFETCH_ABORT 3 diff --git a/target/i386/cpu.h b/target/i386/cpu.h index bd63036334..17ad0b644b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -35,8 +35,6 @@ #define XEN_NR_VIRQS 24 -#define KVM_HAVE_MCE_INJECTION 1 - /* support for self modifying code even if the modified instruction is close to the modifying instruction */ #define TARGET_HAS_PRECISE_SMC From 5a9d472d01a3760a0bae7b93b5d67af8178fbed3 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:03 -0700 Subject: [PATCH 0193/2760] exec/poison: KVM_HAVE_MCE_INJECTION can now be poisoned We prevent common code to use this define by mistake. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-19-pierrick.bouvier@linaro.org> --- include/exec/poison.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/exec/poison.h b/include/exec/poison.h index f267da6083..a09e0c1263 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -73,4 +73,6 @@ #pragma GCC poison CONFIG_SOFTMMU #endif +#pragma GCC poison KVM_HAVE_MCE_INJECTION + #endif From a725f37102317d64f7f23895906f8c8c5f5f1be9 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:04 -0700 Subject: [PATCH 0194/2760] target/arm/cpu: always define kvm related registers This does not hurt, even if they are not used. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-20-pierrick.bouvier@linaro.org> --- target/arm/cpu.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index a8a1a8faf6..ab7412772b 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -971,7 +971,6 @@ struct ArchCPU { */ uint32_t kvm_target; -#ifdef CONFIG_KVM /* KVM init features for this CPU */ uint32_t kvm_init_features[7]; @@ -984,7 +983,6 @@ struct ArchCPU { /* KVM steal time */ OnOffAuto kvm_steal_time; -#endif /* CONFIG_KVM */ /* Uniprocessor system with MP extensions */ bool mp_is_up; From 9fac39750df766c154e0960eca1962159ed50660 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:05 -0700 Subject: [PATCH 0195/2760] target/arm/cpu: flags2 is always uint64_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not rely on target dependent type, but use a fixed type instead. Since the original type is unsigned, it is safe to extend its size without any side effect. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-21-pierrick.bouvier@linaro.org> --- target/arm/cpu.h | 10 ++++------ target/arm/tcg/hflags.c | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index ab7412772b..cc975175c6 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -194,7 +194,7 @@ typedef struct ARMPACKey { /* See the commentary above the TBFLAG field definitions. */ typedef struct CPUARMTBFlags { uint32_t flags; - target_ulong flags2; + uint64_t flags2; } CPUARMTBFlags; typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; @@ -2968,11 +2968,9 @@ uint64_t arm_sctlr(CPUARMState *env, int el); * We collect these two parts in CPUARMTBFlags where they are named * flags and flags2 respectively. * - * The flags that are shared between all execution modes, TBFLAG_ANY, - * are stored in flags. The flags that are specific to a given mode - * are stores in flags2. Since cs_base is sized on the configured - * address size, flags2 always has 64-bits for A64, and a minimum of - * 32-bits for A32 and M32. + * The flags that are shared between all execution modes, TBFLAG_ANY, are stored + * in flags. The flags that are specific to a given mode are stored in flags2. + * flags2 always has 64-bits, even though only 32-bits are used for A32 and M32. * * The bits for 32-bit A-profile and M-profile partially overlap: * diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index 8d79b8b7ae..e51d9f7b15 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -506,8 +506,8 @@ void assert_hflags_rebuild_correctly(CPUARMState *env) if (unlikely(c.flags != r.flags || c.flags2 != r.flags2)) { fprintf(stderr, "TCG hflags mismatch " - "(current:(0x%08x,0x" TARGET_FMT_lx ")" - " rebuilt:(0x%08x,0x" TARGET_FMT_lx ")\n", + "(current:(0x%08x,0x%016" PRIx64 ")" + " rebuilt:(0x%08x,0x%016" PRIx64 ")\n", c.flags, c.flags2, r.flags, r.flags2); abort(); } From 77b0893f60ecabdc796565d130343e50cfdf28f9 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:06 -0700 Subject: [PATCH 0196/2760] target/arm/cpu: define same set of registers for aarch32 and aarch64 To eliminate TARGET_AARCH64, we need to make various definitions common between 32 and 64 bit Arm targets. Added registers are used only by aarch64 code, and the only impact is on the size of CPUARMState, and added zarray (ARMVectorReg zarray[ARM_MAX_VQ * 16]) member (+64KB) It could be eventually possible to allocate this array only for aarch64 emulation, but I'm not sure it's worth the hassle to save a few KB per vcpu. Running qemu-system takes already several hundreds of MB of (resident) memory, and qemu-user takes dozens of MB of (resident) memory anyway. As part of this, we define ARM_MAX_VQ once for aarch32 and aarch64, which will affect zregs field for aarch32. This field is used for MVE and SVE implementations. MVE implementation is clipping index value to 0 or 1 for zregs[*].d[], so we should not touch the rest of data in this case anyway. This change is safe regarding migration, because aarch64 registers still have the same size, and for aarch32, only zregs is modified. Migration code explicitly specify a size of 2 for env.vfp.zregs[0].d, VMSTATE_UINT64_SUB_ARRAY(env.vfp.zregs[0].d, ARMCPU, 0, 2). So extending the storage size has no impact. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-22-pierrick.bouvier@linaro.org> --- target/arm/cpu.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index cc975175c6..b1c3e46326 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -169,17 +169,12 @@ typedef struct ARMGenericTimer { * Align the data for use with TCG host vector operations. */ -#ifdef TARGET_AARCH64 -# define ARM_MAX_VQ 16 -#else -# define ARM_MAX_VQ 1 -#endif +#define ARM_MAX_VQ 16 typedef struct ARMVectorReg { uint64_t d[2 * ARM_MAX_VQ] QEMU_ALIGNED(16); } ARMVectorReg; -#ifdef TARGET_AARCH64 /* In AArch32 mode, predicate registers do not exist at all. */ typedef struct ARMPredicateReg { uint64_t p[DIV_ROUND_UP(2 * ARM_MAX_VQ, 8)] QEMU_ALIGNED(16); @@ -189,7 +184,6 @@ typedef struct ARMPredicateReg { typedef struct ARMPACKey { uint64_t lo, hi; } ARMPACKey; -#endif /* See the commentary above the TBFLAG field definitions. */ typedef struct CPUARMTBFlags { @@ -660,13 +654,11 @@ typedef struct CPUArchState { struct { ARMVectorReg zregs[32]; -#ifdef TARGET_AARCH64 /* Store FFR as pregs[16] to make it easier to treat as any other. */ #define FFR_PRED_NUM 16 ARMPredicateReg pregs[17]; /* Scratch space for aa64 sve predicate temporary. */ ARMPredicateReg preg_tmp; -#endif /* We store these fpcsr fields separately for convenience. */ uint32_t qc[4] QEMU_ALIGNED(16); @@ -711,7 +703,6 @@ typedef struct CPUArchState { uint32_t cregs[16]; } iwmmxt; -#ifdef TARGET_AARCH64 struct { ARMPACKey apia; ARMPACKey apib; @@ -743,7 +734,6 @@ typedef struct CPUArchState { * to keep the offsets into the rest of the structure smaller. */ ARMVectorReg zarray[ARM_MAX_VQ * 16]; -#endif struct CPUBreakpoint *cpu_breakpoint[16]; struct CPUWatchpoint *cpu_watchpoint[16]; From 63de8825af77edd71450f6bacaa55fb88d7f86e2 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:07 -0700 Subject: [PATCH 0197/2760] target/arm/cpu: remove inline stubs for aarch32 emulation Directly condition associated calls in target/arm/helper.c for now. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-23-pierrick.bouvier@linaro.org> --- target/arm/cpu.h | 8 -------- target/arm/helper.c | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index b1c3e46326..c1a0faed3a 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1222,7 +1222,6 @@ int arm_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, */ void arm_emulate_firmware_reset(CPUState *cpustate, int target_el); -#ifdef TARGET_AARCH64 int aarch64_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq); @@ -1254,13 +1253,6 @@ static inline uint64_t *sve_bswap64(uint64_t *dst, uint64_t *src, int nr) #endif } -#else -static inline void aarch64_sve_narrow_vq(CPUARMState *env, unsigned vq) { } -static inline void aarch64_sve_change_el(CPUARMState *env, int o, - int n, bool a) -{ } -#endif - void aarch64_sync_32_to_64(CPUARMState *env); void aarch64_sync_64_to_32(CPUARMState *env); diff --git a/target/arm/helper.c b/target/arm/helper.c index becbbbd0d8..7fb6e88630 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6563,7 +6563,9 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ new_len = sve_vqm1_for_el(env, cur_el); if (new_len < old_len) { +#ifdef TARGET_AARCH64 aarch64_sve_narrow_vq(env, new_len + 1); +#endif } } @@ -10628,7 +10630,9 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) * Note that new_el can never be 0. If cur_el is 0, then * el0_a64 is is_a64(), else el0_a64 is ignored. */ +#ifdef TARGET_AARCH64 aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); +#endif } if (cur_el < new_el) { @@ -11640,7 +11644,9 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, /* When changing vector length, clear inaccessible state. */ if (new_len < old_len) { +#ifdef TARGET_AARCH64 aarch64_sve_narrow_vq(env, new_len + 1); +#endif } } #endif From 652d19a642b34cd99fc2ce65267a216cb9de8f4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 01:58:18 +0200 Subject: [PATCH 0198/2760] target/arm: Expose Aarch64 helpers unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At worst, for 32-bit arm binary, using these methods will now produce a link time error, instead of a compile time one. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20250403235821.9909-37-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- target/arm/internals.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 01408e40a3..d24acdd672 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1808,7 +1808,6 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env) return (1ULL << 31) | ((1ULL << pmu_num_counters(env)) - 1); } -#ifdef TARGET_AARCH64 GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cpu, int base_reg); int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg); int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg); @@ -1826,7 +1825,6 @@ void aarch64_max_tcg_initfn(Object *obj); void aarch64_add_pauth_properties(Object *obj); void aarch64_add_sve_properties(Object *obj); void aarch64_add_sme_properties(Object *obj); -#endif /* Read the CONTROL register as the MRS instruction would. */ uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure); From d4ecfc569dcfb33dd9f00afaa6e2bd883fcf1e4a Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:08 -0700 Subject: [PATCH 0199/2760] meson: add common hw files Those files will be compiled once per base architecture ("arm" in this case), instead of being compiled for every variant/bitness of architecture. We make sure to not include target cpu definitions (exec/cpu-defs.h) by defining header guard directly. This way, a given compilation unit can access a specific cpu definition, but not access to compile time defines associated. Previous commits took care to clean up some headers to not rely on cpu-defs.h content. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-24-pierrick.bouvier@linaro.org> --- meson.build | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 657949326b..bcb9d39a38 100644 --- a/meson.build +++ b/meson.build @@ -3682,6 +3682,7 @@ hw_arch = {} target_arch = {} target_system_arch = {} target_user_arch = {} +hw_common_arch = {} # NOTE: the trace/ subdirectory needs the qapi_trace_events variable # that is filled in by qapi/. @@ -4079,6 +4080,34 @@ common_all = static_library('common', implicit_include_directories: false, dependencies: common_ss.all_dependencies()) +# construct common libraries per base architecture +hw_common_arch_libs = {} +foreach target : target_dirs + config_target = config_target_mak[target] + target_base_arch = config_target['TARGET_BASE_ARCH'] + + # check if already generated + if target_base_arch in hw_common_arch_libs + continue + endif + + if target_base_arch in hw_common_arch + target_inc = [include_directories('target' / target_base_arch)] + src = hw_common_arch[target_base_arch] + lib = static_library( + 'hw_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: common_user_inc + target_inc, + implicit_include_directories: false, + # prevent common code to access cpu compile time + # definition, but still allow access to cpu.h + c_args: ['-DCPU_DEFS_H', '-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'], + dependencies: src.all_dependencies()) + hw_common_arch_libs += {target_base_arch: lib} + endif +endforeach + if have_rust # We would like to use --generate-cstr, but it is only available # starting with bindgen 0.66.0. The oldest supported versions @@ -4244,8 +4273,14 @@ foreach target : target_dirs arch_deps += t.dependencies() target_common = common_ss.apply(config_target, strict: false) - objects = common_all.extract_objects(target_common.sources()) + objects = [common_all.extract_objects(target_common.sources())] arch_deps += target_common.dependencies() + if target_type == 'system' and target_base_arch in hw_common_arch_libs + src = hw_common_arch[target_base_arch].apply(config_target, strict: false) + lib = hw_common_arch_libs[target_base_arch] + objects += lib.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif target_specific = specific_ss.apply(config_target, strict: false) arch_srcs += target_specific.sources() From acbebffdda13cf502d70037f0cf60b7eb858a459 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:09 -0700 Subject: [PATCH 0200/2760] hw/arm/boot: make compilation unit hw common Now we eliminated poisoned identifiers from headers, this file can now be compiled once for all arm targets. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-25-pierrick.bouvier@linaro.org> --- hw/arm/boot.c | 1 + hw/arm/meson.build | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d3811b896f..f94b940bc3 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -14,6 +14,7 @@ #include #include "hw/arm/boot.h" #include "hw/arm/linux-boot-if.h" +#include "cpu.h" #include "exec/target_page.h" #include "system/kvm.h" #include "system/tcg.h" diff --git a/hw/arm/meson.build b/hw/arm/meson.build index ac473ce7cd..9e8c96059e 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -1,5 +1,5 @@ arm_ss = ss.source_set() -arm_ss.add(files('boot.c')) +arm_common_ss = ss.source_set() arm_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c')) arm_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c')) @@ -75,4 +75,7 @@ system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) +arm_common_ss.add(fdt, files('boot.c')) + hw_arch += {'arm': arm_ss} +hw_common_arch += {'arm': arm_common_ss} From f55cc73dffcf2734d6bd54f4edaceb1b0ed64b0d Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:11 -0700 Subject: [PATCH 0201/2760] hw/arm/digic_boards: prepare compilation unit to be common Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-27-pierrick.bouvier@linaro.org> --- hw/arm/digic_boards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/digic_boards.c b/hw/arm/digic_boards.c index 2492fafeb8..466b8b84c0 100644 --- a/hw/arm/digic_boards.c +++ b/hw/arm/digic_boards.c @@ -80,7 +80,7 @@ static void digic4_board_init(MachineState *machine, DigicBoard *board) static void digic_load_rom(DigicState *s, hwaddr addr, hwaddr max_size, const char *filename) { - target_long rom_size; + ssize_t rom_size; if (qtest_enabled()) { /* qtest runs no code so don't attempt a ROM load which From c16ee1384b3b4cddf9777ce76813e36247f6e895 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:12 -0700 Subject: [PATCH 0202/2760] hw/arm/xlnx-zynqmp: prepare compilation unit to be common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove kvm unused headers. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-28-pierrick.bouvier@linaro.org> --- hw/arm/xlnx-zynqmp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index d6022ff2d3..ec2b3a41ed 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -22,9 +22,7 @@ #include "hw/intc/arm_gic_common.h" #include "hw/misc/unimp.h" #include "hw/boards.h" -#include "system/kvm.h" #include "system/system.h" -#include "kvm_arm.h" #include "target/arm/cpu-qom.h" #include "target/arm/gtimer.h" From 51cc143e83875c3b90570e80d47d330dd502487a Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:13 -0700 Subject: [PATCH 0203/2760] hw/arm/xlnx-versal: prepare compilation unit to be common MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove kvm unused headers. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-29-pierrick.bouvier@linaro.org> --- hw/arm/xlnx-versal.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index 278545a3f7..f0b383b29e 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -17,9 +17,7 @@ #include "hw/sysbus.h" #include "net/net.h" #include "system/system.h" -#include "system/kvm.h" #include "hw/arm/boot.h" -#include "kvm_arm.h" #include "hw/misc/unimp.h" #include "hw/arm/xlnx-versal.h" #include "qemu/log.h" From 6f4e8a92bbd9590ff87eda638bda82ec1d255f81 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 24 Mar 2025 21:59:14 -0700 Subject: [PATCH 0204/2760] hw/arm: make most of the compilation units common Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Signed-off-by: Richard Henderson Message-ID: <20250325045915.994760-30-pierrick.bouvier@linaro.org> --- hw/arm/meson.build | 112 ++++++++++++++++++++++----------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 9e8c96059e..09b1cfe5b5 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -2,43 +2,43 @@ arm_ss = ss.source_set() arm_common_ss = ss.source_set() arm_ss.add(when: 'CONFIG_ARM_VIRT', if_true: files('virt.c')) arm_ss.add(when: 'CONFIG_ACPI', if_true: files('virt-acpi-build.c')) -arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c')) -arm_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c')) -arm_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c')) -arm_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c')) -arm_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c')) -arm_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c')) -arm_ss.add(when: 'CONFIG_MUSICPAL', if_true: files('musicpal.c')) -arm_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c')) -arm_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c')) -arm_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c')) -arm_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm8xx.c', 'npcm8xx_boards.c')) -arm_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c')) +arm_common_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic_boards.c')) +arm_common_ss.add(when: 'CONFIG_EMCRAFT_SF2', if_true: files('msf2-som.c')) +arm_common_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c')) +arm_common_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c')) +arm_common_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c')) +arm_common_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c')) +arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [pixman, files('musicpal.c')]) +arm_common_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c')) +arm_common_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c')) +arm_common_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c')) +arm_common_ss.add(when: 'CONFIG_NPCM8XX', if_true: files('npcm8xx.c', 'npcm8xx_boards.c')) +arm_common_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview.c')) arm_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa-ref.c')) -arm_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c')) -arm_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c')) -arm_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c')) -arm_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c')) +arm_common_ss.add(when: 'CONFIG_STELLARIS', if_true: files('stellaris.c')) +arm_common_ss.add(when: 'CONFIG_STM32VLDISCOVERY', if_true: files('stm32vldiscovery.c')) +arm_common_ss.add(when: 'CONFIG_ZYNQ', if_true: files('xilinx_zynq.c')) +arm_common_ss.add(when: 'CONFIG_SABRELITE', if_true: files('sabrelite.c')) -arm_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c')) -arm_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c')) -arm_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c')) -arm_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c')) -arm_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c')) -arm_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c')) -arm_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c')) +arm_common_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m.c')) +arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210.c')) +arm_common_ss.add(when: 'CONFIG_DIGIC', if_true: files('digic.c')) +arm_common_ss.add(when: 'CONFIG_OMAP', if_true: files('omap1.c')) +arm_common_ss.add(when: 'CONFIG_ALLWINNER_A10', if_true: files('allwinner-a10.c', 'cubieboard.c')) +arm_common_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3.c', 'orangepi.c')) +arm_common_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40.c', 'bananapi_m2u.c')) arm_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2836.c', 'raspi.c')) -arm_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c')) -arm_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) -arm_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) -arm_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) -arm_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c')) -arm_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c')) -arm_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) -arm_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX6', if_true: files('fsl-imx6.c')) +arm_common_ss.add(when: ['CONFIG_RASPI', 'TARGET_AARCH64'], if_true: files('bcm2838.c', 'raspi4b.c')) +arm_common_ss.add(when: 'CONFIG_STM32F100_SOC', if_true: files('stm32f100_soc.c')) +arm_common_ss.add(when: 'CONFIG_STM32F205_SOC', if_true: files('stm32f205_soc.c')) +arm_common_ss.add(when: 'CONFIG_STM32F405_SOC', if_true: files('stm32f405_soc.c')) +arm_common_ss.add(when: 'CONFIG_B_L475E_IOT01A', if_true: files('b-l475e-iot01a.c')) +arm_common_ss.add(when: 'CONFIG_STM32L4X5_SOC', if_true: files('stm32l4x5_soc.c')) +arm_common_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp.c', 'xlnx-zcu102.c')) +arm_common_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal.c', 'xlnx-versal-virt.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX25', if_true: files('fsl-imx25.c', 'imx25_pdk.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX31', if_true: files('fsl-imx31.c', 'kzm.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX6', if_true: files('fsl-imx6.c')) arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed.c', 'aspeed_soc_common.c', @@ -47,33 +47,33 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_ast10x0.c', 'aspeed_eeprom.c', 'fby35.c')) -arm_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files('aspeed_ast27x0.c')) -arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) -arm_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) -arm_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) -arm_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c')) -arm_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c')) -arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) -arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) -arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) +arm_common_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files('aspeed_ast27x0.c')) +arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) +arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) +arm_common_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) +arm_common_ss.add(when: 'CONFIG_MUSCA', if_true: files('musca.c')) +arm_common_ss.add(when: 'CONFIG_ARMSSE', if_true: files('armsse.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP', if_true: files('fsl-imx8mp.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX8MP_EVK', if_true: files('imx8mp-evk.c')) +arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmuv3.c')) +arm_common_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c')) +arm_common_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c')) arm_ss.add(when: 'CONFIG_XEN', if_true: files( 'xen-stubs.c', 'xen-pvh.c', )) -system_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) -system_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c')) -system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c')) -system_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c')) -system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c')) -system_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c')) -system_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c')) -system_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) -system_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) -system_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) +arm_common_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c')) +arm_common_ss.add(when: 'CONFIG_COLLIE', if_true: files('collie.c')) +arm_common_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4_boards.c')) +arm_common_ss.add(when: 'CONFIG_NETDUINO2', if_true: files('netduino2.c')) +arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_peripherals.c')) +arm_common_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2838_peripherals.c')) +arm_common_ss.add(when: 'CONFIG_STRONGARM', if_true: files('strongarm.c')) +arm_common_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) +arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) +arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) arm_common_ss.add(fdt, files('boot.c')) From 8280a8b86659bf3c6965ccdad8458ab366817d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Apr 2025 15:37:26 +0100 Subject: [PATCH 0205/2760] target/riscv: Do not expose rv128 CPU on user mode emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As Richard mentioned: We should allow RV128 in user-mode at all until there's a kernel abi for it. Remove the experimental 'x-rv128' CPU on user emulation (since it is experimental, no deprecation period is required). Reported-by: Richard Henderson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/riscv/cpu.c | 10 ++++------ target/riscv/tcg/tcg-cpu.c | 5 +++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 430b02d2a5..ad534cee51 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -697,7 +697,7 @@ static void rv64_xiangshan_nanhu_cpu_init(Object *obj) #endif } -#ifdef CONFIG_TCG +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) static void rv128_base_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); @@ -708,11 +708,9 @@ static void rv128_base_cpu_init(Object *obj) /* Set latest version of privileged specification */ env->priv_ver = PRIV_VERSION_LATEST; -#ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); -#endif } -#endif /* CONFIG_TCG */ +#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ static void rv64i_bare_cpu_init(Object *obj) { @@ -3255,9 +3253,9 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, MXL_RV64, rv64_xiangshan_nanhu_cpu_init), -#ifdef CONFIG_TCG +#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, MXL_RV128, rv128_base_cpu_init), -#endif /* CONFIG_TCG */ +#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, MXL_RV64, rv64i_bare_cpu_init), DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64E, MXL_RV64, rv64e_bare_cpu_init), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, MXL_RV64, rva22u64_profile_cpu_init), diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 710449d17e..5d0429b4d0 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1046,7 +1046,6 @@ static bool riscv_cpu_is_generic(Object *cpu_obj) static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) { RISCVCPU *cpu = RISCV_CPU(cs); - RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); if (!riscv_cpu_tcg_compatible(cpu)) { g_autofree char *name = riscv_cpu_get_name(cpu); @@ -1055,6 +1054,9 @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) return false; } +#ifndef CONFIG_USER_ONLY + RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); + if (mcc->misa_mxl_max >= MXL_RV128 && qemu_tcg_mttcg_enabled()) { /* Missing 128-bit aligned atomics */ error_setg(errp, @@ -1063,7 +1065,6 @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) return false; } -#ifndef CONFIG_USER_ONLY CPURISCVState *env = &cpu->env; tcg_cflags_set(CPU(cs), CF_PCREL); From 79b835f1395ea5cba9a1d5f02c0fb1a429d48e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 3 Apr 2025 23:37:54 +0200 Subject: [PATCH 0206/2760] tcg: Include missing 'cpu.h' in translate-all.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit tb_check_watchpoint() calls cpu_get_tb_cpu_state(), which is declared in each "cpu.h" header. It is indirectly included via "tcg/insn-start-words.h". Since we want to rework "tcg/insn-start-words.h", removing "cpu.h" in the next commit, add the missing header now, otherwise we'd get: accel/tcg/translate-all.c:598:9: error: call to undeclared function 'cpu_get_tb_cpu_state' [-Wimplicit-function-declaration] 598 | cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 1 + 1 file changed, 1 insertion(+) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index ed41fc5d0c..c5590eb695 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -69,6 +69,7 @@ #include "internal-target.h" #include "tcg/perf.h" #include "tcg/insn-start-words.h" +#include "cpu.h" TBContext tb_ctx; From 21d41c566d0694a90836d5c7ae4c6b279f5312a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 19 Mar 2025 12:46:47 +0100 Subject: [PATCH 0207/2760] tcg: Declare TARGET_INSN_START_EXTRA_WORDS in 'cpu-param.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To avoid including the huge "cpu.h" for a simple definition, move TARGET_INSN_START_EXTRA_WORDS to "cpu-param.h". Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/tcg/insn-start-words.h | 2 +- target/arm/cpu-param.h | 7 +++++++ target/arm/cpu.h | 6 ------ target/hppa/cpu-param.h | 2 ++ target/hppa/cpu.h | 2 -- target/i386/cpu-param.h | 2 ++ target/i386/cpu.h | 2 -- target/m68k/cpu-param.h | 2 ++ target/m68k/cpu.h | 2 -- target/microblaze/cpu-param.h | 2 ++ target/microblaze/cpu.h | 2 -- target/mips/cpu-param.h | 2 ++ target/mips/cpu.h | 2 -- target/openrisc/cpu-param.h | 2 ++ target/openrisc/cpu.h | 2 -- target/riscv/cpu-param.h | 8 ++++++++ target/riscv/cpu.h | 6 ------ target/s390x/cpu-param.h | 2 ++ target/s390x/cpu.h | 2 -- target/sh4/cpu-param.h | 2 ++ target/sh4/cpu.h | 2 -- target/sparc/cpu-param.h | 2 ++ target/sparc/cpu.h | 1 - 23 files changed, 34 insertions(+), 30 deletions(-) diff --git a/include/tcg/insn-start-words.h b/include/tcg/insn-start-words.h index 50c18bd326..c439c09f2f 100644 --- a/include/tcg/insn-start-words.h +++ b/include/tcg/insn-start-words.h @@ -6,7 +6,7 @@ #ifndef TARGET_INSN_START_WORDS -#include "cpu.h" +#include "cpu-param.h" #ifndef TARGET_INSN_START_EXTRA_WORDS # define TARGET_INSN_START_WORDS 1 diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index a7ae42d17d..2cee4be693 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -37,6 +37,13 @@ # define TARGET_PAGE_BITS_LEGACY 10 #endif /* !CONFIG_USER_ONLY */ +/* + * ARM-specific extra insn start words: + * 1: Conditional execution bits + * 2: Partial exception syndrome for data aborts + */ +#define TARGET_INSN_START_EXTRA_WORDS 2 + /* ARM processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index c1a0faed3a..3705b34285 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -98,12 +98,6 @@ #define offsetofhigh32(S, M) (offsetof(S, M) + sizeof(uint32_t)) #endif -/* ARM-specific extra insn start words: - * 1: Conditional execution bits - * 2: Partial exception syndrome for data aborts - */ -#define TARGET_INSN_START_EXTRA_WORDS 2 - /* The 2nd extra word holding syndrome info for data aborts does not use * the upper 6 bits nor the lower 13 bits. We mask and shift it down to * help the sleb128 encoder do a better job. diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h index 7ed6b5741e..68ed84e84a 100644 --- a/target/hppa/cpu-param.h +++ b/target/hppa/cpu-param.h @@ -19,6 +19,8 @@ #define TARGET_PAGE_BITS 12 +#define TARGET_INSN_START_EXTRA_WORDS 2 + /* PA-RISC 1.x processors have a strong memory model. */ /* * ??? While we do not yet implement PA-RISC 2.0, those processors have diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index da5f8adcd5..acc9937240 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -48,8 +48,6 @@ #define PRIV_KERNEL 0 #define PRIV_USER 3 -#define TARGET_INSN_START_EXTRA_WORDS 2 - /* No need to flush MMU_ABS*_IDX */ #define HPPA_MMU_FLUSH_MASK \ (1 << MMU_KERNEL_IDX | 1 << MMU_KERNEL_P_IDX | \ diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h index b0e884c5d7..0c8efce861 100644 --- a/target/i386/cpu-param.h +++ b/target/i386/cpu-param.h @@ -22,6 +22,8 @@ #endif #define TARGET_PAGE_BITS 12 +#define TARGET_INSN_START_EXTRA_WORDS 1 + /* The x86 has a strong memory model with some store-after-load re-ordering */ #define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 17ad0b644b..9866595cd0 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1610,8 +1610,6 @@ typedef struct { #define MAX_FIXED_COUNTERS 3 #define MAX_GP_COUNTERS (MSR_IA32_PERF_STATUS - MSR_P6_EVNTSEL0) -#define TARGET_INSN_START_EXTRA_WORDS 1 - #define NB_OPMASK_REGS 8 /* CPU can't have 0xFFFFFFFF APIC ID, use that value to distinguish diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h index 7afbf6d302..256a2b5f8b 100644 --- a/target/m68k/cpu-param.h +++ b/target/m68k/cpu-param.h @@ -17,4 +17,6 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_INSN_START_EXTRA_WORDS 1 + #endif diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 0b70e8c6ab..39d0b9d6d7 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -78,8 +78,6 @@ #define M68K_MAX_TTR 2 #define TTR(type, index) ttr[((type & ACCESS_CODE) == ACCESS_CODE) * 2 + index] -#define TARGET_INSN_START_EXTRA_WORDS 1 - typedef CPU_LDoubleU FPReg; typedef struct CPUArchState { diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h index c866ec6c14..5d55e0e3c4 100644 --- a/target/microblaze/cpu-param.h +++ b/target/microblaze/cpu-param.h @@ -27,6 +27,8 @@ /* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */ #define TARGET_PAGE_BITS 12 +#define TARGET_INSN_START_EXTRA_WORDS 1 + /* MicroBlaze is always in-order. */ #define TCG_GUEST_DEFAULT_MO TCG_MO_ALL diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 2bfa396c96..d511f22a55 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -233,8 +233,6 @@ typedef struct CPUArchState CPUMBState; #define STREAM_CONTROL (1 << 3) #define STREAM_NONBLOCK (1 << 4) -#define TARGET_INSN_START_EXTRA_WORDS 1 - /* use-non-secure property masks */ #define USE_NON_SECURE_M_AXI_DP_MASK 0x1 #define USE_NON_SECURE_M_AXI_IP_MASK 0x2 diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h index 8fcb1b4f5f..99ca8d1684 100644 --- a/target/mips/cpu-param.h +++ b/target/mips/cpu-param.h @@ -20,6 +20,8 @@ #endif #define TARGET_PAGE_BITS 12 +#define TARGET_INSN_START_EXTRA_WORDS 2 + #define TCG_GUEST_DEFAULT_MO (0) #endif diff --git a/target/mips/cpu.h b/target/mips/cpu.h index 20f31370bc..d16f9a7220 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -100,8 +100,6 @@ struct CPUMIPSFPUContext { #define FP_UNIMPLEMENTED 32 }; -#define TARGET_INSN_START_EXTRA_WORDS 2 - typedef struct CPUMIPSMVPContext CPUMIPSMVPContext; struct CPUMIPSMVPContext { int32_t CP0_MVPControl; diff --git a/target/openrisc/cpu-param.h b/target/openrisc/cpu-param.h index 37627f2c39..7ea0ecb55a 100644 --- a/target/openrisc/cpu-param.h +++ b/target/openrisc/cpu-param.h @@ -12,6 +12,8 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_INSN_START_EXTRA_WORDS 1 + #define TCG_GUEST_DEFAULT_MO (0) #endif diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 19ee85ff5a..569819bfb0 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -40,8 +40,6 @@ struct OpenRISCCPUClass { ResettablePhases parent_phases; }; -#define TARGET_INSN_START_EXTRA_WORDS 1 - enum { MMU_NOMMU_IDX = 0, MMU_SUPERVISOR_IDX = 1, diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h index fba30e966a..ff4ba81965 100644 --- a/target/riscv/cpu-param.h +++ b/target/riscv/cpu-param.h @@ -16,6 +16,14 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 32 /* sv32 */ #endif #define TARGET_PAGE_BITS 12 /* 4 KiB Pages */ + +/* + * RISC-V-specific extra insn start words: + * 1: Original instruction opcode + * 2: more information about instruction + */ +#define TARGET_INSN_START_EXTRA_WORDS 2 + /* * The current MMU Modes are: * - U mode 0b000 diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 867e539b53..167909c89b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -45,12 +45,6 @@ typedef struct CPUArchState CPURISCVState; # define TYPE_RISCV_CPU_BASE TYPE_RISCV_CPU_BASE64 #endif -/* - * RISC-V-specific extra insn start words: - * 1: Original instruction opcode - * 2: more information about instruction - */ -#define TARGET_INSN_START_EXTRA_WORDS 2 /* * b0: Whether a instruction always raise a store AMO or not. */ diff --git a/target/s390x/cpu-param.h b/target/s390x/cpu-param.h index 5c331ec424..a8a4377f4f 100644 --- a/target/s390x/cpu-param.h +++ b/target/s390x/cpu-param.h @@ -12,6 +12,8 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 64 #define TARGET_VIRT_ADDR_SPACE_BITS 64 +#define TARGET_INSN_START_EXTRA_WORDS 2 + /* * The z/Architecture has a strong memory model with some * store-after-load re-ordering. diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 940eda8dd1..90f64ee20c 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -37,8 +37,6 @@ #define TARGET_HAS_PRECISE_SMC -#define TARGET_INSN_START_EXTRA_WORDS 2 - #define MMU_USER_IDX 0 #define S390_MAX_CPUS 248 diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h index 2b6e11dd0a..f328715ee8 100644 --- a/target/sh4/cpu-param.h +++ b/target/sh4/cpu-param.h @@ -16,4 +16,6 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif +#define TARGET_INSN_START_EXTRA_WORDS 1 + #endif diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 7752a0c2e1..906f99ddf0 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -127,8 +127,6 @@ typedef struct tlb_t { #define UTLB_SIZE 64 #define ITLB_SIZE 4 -#define TARGET_INSN_START_EXTRA_WORDS 1 - enum sh_features { SH_FEATURE_SH4A = 1, SH_FEATURE_BCR3_AND_BCR4 = 2, diff --git a/target/sparc/cpu-param.h b/target/sparc/cpu-param.h index 6952ee2b82..62d47b804b 100644 --- a/target/sparc/cpu-param.h +++ b/target/sparc/cpu-param.h @@ -21,6 +21,8 @@ # define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif +#define TARGET_INSN_START_EXTRA_WORDS 1 + /* * From Oracle SPARC Architecture 2015: * diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 734dfdb1d3..83ac818933 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -223,7 +223,6 @@ typedef struct trap_state { uint32_t tt; } trap_state; #endif -#define TARGET_INSN_START_EXTRA_WORDS 1 typedef struct sparc_def_t { const char *name; From 4ff1b33edf95497a8e6f0615a3ae91f736cf1f8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 19 Mar 2025 12:46:55 +0100 Subject: [PATCH 0208/2760] tcg: Always define TARGET_INSN_START_EXTRA_WORDS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not define TARGET_INSN_START_EXTRA_WORDS under the hood, have each target explicitly define it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- include/tcg/insn-start-words.h | 4 ---- include/tcg/tcg-op.h | 2 +- target/alpha/cpu-param.h | 2 ++ target/avr/cpu-param.h | 2 ++ target/hexagon/cpu-param.h | 2 ++ target/loongarch/cpu-param.h | 2 ++ target/ppc/cpu-param.h | 2 ++ target/rx/cpu-param.h | 2 ++ target/tricore/cpu-param.h | 2 ++ target/xtensa/cpu-param.h | 2 ++ 10 files changed, 17 insertions(+), 5 deletions(-) diff --git a/include/tcg/insn-start-words.h b/include/tcg/insn-start-words.h index c439c09f2f..d416d19bcf 100644 --- a/include/tcg/insn-start-words.h +++ b/include/tcg/insn-start-words.h @@ -8,10 +8,6 @@ #include "cpu-param.h" -#ifndef TARGET_INSN_START_EXTRA_WORDS -# define TARGET_INSN_START_WORDS 1 -#else # define TARGET_INSN_START_WORDS (1 + TARGET_INSN_START_EXTRA_WORDS) -#endif #endif /* TARGET_INSN_START_WORDS */ diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index bc46b5570c..cded92a447 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -23,7 +23,7 @@ # error #endif -#ifndef TARGET_INSN_START_EXTRA_WORDS +#if TARGET_INSN_START_EXTRA_WORDS == 0 static inline void tcg_gen_insn_start(target_ulong pc) { TCGOp *op = tcg_emit_op(INDEX_op_insn_start, 64 / TCG_TARGET_REG_BITS); diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index 63989e71c0..dd44feb179 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -24,6 +24,8 @@ # define TARGET_VIRT_ADDR_SPACE_BITS (30 + TARGET_PAGE_BITS) #endif +#define TARGET_INSN_START_EXTRA_WORDS 0 + /* Alpha processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h index f5248ce9e7..9d37848d97 100644 --- a/target/avr/cpu-param.h +++ b/target/avr/cpu-param.h @@ -25,6 +25,8 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 24 #define TARGET_VIRT_ADDR_SPACE_BITS 24 +#define TARGET_INSN_START_EXTRA_WORDS 0 + #define TCG_GUEST_DEFAULT_MO 0 #endif diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 45ee7b4640..635d509e74 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -23,4 +23,6 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 36 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_INSN_START_EXTRA_WORDS 0 + #endif diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h index 52437946e5..dbe414bb35 100644 --- a/target/loongarch/cpu-param.h +++ b/target/loongarch/cpu-param.h @@ -13,6 +13,8 @@ #define TARGET_PAGE_BITS 12 +#define TARGET_INSN_START_EXTRA_WORDS 0 + #define TCG_GUEST_DEFAULT_MO (0) #endif diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h index 553ad2f4c6..d0651d2ac8 100644 --- a/target/ppc/cpu-param.h +++ b/target/ppc/cpu-param.h @@ -37,6 +37,8 @@ # define TARGET_PAGE_BITS 12 #endif +#define TARGET_INSN_START_EXTRA_WORDS 0 + #define TCG_GUEST_DEFAULT_MO 0 #endif diff --git a/target/rx/cpu-param.h b/target/rx/cpu-param.h index ef1970a09e..84934f3bca 100644 --- a/target/rx/cpu-param.h +++ b/target/rx/cpu-param.h @@ -24,4 +24,6 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_INSN_START_EXTRA_WORDS 0 + #endif diff --git a/target/tricore/cpu-param.h b/target/tricore/cpu-param.h index 790242ef3d..eb33a67c41 100644 --- a/target/tricore/cpu-param.h +++ b/target/tricore/cpu-param.h @@ -12,4 +12,6 @@ #define TARGET_PHYS_ADDR_SPACE_BITS 32 #define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_INSN_START_EXTRA_WORDS 0 + #endif diff --git a/target/xtensa/cpu-param.h b/target/xtensa/cpu-param.h index 5e4848ad05..e7cb747aaa 100644 --- a/target/xtensa/cpu-param.h +++ b/target/xtensa/cpu-param.h @@ -16,6 +16,8 @@ #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif +#define TARGET_INSN_START_EXTRA_WORDS 0 + /* Xtensa processors have a weak memory model */ #define TCG_GUEST_DEFAULT_MO (0) From 231a1c0ff46ae442431fb7a6e5d6f36765628b68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:13:20 +0200 Subject: [PATCH 0209/2760] exec: Restrict 'cpu-ldst-common.h' to accel/tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/translator.c | 2 +- include/{exec => accel/tcg}/cpu-ldst-common.h | 6 +++--- include/exec/cpu_ldst.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename include/{exec => accel/tcg}/cpu-ldst-common.h (97%) diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c index c53bbdef99..034f2f359e 100644 --- a/accel/tcg/translator.c +++ b/accel/tcg/translator.c @@ -11,7 +11,7 @@ #include "qemu/bswap.h" #include "qemu/log.h" #include "qemu/error-report.h" -#include "exec/cpu-ldst-common.h" +#include "accel/tcg/cpu-ldst-common.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/target_page.h" #include "exec/translator.h" diff --git a/include/exec/cpu-ldst-common.h b/include/accel/tcg/cpu-ldst-common.h similarity index 97% rename from include/exec/cpu-ldst-common.h rename to include/accel/tcg/cpu-ldst-common.h index c46a6ade5d..8bf17c2fab 100644 --- a/include/exec/cpu-ldst-common.h +++ b/include/accel/tcg/cpu-ldst-common.h @@ -4,8 +4,8 @@ * SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef CPU_LDST_COMMON_H -#define CPU_LDST_COMMON_H +#ifndef ACCEL_TCG_CPU_LDST_COMMON_H +#define ACCEL_TCG_CPU_LDST_COMMON_H #ifndef CONFIG_TCG #error Can only include this header with TCG @@ -119,4 +119,4 @@ uint32_t cpu_ldl_code_mmu(CPUArchState *env, vaddr addr, uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, MemOpIdx oi, uintptr_t ra); -#endif /* CPU_LDST_COMMON_H */ +#endif /* ACCEL_TCG_CPU_LDST_COMMON_H */ diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h index 63847f6e61..74761ba5f3 100644 --- a/include/exec/cpu_ldst.h +++ b/include/exec/cpu_ldst.h @@ -67,7 +67,7 @@ #endif #include "exec/cpu-common.h" -#include "exec/cpu-ldst-common.h" +#include "accel/tcg/cpu-ldst-common.h" #include "accel/tcg/cpu-mmu-index.h" #include "exec/abi_ptr.h" From 42fa9665e598c268a7ccfab5b92636618d9574ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:14:36 +0200 Subject: [PATCH 0210/2760] exec: Restrict 'cpu_ldst.h' to accel/tcg/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mechanical change using: $ sed -i -e 's,exec/cpu_ldst,accel/tcg/cpu-ldst,' \ $(git grep -l exec/cpu_ldst.h) Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 2 +- accel/tcg/user-exec.c | 2 +- bsd-user/qemu.h | 2 +- include/{exec/cpu_ldst.h => accel/tcg/cpu-ldst.h} | 6 +++--- include/exec/exec-all.h | 2 +- linux-user/qemu.h | 2 +- target/alpha/mem_helper.c | 2 +- target/arm/tcg/helper-a64.c | 2 +- target/arm/tcg/m_helper.c | 2 +- target/arm/tcg/mte_helper.c | 2 +- target/arm/tcg/mve_helper.c | 2 +- target/arm/tcg/op_helper.c | 2 +- target/arm/tcg/pauth_helper.c | 2 +- target/arm/tcg/sme_helper.c | 2 +- target/arm/tcg/sve_ldst_internal.h | 2 +- target/avr/helper.c | 2 +- target/hexagon/op_helper.c | 2 +- target/hexagon/translate.c | 2 +- target/hppa/op_helper.c | 2 +- target/i386/tcg/access.c | 2 +- target/i386/tcg/fpu_helper.c | 2 +- target/i386/tcg/mem_helper.c | 2 +- target/i386/tcg/mpx_helper.c | 2 +- target/i386/tcg/seg_helper.c | 2 +- target/i386/tcg/system/excp_helper.c | 2 +- target/i386/tcg/system/misc_helper.c | 2 +- target/i386/tcg/system/seg_helper.c | 2 +- target/i386/tcg/system/svm_helper.c | 2 +- target/i386/tcg/user/seg_helper.c | 2 +- target/loongarch/cpu.c | 2 +- target/loongarch/tcg/csr_helper.c | 2 +- target/loongarch/tcg/fpu_helper.c | 2 +- target/loongarch/tcg/iocsr_helper.c | 2 +- target/loongarch/tcg/op_helper.c | 2 +- target/loongarch/tcg/tlb_helper.c | 2 +- target/m68k/fpu_helper.c | 2 +- target/m68k/op_helper.c | 2 +- target/microblaze/cpu.c | 2 +- target/microblaze/op_helper.c | 2 +- target/microblaze/translate.c | 2 +- target/mips/tcg/ldst_helper.c | 2 +- target/mips/tcg/msa_helper.c | 2 +- target/mips/tcg/system/tlb_helper.c | 2 +- target/ppc/mem_helper.c | 2 +- target/ppc/mmu_helper.c | 2 +- target/ppc/tcg-excp_helper.c | 2 +- target/riscv/op_helper.c | 2 +- target/riscv/vector_helper.c | 2 +- target/riscv/zce_helper.c | 2 +- target/rx/helper.c | 2 +- target/rx/op_helper.c | 2 +- target/s390x/tcg/crypto_helper.c | 2 +- target/s390x/tcg/int_helper.c | 2 +- target/s390x/tcg/mem_helper.c | 2 +- target/s390x/tcg/misc_helper.c | 2 +- target/s390x/tcg/vec_helper.c | 2 +- target/sh4/op_helper.c | 2 +- target/sparc/int32_helper.c | 2 +- target/sparc/ldst_helper.c | 2 +- target/tricore/op_helper.c | 2 +- target/tricore/translate.c | 2 +- 61 files changed, 63 insertions(+), 63 deletions(-) rename include/{exec/cpu_ldst.h => accel/tcg/cpu-ldst.h} (99%) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 0de46903dd..2cafd38d2a 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -23,7 +23,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #include "system/memory.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" #include "system/ram_addr.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 7f57d8f1af..1b878ead7a 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -26,7 +26,7 @@ #include "tcg/tcg.h" #include "qemu/bitops.h" #include "qemu/rcu.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "user/cpu_loop.h" #include "qemu/main-loop.h" #include "user/page-protection.h" diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index c1c508281a..244670dd24 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -22,7 +22,7 @@ #include "qemu/int128.h" #include "cpu.h" #include "qemu/units.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "user/abitypes.h" diff --git a/include/exec/cpu_ldst.h b/include/accel/tcg/cpu-ldst.h similarity index 99% rename from include/exec/cpu_ldst.h rename to include/accel/tcg/cpu-ldst.h index 74761ba5f3..f97a730703 100644 --- a/include/exec/cpu_ldst.h +++ b/include/accel/tcg/cpu-ldst.h @@ -59,8 +59,8 @@ * The "mmu" suffix carries the full MemOpIdx, with both mmu_idx and the * MemOp including alignment requirements. The alignment will be enforced. */ -#ifndef CPU_LDST_H -#define CPU_LDST_H +#ifndef ACCEL_TCG_CPU_LDST_H +#define ACCEL_TCG_CPU_LDST_H #ifndef CONFIG_TCG #error Can only include this header with TCG @@ -560,4 +560,4 @@ static inline void clear_helper_retaddr(void) #define clear_helper_retaddr() do { } while (0) #endif -#endif /* CPU_LDST_H */ +#endif /* ACCEL_TCG_CPU_LDST_H */ diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index f52a680f42..70608a11b6 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -21,7 +21,7 @@ #define EXEC_ALL_H #if defined(CONFIG_USER_ONLY) -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #endif #include "exec/mmu-access-type.h" #include "exec/translation-block.h" diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 948de8431a..0b19fa43e6 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -2,7 +2,7 @@ #define QEMU_H #include "cpu.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "user/abitypes.h" #include "user/page-protection.h" diff --git a/target/alpha/mem_helper.c b/target/alpha/mem_helper.c index 872955f5e7..a4d5adb40c 100644 --- a/target/alpha/mem_helper.c +++ b/target/alpha/mem_helper.c @@ -21,7 +21,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" static void do_unaligned_access(CPUAlphaState *env, vaddr addr, uintptr_t retaddr) { diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 507dbc1a44..08d8f63ffe 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -30,7 +30,7 @@ #include "qemu/crc32c.h" #include "exec/cpu-common.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "qemu/int128.h" diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index f7354f3c6e..37dc98dc35 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -18,7 +18,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #ifdef CONFIG_TCG -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "semihosting/common-semi.h" #endif #if !defined(CONFIG_USER_ONLY) diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 888c670754..7dc5fb776b 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -29,7 +29,7 @@ #else #include "system/ram_addr.h" #endif -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index 274003e2e5..f9f67d1f88 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -22,7 +22,7 @@ #include "internals.h" #include "vec_internal.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "tcg/tcg.h" #include "fpu/softfloat.h" diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index 71ba406782..38d49cbb9d 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -24,7 +24,7 @@ #include "internals.h" #include "cpu-features.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "cpregs.h" #define SIGNBIT (uint32_t)0x80000000 diff --git a/target/arm/tcg/pauth_helper.c b/target/arm/tcg/pauth_helper.c index c4b143024f..59bf27541d 100644 --- a/target/arm/tcg/pauth_helper.c +++ b/target/arm/tcg/pauth_helper.c @@ -22,7 +22,7 @@ #include "internals.h" #include "cpu-features.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "qemu/xxhash.h" diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index dcc48e43db..96b84c37a2 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -22,7 +22,7 @@ #include "internals.h" #include "tcg/tcg-gvec-desc.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "qemu/int128.h" #include "fpu/softfloat.h" diff --git a/target/arm/tcg/sve_ldst_internal.h b/target/arm/tcg/sve_ldst_internal.h index 4f159ec4ad..f2243daf37 100644 --- a/target/arm/tcg/sve_ldst_internal.h +++ b/target/arm/tcg/sve_ldst_internal.h @@ -20,7 +20,7 @@ #ifndef TARGET_ARM_SVE_LDST_INTERNAL_H #define TARGET_ARM_SVE_LDST_INTERNAL_H -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" /* * Load one element into @vd + @reg_off from @host. diff --git a/target/avr/helper.c b/target/avr/helper.c index 32cbf17919..afa591470f 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -27,7 +27,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" bool avr_cpu_exec_interrupt(CPUState *cs, int interrupt_request) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 6da8db8ea5..3f3d86db2b 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -18,7 +18,7 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "cpu.h" diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index fe7858703c..dd26801e64 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -23,7 +23,7 @@ #include "exec/helper-gen.h" #include "exec/helper-proto.h" #include "exec/translation-block.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/log.h" #include "internal.h" #include "attribs.h" diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index beb8f88799..2398ce2c64 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "qemu/timer.h" #include "trace.h" #ifdef CONFIG_USER_ONLY diff --git a/target/i386/tcg/access.c b/target/i386/tcg/access.c index 5a4721dcee..0fdd587edd 100644 --- a/target/i386/tcg/access.c +++ b/target/i386/tcg/access.c @@ -3,7 +3,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "exec/target_page.h" #include "access.h" diff --git a/target/i386/tcg/fpu_helper.c b/target/i386/tcg/fpu_helper.c index c1184ca219..1cbadb1453 100644 --- a/target/i386/tcg/fpu_helper.c +++ b/target/i386/tcg/fpu_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "tcg-cpu.h" #include "exec/cputlb.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "fpu/softfloat-macros.h" diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c index 3ef84e90d9..84a0815217 100644 --- a/target/i386/tcg/mem_helper.c +++ b/target/i386/tcg/mem_helper.c @@ -21,7 +21,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "qemu/int128.h" #include "qemu/atomic128.h" #include "tcg/tcg.h" diff --git a/target/i386/tcg/mpx_helper.c b/target/i386/tcg/mpx_helper.c index b942665adc..a0f816dfae 100644 --- a/target/i386/tcg/mpx_helper.c +++ b/target/i386/tcg/mpx_helper.c @@ -20,7 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "exec/target_page.h" #include "helper-tcg.h" diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 9dfbc4208c..3af902e0ec 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -23,7 +23,7 @@ #include "qemu/log.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/log.h" #include "helper-tcg.h" #include "seg_helper.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index a563c9b35e..93614aa3e5 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -19,7 +19,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" diff --git a/target/i386/tcg/system/misc_helper.c b/target/i386/tcg/system/misc_helper.c index 67896c8c87..9c3f5cc99b 100644 --- a/target/i386/tcg/system/misc_helper.c +++ b/target/i386/tcg/system/misc_helper.c @@ -21,7 +21,7 @@ #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "system/address-spaces.h" #include "system/memory.h" #include "exec/cputlb.h" diff --git a/target/i386/tcg/system/seg_helper.c b/target/i386/tcg/system/seg_helper.c index b07cc9f9b1..d4ea890c12 100644 --- a/target/i386/tcg/system/seg_helper.c +++ b/target/i386/tcg/system/seg_helper.c @@ -23,7 +23,7 @@ #include "qemu/main-loop.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "tcg/helper-tcg.h" #include "../seg_helper.h" diff --git a/target/i386/tcg/system/svm_helper.c b/target/i386/tcg/system/svm_helper.c index f9982b72d1..b27049b9ed 100644 --- a/target/i386/tcg/system/svm_helper.c +++ b/target/i386/tcg/system/svm_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cputlb.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "tcg/helper-tcg.h" /* Secure Virtual Machine helpers */ diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c index c45f2ac2ba..5692dd5195 100644 --- a/target/i386/tcg/user/seg_helper.c +++ b/target/i386/tcg/user/seg_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "tcg/helper-tcg.h" #include "tcg/seg_helper.h" diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index cb96b17911..4cc8e02f70 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -29,7 +29,7 @@ #include #endif #ifdef CONFIG_TCG -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "tcg/tcg.h" #endif diff --git a/target/loongarch/tcg/csr_helper.c b/target/loongarch/tcg/csr_helper.c index 6a7a65c860..2942d7feb8 100644 --- a/target/loongarch/tcg/csr_helper.c +++ b/target/loongarch/tcg/csr_helper.c @@ -13,7 +13,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/cputlb.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "hw/irq.h" #include "cpu-csr.h" diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c index a83acf64b0..fc3fd0561e 100644 --- a/target/loongarch/tcg/fpu_helper.c +++ b/target/loongarch/tcg/fpu_helper.c @@ -9,7 +9,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" #include "internals.h" diff --git a/target/loongarch/tcg/iocsr_helper.c b/target/loongarch/tcg/iocsr_helper.c index b6916f53d2..e62170de3c 100644 --- a/target/loongarch/tcg/iocsr_helper.c +++ b/target/loongarch/tcg/iocsr_helper.c @@ -10,7 +10,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #define GET_MEMTXATTRS(cas) \ ((MemTxAttrs){.requester_id = env_cpu(cas)->cpu_index}) diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c index b17208e5b9..94e3b28016 100644 --- a/target/loongarch/tcg/op_helper.c +++ b/target/loongarch/tcg/op_helper.c @@ -11,7 +11,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "internals.h" #include "qemu/crc32c.h" #include /* for crc32 */ diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index 0d6c9844a6..9a76a2a205 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -16,7 +16,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/log.h" #include "cpu-csr.h" diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index eb1cb8c687..ac4a0d85be 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "softfloat.h" /* diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 15bad5dd46..242aecccbb 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -21,7 +21,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "semihosting/semihost.h" #if !defined(CONFIG_USER_ONLY) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 88baeb6807..d10ae0702a 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -28,7 +28,7 @@ #include "qemu/module.h" #include "hw/qdev-properties.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/gdbstub.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index f6378030b7..4624ce5b67 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -24,7 +24,7 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" void helper_put(uint32_t id, uint32_t ctrl, uint32_t data) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 4bb867c969..7dcad6cf0d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -21,7 +21,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c index f92a923d7a..2fb879fcbc 100644 --- a/target/mips/tcg/ldst_helper.c +++ b/target/mips/tcg/ldst_helper.c @@ -24,7 +24,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/memop.h" #include "internal.h" diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index 969dd34b3e..14de4a71ff 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -22,7 +22,7 @@ #include "internal.h" #include "tcg/tcg.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "exec/memop.h" #include "exec/target_page.h" diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c index d239fa9353..e477ef812a 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -25,7 +25,7 @@ #include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/log.h" #include "exec/helper-proto.h" diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 0967624afe..d7e8d678f4 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -24,7 +24,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "helper_regs.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "internal.h" #include "qemu/atomic128.h" diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index c90ceb7d60..2138666122 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -37,7 +37,7 @@ #include "mmu-radix64.h" #include "mmu-booke.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" /* #define FLUSH_ALL_TLBS */ diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c index c422648cfd..2b15e5f2f0 100644 --- a/target/ppc/tcg-excp_helper.c +++ b/target/ppc/tcg-excp_helper.c @@ -20,7 +20,7 @@ #include "qemu/main-loop.h" #include "qemu/log.h" #include "target/ppc/cpu.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "system/runstate.h" diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f3d26b6b95..5b0db2c45a 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -23,7 +23,7 @@ #include "internals.h" #include "exec/exec-all.h" #include "exec/cputlb.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" #include "trace.h" diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7de6cbae5c..b8ae704457 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/memop.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" diff --git a/target/riscv/zce_helper.c b/target/riscv/zce_helper.c index b433bda16d..50d65f386c 100644 --- a/target/riscv/zce_helper.c +++ b/target/riscv/zce_helper.c @@ -20,7 +20,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" target_ulong HELPER(cm_jalt)(CPURISCVState *env, uint32_t index) { diff --git a/target/rx/helper.c b/target/rx/helper.c index e8aabf40ff..0640ab322b 100644 --- a/target/rx/helper.c +++ b/target/rx/helper.c @@ -20,7 +20,7 @@ #include "qemu/bitops.h" #include "cpu.h" #include "exec/log.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "hw/irq.h" void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte) diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c index b3ed822dd1..a2f1f3824d 100644 --- a/target/rx/op_helper.c +++ b/target/rx/op_helper.c @@ -21,7 +21,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" #include "tcg/debug-assert.h" diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 93aabd236f..642c1b18c4 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -18,7 +18,7 @@ #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" static uint64_t R(uint64_t x, int c) { diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index 2af970f2c8..253c036415 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -25,7 +25,7 @@ #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" /* #define DEBUG_HELPER */ #ifdef DEBUG_HELPER diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index d5eece4384..0cdfd380ce 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -28,7 +28,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/page-protection.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index e02f443850..d5088493ea 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -28,7 +28,7 @@ #include "qemu/timer.h" #include "exec/exec-all.h" #include "exec/cputlb.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/target_page.h" #include "qapi/error.h" #include "tcg_s390x.h" diff --git a/target/s390x/tcg/vec_helper.c b/target/s390x/tcg/vec_helper.c index dafc4c3582..781ccc565b 100644 --- a/target/s390x/tcg/vec_helper.c +++ b/target/s390x/tcg/vec_helper.c @@ -16,7 +16,7 @@ #include "tcg/tcg.h" #include "tcg/tcg-gvec-desc.h" #include "exec/helper-proto.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/exec-all.h" void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3, diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index 99394b714c..e7fcad3c1b 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -20,7 +20,7 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" #ifndef CONFIG_USER_ONLY diff --git a/target/sparc/int32_helper.c b/target/sparc/int32_helper.c index f026606102..39db4ffa70 100644 --- a/target/sparc/int32_helper.c +++ b/target/sparc/int32_helper.c @@ -21,7 +21,7 @@ #include "qemu/main-loop.h" #include "cpu.h" #include "trace.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "exec/log.h" #include "system/runstate.h" diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 3fa5e78816..4c5dba19d1 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -27,7 +27,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "system/memory.h" #ifdef CONFIG_USER_ONLY #include "user/page-protection.h" diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index a0d5a0da1d..ae559b6922 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -19,7 +19,7 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include /* for crc32 */ diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 5c7ed395ca..7cd26d8eab 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -22,7 +22,7 @@ #include "cpu.h" #include "exec/exec-all.h" #include "tcg/tcg-op.h" -#include "exec/cpu_ldst.h" +#include "accel/tcg/cpu-ldst.h" #include "qemu/qemu-print.h" #include "exec/helper-proto.h" From d864cbb65da2220038a9b3aff98ae7f73a3198d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 1 Apr 2025 10:27:42 +0200 Subject: [PATCH 0211/2760] exec: Do not include 'accel/tcg/cpu-ldst.h' in 'exec-all.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only 2 files requiring "accel/tcg/cpu-ldst.h" API do not include it: - accel/tcg/cpu-exec.c - target/arm/tcg/sve_helper.c Include it there and remove it from "exec/exec-all.h". Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + include/exec/exec-all.h | 3 --- target/arm/tcg/sve_helper.c | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 5ced3879ac..b00f046b29 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "qapi/type-helpers.h" #include "hw/core/cpu.h" +#include "accel/tcg/cpu-ldst.h" #include "accel/tcg/cpu-ops.h" #include "trace.h" #include "disas/disas.h" diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 70608a11b6..944b579d91 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -20,9 +20,6 @@ #ifndef EXEC_ALL_H #define EXEC_ALL_H -#if defined(CONFIG_USER_ONLY) -#include "accel/tcg/cpu-ldst.h" -#endif #include "exec/mmu-access-type.h" #include "exec/translation-block.h" diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index 9b0d40c9e1..87b6b4b3e6 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -30,6 +30,7 @@ #include "tcg/tcg.h" #include "vec_internal.h" #include "sve_ldst_internal.h" +#include "accel/tcg/cpu-ldst.h" #include "accel/tcg/cpu-ops.h" #ifdef CONFIG_USER_ONLY #include "user/page-protection.h" From c2ba9fea42391c316794c78f0f6f01760b1fb0f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 12:10:45 +0100 Subject: [PATCH 0212/2760] tcg: Always define TCG_GUEST_DEFAULT_MO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only require the TCG_GUEST_DEFAULT_MO for MTTCG-enabled frontends, otherwise we use a default value of TCG_MO_ALL. In order to simplify, require the definition for all targets, defining it for hexagon, m68k, rx, sh4 and tricore. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 4 ---- target/hexagon/cpu-param.h | 3 +++ target/m68k/cpu-param.h | 3 +++ target/rx/cpu-param.h | 3 +++ target/sh4/cpu-param.h | 3 +++ target/tricore/cpu-param.h | 3 +++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c5590eb695..7467255f6e 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -353,11 +353,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; #endif tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; -#ifdef TCG_GUEST_DEFAULT_MO tcg_ctx->guest_mo = TCG_GUEST_DEFAULT_MO; -#else - tcg_ctx->guest_mo = TCG_MO_ALL; -#endif restart_translate: trace_translate_block(tb, pc, tb->tc.ptr); diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 635d509e74..7cc63a01d4 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -25,4 +25,7 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 +/* MTTCG not yet supported: require strict ordering */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + #endif diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h index 256a2b5f8b..10a8d74bfa 100644 --- a/target/m68k/cpu-param.h +++ b/target/m68k/cpu-param.h @@ -19,4 +19,7 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 +/* MTTCG not yet supported: require strict ordering */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + #endif diff --git a/target/rx/cpu-param.h b/target/rx/cpu-param.h index 84934f3bca..fe39a77ca3 100644 --- a/target/rx/cpu-param.h +++ b/target/rx/cpu-param.h @@ -26,4 +26,7 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 +/* MTTCG not yet supported: require strict ordering */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + #endif diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h index f328715ee8..acdf239749 100644 --- a/target/sh4/cpu-param.h +++ b/target/sh4/cpu-param.h @@ -18,4 +18,7 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 +/* MTTCG not yet supported: require strict ordering */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + #endif diff --git a/target/tricore/cpu-param.h b/target/tricore/cpu-param.h index eb33a67c41..45fde756b6 100644 --- a/target/tricore/cpu-param.h +++ b/target/tricore/cpu-param.h @@ -14,4 +14,7 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 +/* MTTCG not yet supported: require strict ordering */ +#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL + #endif From adb86e48ad3db9031a5963e03a8be2e2798bf9d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 12:16:28 +0100 Subject: [PATCH 0213/2760] tcg: Simplify tcg_req_mo() macro MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that TCG_GUEST_DEFAULT_MO is always defined, simplify the tcg_req_mo() macro. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/internal-target.h | 9 +-------- accel/tcg/tcg-all.c | 3 --- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 05abaeb8e0..1a46a7c87d 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -52,17 +52,10 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); * memory ordering vs the host memory ordering. A non-zero * result indicates that some barrier is required. * - * If TCG_GUEST_DEFAULT_MO is not defined, assume that the - * guest requires strict ordering. - * * This is a macro so that it's constant even without optimization. */ -#ifdef TCG_GUEST_DEFAULT_MO -# define tcg_req_mo(type) \ +#define tcg_req_mo(type) \ ((type) & TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) -#else -# define tcg_req_mo(type) ((type) & ~TCG_TARGET_DEFAULT_MO) -#endif /** * cpu_req_mo: diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 7a5b810b88..a5a1fd6a11 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -77,9 +77,6 @@ static bool default_mttcg_enabled(void) return false; } #ifdef TARGET_SUPPORTS_MTTCG -# ifndef TCG_GUEST_DEFAULT_MO -# error "TARGET_SUPPORTS_MTTCG without TCG_GUEST_DEFAULT_MO" -# endif return true; #else return false; From 04583ce7e032ee8e0a12756b69dc67ad7b399997 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 19:01:52 +0100 Subject: [PATCH 0214/2760] tcg: Define guest_default_memory_order in TCGCPUOps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the TCGCPUOps::guest_default_memory_order field and have each target initialize it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/accel/tcg/cpu-ops.h | 8 ++++++++ target/alpha/cpu.c | 2 ++ target/arm/cpu.c | 2 ++ target/arm/tcg/cpu-v7m.c | 2 ++ target/avr/cpu.c | 1 + target/hexagon/cpu.c | 1 + target/hppa/cpu.c | 2 ++ target/i386/tcg/tcg-cpu.c | 1 + target/loongarch/cpu.c | 2 ++ target/m68k/cpu.c | 2 ++ target/microblaze/cpu.c | 2 ++ target/mips/cpu.c | 2 ++ target/openrisc/cpu.c | 2 ++ target/ppc/cpu_init.c | 1 + target/riscv/tcg/tcg-cpu.c | 2 ++ target/rx/cpu.c | 2 ++ target/s390x/cpu.c | 2 ++ target/sh4/cpu.c | 2 ++ target/sparc/cpu.c | 2 ++ target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 2 ++ 21 files changed, 43 insertions(+) diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 106a0688da..a4932fc5d7 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -16,8 +16,16 @@ #include "exec/memop.h" #include "exec/mmu-access-type.h" #include "exec/vaddr.h" +#include "tcg/tcg-mo.h" struct TCGCPUOps { + + /** + * @guest_default_memory_order: default barrier that is required + * for the guest memory ordering. + */ + TCGBar guest_default_memory_order; + /** * @initialize: Initialize TCG state * diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 99d839a279..6f931117a2 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -235,6 +235,8 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps alpha_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = alpha_translate_init, .translate_code = alpha_translate_code, .synchronize_from_tb = alpha_cpu_synchronize_from_tb, diff --git a/target/arm/cpu.c b/target/arm/cpu.c index c9e043bc9b..3f20e258fd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2671,6 +2671,8 @@ static const struct SysemuCPUOps arm_sysemu_ops = { #ifdef CONFIG_TCG static const TCGCPUOps arm_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = arm_translate_init, .translate_code = arm_translate_code, .synchronize_from_tb = arm_cpu_synchronize_from_tb, diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 1a913faa50..4553fe9de0 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -232,6 +232,8 @@ static void cortex_m55_initfn(Object *obj) } static const TCGCPUOps arm_v7m_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = arm_translate_init, .translate_code = arm_translate_code, .synchronize_from_tb = arm_cpu_synchronize_from_tb, diff --git a/target/avr/cpu.c b/target/avr/cpu.c index feb73e722b..67918684fa 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -224,6 +224,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps avr_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, .initialize = avr_cpu_tcg_init, .translate_code = avr_cpu_translate_code, .synchronize_from_tb = avr_cpu_synchronize_from_tb, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index ad1f303fbc..b12e0dccd0 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -325,6 +325,7 @@ static void hexagon_cpu_init(Object *obj) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps hexagon_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, .initialize = hexagon_translate_init, .translate_code = hexagon_translate_code, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 51bff0c5d6..ac4560febe 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -253,6 +253,8 @@ static const struct SysemuCPUOps hppa_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps hppa_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = hppa_translate_init, .translate_code = hppa_translate_code, .synchronize_from_tb = hppa_cpu_synchronize_from_tb, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 35b17f2b18..3e1b315340 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -125,6 +125,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps x86_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, .initialize = tcg_x86_init, .translate_code = x86_translate_code, .synchronize_from_tb = x86_cpu_synchronize_from_tb, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 4cc8e02f70..ee74509a66 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -864,6 +864,8 @@ static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps loongarch_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = loongarch_translate_init, .translate_code = loongarch_translate_code, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 4409d8941c..bfde9b8594 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -589,6 +589,8 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps m68k_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = m68k_tcg_init, .translate_code = m68k_translate_code, .restore_state_to_opc = m68k_restore_state_to_opc, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index d10ae0702a..e46863574c 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -427,6 +427,8 @@ static const struct SysemuCPUOps mb_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps mb_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = mb_tcg_init, .translate_code = mb_translate_code, .synchronize_from_tb = mb_cpu_synchronize_from_tb, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index cb0d6dde0e..67a8550cc1 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -551,6 +551,8 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) } static const TCGCPUOps mips_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = mips_tcg_init, .translate_code = mips_translate_code, .synchronize_from_tb = mips_cpu_synchronize_from_tb, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index dc55594a7d..e62c698a40 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -243,6 +243,8 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps openrisc_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = openrisc_translate_init, .translate_code = openrisc_translate_code, .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index fd8c42069e..1cf18e0dae 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7479,6 +7479,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps ppc_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, .initialize = ppc_translate_init, .translate_code = ppc_translate_code, .restore_state_to_opc = ppc_restore_state_to_opc, diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 5d0429b4d0..ded2d68ad7 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -140,6 +140,8 @@ static void riscv_restore_state_to_opc(CPUState *cs, } static const TCGCPUOps riscv_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = riscv_translate_init, .translate_code = riscv_translate_code, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index e14d9cbef9..d7eac551fd 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -204,6 +204,8 @@ static const struct SysemuCPUOps rx_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps rx_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = rx_translate_init, .translate_code = rx_translate_code, .synchronize_from_tb = rx_cpu_synchronize_from_tb, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index d15b1943e0..f232d82fa3 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -345,6 +345,8 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, } static const TCGCPUOps s390_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = s390x_translate_init, .translate_code = s390x_translate_code, .restore_state_to_opc = s390x_restore_state_to_opc, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index df093988cb..29f4be7ba9 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -262,6 +262,8 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps superh_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = sh4_translate_init, .translate_code = sh4_translate_code, .synchronize_from_tb = superh_cpu_synchronize_from_tb, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index af3cec43e7..ef04efcb18 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1001,6 +1001,8 @@ static const struct SysemuCPUOps sparc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps sparc_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = sparc_tcg_init, .translate_code = sparc_translate_code, .synchronize_from_tb = sparc_cpu_synchronize_from_tb, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 833a93d37a..3bf399335a 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -172,6 +172,7 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps tricore_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, .initialize = tricore_tcg_init, .translate_code = tricore_translate_code, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 51f9ee9e89..2347106495 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -232,6 +232,8 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps xtensa_tcg_ops = { + .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .initialize = xtensa_translate_init, .translate_code = xtensa_translate_code, .debug_excp_handler = xtensa_breakpoint_handler, From 9c1f8062d4d0ee47981bf1aead1b877bdf08296e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 19:05:31 +0100 Subject: [PATCH 0215/2760] tcg: Remove use of TCG_GUEST_DEFAULT_MO in tb_gen_code() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use TCGCPUOps::guest_default_memory_order to set TCGContext::guest_mo. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 7467255f6e..c007b9a190 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -353,7 +353,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; #endif tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; - tcg_ctx->guest_mo = TCG_GUEST_DEFAULT_MO; + tcg_ctx->guest_mo = cpu->cc->tcg_ops->guest_default_memory_order; restart_translate: trace_translate_block(tb, pc, tb->tc.ptr); From eacd8c7cef297bafa53deaf8d9b9d368acff3936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 18:52:37 +0100 Subject: [PATCH 0216/2760] tcg: Propagate CPUState argument to cpu_req_mo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of having tcg_req_mo() access CPUState in the next commit, pass it to cpu_req_mo(), its single caller. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 20 ++++++++++---------- accel/tcg/internal-target.h | 3 ++- accel/tcg/user-exec.c | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 2cafd38d2a..35b1ff03a5 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2324,7 +2324,7 @@ static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, MMULookupLocals l; bool crosspage; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); tcg_debug_assert(!crosspage); @@ -2339,7 +2339,7 @@ static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uint16_t ret; uint8_t a, b; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_2(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2363,7 +2363,7 @@ static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, bool crosspage; uint32_t ret; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_4(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2384,7 +2384,7 @@ static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, bool crosspage; uint64_t ret; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(cpu, addr, oi, ra, access_type, &l); if (likely(!crosspage)) { return do_ld_8(cpu, &l.page[0], l.mmu_idx, access_type, l.memop, ra); @@ -2407,7 +2407,7 @@ static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, Int128 ret; int first; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_LOAD, &l); if (likely(!crosspage)) { if (unlikely(l.page[0].flags & TLB_MMIO)) { @@ -2735,7 +2735,7 @@ static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, MMULookupLocals l; bool crosspage; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); tcg_debug_assert(!crosspage); @@ -2749,7 +2749,7 @@ static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, bool crosspage; uint8_t a, b; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_2(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2771,7 +2771,7 @@ static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, MMULookupLocals l; bool crosspage; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_4(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2792,7 +2792,7 @@ static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, MMULookupLocals l; bool crosspage; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { do_st_8(cpu, &l.page[0], val, l.mmu_idx, l.memop, ra); @@ -2815,7 +2815,7 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, uint64_t a, b; int first; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); crosspage = mmu_lookup(cpu, addr, oi, ra, MMU_DATA_STORE, &l); if (likely(!crosspage)) { if (unlikely(l.page[0].flags & TLB_MMIO)) { diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 1a46a7c87d..23aac39b57 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -59,12 +59,13 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); /** * cpu_req_mo: + * @cpu: CPUState * @type: TCGBar * * If tcg_req_mo indicates a barrier for @type is required * for the guest memory model, issue a host memory barrier. */ -#define cpu_req_mo(type) \ +#define cpu_req_mo(cpu, type) \ do { \ if (tcg_req_mo(type)) { \ smp_mb(); \ diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 1b878ead7a..3f4d682446 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -1061,7 +1061,7 @@ static uint8_t do_ld1_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, void *haddr; uint8_t ret; - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, access_type); ret = ldub_p(haddr); clear_helper_retaddr(); @@ -1075,7 +1075,7 @@ static uint16_t do_ld2_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uint16_t ret; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); ret = load_atom_2(cpu, ra, haddr, mop); clear_helper_retaddr(); @@ -1093,7 +1093,7 @@ static uint32_t do_ld4_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uint32_t ret; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); ret = load_atom_4(cpu, ra, haddr, mop); clear_helper_retaddr(); @@ -1111,7 +1111,7 @@ static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uint64_t ret; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, access_type); ret = load_atom_8(cpu, ra, haddr, mop); clear_helper_retaddr(); @@ -1130,7 +1130,7 @@ static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr, MemOp mop = get_memop(oi); tcg_debug_assert((mop & MO_SIZE) == MO_128); - cpu_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD); + cpu_req_mo(cpu, TCG_MO_LD_LD | TCG_MO_ST_LD); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_LOAD); ret = load_atom_16(cpu, ra, haddr, mop); clear_helper_retaddr(); @@ -1146,7 +1146,7 @@ static void do_st1_mmu(CPUState *cpu, vaddr addr, uint8_t val, { void *haddr; - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(cpu, addr, get_memop(oi), ra, MMU_DATA_STORE); stb_p(haddr, val); clear_helper_retaddr(); @@ -1158,7 +1158,7 @@ static void do_st2_mmu(CPUState *cpu, vaddr addr, uint16_t val, void *haddr; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1174,7 +1174,7 @@ static void do_st4_mmu(CPUState *cpu, vaddr addr, uint32_t val, void *haddr; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1190,7 +1190,7 @@ static void do_st8_mmu(CPUState *cpu, vaddr addr, uint64_t val, void *haddr; MemOp mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { @@ -1206,7 +1206,7 @@ static void do_st16_mmu(CPUState *cpu, vaddr addr, Int128 val, void *haddr; MemOpIdx mop = get_memop(oi); - cpu_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); + cpu_req_mo(cpu, TCG_MO_LD_ST | TCG_MO_ST_ST); haddr = cpu_mmu_lookup(cpu, addr, mop, ra, MMU_DATA_STORE); if (mop & MO_BSWAP) { From 0eca13c29a0823850cf3308528b0de0ed4608c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 12:18:26 +0100 Subject: [PATCH 0217/2760] tcg: Have tcg_req_mo() use TCGCPUOps::guest_default_memory_order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to use TCG with multiple targets, replace the compile time use of TCG_GUEST_DEFAULT_MO by a runtime access to TCGCPUOps::guest_default_memory_order via CPUState. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/internal-target.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index 23aac39b57..f5a3fd7e40 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -46,16 +46,15 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); /** * tcg_req_mo: + * @guest_mo: Guest default memory order * @type: TCGBar * * Filter @type to the barrier that is required for the guest * memory ordering vs the host memory ordering. A non-zero * result indicates that some barrier is required. - * - * This is a macro so that it's constant even without optimization. */ -#define tcg_req_mo(type) \ - ((type) & TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO) +#define tcg_req_mo(guest_mo, type) \ + ((type) & guest_mo & ~TCG_TARGET_DEFAULT_MO) /** * cpu_req_mo: @@ -67,7 +66,7 @@ G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); */ #define cpu_req_mo(cpu, type) \ do { \ - if (tcg_req_mo(type)) { \ + if (tcg_req_mo(cpu->cc->tcg_ops->guest_default_memory_order, type)) { \ smp_mb(); \ } \ } while (0) From 8201f1a29c95bca095bdd6e6c6eba42d8d06499b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 21 Mar 2025 19:02:35 +0100 Subject: [PATCH 0218/2760] tcg: Remove the TCG_GUEST_DEFAULT_MO definition globally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By directly using TCGCPUOps::guest_default_memory_order, we don't need the TCG_GUEST_DEFAULT_MO definition anymore. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/multi-thread-tcg.rst | 4 ++-- target/alpha/cpu-param.h | 3 --- target/alpha/cpu.c | 3 ++- target/arm/cpu-param.h | 3 --- target/arm/cpu.c | 3 ++- target/arm/tcg/cpu-v7m.c | 3 ++- target/avr/cpu-param.h | 2 -- target/avr/cpu.c | 2 +- target/hexagon/cpu-param.h | 3 --- target/hexagon/cpu.c | 3 ++- target/hppa/cpu-param.h | 8 -------- target/hppa/cpu.c | 8 +++++++- target/i386/cpu-param.h | 3 --- target/i386/tcg/tcg-cpu.c | 5 ++++- target/loongarch/cpu-param.h | 2 -- target/loongarch/cpu.c | 2 +- target/m68k/cpu-param.h | 3 --- target/m68k/cpu.c | 3 ++- target/microblaze/cpu-param.h | 3 --- target/microblaze/cpu.c | 3 ++- target/mips/cpu-param.h | 2 -- target/mips/cpu.c | 2 +- target/openrisc/cpu-param.h | 2 -- target/openrisc/cpu.c | 2 +- target/ppc/cpu-param.h | 2 -- target/ppc/cpu_init.c | 2 +- target/riscv/cpu-param.h | 2 -- target/riscv/tcg/tcg-cpu.c | 2 +- target/rx/cpu-param.h | 3 --- target/rx/cpu.c | 3 ++- target/s390x/cpu-param.h | 6 ------ target/s390x/cpu.c | 6 +++++- target/sh4/cpu-param.h | 3 --- target/sh4/cpu.c | 3 ++- target/sparc/cpu-param.h | 23 ----------------------- target/sparc/cpu.c | 23 ++++++++++++++++++++++- target/tricore/cpu-param.h | 3 --- target/tricore/cpu.c | 3 ++- target/xtensa/cpu-param.h | 3 --- target/xtensa/cpu.c | 3 ++- 40 files changed, 66 insertions(+), 101 deletions(-) diff --git a/docs/devel/multi-thread-tcg.rst b/docs/devel/multi-thread-tcg.rst index b0f473961d..14a2a9dc7b 100644 --- a/docs/devel/multi-thread-tcg.rst +++ b/docs/devel/multi-thread-tcg.rst @@ -28,8 +28,8 @@ vCPU Scheduling We introduce a new running mode where each vCPU will run on its own user-space thread. This is enabled by default for all FE/BE combinations where the host memory model is able to accommodate the -guest (TCG_GUEST_DEFAULT_MO & ~TCG_TARGET_DEFAULT_MO is zero) and the -guest has had the required work done to support this safely +guest (TCGCPUOps::guest_default_memory_order & ~TCG_TARGET_DEFAULT_MO is zero) +and the guest has had the required work done to support this safely (TARGET_SUPPORTS_MTTCG). System emulation will fall back to the original round robin approach diff --git a/target/alpha/cpu-param.h b/target/alpha/cpu-param.h index dd44feb179..a799f42db3 100644 --- a/target/alpha/cpu-param.h +++ b/target/alpha/cpu-param.h @@ -26,7 +26,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -/* Alpha processors have a weak memory model */ -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 6f931117a2..eeaf3a81c1 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -235,7 +235,8 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps alpha_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* Alpha processors have a weak memory model */ + .guest_default_memory_order = 0, .initialize = alpha_translate_init, .translate_code = alpha_translate_code, diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 2cee4be693..5c5bc8a009 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -44,7 +44,4 @@ */ #define TARGET_INSN_START_EXTRA_WORDS 2 -/* ARM processors have a weak memory model */ -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3f20e258fd..3e9760b551 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2671,7 +2671,8 @@ static const struct SysemuCPUOps arm_sysemu_ops = { #ifdef CONFIG_TCG static const TCGCPUOps arm_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* ARM processors have a weak memory model */ + .guest_default_memory_order = 0, .initialize = arm_translate_init, .translate_code = arm_translate_code, diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 4553fe9de0..89d4e4b4a2 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -232,7 +232,8 @@ static void cortex_m55_initfn(Object *obj) } static const TCGCPUOps arm_v7m_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* ARM processors have a weak memory model */ + .guest_default_memory_order = 0, .initialize = arm_translate_init, .translate_code = arm_translate_code, diff --git a/target/avr/cpu-param.h b/target/avr/cpu-param.h index 9d37848d97..f74bfc2580 100644 --- a/target/avr/cpu-param.h +++ b/target/avr/cpu-param.h @@ -27,6 +27,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -#define TCG_GUEST_DEFAULT_MO 0 - #endif diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 67918684fa..8f79cf4c08 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -224,7 +224,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps avr_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = avr_cpu_tcg_init, .translate_code = avr_cpu_translate_code, .synchronize_from_tb = avr_cpu_synchronize_from_tb, diff --git a/target/hexagon/cpu-param.h b/target/hexagon/cpu-param.h index 7cc63a01d4..635d509e74 100644 --- a/target/hexagon/cpu-param.h +++ b/target/hexagon/cpu-param.h @@ -25,7 +25,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -/* MTTCG not yet supported: require strict ordering */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index b12e0dccd0..3d14e5cc6a 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -325,7 +325,8 @@ static void hexagon_cpu_init(Object *obj) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps hexagon_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MTTCG not yet supported: require strict ordering */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = hexagon_translate_init, .translate_code = hexagon_translate_code, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, diff --git a/target/hppa/cpu-param.h b/target/hppa/cpu-param.h index 68ed84e84a..9bf7ac76d0 100644 --- a/target/hppa/cpu-param.h +++ b/target/hppa/cpu-param.h @@ -21,12 +21,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 2 -/* PA-RISC 1.x processors have a strong memory model. */ -/* - * ??? While we do not yet implement PA-RISC 2.0, those processors have - * a weak memory model, but with TLB bits that force ordering on a per-page - * basis. It's probably easier to fall back to a strong memory model. - */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index ac4560febe..dfbd933056 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -253,7 +253,13 @@ static const struct SysemuCPUOps hppa_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps hppa_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* PA-RISC 1.x processors have a strong memory model. */ + /* + * ??? While we do not yet implement PA-RISC 2.0, those processors have + * a weak memory model, but with TLB bits that force ordering on a per-page + * basis. It's probably easier to fall back to a strong memory model. + */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = hppa_translate_init, .translate_code = hppa_translate_code, diff --git a/target/i386/cpu-param.h b/target/i386/cpu-param.h index 0c8efce861..ebb844bcc8 100644 --- a/target/i386/cpu-param.h +++ b/target/i386/cpu-param.h @@ -24,7 +24,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -/* The x86 has a strong memory model with some store-after-load re-ordering */ -#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) - #endif diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 3e1b315340..d941df0956 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -125,7 +125,10 @@ static bool x86_debug_check_breakpoint(CPUState *cs) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps x86_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* + * The x86 has a strong memory model with some store-after-load re-ordering + */ + .guest_default_memory_order = TCG_MO_ALL & ~TCG_MO_ST_LD, .initialize = tcg_x86_init, .translate_code = x86_translate_code, .synchronize_from_tb = x86_cpu_synchronize_from_tb, diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h index dbe414bb35..58cc45a377 100644 --- a/target/loongarch/cpu-param.h +++ b/target/loongarch/cpu-param.h @@ -15,6 +15,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index ee74509a66..f5b8ef29ab 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -864,7 +864,7 @@ static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) #include "accel/tcg/cpu-ops.h" static const TCGCPUOps loongarch_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = loongarch_translate_init, .translate_code = loongarch_translate_code, diff --git a/target/m68k/cpu-param.h b/target/m68k/cpu-param.h index 10a8d74bfa..256a2b5f8b 100644 --- a/target/m68k/cpu-param.h +++ b/target/m68k/cpu-param.h @@ -19,7 +19,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -/* MTTCG not yet supported: require strict ordering */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index bfde9b8594..b2d8c8f1de 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -589,7 +589,8 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps m68k_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MTTCG not yet supported: require strict ordering */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = m68k_tcg_init, .translate_code = m68k_translate_code, diff --git a/target/microblaze/cpu-param.h b/target/microblaze/cpu-param.h index 5d55e0e3c4..e0a3794513 100644 --- a/target/microblaze/cpu-param.h +++ b/target/microblaze/cpu-param.h @@ -29,7 +29,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -/* MicroBlaze is always in-order. */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index e46863574c..4efba0dddb 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -427,7 +427,8 @@ static const struct SysemuCPUOps mb_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps mb_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MicroBlaze is always in-order. */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = mb_tcg_init, .translate_code = mb_translate_code, diff --git a/target/mips/cpu-param.h b/target/mips/cpu-param.h index 99ca8d1684..58f450827f 100644 --- a/target/mips/cpu-param.h +++ b/target/mips/cpu-param.h @@ -22,6 +22,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 2 -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 67a8550cc1..2ae7ba4407 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -551,7 +551,7 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) } static const TCGCPUOps mips_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = mips_tcg_init, .translate_code = mips_translate_code, diff --git a/target/openrisc/cpu-param.h b/target/openrisc/cpu-param.h index 7ea0ecb55a..b4f57bbe69 100644 --- a/target/openrisc/cpu-param.h +++ b/target/openrisc/cpu-param.h @@ -14,6 +14,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index e62c698a40..87fe779042 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -243,7 +243,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps openrisc_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = openrisc_translate_init, .translate_code = openrisc_translate_code, diff --git a/target/ppc/cpu-param.h b/target/ppc/cpu-param.h index d0651d2ac8..e4ed9080ee 100644 --- a/target/ppc/cpu-param.h +++ b/target/ppc/cpu-param.h @@ -39,6 +39,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -#define TCG_GUEST_DEFAULT_MO 0 - #endif diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 1cf18e0dae..9ba775971a 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7479,7 +7479,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps ppc_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = ppc_translate_init, .translate_code = ppc_translate_code, .restore_state_to_opc = ppc_restore_state_to_opc, diff --git a/target/riscv/cpu-param.h b/target/riscv/cpu-param.h index ff4ba81965..cfdc67c258 100644 --- a/target/riscv/cpu-param.h +++ b/target/riscv/cpu-param.h @@ -34,6 +34,4 @@ * - M mode HLV/HLVX/HSV 0b111 */ -#define TCG_GUEST_DEFAULT_MO 0 - #endif diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index ded2d68ad7..50e81b2e52 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -140,7 +140,7 @@ static void riscv_restore_state_to_opc(CPUState *cs, } static const TCGCPUOps riscv_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + .guest_default_memory_order = 0, .initialize = riscv_translate_init, .translate_code = riscv_translate_code, diff --git a/target/rx/cpu-param.h b/target/rx/cpu-param.h index fe39a77ca3..84934f3bca 100644 --- a/target/rx/cpu-param.h +++ b/target/rx/cpu-param.h @@ -26,7 +26,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -/* MTTCG not yet supported: require strict ordering */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/rx/cpu.c b/target/rx/cpu.c index d7eac551fd..f073fe8fc9 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -204,7 +204,8 @@ static const struct SysemuCPUOps rx_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps rx_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MTTCG not yet supported: require strict ordering */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = rx_translate_init, .translate_code = rx_translate_code, diff --git a/target/s390x/cpu-param.h b/target/s390x/cpu-param.h index a8a4377f4f..abfae3bedf 100644 --- a/target/s390x/cpu-param.h +++ b/target/s390x/cpu-param.h @@ -14,10 +14,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 2 -/* - * The z/Architecture has a strong memory model with some - * store-after-load re-ordering. - */ -#define TCG_GUEST_DEFAULT_MO (TCG_MO_ALL & ~TCG_MO_ST_LD) - #endif diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index f232d82fa3..1e101b5afe 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -345,7 +345,11 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, } static const TCGCPUOps s390_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* + * The z/Architecture has a strong memory model with some + * store-after-load re-ordering. + */ + .guest_default_memory_order = TCG_MO_ALL & ~TCG_MO_ST_LD, .initialize = s390x_translate_init, .translate_code = s390x_translate_code, diff --git a/target/sh4/cpu-param.h b/target/sh4/cpu-param.h index acdf239749..f328715ee8 100644 --- a/target/sh4/cpu-param.h +++ b/target/sh4/cpu-param.h @@ -18,7 +18,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -/* MTTCG not yet supported: require strict ordering */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 29f4be7ba9..7a05301c6f 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -262,7 +262,8 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps superh_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MTTCG not yet supported: require strict ordering */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = sh4_translate_init, .translate_code = sh4_translate_code, diff --git a/target/sparc/cpu-param.h b/target/sparc/cpu-param.h index 62d47b804b..45eea9d6ba 100644 --- a/target/sparc/cpu-param.h +++ b/target/sparc/cpu-param.h @@ -23,27 +23,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 1 -/* - * From Oracle SPARC Architecture 2015: - * - * Compatibility notes: The PSO memory model described in SPARC V8 and - * SPARC V9 compatibility architecture specifications was never implemented - * in a SPARC V9 implementation and is not included in the Oracle SPARC - * Architecture specification. - * - * The RMO memory model described in the SPARC V9 specification was - * implemented in some non-Sun SPARC V9 implementations, but is not - * directly supported in Oracle SPARC Architecture 2015 implementations. - * - * Therefore always use TSO in QEMU. - * - * D.5 Specification of Partial Store Order (PSO) - * ... [loads] are followed by an implied MEMBAR #LoadLoad | #LoadStore. - * - * D.6 Specification of Total Store Order (TSO) - * ... PSO with the additional requirement that all [stores] are followed - * by an implied MEMBAR #StoreStore. - */ -#define TCG_GUEST_DEFAULT_MO (TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST) - #endif diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index ef04efcb18..56d9417ae3 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1001,7 +1001,28 @@ static const struct SysemuCPUOps sparc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps sparc_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* + * From Oracle SPARC Architecture 2015: + * + * Compatibility notes: The PSO memory model described in SPARC V8 and + * SPARC V9 compatibility architecture specifications was never + * implemented in a SPARC V9 implementation and is not included in the + * Oracle SPARC Architecture specification. + * + * The RMO memory model described in the SPARC V9 specification was + * implemented in some non-Sun SPARC V9 implementations, but is not + * directly supported in Oracle SPARC Architecture 2015 implementations. + * + * Therefore always use TSO in QEMU. + * + * D.5 Specification of Partial Store Order (PSO) + * ... [loads] are followed by an implied MEMBAR #LoadLoad | #LoadStore. + * + * D.6 Specification of Total Store Order (TSO) + * ... PSO with the additional requirement that all [stores] are followed + * by an implied MEMBAR #StoreStore. + */ + .guest_default_memory_order = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST, .initialize = sparc_tcg_init, .translate_code = sparc_translate_code, diff --git a/target/tricore/cpu-param.h b/target/tricore/cpu-param.h index 45fde756b6..eb33a67c41 100644 --- a/target/tricore/cpu-param.h +++ b/target/tricore/cpu-param.h @@ -14,7 +14,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -/* MTTCG not yet supported: require strict ordering */ -#define TCG_GUEST_DEFAULT_MO TCG_MO_ALL - #endif diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 3bf399335a..c68954b409 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -172,7 +172,8 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps tricore_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* MTTCG not yet supported: require strict ordering */ + .guest_default_memory_order = TCG_MO_ALL, .initialize = tricore_tcg_init, .translate_code = tricore_translate_code, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, diff --git a/target/xtensa/cpu-param.h b/target/xtensa/cpu-param.h index e7cb747aaa..7a0c22c900 100644 --- a/target/xtensa/cpu-param.h +++ b/target/xtensa/cpu-param.h @@ -18,7 +18,4 @@ #define TARGET_INSN_START_EXTRA_WORDS 0 -/* Xtensa processors have a weak memory model */ -#define TCG_GUEST_DEFAULT_MO (0) - #endif diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 2347106495..2cbf4e3010 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -232,7 +232,8 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps xtensa_tcg_ops = { - .guest_default_memory_order = TCG_GUEST_DEFAULT_MO, + /* Xtensa processors have a weak memory model */ + .guest_default_memory_order = 0, .initialize = xtensa_translate_init, .translate_code = xtensa_translate_code, From 9638cb59ee3d3a505f4bb6b9a4bcc49c3df4edcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 18:45:29 +0100 Subject: [PATCH 0219/2760] tcg: Move cpu_req_mo() macro to target-agnostic 'backend-ldst.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- accel/tcg/backend-ldst.h | 41 +++++++++++++++++++++++++++++++++++++ accel/tcg/cputlb.c | 1 + accel/tcg/internal-target.h | 28 ------------------------- accel/tcg/user-exec.c | 1 + 4 files changed, 43 insertions(+), 28 deletions(-) create mode 100644 accel/tcg/backend-ldst.h diff --git a/accel/tcg/backend-ldst.h b/accel/tcg/backend-ldst.h new file mode 100644 index 0000000000..9c3a407a5a --- /dev/null +++ b/accel/tcg/backend-ldst.h @@ -0,0 +1,41 @@ +/* + * Internal memory barrier helpers for QEMU (target agnostic) + * + * Copyright (c) 2003 Fabrice Bellard + * + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_BACKEND_LDST_H +#define ACCEL_TCG_BACKEND_LDST_H + +#include "tcg-target-mo.h" + +/** + * tcg_req_mo: + * @guest_mo: Guest default memory order + * @type: TCGBar + * + * Filter @type to the barrier that is required for the guest + * memory ordering vs the host memory ordering. A non-zero + * result indicates that some barrier is required. + */ +#define tcg_req_mo(guest_mo, type) \ + ((type) & guest_mo & ~TCG_TARGET_DEFAULT_MO) + +/** + * cpu_req_mo: + * @cpu: CPUState + * @type: TCGBar + * + * If tcg_req_mo indicates a barrier for @type is required + * for the guest memory model, issue a host memory barrier. + */ +#define cpu_req_mo(cpu, type) \ + do { \ + if (tcg_req_mo(cpu->cc->tcg_ops->guest_default_memory_order, type)) { \ + smp_mb(); \ + } \ + } while (0) + +#endif diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 35b1ff03a5..d9fb68d719 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -48,6 +48,7 @@ #include "qemu/plugin-memory.h" #endif #include "tcg/tcg-ldst.h" +#include "backend-ldst.h" /* DEBUG defines, enable DEBUG_TLB_LOG to log to the CPU_LOG_MMU target */ diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h index f5a3fd7e40..9a9cef3140 100644 --- a/accel/tcg/internal-target.h +++ b/accel/tcg/internal-target.h @@ -13,7 +13,6 @@ #include "exec/exec-all.h" #include "exec/translation-block.h" #include "tb-internal.h" -#include "tcg-target-mo.h" #include "exec/mmap-lock.h" /* @@ -44,31 +43,4 @@ void page_table_config_init(void); G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); #endif /* CONFIG_USER_ONLY */ -/** - * tcg_req_mo: - * @guest_mo: Guest default memory order - * @type: TCGBar - * - * Filter @type to the barrier that is required for the guest - * memory ordering vs the host memory ordering. A non-zero - * result indicates that some barrier is required. - */ -#define tcg_req_mo(guest_mo, type) \ - ((type) & guest_mo & ~TCG_TARGET_DEFAULT_MO) - -/** - * cpu_req_mo: - * @cpu: CPUState - * @type: TCGBar - * - * If tcg_req_mo indicates a barrier for @type is required - * for the guest memory model, issue a host memory barrier. - */ -#define cpu_req_mo(cpu, type) \ - do { \ - if (tcg_req_mo(cpu->cc->tcg_ops->guest_default_memory_order, type)) { \ - smp_mb(); \ - } \ - } while (0) - #endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 3f4d682446..5eef8e7f18 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -37,6 +37,7 @@ #include "qemu/int128.h" #include "trace.h" #include "tcg/tcg-ldst.h" +#include "backend-ldst.h" #include "internal-common.h" #include "internal-target.h" #include "tb-internal.h" From a9d107fa0eacf6c999c042b276e54a7058ae0bf9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Apr 2025 16:30:57 -0700 Subject: [PATCH 0220/2760] tcg: Pass max_threads not max_cpus to tcg_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In effect, hoist the check for mttcg from tcg_n_regions() to tcg_init_machine(). Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 14 ++++++++------ include/tcg/startup.h | 6 +++--- tcg/region.c | 27 ++++++++++++--------------- tcg/tcg-internal.h | 2 +- tcg/tcg.c | 14 +++++++------- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index a5a1fd6a11..3efc7350eb 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -103,18 +103,20 @@ bool one_insn_per_tb; static int tcg_init_machine(MachineState *ms) { TCGState *s = TCG_STATE(current_accel()); -#ifdef CONFIG_USER_ONLY - unsigned max_cpus = 1; -#else - unsigned max_cpus = ms->smp.max_cpus; -#endif + unsigned max_threads = 1; tcg_allowed = true; mttcg_enabled = s->mttcg_enabled; page_init(); tb_htable_init(); - tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_cpus); + +#ifndef CONFIG_USER_ONLY + if (mttcg_enabled) { + max_threads = ms->smp.max_cpus; + } +#endif + tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads); #if defined(CONFIG_SOFTMMU) /* diff --git a/include/tcg/startup.h b/include/tcg/startup.h index f71305765c..95f574af2b 100644 --- a/include/tcg/startup.h +++ b/include/tcg/startup.h @@ -29,12 +29,12 @@ * tcg_init: Initialize the TCG runtime * @tb_size: translation buffer size * @splitwx: use separate rw and rx mappings - * @max_cpus: number of vcpus in system mode + * @max_threads: number of vcpu threads in system mode * * Allocate and initialize TCG resources, especially the JIT buffer. - * In user-only mode, @max_cpus is unused. + * In user-only mode, @max_threads is unused. */ -void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus); +void tcg_init(size_t tb_size, int splitwx, unsigned max_threads); /** * tcg_register_thread: Register this thread with the TCG runtime diff --git a/tcg/region.c b/tcg/region.c index 478ec051c4..7ea0b37a84 100644 --- a/tcg/region.c +++ b/tcg/region.c @@ -422,7 +422,7 @@ void tcg_region_reset_all(void) tcg_region_tree_reset_all(); } -static size_t tcg_n_regions(size_t tb_size, unsigned max_cpus) +static size_t tcg_n_regions(size_t tb_size, unsigned max_threads) { #ifdef CONFIG_USER_ONLY return 1; @@ -431,24 +431,25 @@ static size_t tcg_n_regions(size_t tb_size, unsigned max_cpus) /* * It is likely that some vCPUs will translate more code than others, - * so we first try to set more regions than max_cpus, with those regions + * so we first try to set more regions than threads, with those regions * being of reasonable size. If that's not possible we make do by evenly * dividing the code_gen_buffer among the vCPUs. + * + * Use a single region if all we have is one vCPU thread. */ - /* Use a single region if all we have is one vCPU thread */ - if (max_cpus == 1 || !qemu_tcg_mttcg_enabled()) { + if (max_threads == 1) { return 1; } /* - * Try to have more regions than max_cpus, with each region being >= 2 MB. + * Try to have more regions than threads, with each region being >= 2 MB. * If we can't, then just allocate one region per vCPU thread. */ n_regions = tb_size / (2 * MiB); - if (n_regions <= max_cpus) { - return max_cpus; + if (n_regions <= max_threads) { + return max_threads; } - return MIN(n_regions, max_cpus * 8); + return MIN(n_regions, max_threads * 8); #endif } @@ -731,11 +732,7 @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp) * and then assigning regions to TCG threads so that the threads can translate * code in parallel without synchronization. * - * In system-mode the number of TCG threads is bounded by max_cpus, so we use at - * least max_cpus regions in MTTCG. In !MTTCG we use a single region. - * Note that the TCG options from the command-line (i.e. -accel accel=tcg,[...]) - * must have been parsed before calling this function, since it calls - * qemu_tcg_mttcg_enabled(). + * In system-mode the number of TCG threads is bounded by max_threads, * * In user-mode we use a single region. Having multiple regions in user-mode * is not supported, because the number of vCPU threads (recall that each thread @@ -749,7 +746,7 @@ static int alloc_code_gen_buffer(size_t size, int splitwx, Error **errp) * in practice. Multi-threaded guests share most if not all of their translated * code, which makes parallel code generation less appealing than in system-mode */ -void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus) +void tcg_region_init(size_t tb_size, int splitwx, unsigned max_threads) { const size_t page_size = qemu_real_host_page_size(); size_t region_size; @@ -787,7 +784,7 @@ void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus) * As a result of this we might end up with a few extra pages at the end of * the buffer; we will assign those to the last region. */ - region.n = tcg_n_regions(tb_size, max_cpus); + region.n = tcg_n_regions(tb_size, max_threads); region_size = tb_size / region.n; region_size = QEMU_ALIGN_DOWN(region_size, page_size); diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index a648ee7a0e..ff85fb23fa 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -34,7 +34,7 @@ extern TCGContext **tcg_ctxs; extern unsigned int tcg_cur_ctxs; extern unsigned int tcg_max_ctxs; -void tcg_region_init(size_t tb_size, int splitwx, unsigned max_cpus); +void tcg_region_init(size_t tb_size, int splitwx, unsigned max_threads); bool tcg_region_alloc(TCGContext *s); void tcg_region_initial_alloc(TCGContext *s); void tcg_region_prologue_set(TCGContext *s); diff --git a/tcg/tcg.c b/tcg/tcg.c index dfd48b8264..ec7f6743d7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1499,7 +1499,7 @@ static void process_constraint_sets(void); static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type, TCGReg reg, const char *name); -static void tcg_context_init(unsigned max_cpus) +static void tcg_context_init(unsigned max_threads) { TCGContext *s = &tcg_init_ctx; int n, i; @@ -1538,15 +1538,15 @@ static void tcg_context_init(unsigned max_cpus) * In user-mode we simply share the init context among threads, since we * use a single region. See the documentation tcg_region_init() for the * reasoning behind this. - * In system-mode we will have at most max_cpus TCG threads. + * In system-mode we will have at most max_threads TCG threads. */ #ifdef CONFIG_USER_ONLY tcg_ctxs = &tcg_ctx; tcg_cur_ctxs = 1; tcg_max_ctxs = 1; #else - tcg_max_ctxs = max_cpus; - tcg_ctxs = g_new0(TCGContext *, max_cpus); + tcg_max_ctxs = max_threads; + tcg_ctxs = g_new0(TCGContext *, max_threads); #endif tcg_debug_assert(!tcg_regset_test_reg(s->reserved_regs, TCG_AREG0)); @@ -1554,10 +1554,10 @@ static void tcg_context_init(unsigned max_cpus) tcg_env = temp_tcgv_ptr(ts); } -void tcg_init(size_t tb_size, int splitwx, unsigned max_cpus) +void tcg_init(size_t tb_size, int splitwx, unsigned max_threads) { - tcg_context_init(max_cpus); - tcg_region_init(tb_size, splitwx, max_cpus); + tcg_context_init(max_threads); + tcg_region_init(tb_size, splitwx, max_threads); } /* From 60b2c2e66b81c323c0bc70ea4233cdbf8cdae5b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 00:04:16 +0200 Subject: [PATCH 0221/2760] tcg: Move qemu_tcg_mttcg_enabled() to 'system/tcg.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qemu_tcg_mttcg_enabled() is specific to 1/ TCG and 2/ system emulation. Move the prototype declaration to "system/tcg.h", reducing 'mttcg_enabled' variable scope. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-ID: <20250403220420.78937-17-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 17 ++++++++++++++--- include/hw/core/cpu.h | 9 --------- include/system/tcg.h | 8 ++++++++ target/riscv/tcg/tcg-cpu.c | 1 + 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 3efc7350eb..bb759cec07 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -38,6 +38,7 @@ #include "hw/qdev-core.h" #else #include "hw/boards.h" +#include "system/tcg.h" #endif #include "internal-common.h" #include "cpu-param.h" @@ -58,6 +59,17 @@ typedef struct TCGState TCGState; DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE, TYPE_TCG_ACCEL) +#ifndef CONFIG_USER_ONLY + +static bool mttcg_enabled; + +bool qemu_tcg_mttcg_enabled(void) +{ + return mttcg_enabled; +} + +#endif /* !CONFIG_USER_ONLY */ + /* * We default to false if we know other options have been enabled * which are currently incompatible with MTTCG. Otherwise when each @@ -97,7 +109,6 @@ static void tcg_accel_instance_init(Object *obj) #endif } -bool mttcg_enabled; bool one_insn_per_tb; static int tcg_init_machine(MachineState *ms) @@ -106,14 +117,14 @@ static int tcg_init_machine(MachineState *ms) unsigned max_threads = 1; tcg_allowed = true; - mttcg_enabled = s->mttcg_enabled; page_init(); tb_htable_init(); #ifndef CONFIG_USER_ONLY - if (mttcg_enabled) { + if (s->mttcg_enabled) { max_threads = ms->smp.max_cpus; + mttcg_enabled = true; } #endif tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads); diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 10b6b25b34..c8d6abff19 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -594,15 +594,6 @@ extern CPUTailQ cpus_queue; extern __thread CPUState *current_cpu; -/** - * qemu_tcg_mttcg_enabled: - * Check whether we are running MultiThread TCG or not. - * - * Returns: %true if we are in MTTCG mode %false otherwise. - */ -extern bool mttcg_enabled; -#define qemu_tcg_mttcg_enabled() (mttcg_enabled) - /** * cpu_paging_enabled: * @cpu: The CPU whose state is to be inspected. diff --git a/include/system/tcg.h b/include/system/tcg.h index 73229648c6..7622dcea30 100644 --- a/include/system/tcg.h +++ b/include/system/tcg.h @@ -17,4 +17,12 @@ extern bool tcg_allowed; #define tcg_enabled() 0 #endif +/** + * qemu_tcg_mttcg_enabled: + * Check whether we are running MultiThread TCG or not. + * + * Returns: %true if we are in MTTCG mode %false otherwise. + */ +bool qemu_tcg_mttcg_enabled(void); + #endif diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 50e81b2e52..88f7cdb887 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -36,6 +36,7 @@ #include "tcg/tcg.h" #ifndef CONFIG_USER_ONLY #include "hw/boards.h" +#include "system/tcg.h" #endif /* Hash that stores user set extensions */ From 61fc4c2bfaee8f4da75ce217911f103da7a8a69e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Apr 2025 18:10:53 -0700 Subject: [PATCH 0222/2760] accel/tcg: Remove mttcg_enabled In qemu_tcg_mttcg_enabled, read the value from TCGState and eliminate the separate global variable. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index bb759cec07..b754f92905 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -60,14 +60,11 @@ DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE, TYPE_TCG_ACCEL) #ifndef CONFIG_USER_ONLY - -static bool mttcg_enabled; - bool qemu_tcg_mttcg_enabled(void) { - return mttcg_enabled; + TCGState *s = TCG_STATE(current_accel()); + return s->mttcg_enabled; } - #endif /* !CONFIG_USER_ONLY */ /* @@ -124,7 +121,6 @@ static int tcg_init_machine(MachineState *ms) #ifndef CONFIG_USER_ONLY if (s->mttcg_enabled) { max_threads = ms->smp.max_cpus; - mttcg_enabled = true; } #endif tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads); From d1aa577228e6eeda3589c6480d994ee4bd0d23e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Apr 2025 16:48:24 +0200 Subject: [PATCH 0223/2760] tcg: Convert TCGState::mttcg_enabled to TriState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the OnOffAuto type as 3-state. Since the TCGState instance is zero-initialized, the mttcg_enabled is initialzed as AUTO (ON_OFF_AUTO_AUTO). In tcg_init_machine(), if mttcg_enabled is still AUTO, set a default value (effectively inlining the default_mttcg_enabled() method content). In the tcg_get_thread() getter, consider AUTO / OFF states as "single", otherwise ON is "multi". Reviewed-by: Anton Johansson Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 74 ++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index b754f92905..fa77a4c5a2 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -32,6 +32,7 @@ #include "qemu/error-report.h" #include "qemu/accel.h" #include "qemu/atomic.h" +#include "qapi/qapi-types-common.h" #include "qapi/qapi-builtin-visit.h" #include "qemu/units.h" #if defined(CONFIG_USER_ONLY) @@ -47,7 +48,7 @@ struct TCGState { AccelState parent_obj; - bool mttcg_enabled; + OnOffAuto mttcg_enabled; bool one_insn_per_tb; int splitwx_enabled; unsigned long tb_size; @@ -63,41 +64,14 @@ DECLARE_INSTANCE_CHECKER(TCGState, TCG_STATE, bool qemu_tcg_mttcg_enabled(void) { TCGState *s = TCG_STATE(current_accel()); - return s->mttcg_enabled; + return s->mttcg_enabled == ON_OFF_AUTO_ON; } #endif /* !CONFIG_USER_ONLY */ -/* - * We default to false if we know other options have been enabled - * which are currently incompatible with MTTCG. Otherwise when each - * guest (target) has been updated to support: - * - atomic instructions - * - memory ordering primitives (barriers) - * they can set the appropriate CONFIG flags in ${target}-softmmu.mak - * - * Once a guest architecture has been converted to the new primitives - * there is one remaining limitation to check: - * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) - */ - -static bool default_mttcg_enabled(void) -{ - if (icount_enabled()) { - return false; - } -#ifdef TARGET_SUPPORTS_MTTCG - return true; -#else - return false; -#endif -} - static void tcg_accel_instance_init(Object *obj) { TCGState *s = TCG_STATE(obj); - s->mttcg_enabled = default_mttcg_enabled(); - /* If debugging enabled, default "auto on", otherwise off. */ #if defined(CONFIG_DEBUG_TCG) && !defined(CONFIG_USER_ONLY) s->splitwx_enabled = -1; @@ -113,16 +87,40 @@ static int tcg_init_machine(MachineState *ms) TCGState *s = TCG_STATE(current_accel()); unsigned max_threads = 1; +#ifndef CONFIG_USER_ONLY +# ifdef TARGET_SUPPORTS_MTTCG + bool mttcg_supported = true; +# else + bool mttcg_supported = false; +# endif + if (s->mttcg_enabled == ON_OFF_AUTO_AUTO) { + /* + * We default to false if we know other options have been enabled + * which are currently incompatible with MTTCG. Otherwise when each + * guest (target) has been updated to support: + * - atomic instructions + * - memory ordering primitives (barriers) + * they can set the appropriate CONFIG flags in ${target}-softmmu.mak + * + * Once a guest architecture has been converted to the new primitives + * there is one remaining limitation to check: + * - The guest can't be oversized (e.g. 64 bit guest on 32 bit host) + */ + if (mttcg_supported && !icount_enabled()) { + s->mttcg_enabled = ON_OFF_AUTO_ON; + } else { + s->mttcg_enabled = ON_OFF_AUTO_OFF; + } + } + if (s->mttcg_enabled == ON_OFF_AUTO_ON) { + max_threads = ms->smp.max_cpus; + } +#endif + tcg_allowed = true; page_init(); tb_htable_init(); - -#ifndef CONFIG_USER_ONLY - if (s->mttcg_enabled) { - max_threads = ms->smp.max_cpus; - } -#endif tcg_init(s->tb_size * MiB, s->splitwx_enabled, max_threads); #if defined(CONFIG_SOFTMMU) @@ -144,7 +142,7 @@ static char *tcg_get_thread(Object *obj, Error **errp) { TCGState *s = TCG_STATE(obj); - return g_strdup(s->mttcg_enabled ? "multi" : "single"); + return g_strdup(s->mttcg_enabled == ON_OFF_AUTO_ON ? "multi" : "single"); } static void tcg_set_thread(Object *obj, const char *value, Error **errp) @@ -159,10 +157,10 @@ static void tcg_set_thread(Object *obj, const char *value, Error **errp) warn_report("Guest not yet converted to MTTCG - " "you may get unexpected results"); #endif - s->mttcg_enabled = true; + s->mttcg_enabled = ON_OFF_AUTO_ON; } } else if (strcmp(value, "single") == 0) { - s->mttcg_enabled = false; + s->mttcg_enabled = ON_OFF_AUTO_OFF; } else { error_setg(errp, "Invalid 'thread' setting %s", value); } From 84cde4af081b9fa9c0fc82d3f1a8da406b4ba9e4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 4 Apr 2025 18:52:36 -0700 Subject: [PATCH 0224/2760] accel/tcg: Move mttcg warning to tcg_init_machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Delay the warning to tcg_init_machine, because we will have resolved the CPUClass at that point. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index fa77a4c5a2..ecdd48847c 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -93,7 +93,8 @@ static int tcg_init_machine(MachineState *ms) # else bool mttcg_supported = false; # endif - if (s->mttcg_enabled == ON_OFF_AUTO_AUTO) { + switch (s->mttcg_enabled) { + case ON_OFF_AUTO_AUTO: /* * We default to false if we know other options have been enabled * which are currently incompatible with MTTCG. Otherwise when each @@ -108,12 +109,22 @@ static int tcg_init_machine(MachineState *ms) */ if (mttcg_supported && !icount_enabled()) { s->mttcg_enabled = ON_OFF_AUTO_ON; + max_threads = ms->smp.max_cpus; } else { s->mttcg_enabled = ON_OFF_AUTO_OFF; } - } - if (s->mttcg_enabled == ON_OFF_AUTO_ON) { + break; + case ON_OFF_AUTO_ON: + if (!mttcg_supported) { + warn_report("Guest not yet converted to MTTCG - " + "you may get unexpected results"); + } max_threads = ms->smp.max_cpus; + break; + case ON_OFF_AUTO_OFF: + break; + default: + g_assert_not_reached(); } #endif @@ -153,10 +164,6 @@ static void tcg_set_thread(Object *obj, const char *value, Error **errp) if (icount_enabled()) { error_setg(errp, "No MTTCG when icount is enabled"); } else { -#ifndef TARGET_SUPPORTS_MTTCG - warn_report("Guest not yet converted to MTTCG - " - "you may get unexpected results"); -#endif s->mttcg_enabled = ON_OFF_AUTO_ON; } } else if (strcmp(value, "single") == 0) { From f50d0f335a6e48ac757cb7e534542822a8db8211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 5 Apr 2025 18:13:05 +0200 Subject: [PATCH 0225/2760] target/riscv: Remove AccelCPUClass::cpu_class_init need MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose riscv_tcg_ops symbol, then directly set it as CPUClass::tcg_ops in TYPE_RISCV_CPU's class_init(), using CONFIG_TCG #ifdef'ry. No need for the AccelCPUClass::cpu_class_init() handler anymore. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20250405161320.76854-2-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- target/riscv/cpu.c | 3 +++ target/riscv/tcg/tcg-cpu.c | 16 +--------------- target/riscv/tcg/tcg-cpu.h | 2 ++ 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index ad534cee51..2b830b3317 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -3054,6 +3054,9 @@ static void riscv_cpu_common_class_init(ObjectClass *c, void *data) cc->get_arch_id = riscv_get_arch_id; #endif cc->gdb_arch_name = riscv_gdb_arch_name; +#ifdef CONFIG_TCG + cc->tcg_ops = &riscv_tcg_ops; +#endif /* CONFIG_TCG */ device_class_set_props(dc, riscv_cpu_properties); } diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 88f7cdb887..44fdf6c4cf 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -140,7 +140,7 @@ static void riscv_restore_state_to_opc(CPUState *cs, env->excp_uw2 = data[2]; } -static const TCGCPUOps riscv_tcg_ops = { +const TCGCPUOps riscv_tcg_ops = { .guest_default_memory_order = 0, .initialize = riscv_translate_init, @@ -1527,24 +1527,10 @@ static void riscv_tcg_cpu_instance_init(CPUState *cs) } } -static void riscv_tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) -{ - /* - * All cpus use the same set of operations. - */ - cc->tcg_ops = &riscv_tcg_ops; -} - -static void riscv_tcg_cpu_class_init(CPUClass *cc) -{ - cc->init_accel_cpu = riscv_tcg_cpu_init_ops; -} - static void riscv_tcg_cpu_accel_class_init(ObjectClass *oc, void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); - acc->cpu_class_init = riscv_tcg_cpu_class_init; acc->cpu_instance_init = riscv_tcg_cpu_instance_init; acc->cpu_target_realize = riscv_tcg_cpu_realize; } diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h index ce94253fe4..a23716a5ac 100644 --- a/target/riscv/tcg/tcg-cpu.h +++ b/target/riscv/tcg/tcg-cpu.h @@ -26,6 +26,8 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp); bool riscv_cpu_tcg_compatible(RISCVCPU *cpu); +extern const TCGCPUOps riscv_tcg_ops; + struct DisasContext; struct RISCVCPUConfig; typedef struct RISCVDecoder { From a522b04bb9cf67789116ad7a6165946d4b214bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 5 Apr 2025 18:13:06 +0200 Subject: [PATCH 0226/2760] target/i386: Remove AccelCPUClass::cpu_class_init need MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expose x86_tcg_ops symbol, then directly set it as CPUClass::tcg_ops in TYPE_X86_CPU's class_init(), using CONFIG_TCG #ifdef'ry. No need for the AccelCPUClass::cpu_class_init() handler anymore. Signed-off-by: Philippe Mathieu-Daudé Message-ID: <20250405161320.76854-3-philmd@linaro.org> Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson --- target/i386/cpu.c | 4 ++++ target/i386/tcg/tcg-cpu.c | 14 +------------- target/i386/tcg/tcg-cpu.h | 4 ++++ 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 57f62cc869..1f970aa4da 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -43,6 +43,7 @@ #include "hw/boards.h" #include "hw/i386/sgx-epc.h" #endif +#include "tcg/tcg-cpu.h" #include "disas/capstone.h" #include "cpu-internal.h" @@ -8915,6 +8916,9 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) #ifndef CONFIG_USER_ONLY cc->sysemu_ops = &i386_sysemu_ops; #endif /* !CONFIG_USER_ONLY */ +#ifdef CONFIG_TCG + cc->tcg_ops = &x86_tcg_ops; +#endif /* CONFIG_TCG */ cc->gdb_arch_name = x86_gdb_arch_name; #ifdef TARGET_X86_64 diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index d941df0956..e13d0f6f86 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -124,7 +124,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs) #include "accel/tcg/cpu-ops.h" -static const TCGCPUOps x86_tcg_ops = { +const TCGCPUOps x86_tcg_ops = { /* * The x86 has a strong memory model with some store-after-load re-ordering */ @@ -152,17 +152,6 @@ static const TCGCPUOps x86_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void x86_tcg_cpu_init_ops(AccelCPUClass *accel_cpu, CPUClass *cc) -{ - /* for x86, all cpus use the same set of operations */ - cc->tcg_ops = &x86_tcg_ops; -} - -static void x86_tcg_cpu_class_init(CPUClass *cc) -{ - cc->init_accel_cpu = x86_tcg_cpu_init_ops; -} - static void x86_tcg_cpu_xsave_init(void) { #define XO(bit, field) \ @@ -211,7 +200,6 @@ static void x86_tcg_cpu_accel_class_init(ObjectClass *oc, void *data) acc->cpu_target_realize = tcg_cpu_realizefn; #endif /* CONFIG_USER_ONLY */ - acc->cpu_class_init = x86_tcg_cpu_class_init; acc->cpu_instance_init = x86_tcg_cpu_instance_init; } static const TypeInfo x86_tcg_cpu_accel_type_info = { diff --git a/target/i386/tcg/tcg-cpu.h b/target/i386/tcg/tcg-cpu.h index 7580f8afb4..85bcd61678 100644 --- a/target/i386/tcg/tcg-cpu.h +++ b/target/i386/tcg/tcg-cpu.h @@ -19,6 +19,8 @@ #ifndef TCG_CPU_H #define TCG_CPU_H +#include "cpu.h" + #define XSAVE_FCW_FSW_OFFSET 0x000 #define XSAVE_FTW_FOP_OFFSET 0x004 #define XSAVE_CWD_RIP_OFFSET 0x008 @@ -76,6 +78,8 @@ QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, zmm_hi256_state) != XSAVE_ZMM_HI256_OFF QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, hi16_zmm_state) != XSAVE_HI16_ZMM_OFFSET); QEMU_BUILD_BUG_ON(offsetof(X86XSaveArea, pkru_state) != XSAVE_PKRU_OFFSET); +extern const TCGCPUOps x86_tcg_ops; + bool tcg_cpu_realizefn(CPUState *cs, Error **errp); int x86_mmu_index_pl(CPUX86State *env, unsigned pl); From a3d40b5effafdd299d1850f0c9956f60199b5b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sat, 5 Apr 2025 18:13:20 +0200 Subject: [PATCH 0227/2760] tcg: Convert TARGET_SUPPORTS_MTTCG to TCGCPUOps::mttcg_supported field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having a compile-time TARGET_SUPPORTS_MTTCG definition, have each target set the 'mttcg_supported' field in the TCGCPUOps structure. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-ID: <20250405161320.76854-17-philmd@linaro.org> Signed-off-by: Richard Henderson --- accel/tcg/tcg-all.c | 11 +++++------ configs/targets/aarch64-softmmu.mak | 1 - configs/targets/alpha-softmmu.mak | 1 - configs/targets/arm-softmmu.mak | 1 - configs/targets/hppa-softmmu.mak | 1 - configs/targets/i386-softmmu.mak | 1 - configs/targets/loongarch64-softmmu.mak | 1 - configs/targets/microblaze-softmmu.mak | 1 - configs/targets/microblazeel-softmmu.mak | 1 - configs/targets/mips-softmmu.mak | 1 - configs/targets/mipsel-softmmu.mak | 1 - configs/targets/or1k-softmmu.mak | 1 - configs/targets/ppc64-softmmu.mak | 1 - configs/targets/riscv32-softmmu.mak | 1 - configs/targets/riscv64-softmmu.mak | 1 - configs/targets/s390x-softmmu.mak | 1 - configs/targets/sparc-softmmu.mak | 1 - configs/targets/sparc64-softmmu.mak | 1 - configs/targets/x86_64-softmmu.mak | 1 - configs/targets/xtensa-softmmu.mak | 1 - configs/targets/xtensaeb-softmmu.mak | 1 - docs/devel/multi-thread-tcg.rst | 2 +- include/accel/tcg/cpu-ops.h | 8 ++++++++ include/exec/poison.h | 1 - target/alpha/cpu.c | 1 + target/arm/cpu.c | 1 + target/arm/tcg/cpu-v7m.c | 1 + target/avr/cpu.c | 1 + target/hexagon/cpu.c | 1 + target/hppa/cpu.c | 1 + target/i386/tcg/tcg-cpu.c | 1 + target/loongarch/cpu.c | 1 + target/m68k/cpu.c | 1 + target/microblaze/cpu.c | 1 + target/mips/cpu.c | 1 + target/openrisc/cpu.c | 1 + target/ppc/cpu_init.c | 1 + target/riscv/tcg/tcg-cpu.c | 1 + target/rx/cpu.c | 1 + target/s390x/cpu.c | 1 + target/sh4/cpu.c | 1 + target/sparc/cpu.c | 1 + target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 1 + 44 files changed, 34 insertions(+), 28 deletions(-) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index ecdd48847c..b0d4e3e136 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -41,8 +41,9 @@ #include "hw/boards.h" #include "system/tcg.h" #endif +#include "accel/tcg/cpu-ops.h" #include "internal-common.h" -#include "cpu-param.h" +#include "cpu.h" struct TCGState { @@ -88,11 +89,9 @@ static int tcg_init_machine(MachineState *ms) unsigned max_threads = 1; #ifndef CONFIG_USER_ONLY -# ifdef TARGET_SUPPORTS_MTTCG - bool mttcg_supported = true; -# else - bool mttcg_supported = false; -# endif + CPUClass *cc = CPU_CLASS(object_class_by_name(CPU_RESOLVING_TYPE)); + bool mttcg_supported = cc->tcg_ops->mttcg_supported; + switch (s->mttcg_enabled) { case ON_OFF_AUTO_AUTO: /* diff --git a/configs/targets/aarch64-softmmu.mak b/configs/targets/aarch64-softmmu.mak index 82cb72cb83..5dfeb35af9 100644 --- a/configs/targets/aarch64-softmmu.mak +++ b/configs/targets/aarch64-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=aarch64 TARGET_BASE_ARCH=arm -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_XML_FILES= gdb-xml/aarch64-core.xml gdb-xml/aarch64-fpu.xml gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml gdb-xml/aarch64-pauth.xml # needed by boot.c diff --git a/configs/targets/alpha-softmmu.mak b/configs/targets/alpha-softmmu.mak index 89f3517aca..5275076e50 100644 --- a/configs/targets/alpha-softmmu.mak +++ b/configs/targets/alpha-softmmu.mak @@ -1,3 +1,2 @@ TARGET_ARCH=alpha -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=64 diff --git a/configs/targets/arm-softmmu.mak b/configs/targets/arm-softmmu.mak index afc64f5927..6a5a8eda94 100644 --- a/configs/targets/arm-softmmu.mak +++ b/configs/targets/arm-softmmu.mak @@ -1,5 +1,4 @@ TARGET_ARCH=arm -TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/arm-core.xml gdb-xml/arm-vfp.xml gdb-xml/arm-vfp3.xml gdb-xml/arm-vfp-sysregs.xml gdb-xml/arm-neon.xml gdb-xml/arm-m-profile.xml gdb-xml/arm-m-profile-mve.xml # needed by boot.c TARGET_NEED_FDT=y diff --git a/configs/targets/hppa-softmmu.mak b/configs/targets/hppa-softmmu.mak index 63ca74ed5e..ea331107a0 100644 --- a/configs/targets/hppa-softmmu.mak +++ b/configs/targets/hppa-softmmu.mak @@ -1,4 +1,3 @@ TARGET_ARCH=hppa TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=64 diff --git a/configs/targets/i386-softmmu.mak b/configs/targets/i386-softmmu.mak index 5dd8921756..e9d89e8ab4 100644 --- a/configs/targets/i386-softmmu.mak +++ b/configs/targets/i386-softmmu.mak @@ -1,5 +1,4 @@ TARGET_ARCH=i386 -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_KVM_HAVE_RESET_PARKED_VCPU=y TARGET_XML_FILES= gdb-xml/i386-32bit.xml diff --git a/configs/targets/loongarch64-softmmu.mak b/configs/targets/loongarch64-softmmu.mak index 351341132f..fc44c54233 100644 --- a/configs/targets/loongarch64-softmmu.mak +++ b/configs/targets/loongarch64-softmmu.mak @@ -1,7 +1,6 @@ TARGET_ARCH=loongarch64 TARGET_BASE_ARCH=loongarch TARGET_KVM_HAVE_GUEST_DEBUG=y -TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/loongarch-base32.xml gdb-xml/loongarch-base64.xml gdb-xml/loongarch-fpu.xml gdb-xml/loongarch-lsx.xml gdb-xml/loongarch-lasx.xml # all boards require libfdt TARGET_NEED_FDT=y diff --git a/configs/targets/microblaze-softmmu.mak b/configs/targets/microblaze-softmmu.mak index 99a33ed44a..23457d0ae6 100644 --- a/configs/targets/microblaze-softmmu.mak +++ b/configs/targets/microblaze-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=microblaze TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y # needed by boot.c TARGET_NEED_FDT=y TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/microblazeel-softmmu.mak b/configs/targets/microblazeel-softmmu.mak index 52cdeae1a2..c82c509623 100644 --- a/configs/targets/microblazeel-softmmu.mak +++ b/configs/targets/microblazeel-softmmu.mak @@ -1,5 +1,4 @@ TARGET_ARCH=microblaze -TARGET_SUPPORTS_MTTCG=y # needed by boot.c TARGET_NEED_FDT=y TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml diff --git a/configs/targets/mips-softmmu.mak b/configs/targets/mips-softmmu.mak index b62a088249..c9588066b8 100644 --- a/configs/targets/mips-softmmu.mak +++ b/configs/targets/mips-softmmu.mak @@ -1,4 +1,3 @@ TARGET_ARCH=mips TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=32 diff --git a/configs/targets/mipsel-softmmu.mak b/configs/targets/mipsel-softmmu.mak index 620ec68178..90e09bdc3e 100644 --- a/configs/targets/mipsel-softmmu.mak +++ b/configs/targets/mipsel-softmmu.mak @@ -1,3 +1,2 @@ TARGET_ARCH=mips -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=32 diff --git a/configs/targets/or1k-softmmu.mak b/configs/targets/or1k-softmmu.mak index adfddb1a8a..0e47d9878b 100644 --- a/configs/targets/or1k-softmmu.mak +++ b/configs/targets/or1k-softmmu.mak @@ -1,5 +1,4 @@ TARGET_ARCH=openrisc -TARGET_SUPPORTS_MTTCG=y TARGET_BIG_ENDIAN=y # needed by boot.c and all boards TARGET_NEED_FDT=y diff --git a/configs/targets/ppc64-softmmu.mak b/configs/targets/ppc64-softmmu.mak index 7cee0e97f4..74572864b3 100644 --- a/configs/targets/ppc64-softmmu.mak +++ b/configs/targets/ppc64-softmmu.mak @@ -1,7 +1,6 @@ TARGET_ARCH=ppc64 TARGET_BASE_ARCH=ppc TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_XML_FILES= gdb-xml/power64-core.xml gdb-xml/power-fpu.xml gdb-xml/power-altivec.xml gdb-xml/power-spe.xml gdb-xml/power-vsx.xml # all boards require libfdt diff --git a/configs/targets/riscv32-softmmu.mak b/configs/targets/riscv32-softmmu.mak index c828066ce6..db55275b86 100644 --- a/configs/targets/riscv32-softmmu.mak +++ b/configs/targets/riscv32-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=riscv32 TARGET_BASE_ARCH=riscv -TARGET_SUPPORTS_MTTCG=y TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-virtual.xml # needed by boot.c TARGET_NEED_FDT=y diff --git a/configs/targets/riscv64-softmmu.mak b/configs/targets/riscv64-softmmu.mak index 09f613d24a..2bdd4a62cd 100644 --- a/configs/targets/riscv64-softmmu.mak +++ b/configs/targets/riscv64-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=riscv64 TARGET_BASE_ARCH=riscv -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-virtual.xml gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-virtual.xml # needed by boot.c diff --git a/configs/targets/s390x-softmmu.mak b/configs/targets/s390x-softmmu.mak index 5242ebe7c2..76dd5de658 100644 --- a/configs/targets/s390x-softmmu.mak +++ b/configs/targets/s390x-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=s390x TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_XML_FILES= gdb-xml/s390x-core64.xml gdb-xml/s390-acr.xml gdb-xml/s390-fpr.xml gdb-xml/s390-vx.xml gdb-xml/s390-cr.xml gdb-xml/s390-virt.xml gdb-xml/s390-virt-kvm.xml gdb-xml/s390-gs.xml TARGET_LONG_BITS=64 diff --git a/configs/targets/sparc-softmmu.mak b/configs/targets/sparc-softmmu.mak index 78c2e25bd1..57801faf1f 100644 --- a/configs/targets/sparc-softmmu.mak +++ b/configs/targets/sparc-softmmu.mak @@ -1,4 +1,3 @@ TARGET_ARCH=sparc TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=32 diff --git a/configs/targets/sparc64-softmmu.mak b/configs/targets/sparc64-softmmu.mak index f7bab97a00..2504e31ae3 100644 --- a/configs/targets/sparc64-softmmu.mak +++ b/configs/targets/sparc64-softmmu.mak @@ -1,5 +1,4 @@ TARGET_ARCH=sparc64 TARGET_BASE_ARCH=sparc TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=64 diff --git a/configs/targets/x86_64-softmmu.mak b/configs/targets/x86_64-softmmu.mak index 1ceefde131..5619b2bc68 100644 --- a/configs/targets/x86_64-softmmu.mak +++ b/configs/targets/x86_64-softmmu.mak @@ -1,6 +1,5 @@ TARGET_ARCH=x86_64 TARGET_BASE_ARCH=i386 -TARGET_SUPPORTS_MTTCG=y TARGET_KVM_HAVE_GUEST_DEBUG=y TARGET_KVM_HAVE_RESET_PARKED_VCPU=y TARGET_XML_FILES= gdb-xml/i386-64bit.xml diff --git a/configs/targets/xtensa-softmmu.mak b/configs/targets/xtensa-softmmu.mak index 65845df4ff..2a9797338a 100644 --- a/configs/targets/xtensa-softmmu.mak +++ b/configs/targets/xtensa-softmmu.mak @@ -1,3 +1,2 @@ TARGET_ARCH=xtensa -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=32 diff --git a/configs/targets/xtensaeb-softmmu.mak b/configs/targets/xtensaeb-softmmu.mak index f1f789d697..5204729af8 100644 --- a/configs/targets/xtensaeb-softmmu.mak +++ b/configs/targets/xtensaeb-softmmu.mak @@ -1,4 +1,3 @@ TARGET_ARCH=xtensa TARGET_BIG_ENDIAN=y -TARGET_SUPPORTS_MTTCG=y TARGET_LONG_BITS=32 diff --git a/docs/devel/multi-thread-tcg.rst b/docs/devel/multi-thread-tcg.rst index 14a2a9dc7b..da9a1530c9 100644 --- a/docs/devel/multi-thread-tcg.rst +++ b/docs/devel/multi-thread-tcg.rst @@ -30,7 +30,7 @@ user-space thread. This is enabled by default for all FE/BE combinations where the host memory model is able to accommodate the guest (TCGCPUOps::guest_default_memory_order & ~TCG_TARGET_DEFAULT_MO is zero) and the guest has had the required work done to support this safely -(TARGET_SUPPORTS_MTTCG). +(TCGCPUOps::mttcg_supported). System emulation will fall back to the original round robin approach if: diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index a4932fc5d7..0e4352513d 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -19,6 +19,14 @@ #include "tcg/tcg-mo.h" struct TCGCPUOps { + /** + * mttcg_supported: multi-threaded TCG is supported + * + * Target (TCG frontend) supports: + * - atomic instructions + * - memory ordering primitives (barriers) + */ + bool mttcg_supported; /** * @guest_default_memory_order: default barrier that is required diff --git a/include/exec/poison.h b/include/exec/poison.h index a09e0c1263..bc422719d8 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -35,7 +35,6 @@ #pragma GCC poison TARGET_HAS_BFLT #pragma GCC poison TARGET_NAME -#pragma GCC poison TARGET_SUPPORTS_MTTCG #pragma GCC poison TARGET_BIG_ENDIAN #pragma GCC poison TCG_GUEST_DEFAULT_MO #pragma GCC poison TARGET_HAS_PRECISE_SMC diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index eeaf3a81c1..35fb145d27 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -237,6 +237,7 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { static const TCGCPUOps alpha_tcg_ops = { /* Alpha processors have a weak memory model */ .guest_default_memory_order = 0, + .mttcg_supported = true, .initialize = alpha_translate_init, .translate_code = alpha_translate_code, diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3e9760b551..377791c84d 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2671,6 +2671,7 @@ static const struct SysemuCPUOps arm_sysemu_ops = { #ifdef CONFIG_TCG static const TCGCPUOps arm_tcg_ops = { + .mttcg_supported = true, /* ARM processors have a weak memory model */ .guest_default_memory_order = 0, diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 89d4e4b4a2..f71560aa43 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -234,6 +234,7 @@ static void cortex_m55_initfn(Object *obj) static const TCGCPUOps arm_v7m_tcg_ops = { /* ARM processors have a weak memory model */ .guest_default_memory_order = 0, + .mttcg_supported = true, .initialize = arm_translate_init, .translate_code = arm_translate_code, diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 8f79cf4c08..84f3b839c9 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -225,6 +225,7 @@ static const struct SysemuCPUOps avr_sysemu_ops = { static const TCGCPUOps avr_tcg_ops = { .guest_default_memory_order = 0, + .mttcg_supported = false, .initialize = avr_cpu_tcg_init, .translate_code = avr_cpu_translate_code, .synchronize_from_tb = avr_cpu_synchronize_from_tb, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 3d14e5cc6a..3c5191282e 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -327,6 +327,7 @@ static void hexagon_cpu_init(Object *obj) static const TCGCPUOps hexagon_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = false, .initialize = hexagon_translate_init, .translate_code = hexagon_translate_code, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index dfbd933056..10e18c945e 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -260,6 +260,7 @@ static const TCGCPUOps hppa_tcg_ops = { * basis. It's probably easier to fall back to a strong memory model. */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = true, .initialize = hppa_translate_init, .translate_code = hppa_translate_code, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index e13d0f6f86..621502c984 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -125,6 +125,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs) #include "accel/tcg/cpu-ops.h" const TCGCPUOps x86_tcg_ops = { + .mttcg_supported = true, /* * The x86 has a strong memory model with some store-after-load re-ordering */ diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index f5b8ef29ab..fe9462b3b7 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -865,6 +865,7 @@ static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) static const TCGCPUOps loongarch_tcg_ops = { .guest_default_memory_order = 0, + .mttcg_supported = true, .initialize = loongarch_translate_init, .translate_code = loongarch_translate_code, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index b2d8c8f1de..99adc5eb91 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -591,6 +591,7 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { static const TCGCPUOps m68k_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = false, .initialize = m68k_tcg_init, .translate_code = m68k_translate_code, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 4efba0dddb..edfb05758b 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -429,6 +429,7 @@ static const struct SysemuCPUOps mb_sysemu_ops = { static const TCGCPUOps mb_tcg_ops = { /* MicroBlaze is always in-order. */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = true, .initialize = mb_tcg_init, .translate_code = mb_translate_code, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 2ae7ba4407..473cecdebc 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -551,6 +551,7 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) } static const TCGCPUOps mips_tcg_ops = { + .mttcg_supported = TARGET_LONG_BITS == 32, .guest_default_memory_order = 0, .initialize = mips_tcg_init, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 87fe779042..6601e0c066 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -244,6 +244,7 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { static const TCGCPUOps openrisc_tcg_ops = { .guest_default_memory_order = 0, + .mttcg_supported = true, .initialize = openrisc_translate_init, .translate_code = openrisc_translate_code, diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 9ba775971a..fde7d71fc6 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7479,6 +7479,7 @@ static const struct SysemuCPUOps ppc_sysemu_ops = { #include "accel/tcg/cpu-ops.h" static const TCGCPUOps ppc_tcg_ops = { + .mttcg_supported = TARGET_LONG_BITS == 64, .guest_default_memory_order = 0, .initialize = ppc_translate_init, .translate_code = ppc_translate_code, diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 44fdf6c4cf..426145c3b9 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -141,6 +141,7 @@ static void riscv_restore_state_to_opc(CPUState *cs, } const TCGCPUOps riscv_tcg_ops = { + .mttcg_supported = true, .guest_default_memory_order = 0, .initialize = riscv_translate_init, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index f073fe8fc9..0a7a2b55b5 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -206,6 +206,7 @@ static const struct SysemuCPUOps rx_sysemu_ops = { static const TCGCPUOps rx_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = false, .initialize = rx_translate_init, .translate_code = rx_translate_code, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 1e101b5afe..41cccc1e69 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -345,6 +345,7 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, } static const TCGCPUOps s390_tcg_ops = { + .mttcg_supported = true, /* * The z/Architecture has a strong memory model with some * store-after-load re-ordering. diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 7a05301c6f..861fdd47f7 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -264,6 +264,7 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { static const TCGCPUOps superh_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = false, .initialize = sh4_translate_init, .translate_code = sh4_translate_code, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 56d9417ae3..f7d231c6f8 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1023,6 +1023,7 @@ static const TCGCPUOps sparc_tcg_ops = { * by an implied MEMBAR #StoreStore. */ .guest_default_memory_order = TCG_MO_LD_LD | TCG_MO_LD_ST | TCG_MO_ST_ST, + .mttcg_supported = true, .initialize = sparc_tcg_init, .translate_code = sparc_translate_code, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index c68954b409..a4f93e7d91 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -174,6 +174,7 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { static const TCGCPUOps tricore_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, + .mttcg_supported = false, .initialize = tricore_tcg_init, .translate_code = tricore_translate_code, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 2cbf4e3010..971e67ad97 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -234,6 +234,7 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { static const TCGCPUOps xtensa_tcg_ops = { /* Xtensa processors have a weak memory model */ .guest_default_memory_order = 0, + .mttcg_supported = true, .initialize = xtensa_translate_init, .translate_code = xtensa_translate_code, From 9d7a951e352e7b99b8d96826ac9fdd384412137a Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Thu, 10 Apr 2025 16:50:04 +0800 Subject: [PATCH 0228/2760] hw/intc/loongarch_pch_msi: Remove gpio input handler MSI interrupt is triggered by writing message on specified memory address. In generic it is used by PCI devices, and no device is connected pch MSI irqchip with GPIO pin line method, here remove gpio input setting for MSI controller. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Tested-by: Song Gao Message-Id: <20250410085004.3577627-1-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_msi.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c index 66b5c1e660..bc93504ff7 100644 --- a/hw/intc/loongarch_pch_msi.c +++ b/hw/intc/loongarch_pch_msi.c @@ -42,13 +42,6 @@ static const MemoryRegionOps loongarch_pch_msi_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void pch_msi_irq_handler(void *opaque, int irq, int level) -{ - LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(opaque); - - qemu_set_irq(s->pch_msi_irq[irq], level); -} - static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp) { LoongArchPCHMSI *s = LOONGARCH_PCH_MSI(dev); @@ -59,9 +52,7 @@ static void loongarch_pch_msi_realize(DeviceState *dev, Error **errp) } s->pch_msi_irq = g_new(qemu_irq, s->irq_num); - qdev_init_gpio_out(dev, s->pch_msi_irq, s->irq_num); - qdev_init_gpio_in(dev, pch_msi_irq_handler, s->irq_num); } static void loongarch_pch_msi_unrealize(DeviceState *dev) From 4ac7eecb7439f6a978b44a0504a446c95f1bcc76 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:09 +0800 Subject: [PATCH 0229/2760] target/loongarch: Move header file helper.h to directory tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Header file helper.h is specified for tcg mode, move this file to directory tcg. And create new file helper.h to include header file in tcg mode. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-2-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/helper.h | 720 +-------------------------------- target/loongarch/tcg/helper.h | 722 ++++++++++++++++++++++++++++++++++ 2 files changed, 724 insertions(+), 718 deletions(-) create mode 100644 target/loongarch/tcg/helper.h diff --git a/target/loongarch/helper.h b/target/loongarch/helper.h index 1d5cb0198c..99981abd01 100644 --- a/target/loongarch/helper.h +++ b/target/loongarch/helper.h @@ -1,722 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (c) 2021 Loongson Technology Corporation Limited + * Copyright (c) 2025 Loongson Technology Corporation Limited */ -DEF_HELPER_2(raise_exception, noreturn, env, i32) - -DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) -DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) - -DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) -DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) - -DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) -DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) -DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl) - -/* Floating-point helper */ -DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmaxa_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmaxa_d, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmina_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fmina_d, TCG_CALL_NO_WG, i64, env, i64, i64) - -DEF_HELPER_FLAGS_5(fmuladd_s, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) -DEF_HELPER_FLAGS_5(fmuladd_d, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) - -DEF_HELPER_FLAGS_3(fscaleb_s, TCG_CALL_NO_WG, i64, env, i64, i64) -DEF_HELPER_FLAGS_3(fscaleb_d, TCG_CALL_NO_WG, i64, env, i64, i64) - -DEF_HELPER_FLAGS_2(flogb_s, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(flogb_d, TCG_CALL_NO_WG, i64, env, i64) - -DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(frsqrt_s, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(frsqrt_d, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(frecip_s, TCG_CALL_NO_WG, i64, env, i64) -DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_WG, i64, env, i64) - -DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64) -DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64) - -/* fcmp.cXXX.s */ -DEF_HELPER_4(fcmp_c_s, i64, env, i64, i64, i32) -/* fcmp.sXXX.s */ -DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32) -/* fcmp.cXXX.d */ -DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32) -/* fcmp.sXXX.d */ -DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32) - -DEF_HELPER_2(fcvt_d_s, i64, env, i64) -DEF_HELPER_2(fcvt_s_d, i64, env, i64) -DEF_HELPER_2(ffint_d_w, i64, env, i64) -DEF_HELPER_2(ffint_d_l, i64, env, i64) -DEF_HELPER_2(ffint_s_w, i64, env, i64) -DEF_HELPER_2(ffint_s_l, i64, env, i64) -DEF_HELPER_2(ftintrm_l_s, i64, env, i64) -DEF_HELPER_2(ftintrm_l_d, i64, env, i64) -DEF_HELPER_2(ftintrm_w_s, i64, env, i64) -DEF_HELPER_2(ftintrm_w_d, i64, env, i64) -DEF_HELPER_2(ftintrp_l_s, i64, env, i64) -DEF_HELPER_2(ftintrp_l_d, i64, env, i64) -DEF_HELPER_2(ftintrp_w_s, i64, env, i64) -DEF_HELPER_2(ftintrp_w_d, i64, env, i64) -DEF_HELPER_2(ftintrz_l_s, i64, env, i64) -DEF_HELPER_2(ftintrz_l_d, i64, env, i64) -DEF_HELPER_2(ftintrz_w_s, i64, env, i64) -DEF_HELPER_2(ftintrz_w_d, i64, env, i64) -DEF_HELPER_2(ftintrne_l_s, i64, env, i64) -DEF_HELPER_2(ftintrne_l_d, i64, env, i64) -DEF_HELPER_2(ftintrne_w_s, i64, env, i64) -DEF_HELPER_2(ftintrne_w_d, i64, env, i64) -DEF_HELPER_2(ftint_l_s, i64, env, i64) -DEF_HELPER_2(ftint_l_d, i64, env, i64) -DEF_HELPER_2(ftint_w_s, i64, env, i64) -DEF_HELPER_2(ftint_w_d, i64, env, i64) -DEF_HELPER_2(frint_s, i64, env, i64) -DEF_HELPER_2(frint_d, i64, env, i64) - -DEF_HELPER_FLAGS_1(set_rounding_mode, TCG_CALL_NO_RWG, void, env) - -DEF_HELPER_1(rdtime_d, i64, env) - -#ifndef CONFIG_USER_ONLY -/* CSRs helper */ -DEF_HELPER_1(csrrd_pgd, i64, env) -DEF_HELPER_1(csrrd_cpuid, i64, env) -DEF_HELPER_1(csrrd_tval, 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) -DEF_HELPER_2(csrwr_tcfg, i64, env, tl) -DEF_HELPER_2(csrwr_ticlr, i64, env, tl) -DEF_HELPER_2(csrwr_pwcl, i64, env, tl) -DEF_HELPER_2(iocsrrd_b, i64, env, tl) -DEF_HELPER_2(iocsrrd_h, i64, env, tl) -DEF_HELPER_2(iocsrrd_w, i64, env, tl) -DEF_HELPER_2(iocsrrd_d, i64, env, tl) -DEF_HELPER_3(iocsrwr_b, void, env, tl, tl) -DEF_HELPER_3(iocsrwr_h, void, env, tl, tl) -DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) -DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) - -/* TLB helper */ -DEF_HELPER_1(tlbwr, void, env) -DEF_HELPER_1(tlbfill, void, env) -DEF_HELPER_1(tlbsrch, void, env) -DEF_HELPER_1(tlbrd, void, env) -DEF_HELPER_1(tlbclr, void, env) -DEF_HELPER_1(tlbflush, void, env) -DEF_HELPER_1(invtlb_all, void, env) -DEF_HELPER_2(invtlb_all_g, void, env, i32) -DEF_HELPER_2(invtlb_all_asid, void, env, tl) -DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl) -DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl) - -DEF_HELPER_4(lddir, tl, env, tl, tl, i32) -DEF_HELPER_4(ldpte, void, env, tl, tl, i32) -DEF_HELPER_1(ertn, void, env) -DEF_HELPER_1(idle, void, env) -#endif - -/* LoongArch LSX */ -DEF_HELPER_FLAGS_4(vhaddw_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhaddw_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vhsubw_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vaddwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsubwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vaddwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsubwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwev_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsubwod_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vaddwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwev_q_du_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vaddwod_q_du_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vavg_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavg_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vavgr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vavgr_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vabsd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vabsd_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vadda_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vadda_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vadda_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vadda_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmini_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmini_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vmaxi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vmaxi_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vmuh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmuh_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmulwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmulwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmulwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmulwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmadd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmadd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmadd_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmsub_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmsub_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmsub_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmaddwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmaddwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vmaddwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmaddwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vdiv_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vdiv_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vmod_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsat_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsat_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_3(vexth_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vexth_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(vext2xv_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_w_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_d_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_d_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_wu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_du_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_du_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vext2xv_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsigncov_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsigncov_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsigncov_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsigncov_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(vmskltz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vmskltz_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vmskltz_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vmskltz_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vmskgez_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vmsknz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vnori_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vsllwil_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsllwil_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsllwil_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_3(vextl_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsllwil_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsllwil_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsllwil_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_3(vextl_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsrlr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlri_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vsrar_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrar_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrar_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrar_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrari_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrari_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrari_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrari_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vsrln_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrln_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrln_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsran_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsran_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsran_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsrlni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrani_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrani_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrani_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrani_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vsrlrn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlrn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrlrn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrarn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrarn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vsrarn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vsrlrni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlrni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlrni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrlrni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrarni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrarni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrarni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vsrarni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vssrln_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrln_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrln_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrln_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrln_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrln_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssran_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vssrlni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrani_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vssrlrn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrlrn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrlrn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrlrn_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrlrn_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrlrn_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vssrarn_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vssrlrni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrlrni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vssrarni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_3(vclo_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclo_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclo_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclo_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclz_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclz_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vclz_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(vpcnt_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vpcnt_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vpcnt_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(vpcnt_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vbitclr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitclr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitclr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitclr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitclri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitclri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitclri_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitclri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vbitset_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitset_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitset_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitset_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitseti_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitseti_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitseti_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitseti_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vbitrev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitrev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitrev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitrev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vbitrevi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitrevi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitrevi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vbitrevi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vfrstp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vfrstp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vfrstpi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vfrstpi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_5(vfadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmul_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmul_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfdiv_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfdiv_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_6(vfmadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfmsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfnmadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfnmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfnmsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(vfnmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_5(vfmax_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmax_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmin_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmin_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_5(vfmaxa_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmaxa_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmina_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfmina_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vflogb_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vflogb_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vfclass_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfclass_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vfsqrt_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfsqrt_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrecip_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrecip_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrsqrt_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrsqrt_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vfcvtl_s_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfcvth_s_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfcvtl_d_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfcvth_d_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfcvt_h_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vfcvt_s_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vfrintrne_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrne_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrz_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrz_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrp_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrp_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrm_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrintrm_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrint_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vfrint_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vftintrne_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrne_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrz_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrz_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrp_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrp_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrm_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrm_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftint_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftint_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrz_wu_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrz_lu_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftint_wu_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftint_lu_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vftintrne_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vftintrz_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vftintrp_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vftintrm_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vftint_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrnel_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrneh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrzl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrzh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrpl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrph_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrml_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintrmh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftintl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vftinth_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vffint_s_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vffint_d_l, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vffint_s_wu, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vffint_d_lu, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vffintl_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(vffinth_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(vffint_s_l, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(vseqi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vseqi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vseqi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vseqi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vslei_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslei_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vslti_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vslti_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_6(vfcmp_c_s, void, env, i32, i32, i32, i32, i32) -DEF_HELPER_6(vfcmp_s_s, void, env, i32, i32, i32, i32, i32) -DEF_HELPER_6(vfcmp_c_d, void, env, i32, i32, i32, i32, i32) -DEF_HELPER_6(vfcmp_s_d, void, env, i32, i32, i32, i32, i32) - -DEF_HELPER_FLAGS_4(vbitseli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_4(vsetanyeqz_b, void, env, i32, i32, i32) -DEF_HELPER_4(vsetanyeqz_h, void, env, i32, i32, i32) -DEF_HELPER_4(vsetanyeqz_w, void, env, i32, i32, i32) -DEF_HELPER_4(vsetanyeqz_d, void, env, i32, i32, i32) -DEF_HELPER_4(vsetallnez_b, void, env, i32, i32, i32) -DEF_HELPER_4(vsetallnez_h, void, env, i32, i32, i32) -DEF_HELPER_4(vsetallnez_w, void, env, i32, i32, i32) -DEF_HELPER_4(vsetallnez_d, void, env, i32, i32, i32) - -DEF_HELPER_FLAGS_4(xvinsve0_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(xvinsve0_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(xvpickve_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(xvpickve_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vpackev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpackod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vpickev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpickod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(vilvl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvl_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvh_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vilvh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(vshuf_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vshuf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vshuf_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vshuf_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vshuf4i_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vshuf4i_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vshuf4i_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vshuf4i_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vperm_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(vpermi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vpermi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vpermi_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) - -DEF_HELPER_FLAGS_4(vextrins_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vextrins_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vextrins_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) -DEF_HELPER_FLAGS_4(vextrins_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +#include "tcg/helper.h" diff --git a/target/loongarch/tcg/helper.h b/target/loongarch/tcg/helper.h new file mode 100644 index 0000000000..1d5cb0198c --- /dev/null +++ b/target/loongarch/tcg/helper.h @@ -0,0 +1,722 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2021 Loongson Technology Corporation Limited + */ + +DEF_HELPER_2(raise_exception, noreturn, env, i32) + +DEF_HELPER_FLAGS_1(bitrev_w, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitrev_d, TCG_CALL_NO_RWG_SE, tl, tl) +DEF_HELPER_FLAGS_1(bitswap, TCG_CALL_NO_RWG_SE, tl, tl) + +DEF_HELPER_FLAGS_3(asrtle_d, TCG_CALL_NO_WG, void, env, tl, tl) +DEF_HELPER_FLAGS_3(asrtgt_d, TCG_CALL_NO_WG, void, env, tl, tl) + +DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl) +DEF_HELPER_FLAGS_2(cpucfg, TCG_CALL_NO_RWG_SE, tl, env, tl) + +/* Floating-point helper */ +DEF_HELPER_FLAGS_3(fadd_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fadd_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fsub_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmul_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fdiv_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmax_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmin_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmaxa_d, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fmina_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_5(fmuladd_s, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) +DEF_HELPER_FLAGS_5(fmuladd_d, TCG_CALL_NO_WG, i64, env, i64, i64, i64, i32) + +DEF_HELPER_FLAGS_3(fscaleb_s, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_3(fscaleb_d, TCG_CALL_NO_WG, i64, env, i64, i64) + +DEF_HELPER_FLAGS_2(flogb_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(flogb_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(fsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frsqrt_d, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_s, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_2(frecip_d, TCG_CALL_NO_WG, i64, env, i64) + +DEF_HELPER_FLAGS_2(fclass_s, TCG_CALL_NO_RWG_SE, i64, env, i64) +DEF_HELPER_FLAGS_2(fclass_d, TCG_CALL_NO_RWG_SE, i64, env, i64) + +/* fcmp.cXXX.s */ +DEF_HELPER_4(fcmp_c_s, i64, env, i64, i64, i32) +/* fcmp.sXXX.s */ +DEF_HELPER_4(fcmp_s_s, i64, env, i64, i64, i32) +/* fcmp.cXXX.d */ +DEF_HELPER_4(fcmp_c_d, i64, env, i64, i64, i32) +/* fcmp.sXXX.d */ +DEF_HELPER_4(fcmp_s_d, i64, env, i64, i64, i32) + +DEF_HELPER_2(fcvt_d_s, i64, env, i64) +DEF_HELPER_2(fcvt_s_d, i64, env, i64) +DEF_HELPER_2(ffint_d_w, i64, env, i64) +DEF_HELPER_2(ffint_d_l, i64, env, i64) +DEF_HELPER_2(ffint_s_w, i64, env, i64) +DEF_HELPER_2(ffint_s_l, i64, env, i64) +DEF_HELPER_2(ftintrm_l_s, i64, env, i64) +DEF_HELPER_2(ftintrm_l_d, i64, env, i64) +DEF_HELPER_2(ftintrm_w_s, i64, env, i64) +DEF_HELPER_2(ftintrm_w_d, i64, env, i64) +DEF_HELPER_2(ftintrp_l_s, i64, env, i64) +DEF_HELPER_2(ftintrp_l_d, i64, env, i64) +DEF_HELPER_2(ftintrp_w_s, i64, env, i64) +DEF_HELPER_2(ftintrp_w_d, i64, env, i64) +DEF_HELPER_2(ftintrz_l_s, i64, env, i64) +DEF_HELPER_2(ftintrz_l_d, i64, env, i64) +DEF_HELPER_2(ftintrz_w_s, i64, env, i64) +DEF_HELPER_2(ftintrz_w_d, i64, env, i64) +DEF_HELPER_2(ftintrne_l_s, i64, env, i64) +DEF_HELPER_2(ftintrne_l_d, i64, env, i64) +DEF_HELPER_2(ftintrne_w_s, i64, env, i64) +DEF_HELPER_2(ftintrne_w_d, i64, env, i64) +DEF_HELPER_2(ftint_l_s, i64, env, i64) +DEF_HELPER_2(ftint_l_d, i64, env, i64) +DEF_HELPER_2(ftint_w_s, i64, env, i64) +DEF_HELPER_2(ftint_w_d, i64, env, i64) +DEF_HELPER_2(frint_s, i64, env, i64) +DEF_HELPER_2(frint_d, i64, env, i64) + +DEF_HELPER_FLAGS_1(set_rounding_mode, TCG_CALL_NO_RWG, void, env) + +DEF_HELPER_1(rdtime_d, i64, env) + +#ifndef CONFIG_USER_ONLY +/* CSRs helper */ +DEF_HELPER_1(csrrd_pgd, i64, env) +DEF_HELPER_1(csrrd_cpuid, i64, env) +DEF_HELPER_1(csrrd_tval, 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) +DEF_HELPER_2(csrwr_tcfg, i64, env, tl) +DEF_HELPER_2(csrwr_ticlr, i64, env, tl) +DEF_HELPER_2(csrwr_pwcl, i64, env, tl) +DEF_HELPER_2(iocsrrd_b, i64, env, tl) +DEF_HELPER_2(iocsrrd_h, i64, env, tl) +DEF_HELPER_2(iocsrrd_w, i64, env, tl) +DEF_HELPER_2(iocsrrd_d, i64, env, tl) +DEF_HELPER_3(iocsrwr_b, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_h, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_w, void, env, tl, tl) +DEF_HELPER_3(iocsrwr_d, void, env, tl, tl) + +/* TLB helper */ +DEF_HELPER_1(tlbwr, void, env) +DEF_HELPER_1(tlbfill, void, env) +DEF_HELPER_1(tlbsrch, void, env) +DEF_HELPER_1(tlbrd, void, env) +DEF_HELPER_1(tlbclr, void, env) +DEF_HELPER_1(tlbflush, void, env) +DEF_HELPER_1(invtlb_all, void, env) +DEF_HELPER_2(invtlb_all_g, void, env, i32) +DEF_HELPER_2(invtlb_all_asid, void, env, tl) +DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl) +DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl) + +DEF_HELPER_4(lddir, tl, env, tl, tl, i32) +DEF_HELPER_4(ldpte, void, env, tl, tl, i32) +DEF_HELPER_1(ertn, void, env) +DEF_HELPER_1(idle, void, env) +#endif + +/* LoongArch LSX */ +DEF_HELPER_FLAGS_4(vhaddw_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhaddw_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vhsubw_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vaddwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsubwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vaddwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsubwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwev_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsubwod_q_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vaddwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwev_q_du_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vaddwod_q_du_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vavg_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavg_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vavgr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vavgr_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vabsd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vabsd_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vadda_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vadda_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vadda_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vadda_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmini_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmini_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vmaxi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vmaxi_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vmuh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmuh_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmulwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmulwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmulwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmulwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmadd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmadd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmadd_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmsub_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmsub_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmsub_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmaddwev_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmaddwev_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_h_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_w_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_d_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vmaddwev_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwev_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_h_bu_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_w_hu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmaddwod_d_wu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vdiv_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vdiv_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_bu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_hu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_wu, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vmod_du, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsat_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsat_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_3(vexth_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vexth_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(vext2xv_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_w_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_d_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_d_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_wu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_du_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_du_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vext2xv_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsigncov_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsigncov_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsigncov_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsigncov_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(vmskltz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vmskltz_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vmskltz_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vmskltz_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vmskgez_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vmsknz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vnori_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vsllwil_h_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsllwil_w_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsllwil_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_3(vextl_q_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsllwil_hu_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsllwil_wu_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsllwil_du_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_3(vextl_qu_du, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsrlr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlri_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vsrar_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrar_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrar_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrar_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrari_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrari_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrari_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrari_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vsrln_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrln_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrln_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsran_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsran_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsran_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsrlni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrani_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrani_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrani_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrani_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vsrlrn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlrn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrlrn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrarn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrarn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vsrarn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vsrlrni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlrni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlrni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrlrni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrarni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrarni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrarni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vsrarni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vssrln_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrln_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrln_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrln_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrln_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrln_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssran_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vssrlni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrani_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vssrlrn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrlrn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrlrn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrlrn_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrlrn_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrlrn_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vssrarn_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vssrlrni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_b_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_h_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_d_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrlrni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_bu_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_hu_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_wu_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vssrarni_du_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_3(vclo_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclo_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclo_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclo_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclz_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclz_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclz_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vclz_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(vpcnt_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vpcnt_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vpcnt_w, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(vpcnt_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vbitclr_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitclr_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitclr_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitclr_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitclri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitclri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitclri_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitclri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vbitset_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitset_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitset_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitset_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitseti_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitseti_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitseti_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitseti_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vbitrev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitrev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitrev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitrev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vbitrevi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitrevi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitrevi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vbitrevi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vfrstp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vfrstp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vfrstpi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vfrstpi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_5(vfadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmul_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmul_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfdiv_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfdiv_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_6(vfmadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfmsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfnmadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfnmadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfnmsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(vfnmsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(vfmax_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmax_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmin_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmin_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(vfmaxa_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmaxa_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmina_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfmina_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vflogb_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vflogb_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vfclass_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfclass_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vfsqrt_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfsqrt_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrecip_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrecip_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrsqrt_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrsqrt_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vfcvtl_s_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfcvth_s_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfcvtl_d_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfcvth_d_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfcvt_h_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vfcvt_s_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vfrintrne_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrne_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrz_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrz_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrp_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrp_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrm_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrintrm_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrint_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vfrint_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vftintrne_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrne_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrz_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrz_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrp_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrp_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrm_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrm_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftint_w_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftint_l_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrz_wu_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrz_lu_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftint_wu_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftint_lu_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vftintrne_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vftintrz_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vftintrp_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vftintrm_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vftint_w_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrnel_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrneh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrzl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrzh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrpl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrph_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrml_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintrmh_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftintl_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vftinth_l_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vffint_s_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vffint_d_l, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vffint_s_wu, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vffint_d_lu, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vffintl_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(vffinth_d_w, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(vffint_s_l, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(vseqi_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vseqi_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vseqi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vseqi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vslei_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslei_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vslti_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_bu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_hu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_wu, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vslti_du, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_6(vfcmp_c_s, void, env, i32, i32, i32, i32, i32) +DEF_HELPER_6(vfcmp_s_s, void, env, i32, i32, i32, i32, i32) +DEF_HELPER_6(vfcmp_c_d, void, env, i32, i32, i32, i32, i32) +DEF_HELPER_6(vfcmp_s_d, void, env, i32, i32, i32, i32, i32) + +DEF_HELPER_FLAGS_4(vbitseli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_4(vsetanyeqz_b, void, env, i32, i32, i32) +DEF_HELPER_4(vsetanyeqz_h, void, env, i32, i32, i32) +DEF_HELPER_4(vsetanyeqz_w, void, env, i32, i32, i32) +DEF_HELPER_4(vsetanyeqz_d, void, env, i32, i32, i32) +DEF_HELPER_4(vsetallnez_b, void, env, i32, i32, i32) +DEF_HELPER_4(vsetallnez_h, void, env, i32, i32, i32) +DEF_HELPER_4(vsetallnez_w, void, env, i32, i32, i32) +DEF_HELPER_4(vsetallnez_d, void, env, i32, i32, i32) + +DEF_HELPER_FLAGS_4(xvinsve0_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(xvinsve0_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(xvpickve_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(xvpickve_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vpackev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpackod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vpickev_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickev_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickev_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickev_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickod_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickod_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickod_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpickod_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(vilvl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvl_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvh_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vilvh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(vshuf_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vshuf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vshuf_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vshuf_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vshuf4i_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vshuf4i_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vshuf4i_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vshuf4i_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vperm_w, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(vpermi_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vpermi_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vpermi_q, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) + +DEF_HELPER_FLAGS_4(vextrins_b, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vextrins_h, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vextrins_w, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) +DEF_HELPER_FLAGS_4(vextrins_d, TCG_CALL_NO_RWG, void, ptr, ptr, i64, i32) From a8d1b5bca5d234bfeaf215c079696735e5aafe71 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:10 +0800 Subject: [PATCH 0230/2760] target/loongarch: Add function loongarch_get_addr_from_tlb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function loongarch_get_addr_from_tlb() is added to get physical address from TLB tables. TLB table only works in TCG mode, in future this function will be moved to TCG directory. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 930466ca48..a326859000 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -7,6 +7,7 @@ */ #include "qemu/osdep.h" +#include "system/tcg.h" #include "cpu.h" #include "internals.h" #include "cpu-csr.h" @@ -141,6 +142,21 @@ bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, return false; } +static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int index, match; + + match = loongarch_tlb_search(env, address, &index); + if (match) { + return loongarch_map_tlb_entry(env, physical, prot, + address, access_type, index, mmu_idx); + } + + return TLBRET_NOMATCH; +} + static int loongarch_page_table_walker(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address) { @@ -221,13 +237,17 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, MMUAccessType access_type, int mmu_idx, int is_debug) { - int index, match; + int ret; - match = loongarch_tlb_search(env, address, &index); - if (match) { - return loongarch_map_tlb_entry(env, physical, prot, - address, access_type, index, mmu_idx); - } else if (is_debug) { + if (tcg_enabled()) { + ret = loongarch_get_addr_from_tlb(env, physical, prot, address, + access_type, mmu_idx); + if (ret != TLBRET_NOMATCH) { + return ret; + } + } + + if (is_debug) { /* * For debugger memory access, we want to do the map when there is a * legal mapping, even if the mapping is not yet in TLB. return 0 if From 885398ee09b5ee3d26d2ee670f468282c9ce8512 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:11 +0800 Subject: [PATCH 0231/2760] target/loongarch: Move function get_dir_base_width to common directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function get_dir_base_width() is used by loongarch_page_table_walker(), so it is used by KVM mode also, here move this function from directory tcg to common directory. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 28 ++++++++++++++++++++++++++++ target/loongarch/tcg/tlb_helper.c | 28 ---------------------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index a326859000..8ae9a448b4 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -157,6 +157,34 @@ static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } +void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, + uint64_t *dir_width, target_ulong level) +{ + switch (level) { + case 1: + *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); + *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); + break; + case 2: + *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); + *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); + break; + case 3: + *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); + *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); + break; + case 4: + *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); + *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); + break; + default: + /* level may be zero for ldpte */ + *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); + *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); + break; + } +} + static int loongarch_page_table_walker(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address) { diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index 70d1b5cf99..e6cfcc55c8 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -27,34 +27,6 @@ bool check_ps(CPULoongArchState *env, uint8_t tlb_ps) return BIT_ULL(tlb_ps) & (env->CSR_PRCFG2); } -void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, - uint64_t *dir_width, target_ulong level) -{ - switch (level) { - case 1: - *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE); - *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH); - break; - case 2: - *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE); - *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH); - break; - case 3: - *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE); - *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH); - break; - case 4: - *dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE); - *dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH); - break; - default: - /* level may be zero for ldpte */ - *dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE); - *dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH); - break; - } -} - static void raise_mmu_exception(CPULoongArchState *env, target_ulong address, MMUAccessType access_type, int tlb_error) { From 566bf2de87160a8a2fe5a1ba1a2f31f6869f4f80 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:12 +0800 Subject: [PATCH 0232/2760] target/loongarch: Add stub function loongarch_get_addr_from_tlb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stub function loongarch_get_addr_from_tlb() is added if option CONFIG_TCG is not enabled, so this function can be called in KVM only mode. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 8ae9a448b4..71180bc345 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -156,7 +156,16 @@ static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } +#else +static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + return TLBRET_NOMATCH; +} +#endif +#ifdef CONFIG_TCG void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, uint64_t *dir_width, target_ulong level) { From d192494a685ff6b132caec8ebdfdbcdcd04408b9 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:13 +0800 Subject: [PATCH 0233/2760] target/loongarch: Set function loongarch_map_address() with common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function loongarch_map_address is to get physical address from virtual address, it is used by qmp commands to dump memory from virtual address. It is used by kvm mode also, here move function loongarch_map_address() out of macro CONFIG_TCG. And it is common code, the similar with function loongarch_page_table_walker(). Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-6-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 71180bc345..9a87cae358 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -165,7 +165,6 @@ static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, } #endif -#ifdef CONFIG_TCG void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, uint64_t *dir_width, target_ulong level) { @@ -295,15 +294,6 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } -#else -static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical, - int *prot, target_ulong address, - MMUAccessType access_type, int mmu_idx, - int is_debug) -{ - return TLBRET_NOMATCH; -} -#endif static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va, target_ulong dmw) From 9fd0cc4df871d762b91076410b6b6fb637cec0d4 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:14 +0800 Subject: [PATCH 0234/2760] target/loongarch: Define function loongarch_get_addr_from_tlb() non-static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Define function loongarch_get_addr_from_tlb() non-static, and add its definition in header file tcg/tcg_loongarch.h Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-7-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 10 ++-------- target/loongarch/tcg/tcg_loongarch.h | 5 +++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 9a87cae358..97d9caa06e 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -11,6 +11,7 @@ #include "cpu.h" #include "internals.h" #include "cpu-csr.h" +#include "tcg/tcg_loongarch.h" #ifdef CONFIG_TCG static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, @@ -142,7 +143,7 @@ bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, return false; } -static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, +int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type, int mmu_idx) { @@ -156,13 +157,6 @@ static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, return TLBRET_NOMATCH; } -#else -static int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, - int *prot, target_ulong address, - MMUAccessType access_type, int mmu_idx) -{ - return TLBRET_NOMATCH; -} #endif void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, diff --git a/target/loongarch/tcg/tcg_loongarch.h b/target/loongarch/tcg/tcg_loongarch.h index da2539e995..b29427d981 100644 --- a/target/loongarch/tcg/tcg_loongarch.h +++ b/target/loongarch/tcg/tcg_loongarch.h @@ -6,7 +6,12 @@ */ #ifndef TARGET_LOONGARCH_TCG_LOONGARCH_H #define TARGET_LOONGARCH_TCG_LOONGARCH_H +#include "cpu.h" void loongarch_csr_translate_init(void); +int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx); + #endif /* TARGET_LOONGARCH_TCG_LOONGARCH_H */ From 9c9ffc013db126727d6121754e461550ba60a69f Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:15 +0800 Subject: [PATCH 0235/2760] target/loongarch: Move function loongarch_tlb_search to directory tcg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function loongarch_tlb_search() and loongarch_map_tlb_entry() works only in TCG mode, move these functions to directory tcg. There is no any function change, only code moving. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-8-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu_helper.c | 146 ------------------------------ target/loongarch/tcg/tlb_helper.c | 145 +++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+), 146 deletions(-) diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c index 97d9caa06e..998857b8dc 100644 --- a/target/loongarch/cpu_helper.c +++ b/target/loongarch/cpu_helper.c @@ -13,152 +13,6 @@ #include "cpu-csr.h" #include "tcg/tcg_loongarch.h" -#ifdef CONFIG_TCG -static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, - int *prot, target_ulong address, - int access_type, int index, int mmu_idx) -{ - LoongArchTLB *tlb = &env->tlb[index]; - uint64_t plv = mmu_idx; - uint64_t tlb_entry, tlb_ppn; - uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; - - if (index >= LOONGARCH_STLB) { - tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); - } else { - tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); - } - n = (address >> tlb_ps) & 0x1;/* Odd or even */ - - tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; - tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); - tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); - tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); - if (is_la64(env)) { - tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); - tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); - tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); - tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); - } else { - tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); - tlb_nx = 0; - tlb_nr = 0; - tlb_rplv = 0; - } - - /* Remove sw bit between bit12 -- bit PS*/ - tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) -1)); - - /* Check access rights */ - if (!tlb_v) { - return TLBRET_INVALID; - } - - if (access_type == MMU_INST_FETCH && tlb_nx) { - return TLBRET_XI; - } - - if (access_type == MMU_DATA_LOAD && tlb_nr) { - return TLBRET_RI; - } - - if (((tlb_rplv == 0) && (plv > tlb_plv)) || - ((tlb_rplv == 1) && (plv != tlb_plv))) { - return TLBRET_PE; - } - - if ((access_type == MMU_DATA_STORE) && !tlb_d) { - return TLBRET_DIRTY; - } - - *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | - (address & MAKE_64BIT_MASK(0, tlb_ps)); - *prot = PAGE_READ; - if (tlb_d) { - *prot |= PAGE_WRITE; - } - if (!tlb_nx) { - *prot |= PAGE_EXEC; - } - return TLBRET_MATCH; -} - -/* - * One tlb entry holds an adjacent odd/even pair, the vpn is the - * content of the virtual page number divided by 2. So the - * compare vpn is bit[47:15] for 16KiB page. while the vppn - * field in tlb entry contains bit[47:13], so need adjust. - * virt_vpn = vaddr[47:13] - */ -bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, - int *index) -{ - LoongArchTLB *tlb; - uint16_t csr_asid, tlb_asid, stlb_idx; - uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; - int i, compare_shift; - uint64_t vpn, tlb_vppn; - - csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); - stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); - vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); - stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ - compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; - - /* Search STLB */ - for (i = 0; i < 8; ++i) { - tlb = &env->tlb[i * 256 + stlb_idx]; - tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); - if (tlb_e) { - tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); - tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); - tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - - if ((tlb_g == 1 || tlb_asid == csr_asid) && - (vpn == (tlb_vppn >> compare_shift))) { - *index = i * 256 + stlb_idx; - return true; - } - } - } - - /* Search MTLB */ - for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { - tlb = &env->tlb[i]; - tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); - if (tlb_e) { - tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); - tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); - tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); - tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); - compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; - vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); - if ((tlb_g == 1 || tlb_asid == csr_asid) && - (vpn == (tlb_vppn >> compare_shift))) { - *index = i; - return true; - } - } - } - return false; -} - -int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, - int *prot, target_ulong address, - MMUAccessType access_type, int mmu_idx) -{ - int index, match; - - match = loongarch_tlb_search(env, address, &index); - if (match) { - return loongarch_map_tlb_entry(env, physical, prot, - address, access_type, index, mmu_idx); - } - - return TLBRET_NOMATCH; -} -#endif - void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, uint64_t *dir_width, target_ulong level) { diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index e6cfcc55c8..8509aa99cf 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -18,6 +18,7 @@ #include "exec/cpu_ldst.h" #include "exec/log.h" #include "cpu-csr.h" +#include "tcg/tcg_loongarch.h" bool check_ps(CPULoongArchState *env, uint8_t tlb_ps) { @@ -201,6 +202,66 @@ static uint32_t get_random_tlb(uint32_t low, uint32_t high) return val % (high - low + 1) + low; } +/* + * One tlb entry holds an adjacent odd/even pair, the vpn is the + * content of the virtual page number divided by 2. So the + * compare vpn is bit[47:15] for 16KiB page. while the vppn + * field in tlb entry contains bit[47:13], so need adjust. + * virt_vpn = vaddr[47:13] + */ +bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, + int *index) +{ + LoongArchTLB *tlb; + uint16_t csr_asid, tlb_asid, stlb_idx; + uint8_t tlb_e, tlb_ps, tlb_g, stlb_ps; + int i, compare_shift; + uint64_t vpn, tlb_vppn; + + csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID); + stlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + vpn = (vaddr & TARGET_VIRT_MASK) >> (stlb_ps + 1); + stlb_idx = vpn & 0xff; /* VA[25:15] <==> TLBIDX.index for 16KiB Page */ + compare_shift = stlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + + /* Search STLB */ + for (i = 0; i < 8; ++i) { + tlb = &env->tlb[i * 256 + stlb_idx]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i * 256 + stlb_idx; + return true; + } + } + } + + /* Search MTLB */ + for (i = LOONGARCH_STLB; i < LOONGARCH_TLB_MAX; ++i) { + tlb = &env->tlb[i]; + tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E); + if (tlb_e) { + tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN); + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID); + tlb_g = FIELD_EX64(tlb->tlb_entry0, TLBENTRY, G); + compare_shift = tlb_ps + 1 - R_TLB_MISC_VPPN_SHIFT; + vpn = (vaddr & TARGET_VIRT_MASK) >> (tlb_ps + 1); + if ((tlb_g == 1 || tlb_asid == csr_asid) && + (vpn == (tlb_vppn >> compare_shift))) { + *index = i; + return true; + } + } + } + return false; +} + void helper_tlbsrch(CPULoongArchState *env) { int index, match; @@ -609,3 +670,87 @@ void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd, } env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps); } + +static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + int access_type, int index, int mmu_idx) +{ + LoongArchTLB *tlb = &env->tlb[index]; + uint64_t plv = mmu_idx; + uint64_t tlb_entry, tlb_ppn; + uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv; + + if (index >= LOONGARCH_STLB) { + tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS); + } else { + tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS); + } + n = (address >> tlb_ps) & 0x1;/* Odd or even */ + + tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0; + tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V); + tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D); + tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV); + if (is_la64(env)) { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN); + tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX); + tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR); + tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV); + } else { + tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN); + tlb_nx = 0; + tlb_nr = 0; + tlb_rplv = 0; + } + + /* Remove sw bit between bit12 -- bit PS*/ + tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) - 1)); + + /* Check access rights */ + if (!tlb_v) { + return TLBRET_INVALID; + } + + if (access_type == MMU_INST_FETCH && tlb_nx) { + return TLBRET_XI; + } + + if (access_type == MMU_DATA_LOAD && tlb_nr) { + return TLBRET_RI; + } + + if (((tlb_rplv == 0) && (plv > tlb_plv)) || + ((tlb_rplv == 1) && (plv != tlb_plv))) { + return TLBRET_PE; + } + + if ((access_type == MMU_DATA_STORE) && !tlb_d) { + return TLBRET_DIRTY; + } + + *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) | + (address & MAKE_64BIT_MASK(0, tlb_ps)); + *prot = PAGE_READ; + if (tlb_d) { + *prot |= PAGE_WRITE; + } + if (!tlb_nx) { + *prot |= PAGE_EXEC; + } + return TLBRET_MATCH; +} + +int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, + int *prot, target_ulong address, + MMUAccessType access_type, int mmu_idx) +{ + int index, match; + + match = loongarch_tlb_search(env, address, &index); + if (match) { + return loongarch_map_tlb_entry(env, physical, prot, + address, access_type, index, mmu_idx); + } + + return TLBRET_NOMATCH; +} From ad5233ba5c7dcc92ee79d015f2168fb7e0279118 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:16 +0800 Subject: [PATCH 0236/2760] target/loongarch: Add static definition with function loongarch_tlb_search() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function loongarch_tlb_search() is only referenced in file tcg/tlb_helper.c, define this function with static attribution. Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-9-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/internals.h | 2 -- target/loongarch/tcg/tlb_helper.c | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 9fdc3059d8..3a079feb1d 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -54,8 +54,6 @@ uint64_t cpu_loongarch_get_constant_timer_counter(LoongArchCPU *cpu); uint64_t cpu_loongarch_get_constant_timer_ticks(LoongArchCPU *cpu); void cpu_loongarch_store_constant_timer_config(LoongArchCPU *cpu, uint64_t value); -bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, - int *index); int get_physical_address(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type, int mmu_idx, int is_debug); diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index 8509aa99cf..2fdd10022b 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -209,8 +209,8 @@ static uint32_t get_random_tlb(uint32_t low, uint32_t high) * field in tlb entry contains bit[47:13], so need adjust. * virt_vpn = vaddr[47:13] */ -bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, - int *index) +static bool loongarch_tlb_search(CPULoongArchState *env, target_ulong vaddr, + int *index) { LoongArchTLB *tlb; uint16_t csr_asid, tlb_asid, stlb_idx; From 0d4c2e408d418ec5c412ec9f58e7b8f3aecc6948 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 23 Apr 2025 16:04:17 +0800 Subject: [PATCH 0237/2760] target/loongarch: Move definition of TCG specified function to tcg directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function loongarch_cpu_tlb_fill() only works in TCG mode, move its definition from header file internals.h to file tcg/tcg_loongarch.h Signed-off-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250423080417.3739809-10-maobibo@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu.c | 1 + target/loongarch/internals.h | 5 ----- target/loongarch/tcg/tcg_loongarch.h | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index ea1665e270..bf3d592574 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -32,6 +32,7 @@ #include "exec/cpu_ldst.h" #include "tcg/tcg.h" #endif +#include "tcg/tcg_loongarch.h" const char * const regnames[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h index 3a079feb1d..a7384b0d31 100644 --- a/target/loongarch/internals.h +++ b/target/loongarch/internals.h @@ -61,11 +61,6 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base, uint64_t *dir_width, target_ulong level); hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -#ifdef CONFIG_TCG -bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, - MMUAccessType access_type, int mmu_idx, - bool probe, uintptr_t retaddr); -#endif #endif /* !CONFIG_USER_ONLY */ uint64_t read_fcc(CPULoongArchState *env); diff --git a/target/loongarch/tcg/tcg_loongarch.h b/target/loongarch/tcg/tcg_loongarch.h index b29427d981..fd4e116022 100644 --- a/target/loongarch/tcg/tcg_loongarch.h +++ b/target/loongarch/tcg/tcg_loongarch.h @@ -10,6 +10,10 @@ void loongarch_csr_translate_init(void); +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size, + MMUAccessType access_type, int mmu_idx, + bool probe, uintptr_t retaddr); + int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical, int *prot, target_ulong address, MMUAccessType access_type, int mmu_idx); From a9d3d1dff6f9e1544e8a84e74645b8e4fe08c0ad Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Mon, 14 Apr 2025 15:49:52 +0800 Subject: [PATCH 0238/2760] linux-user/loongarch64: Decode BRK break codes for FPE signals Handle specific LoongArch BRK break codes in user-mode emulation to deliver accurate floating-point exception signals. Specifically, BRK_OVERFLOW (6) triggers TARGET_FPE_INTOVF, and BRK_DIVZERO (7) triggers TARGET_FPE_INTDIV. Other BRK codes fall back to a generic SIGTRAP. This improves correctness for programs that rely on BRK to signal overflow or divide-by-zero conditions. Signed-off-by: WANG Rui Acked-by: Song Gao Message-Id: <20250414074952.6253-1-wangrui@loongson.cn> Signed-off-by: Song Gao --- linux-user/loongarch64/cpu_loop.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/linux-user/loongarch64/cpu_loop.c b/linux-user/loongarch64/cpu_loop.c index 0614d3de22..ec8a06c88c 100644 --- a/linux-user/loongarch64/cpu_loop.c +++ b/linux-user/loongarch64/cpu_loop.c @@ -11,6 +11,12 @@ #include "user/cpu_loop.h" #include "signal-common.h" +/* Break codes */ +enum { + BRK_OVERFLOW = 6, + BRK_DIVZERO = 7 +}; + void cpu_loop(CPULoongArchState *env) { CPUState *cs = env_cpu(env); @@ -66,9 +72,26 @@ void cpu_loop(CPULoongArchState *env) force_sig_fault(TARGET_SIGFPE, si_code, env->pc); break; case EXCP_DEBUG: - case EXCCODE_BRK: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); break; + case EXCCODE_BRK: + { + unsigned int opcode; + + get_user_u32(opcode, env->pc); + + switch (opcode & 0x7fff) { + case BRK_OVERFLOW: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc); + break; + case BRK_DIVZERO: + force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc); + break; + default: + force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc); + } + } + break; case EXCCODE_BCE: force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc); break; From 256df51e727235b3d5e937ca2784c45663c00f59 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Fri, 18 Apr 2025 16:21:01 +0800 Subject: [PATCH 0239/2760] target/loongarch: Add CRC feature flag and use it to gate CRC instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces the obsolete IOCSR_BRD bit with CRC in cpucfg1[25], in both LA464 and LA132 CPU initialization functions. The corresponding field macro in `cpu.h` is updated to reflect this change. Additionally, the availability macro `avail_CRC()` is introduced in `translate.h` to check the CRC feature flag. All CRC-related instruction translations are updated to be gated by the new CRC feature flag instead of hardcoded CPU features. This ensures correctness and configurability when enabling CRC instructions based on hardware capabilities. Signed-off-by: WANG Rui Reviewed-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Message-Id: <20250418082103.447780-2-wangrui@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/cpu.c | 4 ++-- target/loongarch/cpu.h | 2 +- .../loongarch/tcg/insn_trans/trans_extra.c.inc | 16 ++++++++-------- target/loongarch/translate.h | 1 + 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index bf3d592574..588f5fd021 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -432,7 +432,7 @@ static void loongarch_la464_initfn(Object *obj) data = FIELD_DP32(data, CPUCFG1, EP, 1); data = FIELD_DP32(data, CPUCFG1, RPLV, 1); data = FIELD_DP32(data, CPUCFG1, HP, 1); - data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); + data = FIELD_DP32(data, CPUCFG1, CRC, 1); env->cpucfg[1] = data; data = 0; @@ -531,7 +531,7 @@ static void loongarch_la132_initfn(Object *obj) data = FIELD_DP32(data, CPUCFG1, EP, 0); data = FIELD_DP32(data, CPUCFG1, RPLV, 0); data = FIELD_DP32(data, CPUCFG1, HP, 1); - data = FIELD_DP32(data, CPUCFG1, IOCSR_BRD, 1); + data = FIELD_DP32(data, CPUCFG1, CRC, 1); env->cpucfg[1] = data; } diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 254e4fbdcd..ab76a0b451 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -129,7 +129,7 @@ FIELD(CPUCFG1, RI, 21, 1) FIELD(CPUCFG1, EP, 22, 1) FIELD(CPUCFG1, RPLV, 23, 1) FIELD(CPUCFG1, HP, 24, 1) -FIELD(CPUCFG1, IOCSR_BRD, 25, 1) +FIELD(CPUCFG1, CRC, 25, 1) FIELD(CPUCFG1, MSG_INT, 26, 1) /* cpucfg[1].arch */ diff --git a/target/loongarch/tcg/insn_trans/trans_extra.c.inc b/target/loongarch/tcg/insn_trans/trans_extra.c.inc index cfa361fecf..eda3d6e561 100644 --- a/target/loongarch/tcg/insn_trans/trans_extra.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_extra.c.inc @@ -97,11 +97,11 @@ static bool gen_crc(DisasContext *ctx, arg_rrr *a, return true; } -TRANS(crc_w_b_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) -TRANS(crc_w_h_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) -TRANS(crc_w_w_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) -TRANS(crc_w_d_w, 64, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) -TRANS(crcc_w_b_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) -TRANS(crcc_w_h_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) -TRANS(crcc_w_w_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) -TRANS(crcc_w_d_w, 64, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) +TRANS(crc_w_b_w, CRC, gen_crc, gen_helper_crc32, tcg_constant_tl(1)) +TRANS(crc_w_h_w, CRC, gen_crc, gen_helper_crc32, tcg_constant_tl(2)) +TRANS(crc_w_w_w, CRC, gen_crc, gen_helper_crc32, tcg_constant_tl(4)) +TRANS(crc_w_d_w, CRC, gen_crc, gen_helper_crc32, tcg_constant_tl(8)) +TRANS(crcc_w_b_w, CRC, gen_crc, gen_helper_crc32c, tcg_constant_tl(1)) +TRANS(crcc_w_h_w, CRC, gen_crc, gen_helper_crc32c, tcg_constant_tl(2)) +TRANS(crcc_w_w_w, CRC, gen_crc, gen_helper_crc32c, tcg_constant_tl(4)) +TRANS(crcc_w_d_w, CRC, gen_crc, gen_helper_crc32c, tcg_constant_tl(8)) diff --git a/target/loongarch/translate.h b/target/loongarch/translate.h index 195f53573a..018dc5eb17 100644 --- a/target/loongarch/translate.h +++ b/target/loongarch/translate.h @@ -25,6 +25,7 @@ #define avail_LSX(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LSX)) #define avail_LASX(C) (FIELD_EX32((C)->cpucfg2, CPUCFG2, LASX)) #define avail_IOCSR(C) (FIELD_EX32((C)->cpucfg1, CPUCFG1, IOCSR)) +#define avail_CRC(C) (FIELD_EX32((C)->cpucfg1, CPUCFG1, CRC)) /* * If an operation is being performed on less than TARGET_LONG_BITS, From 875caabdb1701a7c57ad0655a7963d74afc1b4d9 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Fri, 18 Apr 2025 16:21:02 +0800 Subject: [PATCH 0240/2760] target/loongarch: Guard BCEQZ/BCNEZ instructions with FP feature The BCEQZ and BCNEZ instructions depend on access to condition codes from floating-point comparisons. Previously, these instructions were unconditionally enabled for 64-bit targets. This patch updates their translation to be gated under the `FP` feature flag instead, ensuring they are only available when the floating-point unit is present. This improves correctness for CPUs lacking floating-point support. Signed-off-by: WANG Rui Reviewed-by: Bibo Mao Message-Id: <20250418082103.447780-3-wangrui@loongson.cn> Signed-off-by: Song Gao --- target/loongarch/tcg/insn_trans/trans_branch.c.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/loongarch/tcg/insn_trans/trans_branch.c.inc b/target/loongarch/tcg/insn_trans/trans_branch.c.inc index 221e5159db..f94c1f37ab 100644 --- a/target/loongarch/tcg/insn_trans/trans_branch.c.inc +++ b/target/loongarch/tcg/insn_trans/trans_branch.c.inc @@ -80,5 +80,5 @@ TRANS(bltu, ALL, gen_rr_bc, TCG_COND_LTU) TRANS(bgeu, ALL, gen_rr_bc, TCG_COND_GEU) TRANS(beqz, ALL, gen_rz_bc, TCG_COND_EQ) TRANS(bnez, ALL, gen_rz_bc, TCG_COND_NE) -TRANS(bceqz, 64, gen_cz_bc, TCG_COND_EQ) -TRANS(bcnez, 64, gen_cz_bc, TCG_COND_NE) +TRANS(bceqz, FP, gen_cz_bc, TCG_COND_EQ) +TRANS(bcnez, FP, gen_cz_bc, TCG_COND_NE) From 720a0e417ef0814d90aa884096a643b02ee854dc Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 7 Apr 2025 10:26:41 +0200 Subject: [PATCH 0241/2760] cleanup: Re-run return_directly.cocci MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coccinelle's indentation of virt_create_plic() results in a long line. Avoid that by mimicking the old indentation manually. Don't touch tests/tcg/mips/user/. I'm not sure these files are ours to make style cleanups on. They might be imported third-party code, which we should leave as is to not complicate future updates. Signed-off-by: Markus Armbruster Reviewed-by: Richard Henderson Message-ID: <20250407082643.2310002-2-armbru@redhat.com> Reviewed-by: Philippe Mathieu-Daudé --- hw/gpio/pca9554.c | 5 +---- hw/i386/kvm/xen_xenstore.c | 4 +--- hw/riscv/virt.c | 25 ++++++++++--------------- hw/scsi/esp.c | 5 +---- hw/vfio/common.c | 7 ++----- plugins/api.c | 4 +--- tests/qtest/cmsdk-apb-watchdog-test.c | 6 +----- tests/qtest/pnv-host-i2c-test.c | 4 +--- tests/qtest/stm32l4x5_usart-test.c | 6 +----- tools/i386/qemu-vmsr-helper.c | 5 +---- 10 files changed, 20 insertions(+), 51 deletions(-) diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index fe03bb4b5e..7301fce934 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -118,11 +118,8 @@ static void pca9554_write(PCA9554State *s, uint8_t reg, uint8_t data) static uint8_t pca9554_recv(I2CSlave *i2c) { PCA9554State *s = PCA9554(i2c); - uint8_t ret; - ret = pca9554_read(s, s->pointer & 0x3); - - return ret; + return pca9554_read(s, s->pointer & 0x3); } static int pca9554_send(I2CSlave *i2c, uint8_t data) diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 17802aa33d..227ad7ace3 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -209,7 +209,6 @@ static int xen_xenstore_post_load(void *opaque, int ver) { XenXenstoreState *s = opaque; GByteArray *save; - int ret; /* * As qemu/dom0, rebind to the guest's port. The Windows drivers may @@ -231,8 +230,7 @@ static int xen_xenstore_post_load(void *opaque, int ver) s->impl_state = NULL; s->impl_state_size = 0; - ret = xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s); - return ret; + return xs_impl_deserialize(s->impl, save, xen_domid, fire_watch_cb, s); } static const VMStateDescription xen_xenstore_vmstate = { diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e517002fdf..85849e604c 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1276,27 +1276,22 @@ static FWCfgState *create_fw_cfg(const MachineState *ms) static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket, int base_hartid, int hart_count) { - DeviceState *ret; g_autofree char *plic_hart_config = NULL; /* Per-socket PLIC hart topology configuration string */ plic_hart_config = riscv_plic_hart_config_string(hart_count); /* Per-socket PLIC */ - ret = sifive_plic_create( - memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size, - plic_hart_config, hart_count, base_hartid, - VIRT_IRQCHIP_NUM_SOURCES, - ((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1), - VIRT_PLIC_PRIORITY_BASE, - VIRT_PLIC_PENDING_BASE, - VIRT_PLIC_ENABLE_BASE, - VIRT_PLIC_ENABLE_STRIDE, - VIRT_PLIC_CONTEXT_BASE, - VIRT_PLIC_CONTEXT_STRIDE, - memmap[VIRT_PLIC].size); - - return ret; + return sifive_plic_create( + memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size, + plic_hart_config, hart_count, base_hartid, + VIRT_IRQCHIP_NUM_SOURCES, + ((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1), + VIRT_PLIC_PRIORITY_BASE, VIRT_PLIC_PENDING_BASE, + VIRT_PLIC_ENABLE_BASE, VIRT_PLIC_ENABLE_STRIDE, + VIRT_PLIC_CONTEXT_BASE, + VIRT_PLIC_CONTEXT_STRIDE, + memmap[VIRT_PLIC].size); } static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests, diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index ac841dc32e..01bdfe2701 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -242,10 +242,7 @@ static uint32_t esp_get_stc(ESPState *s) static uint8_t esp_pdma_read(ESPState *s) { - uint8_t val; - - val = esp_fifo_pop(s); - return val; + return esp_fifo_pop(s); } static void esp_pdma_write(ESPState *s, uint8_t val) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 1a0d9290f8..d8aad4e1ce 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -110,8 +110,6 @@ static bool vfio_multiple_devices_migration_is_supported(void) int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp) { - int ret; - if (vfio_multiple_devices_migration_is_supported()) { return 0; } @@ -129,9 +127,8 @@ int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp) error_setg(&multiple_devices_migration_blocker, "Multiple VFIO devices migration is supported only if all of " "them support P2P migration"); - ret = migrate_add_blocker_normal(&multiple_devices_migration_blocker, errp); - - return ret; + return migrate_add_blocker_normal(&multiple_devices_migration_blocker, + errp); } void vfio_unblock_multiple_devices_migration(void) diff --git a/plugins/api.c b/plugins/api.c index 604ce06802..3c9d4832e9 100644 --- a/plugins/api.c +++ b/plugins/api.c @@ -237,12 +237,10 @@ uint64_t qemu_plugin_tb_vaddr(const struct qemu_plugin_tb *tb) struct qemu_plugin_insn * qemu_plugin_tb_get_insn(const struct qemu_plugin_tb *tb, size_t idx) { - struct qemu_plugin_insn *insn; if (unlikely(idx >= tb->n)) { return NULL; } - insn = g_ptr_array_index(tb->insns, idx); - return insn; + return g_ptr_array_index(tb->insns, idx); } /* diff --git a/tests/qtest/cmsdk-apb-watchdog-test.c b/tests/qtest/cmsdk-apb-watchdog-test.c index 53538f98c9..cd0c602361 100644 --- a/tests/qtest/cmsdk-apb-watchdog-test.c +++ b/tests/qtest/cmsdk-apb-watchdog-test.c @@ -364,8 +364,6 @@ static void test_watchdog_inten_luminary(const void *ptr) int main(int argc, char **argv) { - int r; - g_test_init(&argc, &argv, NULL); g_test_set_nonfatal_assertions(); @@ -393,7 +391,5 @@ int main(int argc, char **argv) test_watchdog_inten); } - r = g_test_run(); - - return r; + return g_test_run(); } diff --git a/tests/qtest/pnv-host-i2c-test.c b/tests/qtest/pnv-host-i2c-test.c index 7f64d597ac..51e613ebdc 100644 --- a/tests/qtest/pnv-host-i2c-test.c +++ b/tests/qtest/pnv-host-i2c-test.c @@ -191,12 +191,10 @@ static uint8_t pnv_i2c_pca9554_read_pins(PnvI2cDev *dev) { uint8_t send_buf[1]; uint8_t recv_buf[1]; - uint8_t inputs; send_buf[0] = PCA9554_INPUT; pnv_i2c_send(dev, send_buf, 1); pnv_i2c_recv(dev, recv_buf, 1); - inputs = recv_buf[0]; - return inputs; + return recv_buf[0]; } static void pnv_i2c_pca9554_flip_polarity(PnvI2cDev *dev) diff --git a/tests/qtest/stm32l4x5_usart-test.c b/tests/qtest/stm32l4x5_usart-test.c index 927bab6361..98a7472307 100644 --- a/tests/qtest/stm32l4x5_usart-test.c +++ b/tests/qtest/stm32l4x5_usart-test.c @@ -360,8 +360,6 @@ static void test_clock_enable(void) int main(int argc, char **argv) { - int ret; - g_test_init(&argc, &argv, NULL); g_test_set_nonfatal_assertions(); @@ -372,8 +370,6 @@ int main(int argc, char **argv) qtest_add_func("stm32l4x5/usart/send_str", test_send_str); qtest_add_func("stm32l4x5/usart/ack", test_ack); qtest_add_func("stm32l4x5/usart/clock_enable", test_clock_enable); - ret = g_test_run(); - - return ret; + return g_test_run(); } diff --git a/tools/i386/qemu-vmsr-helper.c b/tools/i386/qemu-vmsr-helper.c index a35dcb88a3..5f19a48cbd 100644 --- a/tools/i386/qemu-vmsr-helper.c +++ b/tools/i386/qemu-vmsr-helper.c @@ -71,7 +71,6 @@ static void compute_default_paths(void) static int is_intel_processor(void) { - int result; int ebx, ecx, edx; /* Execute CPUID instruction with eax=0 (basic identification) */ @@ -87,9 +86,7 @@ static int is_intel_processor(void) * 0x49656e69 = "ineI" * 0x6c65746e = "ntel" */ - result = (ebx == 0x756e6547) && (edx == 0x49656e69) && (ecx == 0x6c65746e); - - return result; + return (ebx == 0x756e6547) && (edx == 0x49656e69) && (ecx == 0x6c65746e); } static int is_rapl_enabled(void) From 8a2b516ba2855c4530388051de2b8d17bc780ea8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 7 Apr 2025 10:26:42 +0200 Subject: [PATCH 0242/2760] cleanup: Drop pointless return at end of function A few functions now end with a label. The next commit will clean them up. Signed-off-by: Markus Armbruster Reviewed-by: Richard Henderson Message-ID: <20250407082643.2310002-3-armbru@redhat.com> [Straightforward conflict with commit 988ad4ccebb6 (hw/loongarch/virt: Fix cpuslot::cpu set at last in virt_cpu_plug()) resolved] --- accel/tcg/cpu-exec.c | 1 - block/gluster.c | 4 ---- block/rbd.c | 1 - block/replication.c | 1 - block/throttle-groups.c | 1 - bsd-user/signal.c | 1 - dump/win_dump.c | 2 -- event-loop-base.c | 2 -- hw/acpi/acpi-cpu-hotplug-stub.c | 8 -------- hw/acpi/acpi-mem-hotplug-stub.c | 5 ----- hw/acpi/acpi-nvdimm-stub.c | 1 - hw/acpi/acpi-pci-hotplug-stub.c | 6 ------ hw/arm/exynos4210.c | 1 - hw/arm/smmu-common.c | 1 - hw/arm/xen-stubs.c | 1 - hw/audio/asc.c | 1 - hw/core/qdev-properties-system.c | 1 - hw/cxl/cxl-host.c | 2 -- hw/display/macfb.c | 1 - hw/display/tcx.c | 1 - hw/display/virtio-gpu-base.c | 1 - hw/dma/sifive_pdma.c | 1 - hw/gpio/aspeed_gpio.c | 5 ----- hw/gpio/bcm2838_gpio.c | 1 - hw/gpio/imx_gpio.c | 2 -- hw/gpio/pl061.c | 1 - hw/hyperv/vmbus.c | 1 - hw/i2c/pm_smbus.c | 1 - hw/i386/intel_iommu.c | 2 -- hw/i386/nitro_enclave.c | 1 - hw/i386/xen/xen-hvm.c | 2 -- hw/input/virtio-input-host.c | 1 - hw/intc/arm_gicv3_cpuif.c | 1 - hw/intc/aspeed_intc.c | 4 ---- hw/intc/mips_gic.c | 1 - hw/ipmi/ipmi_bmc_extern.c | 2 -- hw/ipmi/ipmi_bmc_sim.c | 2 -- hw/ipmi/ipmi_bt.c | 1 - hw/ipmi/ipmi_kcs.c | 1 - hw/loongarch/virt.c | 2 -- hw/m68k/next-cube.c | 1 - hw/m68k/q800.c | 2 -- hw/mem/cxl_type3.c | 4 ---- hw/mem/sparse-mem.c | 1 - hw/misc/i2c-echo.c | 2 -- hw/misc/ivshmem-flat.c | 2 -- hw/misc/mips_cpc.c | 2 -- hw/net/can/ctucan_core.c | 2 -- hw/net/can/xlnx-versal-canfd.c | 2 -- hw/net/imx_fec.c | 1 - hw/net/vmxnet3.c | 1 - hw/nvram/xlnx-versal-efuse-ctrl.c | 1 - hw/ppc/mac_newworld.c | 2 -- hw/ppc/pnv_occ.c | 1 - hw/ppc/spapr_hcall.c | 1 - hw/ppc/spapr_nested.c | 1 - hw/ppc/spapr_nvdimm.c | 2 -- hw/s390x/s390-pci-bus.c | 1 - hw/s390x/s390-pci-vfio.c | 2 -- hw/scsi/megasas.c | 1 - hw/scsi/vhost-scsi.c | 1 - hw/ssi/ibex_spi_host.c | 1 - hw/ssi/pnv_spi.c | 2 -- hw/tpm/tpm_tis_i2c.c | 4 ---- hw/usb/dev-mtp.c | 2 -- hw/usb/dev-serial.c | 2 -- hw/usb/dev-smartcard-reader.c | 1 - hw/usb/dev-uas.c | 1 - hw/vfio/display.c | 1 - hw/vfio/pci.c | 1 - hw/vfio/platform.c | 1 - hw/virtio/vhost-user-fs.c | 1 - hw/virtio/vhost-user-scmi.c | 2 -- hw/virtio/vhost-user-vsock.c | 1 - hw/virtio/vhost-user.c | 2 -- hw/virtio/vhost-vdpa.c | 2 -- hw/virtio/vhost.c | 1 - hw/virtio/virtio-nsm.c | 1 - hw/virtio/virtio.c | 2 -- hw/watchdog/sbsa_gwdt.c | 1 - hw/watchdog/wdt_aspeed.c | 1 - include/system/os-win32.h | 1 - linux-user/xtensa/signal.c | 1 - migration/multifd-nocomp.c | 1 - migration/qemu-file.c | 2 -- migration/ram.c | 2 -- net/colo-compare.c | 2 -- qemu-keymap.c | 1 - qga/commands-win32.c | 4 ---- system/dirtylimit.c | 2 -- target/arm/tcg/helper-a64.c | 2 -- target/i386/kvm/vmsr_energy.c | 1 - target/i386/tcg/translate.c | 1 - target/i386/whpx/whpx-all.c | 11 ----------- target/m68k/helper.c | 1 - target/mips/tcg/system/mips-semi.c | 1 - target/ppc/kvm.c | 1 - target/ppc/kvm_ppc.h | 3 --- target/ppc/translate.c | 1 - target/riscv/debug.c | 6 ------ target/s390x/cpu_models.c | 1 - target/sh4/translate.c | 1 - tests/qtest/ahci-test.c | 1 - tests/qtest/fuzz/generic_fuzz.c | 1 - tests/qtest/libqos/libqos-malloc.c | 1 - tests/qtest/libqtest.c | 1 - tests/qtest/test-x86-cpuid-compat.c | 1 - tests/unit/socket-helpers.c | 1 - tests/unit/test-qgraph.c | 1 - ui/input-linux.c | 1 - ui/vnc.c | 2 -- util/main-loop.c | 1 - util/qht.c | 1 - 113 files changed, 196 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index ef3d967e3a..8e28136392 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -665,7 +665,6 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, out_unlock_next: qemu_spin_unlock(&tb_next->jmp_lock); - return; } static inline bool cpu_handle_halt(CPUState *cpu) diff --git a/block/gluster.c b/block/gluster.c index c6d25ae733..8712aa606a 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -972,8 +972,6 @@ static void qemu_gluster_reopen_commit(BDRVReopenState *state) g_free(state->opaque); state->opaque = NULL; - - return; } @@ -993,8 +991,6 @@ static void qemu_gluster_reopen_abort(BDRVReopenState *state) g_free(state->opaque); state->opaque = NULL; - - return; } #ifdef CONFIG_GLUSTERFS_ZEROFILL diff --git a/block/rbd.c b/block/rbd.c index af984fb7db..7446e66659 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -254,7 +254,6 @@ static void qemu_rbd_parse_filename(const char *filename, QDict *options, done: g_free(buf); qobject_unref(keypairs); - return; } static int qemu_rbd_set_auth(rados_t cluster, BlockdevOptionsRbd *opts, diff --git a/block/replication.c b/block/replication.c index 0020f33843..d6625c51fe 100644 --- a/block/replication.c +++ b/block/replication.c @@ -176,7 +176,6 @@ static void replication_child_perm(BlockDriverState *bs, BdrvChild *c, *nshared = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED; - return; } static int64_t coroutine_fn GRAPH_RDLOCK diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 32553b39e3..9f4d252c74 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -908,7 +908,6 @@ unlock: qemu_mutex_unlock(&tg->lock); qapi_free_ThrottleLimits(argp); error_propagate(errp, local_err); - return; } static void throttle_group_get_limits(Object *obj, Visitor *v, diff --git a/bsd-user/signal.c b/bsd-user/signal.c index a8cfcca130..1aa0fd79d6 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -441,7 +441,6 @@ void queue_signal(CPUArchState *env, int sig, int si_type, ts->sync_signal.pending = sig; /* Signal that a new signal is pending. */ qatomic_set(&ts->signal_pending, 1); - return; } static int fatal_signal(int sig) diff --git a/dump/win_dump.c b/dump/win_dump.c index 2c2576672a..3162e8bd48 100644 --- a/dump/win_dump.c +++ b/dump/win_dump.c @@ -476,8 +476,6 @@ out_free: g_free(saved_ctx); out_cr3: first_x86_cpu->env.cr[3] = saved_cr3; - - return; } #else /* !TARGET_X86_64 */ diff --git a/event-loop-base.c b/event-loop-base.c index 0cfb1c9496..ddf8400a6b 100644 --- a/event-loop-base.c +++ b/event-loop-base.c @@ -73,8 +73,6 @@ static void event_loop_base_set_param(Object *obj, Visitor *v, if (bc->update_params) { bc->update_params(base, errp); } - - return; } static void event_loop_base_complete(UserCreatable *uc, Error **errp) diff --git a/hw/acpi/acpi-cpu-hotplug-stub.c b/hw/acpi/acpi-cpu-hotplug-stub.c index c6c61bb9cd..9872dd55e4 100644 --- a/hw/acpi/acpi-cpu-hotplug-stub.c +++ b/hw/acpi/acpi-cpu-hotplug-stub.c @@ -10,47 +10,39 @@ void acpi_switch_to_modern_cphp(AcpiCpuHotplug *gpe_cpu, CPUHotplugState *cpuhp_state, uint16_t io_port) { - return; } void legacy_acpi_cpu_hotplug_init(MemoryRegion *parent, Object *owner, AcpiCpuHotplug *gpe_cpu, uint16_t base) { - return; } void cpu_hotplug_hw_init(MemoryRegion *as, Object *owner, CPUHotplugState *state, hwaddr base_addr) { - return; } void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list) { - return; } void acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, CPUHotplugState *cpu_st, DeviceState *dev, Error **errp) { - return; } void legacy_acpi_cpu_plug_cb(HotplugHandler *hotplug_dev, AcpiCpuHotplug *g, DeviceState *dev, Error **errp) { - return; } void acpi_cpu_unplug_cb(CPUHotplugState *cpu_st, DeviceState *dev, Error **errp) { - return; } void acpi_cpu_unplug_request_cb(HotplugHandler *hotplug_dev, CPUHotplugState *cpu_st, DeviceState *dev, Error **errp) { - return; } diff --git a/hw/acpi/acpi-mem-hotplug-stub.c b/hw/acpi/acpi-mem-hotplug-stub.c index 73a076a265..7ad0fdcdf2 100644 --- a/hw/acpi/acpi-mem-hotplug-stub.c +++ b/hw/acpi/acpi-mem-hotplug-stub.c @@ -7,29 +7,24 @@ const VMStateDescription vmstate_memory_hotplug; void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, MemHotplugState *state, hwaddr io_base) { - return; } void acpi_memory_ospm_status(MemHotplugState *mem_st, ACPIOSTInfoList ***list) { - return; } void acpi_memory_plug_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, DeviceState *dev, Error **errp) { - return; } void acpi_memory_unplug_cb(MemHotplugState *mem_st, DeviceState *dev, Error **errp) { - return; } void acpi_memory_unplug_request_cb(HotplugHandler *hotplug_dev, MemHotplugState *mem_st, DeviceState *dev, Error **errp) { - return; } diff --git a/hw/acpi/acpi-nvdimm-stub.c b/hw/acpi/acpi-nvdimm-stub.c index 8baff9be6f..65f491d653 100644 --- a/hw/acpi/acpi-nvdimm-stub.c +++ b/hw/acpi/acpi-nvdimm-stub.c @@ -4,5 +4,4 @@ void nvdimm_acpi_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev) { - return; } diff --git a/hw/acpi/acpi-pci-hotplug-stub.c b/hw/acpi/acpi-pci-hotplug-stub.c index dcee3ad7a1..b67b4a92da 100644 --- a/hw/acpi/acpi-pci-hotplug-stub.c +++ b/hw/acpi/acpi-pci-hotplug-stub.c @@ -7,37 +7,31 @@ const VMStateDescription vmstate_acpi_pcihp_pci_status; void acpi_pcihp_init(Object *owner, AcpiPciHpState *s, PCIBus *root_bus, MemoryRegion *address_space_io, uint16_t io_base) { - return; } void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp) { - return; } void acpi_pcihp_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - return; } void acpi_pcihp_device_unplug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp) { - return; } void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s, DeviceState *dev, Error **errp) { - return; } void acpi_pcihp_reset(AcpiPciHpState *s) { - return; } bool acpi_pcihp_is_hotpluggbale_bus(AcpiPciHpState *s, BusState *bus) diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index b452470598..0c27588116 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -462,7 +462,6 @@ static uint64_t exynos4210_chipid_and_omr_read(void *opaque, hwaddr offset, static void exynos4210_chipid_and_omr_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - return; } static const MemoryRegionOps exynos4210_chipid_and_omr_ops = { diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 6e720e1b9a..1aa2eabfbd 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -712,7 +712,6 @@ static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2, tlbe->entry.iova = iova & ~tlbe->entry.addr_mask; /* parent_perm has s2 perm while perm keeps s1 perm. */ tlbe->parent_perm = tlbe_s2->entry.perm; - return; } /** diff --git a/hw/arm/xen-stubs.c b/hw/arm/xen-stubs.c index 5551584dc2..6a83043553 100644 --- a/hw/arm/xen-stubs.c +++ b/hw/arm/xen-stubs.c @@ -14,7 +14,6 @@ void arch_handle_ioreq(XenIOState *state, ioreq_t *req) { hw_error("Invalid ioreq type 0x%x\n", req->type); - return; } void arch_xen_set_memory(XenIOState *state, MemoryRegionSection *section, diff --git a/hw/audio/asc.c b/hw/audio/asc.c index cc205bf063..cea7a1c053 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -406,7 +406,6 @@ static void asc_fifo_write(void *opaque, hwaddr addr, uint64_t value, } else { fs->fifo[addr] = value; } - return; } static const MemoryRegionOps asc_fifo_ops = { diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c index a7dde73c29..8e11e6388b 100644 --- a/hw/core/qdev-properties-system.c +++ b/hw/core/qdev-properties-system.c @@ -793,7 +793,6 @@ separator_error: error_setg(errp, "reserved region fields must be separated with ':'"); out: g_free(str); - return; } const PropertyInfo qdev_prop_reserved_region = { diff --git a/hw/cxl/cxl-host.c b/hw/cxl/cxl-host.c index 2c6b43cd0d..e010163174 100644 --- a/hw/cxl/cxl-host.c +++ b/hw/cxl/cxl-host.c @@ -67,8 +67,6 @@ static void cxl_fixed_memory_window_config(CXLState *cxl_state, cxl_state->fixed_windows = g_list_append(cxl_state->fixed_windows, g_steal_pointer(&fw)); - - return; } void cxl_fmws_link_targets(CXLState *cxl_state, Error **errp) diff --git a/hw/display/macfb.c b/hw/display/macfb.c index e83fc863be..b08eb06cbd 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -383,7 +383,6 @@ static void macfb_sense_write(MacfbState *s, uint32_t val) s->regs[DAFB_MODE_SENSE >> 2] = val; trace_macfb_sense_write(val); - return; } static void macfb_update_mode(MacfbState *s) diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 2cfc1e8f01..5968d33e48 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -729,7 +729,6 @@ static uint64_t tcx_dummy_readl(void *opaque, hwaddr addr, static void tcx_dummy_writel(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - return; } static const MemoryRegionOps tcx_dummy_ops = { diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 7827536ac4..321a6f4998 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -110,7 +110,6 @@ static void virtio_gpu_ui_info(void *opaque, uint32_t idx, QemuUIInfo *info) /* send event to guest */ virtio_gpu_notify_event(g, VIRTIO_GPU_EVENT_DISPLAY); - return; } static void diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c index 25b3d6a155..a115af8d60 100644 --- a/hw/dma/sifive_pdma.c +++ b/hw/dma/sifive_pdma.c @@ -152,7 +152,6 @@ done: error: s->chan[ch].state = DMA_CHAN_STATE_ERROR; s->chan[ch].control |= CONTROL_ERR; - return; } static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch) diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index a5b3f454e8..aedaf5238b 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -800,7 +800,6 @@ static void aspeed_gpio_write_index_mode(void *opaque, hwaddr offset, return; } aspeed_gpio_update(s, set, set->data_value, UINT32_MAX); - return; } static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, @@ -928,7 +927,6 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data, return; } aspeed_gpio_update(s, set, set->data_value, UINT32_MAX); - return; } static int get_set_idx(AspeedGPIOState *s, const char *group, int *group_idx) @@ -1183,7 +1181,6 @@ static void aspeed_gpio_2700_write_control_reg(AspeedGPIOState *s, } aspeed_gpio_update(s, set, set->data_value, UINT32_MAX); - return; } static uint64_t aspeed_gpio_2700_read(void *opaque, hwaddr offset, @@ -1308,8 +1305,6 @@ static void aspeed_gpio_2700_write(void *opaque, hwaddr offset, PRIx64"\n", __func__, offset); break; } - - return; } /* Setup functions */ diff --git a/hw/gpio/bcm2838_gpio.c b/hw/gpio/bcm2838_gpio.c index 0a1739fc46..53be8f2d23 100644 --- a/hw/gpio/bcm2838_gpio.c +++ b/hw/gpio/bcm2838_gpio.c @@ -293,7 +293,6 @@ static void bcm2838_gpio_write(void *opaque, hwaddr offset, uint64_t value, qemu_log_mask(LOG_GUEST_ERROR, "%s: %s: bad offset %"HWADDR_PRIx"\n", TYPE_BCM2838_GPIO, __func__, offset); } - return; } static void bcm2838_gpio_reset(DeviceState *dev) diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c index 549a281ed7..8c8299c4c4 100644 --- a/hw/gpio/imx_gpio.c +++ b/hw/gpio/imx_gpio.c @@ -257,8 +257,6 @@ static void imx_gpio_write(void *opaque, hwaddr offset, uint64_t value, HWADDR_PRIx "\n", TYPE_IMX_GPIO, __func__, offset); break; } - - return; } static const MemoryRegionOps imx_gpio_ops = { diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 60ce4a7f62..2e69785f2a 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -443,7 +443,6 @@ static void pl061_write(void *opaque, hwaddr offset, return; } pl061_update(s); - return; } static void pl061_enter_reset(Object *obj, ResetType type) diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 12a7dc4312..f195e56c83 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2073,7 +2073,6 @@ static void send_unload(VMBus *vmbus) qemu_mutex_unlock(&vmbus->rx_queue_lock); post_msg(vmbus, &msg, sizeof(msg)); - return; } static bool complete_unload(VMBus *vmbus) diff --git a/hw/i2c/pm_smbus.c b/hw/i2c/pm_smbus.c index 3eed8110b9..4e685fd26e 100644 --- a/hw/i2c/pm_smbus.c +++ b/hw/i2c/pm_smbus.c @@ -205,7 +205,6 @@ out: error: s->smb_stat |= STS_DEV_ERR; - return; } static void smb_transaction_start(PMSMBus *s) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index dffd7ee885..0608aec8c5 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4515,8 +4515,6 @@ static void vtd_iommu_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n) trace_vtd_replay_ce_invalid(bus_n, PCI_SLOT(vtd_as->devfn), PCI_FUNC(vtd_as->devfn)); } - - return; } static void vtd_cap_init(IntelIOMMUState *s) diff --git a/hw/i386/nitro_enclave.c b/hw/i386/nitro_enclave.c index a058608afc..4b69f265cc 100644 --- a/hw/i386/nitro_enclave.c +++ b/hw/i386/nitro_enclave.c @@ -203,7 +203,6 @@ static void x86_load_eif(X86MachineState *x86ms, FWCfgState *fw_cfg, unlink(machine->kernel_filename); unlink(machine->initrd_filename); - return; } static bool create_memfd_backend(MachineState *ms, const char *path, diff --git a/hw/i386/xen/xen-hvm.c b/hw/i386/xen/xen-hvm.c index d4516acec6..ceb2242aa7 100644 --- a/hw/i386/xen/xen-hvm.c +++ b/hw/i386/xen/xen-hvm.c @@ -758,6 +758,4 @@ void arch_handle_ioreq(XenIOState *state, ioreq_t *req) default: hw_error("Invalid ioreq type 0x%x\n", req->type); } - - return; } diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index 8bfb17f3c4..b21a79046e 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -178,7 +178,6 @@ static void virtio_input_host_realize(DeviceState *dev, Error **errp) err_close: close(vih->fd); vih->fd = -1; - return; } static void virtio_input_host_unrealize(DeviceState *dev) diff --git a/hw/intc/arm_gicv3_cpuif.c b/hw/intc/arm_gicv3_cpuif.c index de37465bc8..4b4cf09157 100644 --- a/hw/intc/arm_gicv3_cpuif.c +++ b/hw/intc/arm_gicv3_cpuif.c @@ -584,7 +584,6 @@ static void icv_ap_write(CPUARMState *env, const ARMCPRegInfo *ri, } gicv3_cpuif_virt_irq_fiq_update(cs); - return; } static uint64_t icv_bpr_read(CPUARMState *env, const ARMCPRegInfo *ri) diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index f17bf43925..bae7dc95ea 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -448,8 +448,6 @@ static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, s->regs[reg] = data; break; } - - return; } static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset, @@ -496,8 +494,6 @@ static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data, s->regs[reg] = data; break; } - - return; } diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c index 5e3cbeabec..bd1dedd4b9 100644 --- a/hw/intc/mips_gic.c +++ b/hw/intc/mips_gic.c @@ -255,7 +255,6 @@ static void gic_write_vp(MIPSGICState *gic, uint32_t vp_index, hwaddr addr, return; bad_offset: qemu_log_mask(LOG_GUEST_ERROR, "Wrong GIC offset at 0x%" PRIx64 "\n", addr); - return; } static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index 3e9f8c5a50..22cb9b590b 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -142,7 +142,6 @@ static void continue_send(IPMIBmcExtern *ibe) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + 4000000000ULL); } } - return; } static void extern_timeout(void *opaque) @@ -231,7 +230,6 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b, continue_send(ibe); out: - return; } static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 1c60a71831..c6a85e8cd1 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -472,7 +472,6 @@ void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log) ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; k->set_atn(s, 1, attn_irq_enabled(ibs)); out: - return; } static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, uint8_t evd1, uint8_t evd2, uint8_t evd3) @@ -1014,7 +1013,6 @@ static void get_msg(IPMIBmcSim *ibs, } out: - return; } static unsigned char diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c index 28cf6ab218..5cf12c59a8 100644 --- a/hw/ipmi/ipmi_bt.c +++ b/hw/ipmi/ipmi_bt.c @@ -146,7 +146,6 @@ static void ipmi_bt_handle_event(IPMIInterface *ii) sizeof(ib->inmsg), ib->waiting_rsp); } out: - return; } static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id, diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c index 578dd7cef3..ae549fb864 100644 --- a/hw/ipmi/ipmi_kcs.c +++ b/hw/ipmi/ipmi_kcs.c @@ -198,7 +198,6 @@ static void ipmi_kcs_handle_event(IPMIInterface *ii) ik->data_in_reg = -1; IPMI_KCS_SET_IBF(ik->status_reg, 0); out_noibf: - return; } static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id, diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 65c9027feb..b2793c803e 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -948,7 +948,6 @@ static void virt_cpu_unplug(HotplugHandler *hotplug_dev, cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id); cpu_slot->cpu = NULL; - return; } static void virt_cpu_plug(HotplugHandler *hotplug_dev, @@ -973,7 +972,6 @@ static void virt_cpu_plug(HotplugHandler *hotplug_dev, cpu_slot = virt_find_cpu_slot(MACHINE(lvms), cpu->phy_id); cpu_slot->cpu = CPU(dev); - return; } static bool memhp_type_supported(DeviceState *dev) diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 0570e4a76f..7ea7e91032 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -899,7 +899,6 @@ static void next_dummy_en_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { /* Do nothing */ - return; } static uint64_t next_dummy_en_read(void *opaque, hwaddr addr, unsigned size) diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index aeed4c8ddb..1e5b0e21df 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -210,7 +210,6 @@ static uint64_t machine_id_read(void *opaque, hwaddr addr, unsigned size) static void machine_id_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - return; } static const MemoryRegionOps machine_id_ops = { @@ -231,7 +230,6 @@ static uint64_t ramio_read(void *opaque, hwaddr addr, unsigned size) static void ramio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - return; } static const MemoryRegionOps ramio_ops = { diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 6fffa21ead..43aa02ab2a 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -957,7 +957,6 @@ err_free_special_ops: if (ct3d->hostvmem) { address_space_destroy(&ct3d->hostvmem_as); } - return; } static void ct3_exit(PCIDevice *pci_dev) @@ -1511,8 +1510,6 @@ void qmp_cxl_inject_uncorrectable_errors(const char *path, stl_le_p(reg_state + R_CXL_RAS_UNC_ERR_STATUS, unc_err); pcie_aer_inject_error(PCI_DEVICE(obj), &err); - - return; } void qmp_cxl_inject_correctable_error(const char *path, CxlCorErrorType type, @@ -1788,7 +1785,6 @@ void qmp_cxl_inject_dram_event(const char *path, CxlEventLog log, uint8_t flags, if (cxl_event_insert(cxlds, enc_log, (CXLEventRecordRaw *)&dram)) { cxl_event_irq_assert(ct3d); } - return; } void qmp_cxl_inject_memory_module_event(const char *path, CxlEventLog log, diff --git a/hw/mem/sparse-mem.c b/hw/mem/sparse-mem.c index 6a9a591370..8bed5dbe16 100644 --- a/hw/mem/sparse-mem.c +++ b/hw/mem/sparse-mem.c @@ -82,7 +82,6 @@ static void sparse_mem_enter_reset(Object *obj, ResetType type) { SparseMemState *s = SPARSE_MEM(obj); g_hash_table_remove_all(s->mapped); - return; } static const MemoryRegionOps sparse_mem_ops = { diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c index 65d10029dc..fcd407dfc6 100644 --- a/hw/misc/i2c-echo.c +++ b/hw/misc/i2c-echo.c @@ -143,8 +143,6 @@ static void i2c_echo_realize(DeviceState *dev, Error **errp) state->bus = I2C_BUS(bus); state->bh = qemu_bh_new(i2c_echo_bh, state); - - return; } static void i2c_echo_class_init(ObjectClass *oc, void *data) diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c index 40309a8ff3..a0ac7543a2 100644 --- a/hw/misc/ivshmem-flat.c +++ b/hw/misc/ivshmem-flat.c @@ -289,8 +289,6 @@ static void ivshmem_flat_iomem_write(void *opaque, hwaddr offset, trace_ivshmem_flat_read_write_mmr_invalid(offset); break; } - - return; } static const MemoryRegionOps ivshmem_flat_ops = { diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c index 772b8c0017..b7a13d1afb 100644 --- a/hw/misc/mips_cpc.c +++ b/hw/misc/mips_cpc.c @@ -92,8 +92,6 @@ static void cpc_write(void *opaque, hwaddr offset, uint64_t data, "%s: Bad offset 0x%x\n", __func__, (int)offset); break; } - - return; } static uint64_t cpc_read(void *opaque, hwaddr offset, unsigned size) diff --git a/hw/net/can/ctucan_core.c b/hw/net/can/ctucan_core.c index 4402d4cb1f..17131a4e18 100644 --- a/hw/net/can/ctucan_core.c +++ b/hw/net/can/ctucan_core.c @@ -400,8 +400,6 @@ void ctucan_mem_write(CtuCanCoreState *s, hwaddr addr, uint64_t val, ctucan_update_irq(s); } - - return; } uint64_t ctucan_mem_read(CtuCanCoreState *s, hwaddr addr, unsigned size) diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c index dc242e9215..b5a4a4af7e 100644 --- a/hw/net/can/xlnx-versal-canfd.c +++ b/hw/net/can/xlnx-versal-canfd.c @@ -1298,8 +1298,6 @@ static void free_list(GSList *list) } g_slist_free(list); - - return; } static GSList *prepare_tx_data(XlnxVersalCANFDState *s) diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 0f0afda58a..b7c9ee0b9a 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -668,7 +668,6 @@ static void imx_default_write(IMXFECState *s, uint32_t index, uint32_t value) { qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad address at offset 0x%" PRIx32 "\n", TYPE_IMX_FEC, __func__, index * 4); - return; } static void imx_fec_write(IMXFECState *s, uint32_t index, uint32_t value) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 7abed66469..f370d4a2ec 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -932,7 +932,6 @@ static void vmxnet3_rx_update_descr(struct NetRxPkt *pkt, nocsum: rxcd->cnc = 1; - return; } static void diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c index 3246eb3ca6..ff4d544ad6 100644 --- a/hw/nvram/xlnx-versal-efuse-ctrl.c +++ b/hw/nvram/xlnx-versal-efuse-ctrl.c @@ -494,7 +494,6 @@ static void efuse_rd_addr_postw(RegisterInfo *reg, uint64_t val64) ARRAY_FIELD_DP32(s->regs, EFUSE_ISR, RD_DONE, 1); efuse_imr_update_irq(s); - return; } static uint64_t efuse_cache_load_prew(RegisterInfo *reg, uint64_t val64) diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 2d5309d6f5..8109e213a1 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -630,8 +630,6 @@ static void core99_instance_init(Object *obj) object_property_set_description(obj, "via", "Set VIA configuration. " "Valid values are cuda, pmu and pmu-adb"); - - return; } static const TypeInfo core99_machine_info = { diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 177c5e514b..0c9d3daec2 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -150,7 +150,6 @@ static void pnv_occ_common_area_write(void *opaque, hwaddr addr, uint64_t val, unsigned width) { /* callback function defined to occ common area write */ - return; } static const MemoryRegionOps pnv_occ_power8_xscom_ops = { diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 406aea4ecb..29453a880e 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -981,7 +981,6 @@ static void spapr_check_setup_free_hpt(SpaprMachineState *spapr, /* RADIX->HASH || NOTHING->HASH : Allocate HPT */ spapr_setup_hpt(spapr); } - return; } #define FLAGS_MASK 0x01FULL diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c index 201f629203..3797220a29 100644 --- a/hw/ppc/spapr_nested.c +++ b/hw/ppc/spapr_nested.c @@ -1735,7 +1735,6 @@ static void exit_process_output_buffer(SpaprMachineState *spapr, getset_state(spapr, guest, vcpuid, &gsr); address_space_unmap(CPU(cpu)->as, gsb, len, true, len); - return; } static diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 6f875d73b2..6e93ff9b33 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -235,8 +235,6 @@ void spapr_dt_persistent_memory(SpaprMachineState *spapr, void *fdt) spapr_dt_nvdimm(spapr, fdt, offset, nvdimm); } g_slist_free(nvdimms); - - return; } static target_ulong h_scm_read_metadata(PowerPCCPU *cpu, diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 2591ee49c1..d96819f1a4 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -597,7 +597,6 @@ static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, * zpci device" construct. But when we support migration of vfio-pci * devices in future, we need to revisit this. */ - return; } static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index 6236ac7f1e..db152a6252 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -367,6 +367,4 @@ void s390_pci_get_clp_info(S390PCIBusDevice *pbdev) s390_pci_read_group(pbdev, info); s390_pci_read_util(pbdev, info); s390_pci_read_pfip(pbdev, info); - - return; } diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index 9f3b30e6ce..d56bfc711d 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2226,7 +2226,6 @@ static uint64_t megasas_queue_read(void *opaque, hwaddr addr, static void megasas_queue_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - return; } static const MemoryRegionOps megasas_queue_ops = { diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 8039d13fd9..66e0c21c22 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -314,7 +314,6 @@ static void vhost_scsi_realize(DeviceState *dev, Error **errp) if (vhostfd >= 0) { close(vhostfd); } - return; } static void vhost_scsi_unrealize(DeviceState *dev) diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c index 46c7b633c2..6b28cda200 100644 --- a/hw/ssi/ibex_spi_host.c +++ b/hw/ssi/ibex_spi_host.c @@ -154,7 +154,6 @@ static void ibex_spi_host_reset(DeviceState *dev) ibex_spi_txfifo_reset(s); s->init_status = true; - return; } /* diff --git a/hw/ssi/pnv_spi.c b/hw/ssi/pnv_spi.c index 126070393e..367a2ff3bb 100644 --- a/hw/ssi/pnv_spi.c +++ b/hw/ssi/pnv_spi.c @@ -996,7 +996,6 @@ static void operation_sequencer(PnvSpi *s) } /* end of while */ /* Update sequencer index field in status.*/ s->status = SETFIELD(SPI_STS_SEQ_INDEX, s->status, seq_index); - return; } /* end of operation_sequencer() */ /* @@ -1142,7 +1141,6 @@ static void pnv_spi_xscom_write(void *opaque, hwaddr addr, qemu_log_mask(LOG_GUEST_ERROR, "pnv_spi_regs: Invalid xscom " "write at 0x%" PRIx32 "\n", reg); } - return; } static const MemoryRegionOps pnv_spi_xscom_ops = { diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c index 504328e3b0..92d3de1ea3 100644 --- a/hw/tpm/tpm_tis_i2c.c +++ b/hw/tpm/tpm_tis_i2c.c @@ -211,8 +211,6 @@ static inline void tpm_tis_i2c_clear_data(TPMStateI2C *i2cst) i2cst->tis_addr = 0xffffffff; i2cst->reg_name = NULL; memset(i2cst->data, 0, sizeof(i2cst->data)); - - return; } /* Send data to TPM */ @@ -281,8 +279,6 @@ static inline void tpm_tis_i2c_tpm_send(TPMStateI2C *i2cst) tpm_tis_i2c_clear_data(i2cst); } - - return; } /* Callback from TPM to indicate that response is copied */ diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 326c92a43d..4cd14c3df4 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -1234,8 +1234,6 @@ static void usb_mtp_object_delete(MTPState *s, uint32_t handle, default: g_assert_not_reached(); } - - return; } static void usb_mtp_command(MTPState *s, MTPControl *c) diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index aa50a92e26..31f6cf5b31 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -472,8 +472,6 @@ static void usb_serial_token_in(USBSerialState *s, USBPacket *p) s->recv_ptr = (s->recv_ptr + len) % RECV_BUF; packet_len -= len + 2; } - - return; } static void usb_serial_handle_data(USBDevice *dev, USBPacket *p) diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 73deb3ce83..84ca8c48e2 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1069,7 +1069,6 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p) err: p->status = USB_RET_STALL; s->bulk_out_pos = 0; - return; } static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p, diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 44e30013d7..b1d6b6ecc3 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -914,7 +914,6 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) err_stream: error_report("%s: invalid stream %d", __func__, p->stream); p->status = USB_RET_STALL; - return; } static void usb_uas_unrealize(USBDevice *dev) diff --git a/hw/vfio/display.c b/hw/vfio/display.c index ea87830fe0..4fdcef505d 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -104,7 +104,6 @@ static void vfio_display_edid_update(VFIOPCIDevice *vdev, bool enabled, err: trace_vfio_display_edid_write_error(); - return; } static void vfio_display_edid_ui_info(void *opaque, uint32_t idx, diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 7f1532fbed..f87f3ccbe1 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2383,7 +2383,6 @@ static void vfio_add_ext_cap(VFIOPCIDevice *vdev) } g_free(config); - return; } static bool vfio_add_capabilities(VFIOPCIDevice *vdev, Error **errp) diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index 67bc57409c..7b4e100e27 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -418,7 +418,6 @@ fail_vfio: abort(); fail_irqfd: vfio_start_eventfd_injection(sbdev, irq); - return; } /* VFIO skeleton */ diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index 3f00d79ed0..0e8d4b3823 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -267,7 +267,6 @@ err_virtio: g_free(fs->req_vqs); virtio_cleanup(vdev); g_free(fs->vhost_dev.vqs); - return; } static void vuf_device_unrealize(DeviceState *dev) diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c index 410a936ca7..04cd36dd2e 100644 --- a/hw/virtio/vhost-user-scmi.c +++ b/hw/virtio/vhost-user-scmi.c @@ -258,8 +258,6 @@ static void vu_scmi_device_realize(DeviceState *dev, Error **errp) qemu_chr_fe_set_handlers(&scmi->chardev, NULL, NULL, vu_scmi_event, NULL, dev, NULL, true); - - return; } static void vu_scmi_device_unrealize(DeviceState *dev) diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index 293273080b..d21cd4b516 100644 --- a/hw/virtio/vhost-user-vsock.c +++ b/hw/virtio/vhost-user-vsock.c @@ -128,7 +128,6 @@ err_vhost_dev: err_virtio: vhost_vsock_common_unrealize(vdev); vhost_user_cleanup(&vsock->vhost_user); - return; } static void vuv_device_unrealize(DeviceState *dev) diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c index 267b612587..fdc01ab99e 100644 --- a/hw/virtio/vhost-user.c +++ b/hw/virtio/vhost-user.c @@ -654,8 +654,6 @@ static void scrub_shadow_regions(struct vhost_dev *dev, } *nr_rem_reg = rm_idx; *nr_add_reg = add_idx; - - return; } static int send_remove_regions(struct vhost_dev *dev, diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 7efbde3d4c..8b45756ae7 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -288,8 +288,6 @@ static void vhost_vdpa_iommu_region_add(MemoryListener *listener, QLIST_INSERT_HEAD(&s->iommu_list, iommu, iommu_next); memory_region_iommu_replay(iommu->iommu_mr, &iommu->n); - - return; } static void vhost_vdpa_iommu_region_del(MemoryListener *listener, diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 6aa72fd434..4cae7c1664 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -732,7 +732,6 @@ out: memory_region_unref(old_sections[n_old_sections].mr); } g_free(old_sections); - return; } /* Adds the section data to the tmp_section structure. diff --git a/hw/virtio/virtio-nsm.c b/hw/virtio/virtio-nsm.c index b22aa74e34..accf7334e3 100644 --- a/hw/virtio/virtio-nsm.c +++ b/hw/virtio/virtio-nsm.c @@ -1609,7 +1609,6 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq) if (in_elem) { virtqueue_detach_element(vq, in_elem, 0); } - return; } static uint64_t get_features(VirtIODevice *vdev, uint64_t f, Error **errp) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 85110bce37..ffc12635ae 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3648,7 +3648,6 @@ static void virtio_queue_packed_restore_last_avail_idx(VirtIODevice *vdev, int n) { /* We don't have a reference like avail idx in shared memory */ - return; } static void virtio_queue_split_restore_last_avail_idx(VirtIODevice *vdev, @@ -3673,7 +3672,6 @@ void virtio_queue_restore_last_avail_idx(VirtIODevice *vdev, int n) static void virtio_queue_packed_update_used_idx(VirtIODevice *vdev, int n) { /* used idx was updated through set_last_avail_idx() */ - return; } static void virtio_queue_split_update_used_idx(VirtIODevice *vdev, int n) diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c index 65ac42a187..1dd21392a9 100644 --- a/hw/watchdog/sbsa_gwdt.c +++ b/hw/watchdog/sbsa_gwdt.c @@ -174,7 +174,6 @@ static void sbsa_gwdt_write(void *opaque, hwaddr offset, uint64_t data, qemu_log_mask(LOG_GUEST_ERROR, "bad address in control frame write :" " 0x%x\n", (int)offset); } - return; } static void wdt_sbsa_gwdt_reset(DeviceState *dev) diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index d94b83c109..a503b2aea7 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -225,7 +225,6 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data, "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", __func__, offset); } - return; } static const VMStateDescription vmstate_aspeed_wdt = { diff --git a/include/system/os-win32.h b/include/system/os-win32.h index bc623061d8..3aa6cee4c2 100644 --- a/include/system/os-win32.h +++ b/include/system/os-win32.h @@ -130,7 +130,6 @@ static inline int os_mlock(bool on_fault G_GNUC_UNUSED) static inline void os_setup_limits(void) { - return; } #define fsync _commit diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c index 6514b8dd57..ef8b0c3a27 100644 --- a/linux-user/xtensa/signal.c +++ b/linux-user/xtensa/signal.c @@ -241,7 +241,6 @@ void setup_rt_frame(int sig, struct target_sigaction *ka, give_sigsegv: force_sigsegv(sig); - return; } static void restore_sigcontext(CPUXtensaState *env, diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c index ffe75256c9..d0f38b410c 100644 --- a/migration/multifd-nocomp.c +++ b/migration/multifd-nocomp.c @@ -82,7 +82,6 @@ static void multifd_nocomp_send_cleanup(MultiFDSendParams *p, Error **errp) { g_free(p->iov); p->iov = NULL; - return; } static void multifd_ram_prepare_header(MultiFDSendParams *p) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 1303a5bf58..b6ac190034 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -561,8 +561,6 @@ void qemu_put_buffer_at(QEMUFile *f, const uint8_t *buf, size_t buflen, } stat64_add(&mig_stats.qemu_file_transferred, buflen); - - return; } diff --git a/migration/ram.c b/migration/ram.c index 424df6d9f1..dc909f5eef 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -3963,8 +3963,6 @@ static void parse_ramblock_mapped_ram(QEMUFile *f, RAMBlock *block, /* Skip pages array */ qemu_set_offset(f, block->pages_offset + length, SEEK_SET); - - return; } static int parse_ramblock(QEMUFile *f, RAMBlock *block, ram_addr_t length) diff --git a/net/colo-compare.c b/net/colo-compare.c index 165610bfe2..893beed528 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1328,8 +1328,6 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) } QTAILQ_INSERT_TAIL(&net_compares, s, next); qemu_mutex_unlock(&colo_compare_mutex); - - return; } static void colo_flush_packets(void *opaque, void *user_data) diff --git a/qemu-keymap.c b/qemu-keymap.c index 6707067fea..1c081db287 100644 --- a/qemu-keymap.c +++ b/qemu-keymap.c @@ -116,7 +116,6 @@ static void walk_map(struct xkb_keymap *map, xkb_keycode_t code, void *data) if (kshift != kaltgrshift && kaltgr != kaltgrshift) { print_sym(kaltgrshift, qcode, " shift altgr"); } - return; } static void usage(FILE *out) diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 749fdf8895..d4482538ec 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -826,8 +826,6 @@ static void get_disk_properties(HANDLE vol_h, GuestDiskAddress *disk, } out_free: g_free(dev_desc); - - return; } static void get_single_disk_info(int disk_number, @@ -891,7 +889,6 @@ static void get_single_disk_info(int disk_number, err_close: CloseHandle(disk_h); - return; } /* VSS provider works with volumes, thus there is no difference if @@ -2117,7 +2114,6 @@ static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp) rtl_get_version_t rtl_get_version = (rtl_get_version_t)fun; rtl_get_version(info); - return; } static char *ga_get_win_name(const OSVERSIONINFOEXW *os_version, bool id) diff --git a/system/dirtylimit.c b/system/dirtylimit.c index 7dedef8dd4..1626fa5617 100644 --- a/system/dirtylimit.c +++ b/system/dirtylimit.c @@ -337,8 +337,6 @@ static void dirtylimit_adjust_throttle(CPUState *cpu) if (!dirtylimit_done(quota, current)) { dirtylimit_set_throttle(cpu, quota, current); } - - return; } void dirtylimit_process(void) diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 9244848efe..ad3c4f38a1 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -1147,7 +1147,6 @@ static void do_setp(CPUARMState *env, uint32_t syndrome, uint32_t mtedesc, env->ZF = 1; /* our env->ZF encoding is inverted */ env->CF = 0; env->VF = 0; - return; } void HELPER(setp)(CPUARMState *env, uint32_t syndrome, uint32_t mtedesc) @@ -1547,7 +1546,6 @@ static void do_cpyp(CPUARMState *env, uint32_t syndrome, uint32_t wdesc, env->ZF = 1; /* our env->ZF encoding is inverted */ env->CF = 0; env->VF = 0; - return; } void HELPER(cpyp)(CPUARMState *env, uint32_t syndrome, uint32_t wdesc, diff --git a/target/i386/kvm/vmsr_energy.c b/target/i386/kvm/vmsr_energy.c index f499ec6e8b..d6aad5246b 100644 --- a/target/i386/kvm/vmsr_energy.c +++ b/target/i386/kvm/vmsr_energy.c @@ -284,7 +284,6 @@ void vmsr_read_thread_stat(pid_t pid, } fclose(file); - return; } /* Read QEMU stat task folder to retrieve all QEMU threads ID */ diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index abe210cc4e..1bbf09aca7 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -3640,7 +3640,6 @@ static void gen_multi0F(DisasContext *s, X86DecodedInsn *decode) return; illegal_op: gen_illegal_opcode(s); - return; } #include "decode-new.c.inc" diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 41fb8c5a4e..e44d044ecb 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -549,8 +549,6 @@ static void whpx_set_registers(CPUState *cpu, int level) error_report("WHPX: Failed to set virtual processor context, hr=%08lx", hr); } - - return; } static int whpx_get_tsc(CPUState *cpu) @@ -771,8 +769,6 @@ static void whpx_get_registers(CPUState *cpu) } x86_update_hflags(env); - - return; } static HRESULT CALLBACK whpx_emu_ioport_callback( @@ -1570,8 +1566,6 @@ static void whpx_vcpu_pre_run(CPUState *cpu) " hr=%08lx", hr); } } - - return; } static void whpx_vcpu_post_run(CPUState *cpu) @@ -1595,8 +1589,6 @@ static void whpx_vcpu_post_run(CPUState *cpu) vcpu->interruptable = !vcpu->exit_ctx.VpContext.ExecutionState.InterruptShadow; - - return; } static void whpx_vcpu_process_async_events(CPUState *cpu) @@ -1634,8 +1626,6 @@ static void whpx_vcpu_process_async_events(CPUState *cpu) apic_handle_tpr_access_report(x86_cpu->apic_state, env->eip, env->tpr_access_type); } - - return; } static int whpx_vcpu_run(CPUState *cpu) @@ -2280,7 +2270,6 @@ void whpx_destroy_vcpu(CPUState *cpu) whp_dispatch.WHvDeleteVirtualProcessor(whpx->partition, cpu->cpu_index); whp_dispatch.WHvEmulatorDestroyEmulator(vcpu->emulator); g_free(cpu->accel); - return; } void whpx_vcpu_kick(CPUState *cpu) diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 0bf574830f..a37d3f6a96 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -290,7 +290,6 @@ void HELPER(m68k_movec_to)(CPUM68KState *env, uint32_t reg, uint32_t val) /* Invalid control registers will generate an exception. */ raise_exception_ra(env, EXCP_ILLEGAL, 0); - return; } uint32_t HELPER(m68k_movec_from)(CPUM68KState *env, uint32_t reg) diff --git a/target/mips/tcg/system/mips-semi.c b/target/mips/tcg/system/mips-semi.c index df0c3256d9..e822a42614 100644 --- a/target/mips/tcg/system/mips-semi.c +++ b/target/mips/tcg/system/mips-semi.c @@ -374,5 +374,4 @@ void mips_semihosting(CPUMIPSState *env) error_report("Unknown UHI operation %d", op); abort(); } - return; } diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 992356cb75..80f6c185bc 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -1332,7 +1332,6 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level) void kvm_arch_pre_run(CPUState *cs, struct kvm_run *run) { - return; } MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run) diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index a8768c1dfd..a1d9ce9f9a 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -221,7 +221,6 @@ static inline int kvmppc_smt_threads(void) static inline void kvmppc_error_append_smt_possible_hint(Error *const *errp) { - return; } static inline int kvmppc_set_smt_threads(int smt) @@ -259,7 +258,6 @@ static inline target_ulong kvmppc_configure_v3_mmu(PowerPCCPU *cpu, static inline void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online) { - return; } static inline void kvmppc_set_reg_tb_offset(PowerPCCPU *cpu, int64_t tb_offset) @@ -456,7 +454,6 @@ static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) static inline void kvmppc_check_papr_resize_hpt(Error **errp) { - return; } static inline int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, diff --git a/target/ppc/translate.c b/target/ppc/translate.c index a52cbc869a..a9ff5020a2 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -3627,7 +3627,6 @@ static void pmu_count_insns(DisasContext *ctx) #else static void pmu_count_insns(DisasContext *ctx) { - return; } #endif /* #if defined(TARGET_PPC64) */ diff --git a/target/riscv/debug.c b/target/riscv/debug.c index 9db4048523..198d051521 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -551,8 +551,6 @@ static void type2_reg_write(CPURISCVState *env, target_ulong index, default: g_assert_not_reached(); } - - return; } /* type 6 trigger */ @@ -667,8 +665,6 @@ static void type6_reg_write(CPURISCVState *env, target_ulong index, default: g_assert_not_reached(); } - - return; } /* icount trigger type */ @@ -849,8 +845,6 @@ static void itrigger_reg_write(CPURISCVState *env, target_ulong index, default: g_assert_not_reached(); } - - return; } static int itrigger_get_adjust_count(CPURISCVState *env) diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 93a05e43d7..8e0b01dc65 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -578,7 +578,6 @@ static void check_compat_model_failed(Error **errp, error_setg(errp, "%s. Maximum supported model in the current configuration: \'%s\'", msg, max_model->def->name); error_append_hint(errp, "Consider a different accelerator, try \"-accel help\"\n"); - return; } static bool check_compatibility(const S390CPUModel *max_model, diff --git a/target/sh4/translate.c b/target/sh4/translate.c index bcdd558818..57b972e14f 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1792,7 +1792,6 @@ static void _decode_opc(DisasContext * ctx) gen_helper_raise_fpu_disable(tcg_env); } ctx->base.is_jmp = DISAS_NORETURN; - return; } static void decode_opc(DisasContext * ctx) diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c index 88ac6c66ce..e8aabfc13f 100644 --- a/tests/qtest/ahci-test.c +++ b/tests/qtest/ahci-test.c @@ -1881,7 +1881,6 @@ static void test_io_interface(gconstpointer opaque) sector = offset_sector(opts->offset, opts->address_type, bufsize); test_io_rw_interface(opts->address_type, opts->io_type, bufsize, sector); g_free(opts); - return; } static void create_ahci_io_test(enum IOMode type, enum AddrMode addr, diff --git a/tests/qtest/fuzz/generic_fuzz.c b/tests/qtest/fuzz/generic_fuzz.c index d107a496da..b42473d1ce 100644 --- a/tests/qtest/fuzz/generic_fuzz.c +++ b/tests/qtest/fuzz/generic_fuzz.c @@ -572,7 +572,6 @@ static void op_add_dma_pattern(QTestState *s, pattern p = {a.index, a.stride, len - sizeof(a), data + sizeof(a)}; p.index = a.index % p.len; g_array_append_val(dma_patterns, p); - return; } static void op_clear_dma_patterns(QTestState *s, diff --git a/tests/qtest/libqos/libqos-malloc.c b/tests/qtest/libqos/libqos-malloc.c index d7566972c4..c90f8f03f4 100644 --- a/tests/qtest/libqos/libqos-malloc.c +++ b/tests/qtest/libqos/libqos-malloc.c @@ -342,5 +342,4 @@ void migrate_allocator(QGuestAllocator *src, QTAILQ_INIT(src->free); node = mlist_new(src->start, src->end - src->start); QTAILQ_INSERT_HEAD(src->free, node, MLIST_ENTNAME); - return; } diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index fad307d125..358580361d 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -2022,7 +2022,6 @@ void qtest_client_inproc_recv(void *opaque, const char *str) qts->rx = g_string_new(NULL); } g_string_append(qts->rx, str); - return; } void qtest_qom_set_bool(QTestState *s, const char *path, const char *property, diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c index b9603d46fa..c9de47bb26 100644 --- a/tests/qtest/test-x86-cpuid-compat.c +++ b/tests/qtest/test-x86-cpuid-compat.c @@ -193,7 +193,6 @@ static void add_feature_test(const char *name, const char *cpu, args->bitnr = bitnr; args->expected_value = expected_value; qtest_add_data_func(name, args, test_feature_flag); - return; } static void test_plus_minus_subprocess(void) diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c index f3439cc4e5..37db24f72a 100644 --- a/tests/unit/socket-helpers.c +++ b/tests/unit/socket-helpers.c @@ -170,5 +170,4 @@ void socket_check_afunix_support(bool *has_afunix) if (*has_afunix) { close(fd); } - return; } diff --git a/tests/unit/test-qgraph.c b/tests/unit/test-qgraph.c index 334c76c8e7..ca1d60fc18 100644 --- a/tests/unit/test-qgraph.c +++ b/tests/unit/test-qgraph.c @@ -44,7 +44,6 @@ static void *driverfunct(void *obj, QGuestAllocator *machine, void *arg) static void testfunct(void *obj, void *arg, QGuestAllocator *alloc) { - return; } static void check_interface(const char *interface) diff --git a/ui/input-linux.c b/ui/input-linux.c index 381148ea99..203e264212 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -412,7 +412,6 @@ err_read_event_bits: err_close: close(il->fd); - return; } static void input_linux_instance_finalize(Object *obj) diff --git a/ui/vnc.c b/ui/vnc.c index 9241caaad9..9e097dc4b4 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -146,8 +146,6 @@ static void vnc_init_basic_info(SocketAddress *addr, default: abort(); } - - return; } static void vnc_init_basic_info_from_server_addr(QIOChannelSocket *ioc, diff --git a/util/main-loop.c b/util/main-loop.c index acad8c2e6c..979db51a1f 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -212,7 +212,6 @@ static void main_loop_init(EventLoopBase *base, Error **errp) main_loop_update_params(base, errp); mloop = m; - return; } static bool main_loop_can_be_deleted(EventLoopBase *base) diff --git a/util/qht.c b/util/qht.c index 92c6b78759..208c2f4b32 100644 --- a/util/qht.c +++ b/util/qht.c @@ -367,7 +367,6 @@ void qht_map_lock_buckets__no_stale(struct qht *ht, struct qht_map **pmap) qht_map_lock_buckets(map); qht_unlock(ht); *pmap = map; - return; } /* From abb55b1abaaa8521e93d8202dd67b9e70a4ca1a2 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 7 Apr 2025 10:26:43 +0200 Subject: [PATCH 0243/2760] cleanup: Drop pointless label at end of function Signed-off-by: Markus Armbruster Reviewed-by: Richard Henderson Acked-by: Corey Minyard Message-ID: <20250407082643.2310002-4-armbru@redhat.com> --- hw/ipmi/ipmi_bmc_extern.c | 4 +--- hw/ipmi/ipmi_bmc_sim.c | 7 ++----- hw/ipmi/ipmi_bt.c | 7 +++---- hw/ipmi/ipmi_kcs.c | 3 +-- 4 files changed, 7 insertions(+), 14 deletions(-) diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index 22cb9b590b..e563214390 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -213,7 +213,7 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b, rsp[2] = err; ibe->waiting_rsp = false; k->handle_rsp(s, msg_id, rsp, 3); - goto out; + return; } addchar(ibe, msg_id); @@ -228,8 +228,6 @@ static void ipmi_bmc_extern_handle_command(IPMIBmc *b, /* Start the transmit */ continue_send(ibe); - - out: } static void handle_hw_op(IPMIBmcExtern *ibe, unsigned char hw_op) diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index c6a85e8cd1..41fe6835a7 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -465,13 +465,12 @@ void ipmi_bmc_gen_event(IPMIBmc *b, uint8_t *evt, bool log) } if (ibs->msg_flags & IPMI_BMC_MSG_FLAG_EVT_BUF_FULL) { - goto out; + return; } memcpy(ibs->evtbuf, evt, 16); ibs->msg_flags |= IPMI_BMC_MSG_FLAG_EVT_BUF_FULL; k->set_atn(s, 1, attn_irq_enabled(ibs)); - out: } static void gen_event(IPMIBmcSim *ibs, unsigned int sens_num, uint8_t deassert, uint8_t evd1, uint8_t evd2, uint8_t evd3) @@ -996,7 +995,7 @@ static void get_msg(IPMIBmcSim *ibs, if (QTAILQ_EMPTY(&ibs->rcvbufs)) { rsp_buffer_set_error(rsp, 0x80); /* Queue empty */ - goto out; + return; } rsp_buffer_push(rsp, 0); /* Channel 0 */ msg = QTAILQ_FIRST(&ibs->rcvbufs); @@ -1011,8 +1010,6 @@ static void get_msg(IPMIBmcSim *ibs, ibs->msg_flags &= ~IPMI_BMC_MSG_FLAG_RCV_MSG_QUEUE; k->set_atn(s, attn_set(ibs), attn_irq_enabled(ibs)); } - -out: } static unsigned char diff --git a/hw/ipmi/ipmi_bt.c b/hw/ipmi/ipmi_bt.c index 5cf12c59a8..e01d02fe52 100644 --- a/hw/ipmi/ipmi_bt.c +++ b/hw/ipmi/ipmi_bt.c @@ -98,14 +98,14 @@ static void ipmi_bt_handle_event(IPMIInterface *ii) IPMIBT *ib = iic->get_backend_data(ii); if (ib->inlen < 4) { - goto out; + return; } /* Note that overruns are handled by handle_command */ if (ib->inmsg[0] != (ib->inlen - 1)) { /* Length mismatch, just ignore. */ IPMI_BT_SET_BBUSY(ib->control_reg, 1); ib->inlen = 0; - goto out; + return; } if ((ib->inmsg[1] == (IPMI_NETFN_APP << 2)) && (ib->inmsg[3] == IPMI_CMD_GET_BT_INTF_CAP)) { @@ -136,7 +136,7 @@ static void ipmi_bt_handle_event(IPMIInterface *ii) IPMI_BT_SET_B2H_IRQ(ib->mask_reg, 1); ipmi_bt_raise_irq(ib); } - goto out; + return; } ib->waiting_seq = ib->inmsg[2]; ib->inmsg[2] = ib->inmsg[1]; @@ -145,7 +145,6 @@ static void ipmi_bt_handle_event(IPMIInterface *ii) bk->handle_command(ib->bmc, ib->inmsg + 2, ib->inlen - 2, sizeof(ib->inmsg), ib->waiting_rsp); } - out: } static void ipmi_bt_handle_rsp(IPMIInterface *ii, uint8_t msg_id, diff --git a/hw/ipmi/ipmi_kcs.c b/hw/ipmi/ipmi_kcs.c index ae549fb864..d5cfe6c068 100644 --- a/hw/ipmi/ipmi_kcs.c +++ b/hw/ipmi/ipmi_kcs.c @@ -168,7 +168,7 @@ static void ipmi_kcs_handle_event(IPMIInterface *ii) ik->outpos = 0; bk->handle_command(ik->bmc, ik->inmsg, ik->inlen, sizeof(ik->inmsg), ik->waiting_rsp); - goto out_noibf; + return; } else if (ik->cmd_reg == IPMI_KCS_WRITE_END_CMD) { ik->cmd_reg = -1; ik->write_end = 1; @@ -197,7 +197,6 @@ static void ipmi_kcs_handle_event(IPMIInterface *ii) ik->cmd_reg = -1; ik->data_in_reg = -1; IPMI_KCS_SET_IBF(ik->status_reg, 0); - out_noibf: } static void ipmi_kcs_handle_rsp(IPMIInterface *ii, uint8_t msg_id, From fdcb7483ae08f5d21d8b5588413c0b0f3e39cda8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Mar 2025 10:16:53 +0100 Subject: [PATCH 0244/2760] target/hexagon: Explode MO_TExx -> MO_TE | MO_xx MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extract the implicit MO_TE definition in order to replace it in the next commit. Mechanical change using: $ for n in UW UL UQ UO SW SL SQ; do \ sed -i -e "s/MO_TE$n/MO_TE | MO_$n/" \ $(git grep -l MO_TE$n target/hexagon); \ done Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20250312103238.99981-2-philmd@linaro.org> --- target/hexagon/genptr.c | 8 ++++---- target/hexagon/macros.h | 10 +++++----- target/hexagon/translate.c | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 2c5e15cfcf..561e93c9fd 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -329,14 +329,14 @@ void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index) { - tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_TEUL); + tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_TE | MO_UL); tcg_gen_mov_tl(hex_llsc_addr, vaddr); tcg_gen_mov_tl(hex_llsc_val, dest); } static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index) { - tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_TEUQ); + tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_TE | MO_UQ); tcg_gen_mov_tl(hex_llsc_addr, vaddr); tcg_gen_mov_i64(hex_llsc_val_i64, dest); } @@ -756,7 +756,7 @@ static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA) { Insn *insn = ctx->insn; /* Needed for CHECK_NOSHUF */ CHECK_NOSHUF(EA, 8); - tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TEUQ); + tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TE | MO_UQ); } #ifndef CONFIG_HEXAGON_IDEF_PARSER @@ -1230,7 +1230,7 @@ static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); } for (int i = 0; i < sizeof(MMVector) / 8; i++) { - tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TEUQ); + tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TE | MO_UQ); tcg_gen_addi_tl(src, src, 8); tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8); } diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index ee3d4c88e7..57825efa55 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -115,27 +115,27 @@ #define MEM_LOAD2s(DST, VA) \ do { \ CHECK_NOSHUF(VA, 2); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TESW); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_SW); \ } while (0) #define MEM_LOAD2u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 2); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TEUW); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_UW); \ } while (0) #define MEM_LOAD4s(DST, VA) \ do { \ CHECK_NOSHUF(VA, 4); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TESL); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_SL); \ } while (0) #define MEM_LOAD4u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 4); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TEUL); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_UL); \ } while (0) #define MEM_LOAD8u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 8); \ - tcg_gen_qemu_ld_i64(DST, VA, ctx->mem_idx, MO_TEUQ); \ + tcg_gen_qemu_ld_i64(DST, VA, ctx->mem_idx, MO_TE | MO_UQ); \ } while (0) #define MEM_STORE1_FUNC(X) \ diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index dd26801e64..0109f31e19 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -656,17 +656,17 @@ void process_store(DisasContext *ctx, int slot_num) case 2: tcg_gen_qemu_st_tl(hex_store_val32[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TEUW); + ctx->mem_idx, MO_TE | MO_UW); break; case 4: tcg_gen_qemu_st_tl(hex_store_val32[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TEUL); + ctx->mem_idx, MO_TE | MO_UL); break; case 8: tcg_gen_qemu_st_i64(hex_store_val64[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TEUQ); + ctx->mem_idx, MO_TE | MO_UQ); break; default: { From beb38fda0f007b034ea7ff624b9f1db7699aa883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Mar 2025 10:42:31 +0100 Subject: [PATCH 0245/2760] target/hexagon: Replace MO_TE -> MO_LE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We only build the Hexagon target using little endianness order. The MO_TE definition always expands to MO_LE. Use the latter to simplify. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Anton Johansson Message-Id: <20250312103238.99981-3-philmd@linaro.org> --- target/hexagon/genptr.c | 8 ++++---- target/hexagon/idef-parser/parser-helpers.c | 2 +- target/hexagon/macros.h | 10 +++++----- target/hexagon/translate.c | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/target/hexagon/genptr.c b/target/hexagon/genptr.c index 561e93c9fd..08fc5413de 100644 --- a/target/hexagon/genptr.c +++ b/target/hexagon/genptr.c @@ -329,14 +329,14 @@ void gen_set_byte_i64(int N, TCGv_i64 result, TCGv src) static inline void gen_load_locked4u(TCGv dest, TCGv vaddr, int mem_index) { - tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_TE | MO_UL); + tcg_gen_qemu_ld_tl(dest, vaddr, mem_index, MO_LE | MO_UL); tcg_gen_mov_tl(hex_llsc_addr, vaddr); tcg_gen_mov_tl(hex_llsc_val, dest); } static inline void gen_load_locked8u(TCGv_i64 dest, TCGv vaddr, int mem_index) { - tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_TE | MO_UQ); + tcg_gen_qemu_ld_i64(dest, vaddr, mem_index, MO_LE | MO_UQ); tcg_gen_mov_tl(hex_llsc_addr, vaddr); tcg_gen_mov_i64(hex_llsc_val_i64, dest); } @@ -756,7 +756,7 @@ static void gen_load_frame(DisasContext *ctx, TCGv_i64 frame, TCGv EA) { Insn *insn = ctx->insn; /* Needed for CHECK_NOSHUF */ CHECK_NOSHUF(EA, 8); - tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_TE | MO_UQ); + tcg_gen_qemu_ld_i64(frame, EA, ctx->mem_idx, MO_LE | MO_UQ); } #ifndef CONFIG_HEXAGON_IDEF_PARSER @@ -1230,7 +1230,7 @@ static void gen_vreg_load(DisasContext *ctx, intptr_t dstoff, TCGv src, tcg_gen_andi_tl(src, src, ~((int32_t)sizeof(MMVector) - 1)); } for (int i = 0; i < sizeof(MMVector) / 8; i++) { - tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_TE | MO_UQ); + tcg_gen_qemu_ld_i64(tmp, src, ctx->mem_idx, MO_LE | MO_UQ); tcg_gen_addi_tl(src, src, 8); tcg_gen_st_i64(tmp, tcg_env, dstoff + i * 8); } diff --git a/target/hexagon/idef-parser/parser-helpers.c b/target/hexagon/idef-parser/parser-helpers.c index a7dcd85fe4..542af8d0a6 100644 --- a/target/hexagon/idef-parser/parser-helpers.c +++ b/target/hexagon/idef-parser/parser-helpers.c @@ -1761,7 +1761,7 @@ void gen_load(Context *c, YYLTYPE *locp, HexValue *width, if (signedness == SIGNED) { OUT(c, locp, " | MO_SIGN"); } - OUT(c, locp, " | MO_TE);\n"); + OUT(c, locp, " | MO_LE);\n"); } void gen_store(Context *c, YYLTYPE *locp, HexValue *width, HexValue *ea, diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index 57825efa55..e5eb31e671 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -115,27 +115,27 @@ #define MEM_LOAD2s(DST, VA) \ do { \ CHECK_NOSHUF(VA, 2); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_SW); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_LE | MO_SW); \ } while (0) #define MEM_LOAD2u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 2); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_UW); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_LE | MO_UW); \ } while (0) #define MEM_LOAD4s(DST, VA) \ do { \ CHECK_NOSHUF(VA, 4); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_SL); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_LE | MO_SL); \ } while (0) #define MEM_LOAD4u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 4); \ - tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_TE | MO_UL); \ + tcg_gen_qemu_ld_tl(DST, VA, ctx->mem_idx, MO_LE | MO_UL); \ } while (0) #define MEM_LOAD8u(DST, VA) \ do { \ CHECK_NOSHUF(VA, 8); \ - tcg_gen_qemu_ld_i64(DST, VA, ctx->mem_idx, MO_TE | MO_UQ); \ + tcg_gen_qemu_ld_i64(DST, VA, ctx->mem_idx, MO_LE | MO_UQ); \ } while (0) #define MEM_STORE1_FUNC(X) \ diff --git a/target/hexagon/translate.c b/target/hexagon/translate.c index 0109f31e19..02fd40c160 100644 --- a/target/hexagon/translate.c +++ b/target/hexagon/translate.c @@ -656,17 +656,17 @@ void process_store(DisasContext *ctx, int slot_num) case 2: tcg_gen_qemu_st_tl(hex_store_val32[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TE | MO_UW); + ctx->mem_idx, MO_LE | MO_UW); break; case 4: tcg_gen_qemu_st_tl(hex_store_val32[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TE | MO_UL); + ctx->mem_idx, MO_LE | MO_UL); break; case 8: tcg_gen_qemu_st_i64(hex_store_val64[slot_num], hex_store_addr[slot_num], - ctx->mem_idx, MO_TE | MO_UQ); + ctx->mem_idx, MO_LE | MO_UQ); break; default: { From 9ce6caa0d94a52a0ada77f494e8e23e62198aef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 12 Mar 2025 10:18:42 +0100 Subject: [PATCH 0246/2760] target/i386: Replace MO_TE* -> MO_LE* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The x86 architecture is only implemented as little-endian. The MO_TE definition always expands to MO_LE. Replace: - MO_TEUQ -> MO_LEUQ - MO_TE -> MO_LE Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250312142124.15138-1-philmd@linaro.org> --- target/i386/tcg/emit.c.inc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index 4e09e96fc1..ca6bc2ea82 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -1813,7 +1813,7 @@ static void gen_CMPXCHG(DisasContext *s, X86DecodedInsn *decode) static void gen_CMPXCHG16B(DisasContext *s, X86DecodedInsn *decode) { #ifdef TARGET_X86_64 - MemOp mop = MO_TE | MO_128 | MO_ALIGN; + MemOp mop = MO_LE | MO_128 | MO_ALIGN; TCGv_i64 t0, t1; TCGv_i128 cmp, val; @@ -1870,10 +1870,10 @@ static void gen_CMPXCHG8B(DisasContext *s, X86DecodedInsn *decode) /* Only require atomic with LOCK; non-parallel handled in generator. */ if (s->prefix & PREFIX_LOCK) { - tcg_gen_atomic_cmpxchg_i64(old, s->A0, cmp, val, s->mem_index, MO_TEUQ); + tcg_gen_atomic_cmpxchg_i64(old, s->A0, cmp, val, s->mem_index, MO_LEUQ); } else { tcg_gen_nonatomic_cmpxchg_i64(old, s->A0, cmp, val, - s->mem_index, MO_TEUQ); + s->mem_index, MO_LEUQ); } /* Compute the required value of Z. */ From 5dbe25e9db070ea87c173fd9a4dc0932ee6d1b41 Mon Sep 17 00:00:00 2001 From: Tomita Moeko Date: Thu, 13 Mar 2025 23:03:39 +0800 Subject: [PATCH 0247/2760] vfio/igd: Update IGD passthrough documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A previous change made the OpRegion and LPC quirks independent of the existing legacy mode, update the documentation accordingly. More related topics, like creating EFI Option ROM of IGD for OVMF, how to solve the VFIO_DMA_MAP Invalid Argument warning, as well as details on IGD memory internals, are also added. Signed-off-by: Tomita Moeko Reviewed-by: Alex Williamson Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250313150339.358621-1-tomitamoeko@gmail.com Signed-off-by: Cédric Le Goater --- docs/igd-assign.txt | 255 +++++++++++++++++++++++++++++++++----------- 1 file changed, 191 insertions(+), 64 deletions(-) diff --git a/docs/igd-assign.txt b/docs/igd-assign.txt index e17bb50789..3aed7956d5 100644 --- a/docs/igd-assign.txt +++ b/docs/igd-assign.txt @@ -1,44 +1,69 @@ Intel Graphics Device (IGD) assignment with vfio-pci ==================================================== -IGD has two different modes for assignment using vfio-pci: +Using vfio-pci, we can passthrough Intel Graphics Device (IGD) to guest, either +serve as primary and exclusive graphics adapter, or used in combination with an +emulated primary graphics device, depending on the config and guest driver +support. However, IGD devices are not "clean" PCI devices, they use extra +memory regions other than BARs. Special handling is required to make them work +properly, including: -1) Universal Pass-Through (UPT) mode: +* OpRegion for accessing Virtual BIOS Table (VBT) that contains display output + information. +* Data Stolen Memory (DSM) region used as VRAM at early stage (BIOS/UEFI) - In this mode the IGD device is added as a *secondary* (ie. non-primary) - graphics device in combination with an emulated primary graphics device. - This mode *requires* guest driver support to remove the external - dependencies generally associated with IGD (see below). Those guest - drivers only support this mode for Broadwell and newer IGD, according to - Intel. Additionally, this mode by default, and as officially supported - by Intel, does not support direct video output. The intention is to use - this mode either to provide hardware acceleration to the emulated graphics - or to use this mode in combination with guest-based remote access software, - for example VNC (see below for optional output support). This mode - theoretically has no device specific handling dependencies on vfio-pci or - the VM firmware. +Certain guest software also depends on following conditions to work: +(*-Required by) -2) "Legacy" mode: +| Condition | Linux | Windows | VBIOS | EFI GOP | +|---------------------------------------------|-------|---------|-------|---------| +| #1 IGD has a valid OpRegion containing VBT | * ^1 | * | * | * | +| #2 VID/DID of LPC bridge at 00:1f.0 matches | | | * | * | +| #3 IGD is assigned to BDF 00:02.0 | | | * | * | +| #4 IGD has VGA controller device class | | | * | * | +| #5 Host's VGA ranges are mapped to IGD | | | * | | +| #6 Guest has valid VBIOS or UEFI Option ROM | | | * | * | - In this mode the IGD device is intended to be the primary and exclusive - graphics device in the VM[1], as such QEMU does not facilitate any sort - of remote graphics to the VM in this mode. A connected physical monitor - is the intended output device for IGD. This mode includes several - requirements and restrictions: +^1 Though i915 driver is able to mock a OpRegion, it is still recommended to + use the VBT copied from host OpRegion to prevent incorrect configuration. - * IGD must be given address 02.0 on the PCI root bus in the VM - * The host kernel must support vfio extensions for IGD (v4.6) - * vfio VGA support very likely needs to be enabled in the host kernel - * The VM firmware must support specific fw_cfg enablers for IGD - * The VM machine type must support a PCI host bridge at 00.0 (standard) - * The VM machine type must provide or allow to be created a special - ISA/LPC bridge device (vfio-pci-igd-lpc-bridge) on the root bus at - PCI address 1f.0. - * The IGD device must have a VGA ROM, either provided via the romfile - option or loaded automatically through vfio (standard). rombar=0 - will disable legacy mode support. - * Hotplug of the IGD device is not supported. - * The IGD device must be a SandyBridge or newer model device. +For #1, the "x-igd-opregion=on" option exposes a copy of host IGD OpRegion to +guest via fw_cfg, where guest firmware can set up guest OpRegion with it. + +For #2, "x-igd-lpc=on" option copies the IDs of host LPC bridge and host bridge +to guest. Currently this is only supported on i440fx machines as there is +already an ICH9 LPC bridge present on q35 machines, overwriting its IDs may +lead to unexpected behavior. + +For #3, "addr=2.0" assigns IGD to 00:02.0. + +For #4, the primary display must be set to IGD in host BIOS. + +For #5, "x-vga=on" enables guest access to standard VGA IO/MMIO ranges. + +For #6, ROM either provided via the ROM BAR or romfile= option is needed, this +Intel document [1] shows how to dump VBIOS to file. For UEFI Option ROM, see +"Guest firmware" section. + +QEMU also provides a "Legacy" mode that implicitly enables full functionality +on IGD, it is automatically enabled when +* Machine type is i440fx +* IGD is assigned to guest BDF 00:02.0 +* ROM BAR or romfile is present + +In "Legacy" mode, QEMU will automatically setup OpRegion, LPC bridge IDs and +VGA range access, which is equivalent to: + x-igd-opregion=on,x-igd-lpc=on,x-vga=on + +By default, "Legacy" mode won't fail, it continues on error. User can set +"x-igd-legacy-mode=on" to force enabling legacy mode, this also checks if the +conditions above for legacy mode is met, and if any error occurs, QEMU will +fail immediately. Users can also set "x-igd-legacy-mode=off" to disable legacy +mode. + +In legacy mode, as the guest VGA ranges are assigned to IGD device, all other +graphics devices should be removed, this can be done using "-nographic" or +"-vga none" or "-nodefaults", along with adding the device using vfio-pci. For either mode, depending on the host kernel, the i915 driver in the host may generate faults and errors upon re-binding to an IGD device after it @@ -73,31 +98,39 @@ DVI, or DisplayPort) may be unsupported in some use cases. In the author's experience, even DP to VGA adapters can be troublesome while adapters between digital formats work well. -Usage -===== -The intention is for IGD assignment to be transparent for users and thus for -management tools like libvirt. To make use of legacy mode, simply remove all -other graphics options and use "-nographic" and either "-vga none" or -"-nodefaults", along with adding the device using vfio-pci: - -device vfio-pci,host=00:02.0,id=hostdev0,bus=pci.0,addr=0x2 +Options +======= +* x-igd-opregion=[on|*off*] + Copy host IGD OpRegion and expose it to guest with fw_cfg -For UPT mode, retain the default emulated graphics and simply add the vfio-pci -device making use of any other bus address other than 02.0. libvirt will -default to assigning the device a UPT compatible address while legacy mode -users will need to manually edit the XML if using a tool like virt-manager -where the VM device address is not expressly specified. +* x-igd-lpc=[on|*off*] + Creates a dummy LPC bridge at 00:1f:0 with host VID/DID (i440fx only) -An experimental vfio-pci option also exists to enable OpRegion, and thus -external monitor support, for UPT mode. This can be enabled by adding -"x-igd-opregion=on" to the vfio-pci device options for the IGD device. As -with legacy mode, this requires the host to support features introduced in -the v4.6 kernel. If Intel chooses to embrace this support, the option may -be made non-experimental in the future, opening it to libvirt support. +* x-igd-legacy-mode=[on|off|*auto*] + Enable/Disable legacy mode -Developer ABI -============= -Legacy mode IGD support imposes two fw_cfg requirements on the VM firmware: +* x-igd-gms=[hex, default 0] + Overriding DSM region size in GGC register, 0 means uses host value. + Use this only when the DSM size cannot be changed through the + 'DVMT Pre-Allocated' option in host BIOS. + + +Examples +======== +* Adding IGD with automatically legacy mode support + -device vfio-pci,host=00:02.0,id=hostdev0,addr=2.0 + +* Adding IGD with OpRegion and LPC ID hack, but without VGA ranges + (For UEFI guests) + -device vfio-pci,host=00:02.0,id=hostdev0,addr=2.0,x-igd-legacy-mode=off,x-igd-opregion=on,x-igd-lpc=on,romfile=efi_oprom.rom + + +Guest firmware +============== +Guest firmware is responsible for setting up OpRegion and Base of Data Stolen +Memory (BDSM) in guest address space. IGD passthrough support imposes two +fw_cfg requirements on the VM firmware: 1) "etc/igd-opregion" @@ -117,17 +150,111 @@ Legacy mode IGD support imposes two fw_cfg requirements on the VM firmware: Firmware must allocate a reserved memory below 4GB with required 1MB alignment equal to this size. Additionally the base address of this reserved region must be written to the dword BDSM register in PCI config - space of the IGD device at offset 0x5C. As this support is related to - running the IGD ROM, which has other dependencies on the device appearing - at guest address 00:02.0, it's expected that this fw_cfg file is only - relevant to a single PCI class VGA device with Intel vendor ID, appearing - at PCI bus address 00:02.0. + space of the IGD device at offset 0x5C (or 0xC0 for Gen 11+ devices using + 64-bit BDSM). As this support is related to running the IGD ROM, which + has other dependencies on the device appearing at guest address 00:02.0, + it's expected that this fw_cfg file is only relevant to a single PCI + class VGA device with Intel vendor ID, appearing at PCI bus address 00:02.0. + +Upstream Seabios has OpRegion and BDSM (pre-Gen11 device only) support. +However, the support is not accepted by upstream EDK2/OVMF. A recommended +solution is to create a virtual OpRom with following DXE drivers: + +* IgdAssignmentDxe: Set up OpRegion and BDSM according to fw_cfg (must) +* IntelGopDriver: Closed-source Intel GOP driver +* PlatformGopPolicy: Protocol required by IntelGopDriver + +IntelGopDriver and PlatformGopPolicy is only required when enabling GOP on IGD. + +The original IgdAssignmentDxe can be found at [3]. A Intel maintained version +with PlatformGopPolicy for industrial computing is at [4]. There is also an +unofficially maintained version with newer Gen11+ device support at [5]. +You need to build them with EDK2. + +For the IntelGopDriver, Intel never released it to public. You may contact +Intel support to get one as [4] said, if you are an Intel Premier Support +customer, or you can try extracting it from your host firmware using +"UEFI BIOS Updater"[6]. + +Once you got all the required DXE drivers, a Option ROM can be generated with +EfiRom utility in EDK2, using + EfiRom -f 0x8086 -i -o output.rom \ + -e IgdAssignmentDxe.efi PlatformGOPPolicy.efi IntelGopDriver.efi + + +Known issues +============ +When using OVMF as guest firmware, you may encounter the following warning: +warning: vfio_container_dma_map(0x55fab36ce610, 0x380010000000, 0x108000, 0x7fd336000000) = -22 (Invalid argument) + +Solution: +Set the host physical address bits to IOMMU address width using + -cpu host,host-phys-bits-limit= +Or in libvirt XML with + + + +The IOMMU address width can be determined with + echo $(( ((0x$(cat /sys/devices/virtual/iommu/dmar0/intel-iommu/cap) & 0x3F0000) >> 16) + 1 )) +Refer https://edk2.groups.io/g/devel/topic/patch_v1/102359124 for more details + + +Memory View +=========== +IGD has it own address space. To use system RAM as VRAM, a single-level page +table named Global Graphics Translation Table (GTT) is used for the address +translation. Each page table entry points a 4KB page. Illustration below shows +the translation flow on IGD with 64-bit GTT PTEs. + +(PTE_SIZE == 8) +-------------+---+ + | Address | V | V: Valid Bit + +-------------+---+ + | ... | | +IGD:0x01ae9010 0xd740| 0x70ffc000 | 1 | Mem:0x42ba3e010^ +-----------------------> 0xd748| 0x42ba3e000 | 1 +------------------> +(addr >> 12) * PTE_SIZE 0xd750| 0x42ba3f000 | 1 | + | ... | | + +-------------+---+ +^ The address may be remapped by IOMMU + +The memory region store GTT is called GTT Stolen Memory (GSM) it is located +right below the Data Stolen Memory (DSM). Accessing this region directly is +not allowed, any access will immediately freeze the whole system. The only way +to access it is through the second half of MMIO BAR0. + +The Data Stolen Memory is reserved by firmware, and acts as the VRAM in pre-OS +environments. In QEMU, guest firmware (Seabios/OVMF) is responsible for +reserving a continuous region and program its base address to BDSM register, +then let VBIOS/GOP driver initializing this region. Illustration below shows +how DSM is mapped. + + IGD Addr Space Host Addr Space Guest Addr Space + +-------------+ +-------------+ +-------------+ + | | | | | | + | | | | | | + | | +-------------+ +-------------+ + | | | Data Stolen | | Data Stolen | + | | | (Guest) | | (Guest) | + | | +------------>+-------------+<------->+-------------+<--Guest BDSM + | | | Passthrough | | EPT | | Emulated by QEMU +DSMSIZE+-------------+ | with IOMMU | | Mapping | | Programmed by guest FW + | | | | | | | + | | | | | | | + 0+-------------+--+ | | | | + | +-------------+ | | + | | Data Stolen | +-------------+ + | | (Host) | + +------------>+-------------+<--Host BDSM + Non- | | "real" one in HW + Passthrough | | Programmed by host FW + +-------------+ Footnotes ========= -[1] Nothing precludes adding additional emulated or assigned graphics devices - as non-primary, other than the combination typically not working. I only - intend to set user expectations, others are welcome to find working - combinations or fix whatever issues prevent this from working in the common - case. +[1] https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/dump-video-bios.html [2] # echo "vfio-pci" > /sys/bus/pci/devices/0000:00:02.0/driver_override +[3] https://web.archive.org/web/20240827012422/https://bugzilla.tianocore.org/show_bug.cgi?id=935 + Tianocore bugzilla was down since Jan 2025 :( +[4] https://eci.intel.com/docs/3.3/components/kvm-hypervisor.html, Patch 0001-0004 +[5] https://github.com/tomitamoeko/VfioIgdPkg +[6] https://winraid.level1techs.com/t/tool-guide-news-uefi-bios-updater-ubu/30357 From 10c7f1cf2c9d5af28dbc342634eb1f3979a7c379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Mon, 24 Mar 2025 13:33:15 +0100 Subject: [PATCH 0248/2760] vfio: Open code vfio_migration_set_error() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VFIO uses migration_file_set_error() in a couple of places where an 'Error **' parameter is not provided. In MemoryListener handlers : vfio_listener_region_add vfio_listener_log_global_stop vfio_listener_log_sync and in callback routines for IOMMU notifiers : vfio_iommu_map_notify vfio_iommu_map_dirty_notify Hopefully, one day, we will be able to extend these callbacks with an 'Error **' parameter and avoid setting the global migration error. Until then, it seems sensible to clearly identify the use cases, which are limited, and open code vfio_migration_set_error(). One other benefit is an improved error reporting when migration is running. While at it, slightly modify error reporting to only report errors when migration is not active and not always as is currently done. Cc: Prasad Pandit Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250324123315.637827-1-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 60 +++++++++++++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 9b493451c5..5ef14931cd 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -145,13 +145,6 @@ bool vfio_viommu_preset(VFIODevice *vbasedev) return vbasedev->bcontainer->space->as != &address_space_memory; } -static void vfio_set_migration_error(int ret) -{ - if (migration_is_running()) { - migration_file_set_error(ret, NULL); - } -} - bool vfio_device_state_is_running(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; @@ -287,9 +280,14 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) iova, iova + iotlb->addr_mask); if (iotlb->target_as != &address_space_memory) { - error_report("Wrong target AS \"%s\", only system memory is allowed", - iotlb->target_as->name ? iotlb->target_as->name : "none"); - vfio_set_migration_error(-EINVAL); + error_setg(&local_err, + "Wrong target AS \"%s\", only system memory is allowed", + iotlb->target_as->name ? iotlb->target_as->name : "none"); + if (migration_is_running()) { + migration_file_set_error(-EINVAL, local_err); + } else { + error_report_err(local_err); + } return; } @@ -322,11 +320,16 @@ static void vfio_iommu_map_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) ret = vfio_container_dma_unmap(bcontainer, iova, iotlb->addr_mask + 1, iotlb); if (ret) { - error_report("vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", " - "0x%"HWADDR_PRIx") = %d (%s)", - bcontainer, iova, - iotlb->addr_mask + 1, ret, strerror(-ret)); - vfio_set_migration_error(ret); + error_setg(&local_err, + "vfio_container_dma_unmap(%p, 0x%"HWADDR_PRIx", " + "0x%"HWADDR_PRIx") = %d (%s)", + bcontainer, iova, + iotlb->addr_mask + 1, ret, strerror(-ret)); + if (migration_is_running()) { + migration_file_set_error(ret, local_err); + } else { + error_report_err(local_err); + } } } out: @@ -1108,8 +1111,11 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) if (ret) { error_prepend(&local_err, "vfio: Could not stop dirty page tracking - "); - error_report_err(local_err); - vfio_set_migration_error(ret); + if (migration_is_running()) { + migration_file_set_error(ret, local_err); + } else { + error_report_err(local_err); + } } } @@ -1225,14 +1231,14 @@ static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) trace_vfio_iommu_map_dirty_notify(iova, iova + iotlb->addr_mask); if (iotlb->target_as != &address_space_memory) { - error_report("Wrong target AS \"%s\", only system memory is allowed", - iotlb->target_as->name ? iotlb->target_as->name : "none"); + error_setg(&local_err, + "Wrong target AS \"%s\", only system memory is allowed", + iotlb->target_as->name ? iotlb->target_as->name : "none"); goto out; } rcu_read_lock(); if (!vfio_get_xlat_addr(iotlb, NULL, &translated_addr, NULL, &local_err)) { - error_report_err(local_err); goto out_unlock; } @@ -1243,7 +1249,6 @@ static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) "vfio_iommu_map_dirty_notify(%p, 0x%"HWADDR_PRIx", " "0x%"HWADDR_PRIx") failed - ", bcontainer, iova, iotlb->addr_mask + 1); - error_report_err(local_err); } out_unlock: @@ -1251,7 +1256,11 @@ out_unlock: out: if (ret) { - vfio_set_migration_error(ret); + if (migration_is_running()) { + migration_file_set_error(ret, local_err); + } else { + error_report_err(local_err); + } } } @@ -1384,8 +1393,11 @@ static void vfio_listener_log_sync(MemoryListener *listener, if (vfio_log_sync_needed(bcontainer)) { ret = vfio_sync_dirty_bitmap(bcontainer, section, &local_err); if (ret) { - error_report_err(local_err); - vfio_set_migration_error(ret); + if (migration_is_running()) { + migration_file_set_error(ret, local_err); + } else { + error_report_err(local_err); + } } } } From 6a7abe1c96bf5fbaa546c710b147f594c9db562e Mon Sep 17 00:00:00 2001 From: Amit Machhiwal Date: Tue, 8 Apr 2025 18:10:41 +0530 Subject: [PATCH 0249/2760] vfio/spapr: Enhance error handling in vfio_spapr_create_window() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce an Error ** parameter to vfio_spapr_create_window() to enable structured error reporting. This allows the function to propagate detailed errors back to callers. Suggested-by: Cédric Le Goater Signed-off-by: Amit Machhiwal Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250408124042.2695955-2-amachhiw@linux.ibm.com Signed-off-by: Cédric Le Goater --- hw/vfio/spapr.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 66a2d2bb0d..3d6354134c 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -230,9 +230,9 @@ static int vfio_spapr_remove_window(VFIOContainer *container, return 0; } -static int vfio_spapr_create_window(VFIOContainer *container, +static bool vfio_spapr_create_window(VFIOContainer *container, MemoryRegionSection *section, - hwaddr *pgsize) + hwaddr *pgsize, Error **errp) { int ret = 0; VFIOContainerBase *bcontainer = &container->bcontainer; @@ -252,11 +252,11 @@ static int vfio_spapr_create_window(VFIOContainer *container, pgmask = bcontainer->pgsizes & (pagesize | (pagesize - 1)); pagesize = pgmask ? (1ULL << (63 - clz64(pgmask))) : 0; if (!pagesize) { - error_report("Host doesn't support page size 0x%"PRIx64 - ", the supported mask is 0x%lx", - memory_region_iommu_get_min_page_size(iommu_mr), - bcontainer->pgsizes); - return -EINVAL; + error_setg_errno(errp, EINVAL, "Host doesn't support page size 0x%"PRIx64 + ", the supported mask is 0x%lx", + memory_region_iommu_get_min_page_size(iommu_mr), + bcontainer->pgsizes); + return false; } /* @@ -302,17 +302,17 @@ static int vfio_spapr_create_window(VFIOContainer *container, } } if (ret) { - error_report("Failed to create a window, ret = %d (%m)", ret); - return -errno; + error_setg_errno(errp, errno, "Failed to create a window, ret = %d", ret); + return false; } if (create.start_addr != section->offset_within_address_space) { vfio_spapr_remove_window(container, create.start_addr); - error_report("Host doesn't support DMA window at %"HWADDR_PRIx", must be %"PRIx64, - section->offset_within_address_space, - (uint64_t)create.start_addr); - return -EINVAL; + error_setg_errno(errp, EINVAL, "Host doesn't support DMA window at %"HWADDR_PRIx + ", must be %"PRIx64, section->offset_within_address_space, + (uint64_t)create.start_addr); + return false; } trace_vfio_spapr_create_window(create.page_shift, create.levels, @@ -320,7 +320,7 @@ static int vfio_spapr_create_window(VFIOContainer *container, create.start_addr); *pgsize = pagesize; - return 0; + return true; } static bool @@ -377,9 +377,8 @@ vfio_spapr_container_add_section_window(VFIOContainerBase *bcontainer, } } - ret = vfio_spapr_create_window(container, section, &pgsize); - if (ret) { - error_setg_errno(errp, -ret, "Failed to create SPAPR window"); + ret = vfio_spapr_create_window(container, section, &pgsize, errp); + if (!ret) { return false; } From d5e8e6195bcd37292657b5f69d7633b51670caf1 Mon Sep 17 00:00:00 2001 From: Amit Machhiwal Date: Tue, 8 Apr 2025 18:10:42 +0530 Subject: [PATCH 0250/2760] vfio/spapr: Fix L2 crash with PCI device passthrough and memory > 128G MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An L2 KVM guest fails to boot inside a pSeries LPAR when booted with a memory more than 128 GB and PCI device passthrough. The L2 guest also crashes when it is booted with a memory greater than 128 GB and a PCI device is hotplugged later. The issue arises from a conditional check for `levels > 1` in `spapr_tce_create_table()` within L1 KVM. This check is meant to prevent multi-level TCEs, which are not supported by the PowerVM hypervisor. As a result, when QEMU makes a `VFIO_IOMMU_SPAPR_TCE_CREATE` ioctl call with `levels > 1`, it triggers the conditional check and returns `EINVAL`, causing the guest to crash with the following errors: 2025-03-04T06:36:36.133117Z qemu-system-ppc64: Failed to create a window, ret = -1 (Invalid argument) 2025-03-04T06:36:36.133176Z qemu-system-ppc64: Failed to create SPAPR window: Invalid argument qemu: hardware error: vfio: DMA mapping failed, unable to continue Fix this by checking the supported DDW "levels" returned by the VFIO_IOMMU_SPAPR_TCE_GET_INFO ioctl before attempting the TCE create ioctl in KVM. The patch has been tested on KVM guests with memory configurations of up to 390GB, and 450GB on PowerVM and bare-metal environments respectively. Signed-off-by: Amit Machhiwal Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250408124042.2695955-3-amachhiw@linux.ibm.com Signed-off-by: Cédric Le Goater --- hw/vfio/spapr.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 3d6354134c..7e5cb95f6a 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -26,6 +26,7 @@ typedef struct VFIOSpaprContainer { VFIOContainer container; MemoryListener prereg_listener; QLIST_HEAD(, VFIOHostDMAWindow) hostwin_list; + unsigned int levels; } VFIOSpaprContainer; OBJECT_DECLARE_SIMPLE_TYPE(VFIOSpaprContainer, VFIO_IOMMU_SPAPR); @@ -236,9 +237,11 @@ static bool vfio_spapr_create_window(VFIOContainer *container, { int ret = 0; VFIOContainerBase *bcontainer = &container->bcontainer; + VFIOSpaprContainer *scontainer = container_of(container, VFIOSpaprContainer, + container); IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr), pgmask; - unsigned entries, bits_total, bits_per_level, max_levels; + unsigned entries, bits_total, bits_per_level, max_levels, ddw_levels; struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; long rampagesize = qemu_minrampagesize(); @@ -291,16 +294,29 @@ static bool vfio_spapr_create_window(VFIOContainer *container, */ bits_per_level = ctz64(qemu_real_host_page_size()) + 8; create.levels = bits_total / bits_per_level; - if (bits_total % bits_per_level) { - ++create.levels; - } - max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size()); - for ( ; create.levels <= max_levels; ++create.levels) { - ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); - if (!ret) { - break; + + ddw_levels = scontainer->levels; + if (ddw_levels > 1) { + if (bits_total % bits_per_level) { + ++create.levels; } + max_levels = (64 - create.page_shift) / ctz64(qemu_real_host_page_size()); + for ( ; create.levels <= max_levels; ++create.levels) { + ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); + if (!ret) { + break; + } + } + } else { /* ddw_levels == 1 */ + if (create.levels > ddw_levels) { + error_setg_errno(errp, EINVAL, "Host doesn't support multi-level TCE tables" + ". Use larger IO page size. Supported mask is 0x%lx", + bcontainer->pgsizes); + return false; + } + ret = ioctl(container->fd, VFIO_IOMMU_SPAPR_TCE_CREATE, &create); } + if (ret) { error_setg_errno(errp, errno, "Failed to create a window, ret = %d", ret); return false; @@ -501,6 +517,8 @@ static bool vfio_spapr_container_setup(VFIOContainerBase *bcontainer, goto listener_unregister_exit; } + scontainer->levels = info.ddw.levels; + if (v2) { bcontainer->pgsizes = info.ddw.pgsizes; /* From acea0f0fafcf89f374fd7a69a4cd2c91d6d7d68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:46 +0100 Subject: [PATCH 0251/2760] vfio: Move vfio_mig_active() into migration.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_mig_active() is part of the VFIO migration API. Move the definitions where VFIO migration is implemented. Reviewed-by: Avihai Horon Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-2-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-2-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 16 ---------------- hw/vfio/migration.c | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 5ef14931cd..2ea4e12c90 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -65,22 +65,6 @@ int vfio_kvm_device_fd = -1; * Device state interfaces */ -bool vfio_mig_active(void) -{ - VFIODevice *vbasedev; - - if (QLIST_EMPTY(&vfio_device_list)) { - return false; - } - - QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->migration_blocker) { - return false; - } - } - return true; -} - static Error *multiple_devices_migration_blocker; /* diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index fbff46cfc3..b5fb0d2188 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1062,6 +1062,22 @@ void vfio_mig_add_bytes_transferred(unsigned long val) qatomic_add(&bytes_transferred, val); } +bool vfio_mig_active(void) +{ + VFIODevice *vbasedev; + + if (QLIST_EMPTY(&vfio_device_list)) { + return false; + } + + QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->migration_blocker) { + return false; + } + } + return true; +} + /* * Return true when either migration initialized or blocker registered. * Currently only return false when adding blocker fails which will From 426ffab477e22606473282c684b9239f8a30dd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:47 +0100 Subject: [PATCH 0252/2760] vfio: Rename vfio_reset_bytes_transferred() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enforce a 'vfio_mig_' prefix for the VFIO migration API to better reflect the namespace these routines belong to. Reviewed-by: Avihai Horon Reviewed-by: John Levon Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-3-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-3-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/migration.c | 2 +- include/hw/vfio/vfio-common.h | 2 +- migration/target.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index b5fb0d2188..8bf65b8e11 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1052,7 +1052,7 @@ int64_t vfio_mig_bytes_transferred(void) return MIN(qatomic_read(&bytes_transferred), INT64_MAX); } -void vfio_reset_bytes_transferred(void) +void vfio_mig_reset_bytes_transferred(void) { qatomic_set(&bytes_transferred, 0); } diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index f5b3f45a43..f58cae9e55 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -295,7 +295,7 @@ int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp); void vfio_unblock_multiple_devices_migration(void); bool vfio_viommu_preset(VFIODevice *vbasedev); int64_t vfio_mig_bytes_transferred(void); -void vfio_reset_bytes_transferred(void); +void vfio_mig_reset_bytes_transferred(void); void vfio_mig_add_bytes_transferred(unsigned long val); bool vfio_device_state_is_running(VFIODevice *vbasedev); bool vfio_device_state_is_precopy(VFIODevice *vbasedev); diff --git a/migration/target.c b/migration/target.c index a6ffa9a5ce..f5d8cfe7c2 100644 --- a/migration/target.c +++ b/migration/target.c @@ -25,7 +25,7 @@ void migration_populate_vfio_info(MigrationInfo *info) void migration_reset_vfio_bytes_transferred(void) { - vfio_reset_bytes_transferred(); + vfio_mig_reset_bytes_transferred(); } #else void migration_populate_vfio_info(MigrationInfo *info) From e1d4ea53d6e393def88258a3badf8907db33608e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:48 +0100 Subject: [PATCH 0253/2760] vfio: Introduce a new header file for external migration services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The migration core subsystem makes use of the VFIO migration API to collect statistics on the number of bytes transferred. These services are declared in "hw/vfio/vfio-common.h" which also contains VFIO internal declarations. Move the migration declarations into a new header file "hw/vfio/vfio-migration.h" to reduce the exposure of VFIO internals. While at it, use a 'vfio_migration_' prefix for these services. To be noted, vfio_migration_add_bytes_transferred() is a VFIO migration internal service which we will be moved in the subsequent patches. Cc: Kirti Wankhede Cc: Avihai Horon Reviewed-by: Prasad Pandit Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-4-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/migration-multifd.c | 5 +++-- hw/vfio/migration.c | 11 ++++++----- include/hw/vfio/vfio-common.h | 5 +---- include/hw/vfio/vfio-migration.h | 16 ++++++++++++++++ migration/target.c | 8 ++++---- 5 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 include/hw/vfio/vfio-migration.h diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c index 378f6f3bf0..09aa57f5f8 100644 --- a/hw/vfio/migration-multifd.c +++ b/hw/vfio/migration-multifd.c @@ -11,6 +11,7 @@ #include "qemu/osdep.h" #include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-migration.h" #include "migration/misc.h" #include "qapi/error.h" #include "qemu/bswap.h" @@ -575,7 +576,7 @@ vfio_save_complete_precopy_thread_config_state(VFIODevice *vbasedev, return false; } - vfio_mig_add_bytes_transferred(packet_len); + vfio_migration_add_bytes_transferred(packet_len); return true; } @@ -645,7 +646,7 @@ vfio_multifd_save_complete_precopy_thread(SaveLiveCompletePrecopyThreadData *d, goto thread_exit; } - vfio_mig_add_bytes_transferred(packet_size); + vfio_migration_add_bytes_transferred(packet_size); } if (!vfio_save_complete_precopy_thread_config_state(vbasedev, diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 8bf65b8e11..582d65932a 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -17,6 +17,7 @@ #include "system/runstate.h" #include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-migration.h" #include "migration/misc.h" #include "migration/savevm.h" #include "migration/vmstate.h" @@ -373,7 +374,7 @@ static ssize_t vfio_save_block(QEMUFile *f, VFIOMigration *migration) qemu_put_be64(f, VFIO_MIG_FLAG_DEV_DATA_STATE); qemu_put_be64(f, data_size); qemu_put_buffer(f, migration->data_buffer, data_size); - vfio_mig_add_bytes_transferred(data_size); + vfio_migration_add_bytes_transferred(data_size); trace_vfio_save_block(migration->vbasedev->name, data_size); @@ -1047,22 +1048,22 @@ static int vfio_block_migration(VFIODevice *vbasedev, Error *err, Error **errp) /* ---------------------------------------------------------------------- */ -int64_t vfio_mig_bytes_transferred(void) +int64_t vfio_migration_bytes_transferred(void) { return MIN(qatomic_read(&bytes_transferred), INT64_MAX); } -void vfio_mig_reset_bytes_transferred(void) +void vfio_migration_reset_bytes_transferred(void) { qatomic_set(&bytes_transferred, 0); } -void vfio_mig_add_bytes_transferred(unsigned long val) +void vfio_migration_add_bytes_transferred(unsigned long val) { qatomic_add(&bytes_transferred, val); } -bool vfio_mig_active(void) +bool vfio_migration_active(void) { VFIODevice *vbasedev; diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index f58cae9e55..7a551bb230 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -290,13 +290,10 @@ extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; -bool vfio_mig_active(void); int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp); void vfio_unblock_multiple_devices_migration(void); bool vfio_viommu_preset(VFIODevice *vbasedev); -int64_t vfio_mig_bytes_transferred(void); -void vfio_mig_reset_bytes_transferred(void); -void vfio_mig_add_bytes_transferred(unsigned long val); +void vfio_migration_add_bytes_transferred(unsigned long val); bool vfio_device_state_is_running(VFIODevice *vbasedev); bool vfio_device_state_is_precopy(VFIODevice *vbasedev); diff --git a/include/hw/vfio/vfio-migration.h b/include/hw/vfio/vfio-migration.h new file mode 100644 index 0000000000..0d4ecd33d5 --- /dev/null +++ b/include/hw/vfio/vfio-migration.h @@ -0,0 +1,16 @@ +/* + * VFIO migration interface + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_MIGRATION_H +#define HW_VFIO_VFIO_MIGRATION_H + +bool vfio_migration_active(void); +int64_t vfio_migration_bytes_transferred(void); +void vfio_migration_reset_bytes_transferred(void); + +#endif /* HW_VFIO_VFIO_MIGRATION_H */ diff --git a/migration/target.c b/migration/target.c index f5d8cfe7c2..12fd399f0c 100644 --- a/migration/target.c +++ b/migration/target.c @@ -11,21 +11,21 @@ #include CONFIG_DEVICES #ifdef CONFIG_VFIO -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-migration.h" #endif #ifdef CONFIG_VFIO void migration_populate_vfio_info(MigrationInfo *info) { - if (vfio_mig_active()) { + if (vfio_migration_active()) { info->vfio = g_malloc0(sizeof(*info->vfio)); - info->vfio->transferred = vfio_mig_bytes_transferred(); + info->vfio->transferred = vfio_migration_bytes_transferred(); } } void migration_reset_vfio_bytes_transferred(void) { - vfio_mig_reset_bytes_transferred(); + vfio_migration_reset_bytes_transferred(); } #else void migration_populate_vfio_info(MigrationInfo *info) From 0a73045687edb6d4b0dac90ca7ae19bf6b3eeb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:49 +0100 Subject: [PATCH 0254/2760] vfio: Make vfio_un/block_multiple_devices_migration() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both of these routines are only used in file "migration.c". Move them there. Reviewed-by: Joao Martins Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-5-clg@redhat.com Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-5-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 59 ----------------------------------- hw/vfio/migration.c | 59 +++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 2 -- 3 files changed, 59 insertions(+), 61 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 2ea4e12c90..d65e77b93a 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -40,7 +40,6 @@ #include "trace.h" #include "qapi/error.h" #include "migration/misc.h" -#include "migration/blocker.h" #include "migration/qemu-file.h" #include "system/tcg.h" #include "system/tpm.h" @@ -65,64 +64,6 @@ int vfio_kvm_device_fd = -1; * Device state interfaces */ -static Error *multiple_devices_migration_blocker; - -/* - * Multiple devices migration is allowed only if all devices support P2P - * migration. Single device migration is allowed regardless of P2P migration - * support. - */ -static bool vfio_multiple_devices_migration_is_supported(void) -{ - VFIODevice *vbasedev; - unsigned int device_num = 0; - bool all_support_p2p = true; - - QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->migration) { - device_num++; - - if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) { - all_support_p2p = false; - } - } - } - - return all_support_p2p || device_num <= 1; -} - -int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp) -{ - if (vfio_multiple_devices_migration_is_supported()) { - return 0; - } - - if (vbasedev->enable_migration == ON_OFF_AUTO_ON) { - error_setg(errp, "Multiple VFIO devices migration is supported only if " - "all of them support P2P migration"); - return -EINVAL; - } - - if (multiple_devices_migration_blocker) { - return 0; - } - - error_setg(&multiple_devices_migration_blocker, - "Multiple VFIO devices migration is supported only if all of " - "them support P2P migration"); - return migrate_add_blocker_normal(&multiple_devices_migration_blocker, - errp); -} - -void vfio_unblock_multiple_devices_migration(void) -{ - if (!multiple_devices_migration_blocker || - !vfio_multiple_devices_migration_is_supported()) { - return; - } - - migrate_del_blocker(&multiple_devices_migration_blocker); -} bool vfio_viommu_preset(VFIODevice *vbasedev) { diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 582d65932a..ace3d8548e 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1022,6 +1022,65 @@ static int vfio_migration_init(VFIODevice *vbasedev) return 0; } +static Error *multiple_devices_migration_blocker; + +/* + * Multiple devices migration is allowed only if all devices support P2P + * migration. Single device migration is allowed regardless of P2P migration + * support. + */ +static bool vfio_multiple_devices_migration_is_supported(void) +{ + VFIODevice *vbasedev; + unsigned int device_num = 0; + bool all_support_p2p = true; + + QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->migration) { + device_num++; + + if (!(vbasedev->migration->mig_flags & VFIO_MIGRATION_P2P)) { + all_support_p2p = false; + } + } + } + + return all_support_p2p || device_num <= 1; +} + +static int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp) +{ + if (vfio_multiple_devices_migration_is_supported()) { + return 0; + } + + if (vbasedev->enable_migration == ON_OFF_AUTO_ON) { + error_setg(errp, "Multiple VFIO devices migration is supported only if " + "all of them support P2P migration"); + return -EINVAL; + } + + if (multiple_devices_migration_blocker) { + return 0; + } + + error_setg(&multiple_devices_migration_blocker, + "Multiple VFIO devices migration is supported only if all of " + "them support P2P migration"); + return migrate_add_blocker_normal(&multiple_devices_migration_blocker, + errp); +} + +static void vfio_unblock_multiple_devices_migration(void) +{ + if (!multiple_devices_migration_blocker || + !vfio_multiple_devices_migration_is_supported()) { + return; + } + + migrate_del_blocker(&multiple_devices_migration_blocker); +} + static void vfio_migration_deinit(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 7a551bb230..5f1c0bee9d 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -290,8 +290,6 @@ extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; -int vfio_block_multiple_devices_migration(VFIODevice *vbasedev, Error **errp); -void vfio_unblock_multiple_devices_migration(void); bool vfio_viommu_preset(VFIODevice *vbasedev); void vfio_migration_add_bytes_transferred(unsigned long val); bool vfio_device_state_is_running(VFIODevice *vbasedev); From d04a35cb742e6e3b3682e31addb7b68b22b1c6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:50 +0100 Subject: [PATCH 0255/2760] vfio: Make vfio_viommu_preset() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This routine is only used in file "migration.c". Move it there. Reviewed-by: John Levon Reviewed-by: Joao Martins Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-6-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-6-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 5 ----- hw/vfio/migration.c | 5 +++++ include/hw/vfio/vfio-common.h | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index d65e77b93a..679076343a 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -65,11 +65,6 @@ int vfio_kvm_device_fd = -1; */ -bool vfio_viommu_preset(VFIODevice *vbasedev) -{ - return vbasedev->bcontainer->space->as != &address_space_memory; -} - bool vfio_device_state_is_running(VFIODevice *vbasedev) { VFIOMigration *migration = vbasedev->migration; diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index ace3d8548e..b5bb0cd092 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1138,6 +1138,11 @@ bool vfio_migration_active(void) return true; } +static bool vfio_viommu_preset(VFIODevice *vbasedev) +{ + return vbasedev->bcontainer->space->as != &address_space_memory; +} + /* * Return true when either migration initialized or blocker registered. * Currently only return false when adding blocker fails which will diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 5f1c0bee9d..8c56921506 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -290,7 +290,6 @@ extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; -bool vfio_viommu_preset(VFIODevice *vbasedev); void vfio_migration_add_bytes_transferred(unsigned long val); bool vfio_device_state_is_running(VFIODevice *vbasedev); bool vfio_device_state_is_precopy(VFIODevice *vbasedev); From b553d2c414a1b5c5bd3bf8bce0b648ba7f8e2baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:51 +0100 Subject: [PATCH 0256/2760] vfio: Introduce a new header file for internal migration services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all VFIO migration related declarations into "vfio-migration-internal.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". Cc: Kirti Wankhede Cc: Avihai Horon Reviewed-by: Prasad Pandit Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-7-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 1 + hw/vfio/migration-multifd.c | 2 +- hw/vfio/migration.c | 1 + hw/vfio/pci.c | 1 + hw/vfio/vfio-migration-internal.h | 72 +++++++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 52 +--------------------- 6 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 hw/vfio/vfio-migration-internal.h diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 679076343a..bef5414dd7 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -43,6 +43,7 @@ #include "migration/qemu-file.h" #include "system/tcg.h" #include "system/tpm.h" +#include "vfio-migration-internal.h" VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c index 09aa57f5f8..a3005226b9 100644 --- a/hw/vfio/migration-multifd.c +++ b/hw/vfio/migration-multifd.c @@ -11,7 +11,6 @@ #include "qemu/osdep.h" #include "hw/vfio/vfio-common.h" -#include "hw/vfio/vfio-migration.h" #include "migration/misc.h" #include "qapi/error.h" #include "qemu/bswap.h" @@ -22,6 +21,7 @@ #include "io/channel-buffer.h" #include "migration/qemu-file.h" #include "migration-multifd.h" +#include "vfio-migration-internal.h" #include "trace.h" #define VFIO_DEVICE_STATE_CONFIG_STATE (1) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index b5bb0cd092..54f6ca3e7c 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -31,6 +31,7 @@ #include "pci.h" #include "trace.h" #include "hw/hw.h" +#include "vfio-migration-internal.h" /* * This is an arbitrary size based on migration of mlx5 devices, where typically diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index f87f3ccbe1..b0aac2f3a0 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -44,6 +44,7 @@ #include "migration/blocker.h" #include "migration/qemu-file.h" #include "system/iommufd.h" +#include "vfio-migration-internal.h" #define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug" diff --git a/hw/vfio/vfio-migration-internal.h b/hw/vfio/vfio-migration-internal.h new file mode 100644 index 0000000000..ab6a1bad9b --- /dev/null +++ b/hw/vfio/vfio-migration-internal.h @@ -0,0 +1,72 @@ +/* + * VFIO migration + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_MIGRATION_INTERNAL_H +#define HW_VFIO_VFIO_MIGRATION_INTERNAL_H + +#ifdef CONFIG_LINUX +#include +#endif + +#include "qemu/typedefs.h" +#include "qemu/notify.h" + +/* + * Flags to be used as unique delimiters for VFIO devices in the migration + * stream. These flags are composed as: + * 0xffffffff => MSB 32-bit all 1s + * 0xef10 => Magic ID, represents emulated (virtual) function IO + * 0x0000 => 16-bits reserved for flags + * + * The beginning of state information is marked by _DEV_CONFIG_STATE, + * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a + * certain state information is marked by _END_OF_STATE. + */ +#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL) +#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL) +#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) +#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) +#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL) + +typedef struct VFIODevice VFIODevice; +typedef struct VFIOMultifd VFIOMultifd; + +typedef struct VFIOMigration { + struct VFIODevice *vbasedev; + VMChangeStateEntry *vm_state; + NotifierWithReturn migration_state; + uint32_t device_state; + int data_fd; + void *data_buffer; + size_t data_buffer_size; + uint64_t mig_flags; + uint64_t precopy_init_size; + uint64_t precopy_dirty_size; + bool multifd_transfer; + VFIOMultifd *multifd; + bool initial_data_sent; + + bool event_save_iterate_started; + bool event_precopy_empty_hit; +} VFIOMigration; + +bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp); +void vfio_migration_exit(VFIODevice *vbasedev); +int vfio_save_device_config_state(QEMUFile *f, void *opaque, Error **errp); +int vfio_load_device_config_state(QEMUFile *f, void *opaque); + +#ifdef CONFIG_LINUX +int vfio_migration_set_state(VFIODevice *vbasedev, + enum vfio_device_mig_state new_state, + enum vfio_device_mig_state recover_state, + Error **errp); +#endif + +void vfio_migration_add_bytes_transferred(unsigned long val); + +#endif /* HW_VFIO_VFIO_MIGRATION_INTERNAL_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 8c56921506..05c88753ce 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -23,7 +23,6 @@ #include "system/memory.h" #include "qemu/queue.h" -#include "qemu/notify.h" #include "ui/console.h" #include "hw/display/ramfb.h" #ifdef CONFIG_LINUX @@ -36,23 +35,6 @@ #define VFIO_MSG_PREFIX "vfio %s: " -/* - * Flags to be used as unique delimiters for VFIO devices in the migration - * stream. These flags are composed as: - * 0xffffffff => MSB 32-bit all 1s - * 0xef10 => Magic ID, represents emulated (virtual) function IO - * 0x0000 => 16-bits reserved for flags - * - * The beginning of state information is marked by _DEV_CONFIG_STATE, - * _DEV_SETUP_STATE, or _DEV_DATA_STATE, respectively. The end of a - * certain state information is marked by _END_OF_STATE. - */ -#define VFIO_MIG_FLAG_END_OF_STATE (0xffffffffef100001ULL) -#define VFIO_MIG_FLAG_DEV_CONFIG_STATE (0xffffffffef100002ULL) -#define VFIO_MIG_FLAG_DEV_SETUP_STATE (0xffffffffef100003ULL) -#define VFIO_MIG_FLAG_DEV_DATA_STATE (0xffffffffef100004ULL) -#define VFIO_MIG_FLAG_DEV_INIT_DATA_SENT (0xffffffffef100005ULL) - enum { VFIO_DEVICE_TYPE_PCI = 0, VFIO_DEVICE_TYPE_PLATFORM = 1, @@ -78,27 +60,6 @@ typedef struct VFIORegion { uint8_t nr; /* cache the region number for debug */ } VFIORegion; -typedef struct VFIOMultifd VFIOMultifd; - -typedef struct VFIOMigration { - struct VFIODevice *vbasedev; - VMChangeStateEntry *vm_state; - NotifierWithReturn migration_state; - uint32_t device_state; - int data_fd; - void *data_buffer; - size_t data_buffer_size; - uint64_t mig_flags; - uint64_t precopy_init_size; - uint64_t precopy_dirty_size; - bool multifd_transfer; - VFIOMultifd *multifd; - bool initial_data_sent; - - bool event_save_iterate_started; - bool event_precopy_empty_hit; -} VFIOMigration; - struct VFIOGroup; typedef struct VFIOContainer { @@ -136,6 +97,7 @@ typedef struct VFIOIOMMUFDContainer { OBJECT_DECLARE_SIMPLE_TYPE(VFIOIOMMUFDContainer, VFIO_IOMMU_IOMMUFD); typedef struct VFIODeviceOps VFIODeviceOps; +typedef struct VFIOMigration VFIOMigration; typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; @@ -290,13 +252,9 @@ extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; -void vfio_migration_add_bytes_transferred(unsigned long val); bool vfio_device_state_is_running(VFIODevice *vbasedev); bool vfio_device_state_is_precopy(VFIODevice *vbasedev); -int vfio_save_device_config_state(QEMUFile *f, void *opaque, Error **errp); -int vfio_load_device_config_state(QEMUFile *f, void *opaque); - #ifdef CONFIG_LINUX int vfio_get_region_info(VFIODevice *vbasedev, int index, struct vfio_region_info **info); @@ -311,16 +269,8 @@ struct vfio_info_cap_header * vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); struct vfio_info_cap_header * vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id); - -int vfio_migration_set_state(VFIODevice *vbasedev, - enum vfio_device_mig_state new_state, - enum vfio_device_mig_state recover_state, - Error **errp); #endif -bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp); -void vfio_migration_exit(VFIODevice *vbasedev); - int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); bool vfio_devices_all_dirty_tracking_started( const VFIOContainerBase *bcontainer); From eb6caa79162a89a8dcbe6a6d4788acd813b687a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:52 +0100 Subject: [PATCH 0257/2760] vfio: Move vfio_device_state_is_running/precopy() into migration.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These routines are migration related. Move their declaration and implementation under the migration files. Reviewed-by: Prasad Pandit Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-8-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 16 ---------------- hw/vfio/migration.c | 16 ++++++++++++++++ hw/vfio/vfio-migration-internal.h | 2 ++ include/hw/vfio/vfio-common.h | 3 --- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index bef5414dd7..8f55e7b212 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -66,22 +66,6 @@ int vfio_kvm_device_fd = -1; */ -bool vfio_device_state_is_running(VFIODevice *vbasedev) -{ - VFIOMigration *migration = vbasedev->migration; - - return migration->device_state == VFIO_DEVICE_STATE_RUNNING || - migration->device_state == VFIO_DEVICE_STATE_RUNNING_P2P; -} - -bool vfio_device_state_is_precopy(VFIODevice *vbasedev) -{ - VFIOMigration *migration = vbasedev->migration; - - return migration->device_state == VFIO_DEVICE_STATE_PRE_COPY || - migration->device_state == VFIO_DEVICE_STATE_PRE_COPY_P2P; -} - static bool vfio_devices_all_device_dirty_tracking_started( const VFIOContainerBase *bcontainer) { diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 54f6ca3e7c..4da0526325 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1220,3 +1220,19 @@ void vfio_migration_exit(VFIODevice *vbasedev) migrate_del_blocker(&vbasedev->migration_blocker); } + +bool vfio_device_state_is_running(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + + return migration->device_state == VFIO_DEVICE_STATE_RUNNING || + migration->device_state == VFIO_DEVICE_STATE_RUNNING_P2P; +} + +bool vfio_device_state_is_precopy(VFIODevice *vbasedev) +{ + VFIOMigration *migration = vbasedev->migration; + + return migration->device_state == VFIO_DEVICE_STATE_PRE_COPY || + migration->device_state == VFIO_DEVICE_STATE_PRE_COPY_P2P; +} diff --git a/hw/vfio/vfio-migration-internal.h b/hw/vfio/vfio-migration-internal.h index ab6a1bad9b..a8b456b239 100644 --- a/hw/vfio/vfio-migration-internal.h +++ b/hw/vfio/vfio-migration-internal.h @@ -57,6 +57,8 @@ typedef struct VFIOMigration { bool vfio_migration_realize(VFIODevice *vbasedev, Error **errp); void vfio_migration_exit(VFIODevice *vbasedev); +bool vfio_device_state_is_running(VFIODevice *vbasedev); +bool vfio_device_state_is_precopy(VFIODevice *vbasedev); int vfio_save_device_config_state(QEMUFile *f, void *opaque, Error **errp); int vfio_load_device_config_state(QEMUFile *f, void *opaque); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 05c88753ce..fa0b74d5ea 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -252,9 +252,6 @@ extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; -bool vfio_device_state_is_running(VFIODevice *vbasedev); -bool vfio_device_state_is_precopy(VFIODevice *vbasedev); - #ifdef CONFIG_LINUX int vfio_get_region_info(VFIODevice *vbasedev, int index, struct vfio_region_info **info); From aa173cb279e258ff591297fd0dedea43fd6f321d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:53 +0100 Subject: [PATCH 0258/2760] vfio: Introduce a new header file for VFIOdisplay declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all VFIOdisplay related declarations into "vfio-display.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-8-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-9-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/display.c | 2 +- hw/vfio/pci.h | 1 + hw/vfio/vfio-display.h | 41 +++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 28 ------------------------ 4 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 hw/vfio/vfio-display.h diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 4fdcef505d..70cfd685bd 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -16,9 +16,9 @@ #include "qemu/error-report.h" #include "hw/display/edid.h" -#include "ui/console.h" #include "qapi/error.h" #include "pci.h" +#include "vfio-display.h" #include "trace.h" #ifndef DRM_PLANE_TYPE_PRIMARY diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 6c59300248..62fd5f4997 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -20,6 +20,7 @@ #include "qemu/timer.h" #include "qom/object.h" #include "system/kvm.h" +#include "vfio-display.h" #define PCI_ANY_ID (~0) diff --git a/hw/vfio/vfio-display.h b/hw/vfio/vfio-display.h new file mode 100644 index 0000000000..99b8cb67ef --- /dev/null +++ b/hw/vfio/vfio-display.h @@ -0,0 +1,41 @@ +/* + * VFIO display + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_DISPLAY_H +#define HW_VFIO_VFIO_DISPLAY_H + +#include "ui/console.h" +#include "hw/display/ramfb.h" + +typedef struct VFIODMABuf { + QemuDmaBuf *buf; + uint32_t pos_x, pos_y, pos_updates; + uint32_t hot_x, hot_y, hot_updates; + int dmabuf_id; + QTAILQ_ENTRY(VFIODMABuf) next; +} VFIODMABuf; + +typedef struct VFIODisplay { + QemuConsole *con; + RAMFBState *ramfb; + struct vfio_region_info *edid_info; + struct vfio_region_gfx_edid *edid_regs; + uint8_t *edid_blob; + QEMUTimer *edid_link_timer; + struct { + VFIORegion buffer; + DisplaySurface *surface; + } region; + struct { + QTAILQ_HEAD(, VFIODMABuf) bufs; + VFIODMABuf *primary; + VFIODMABuf *cursor; + } dmabuf; +} VFIODisplay; + +#endif /* HW_VFIO_VFIO_DISPLAY_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index fa0b74d5ea..528eafadf9 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -23,8 +23,6 @@ #include "system/memory.h" #include "qemu/queue.h" -#include "ui/console.h" -#include "hw/display/ramfb.h" #ifdef CONFIG_LINUX #include #endif @@ -182,32 +180,6 @@ typedef struct VFIOGroup { #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" -typedef struct VFIODMABuf { - QemuDmaBuf *buf; - uint32_t pos_x, pos_y, pos_updates; - uint32_t hot_x, hot_y, hot_updates; - int dmabuf_id; - QTAILQ_ENTRY(VFIODMABuf) next; -} VFIODMABuf; - -typedef struct VFIODisplay { - QemuConsole *con; - RAMFBState *ramfb; - struct vfio_region_info *edid_info; - struct vfio_region_gfx_edid *edid_regs; - uint8_t *edid_blob; - QEMUTimer *edid_link_timer; - struct { - VFIORegion buffer; - DisplaySurface *surface; - } region; - struct { - QTAILQ_HEAD(, VFIODMABuf) bufs; - VFIODMABuf *primary; - VFIODMABuf *cursor; - } dmabuf; -} VFIODisplay; - VFIOAddressSpace *vfio_get_address_space(AddressSpace *as); void vfio_put_address_space(VFIOAddressSpace *space); void vfio_address_space_insert(VFIOAddressSpace *space, From 5a339dd8c1e34e13ae7f64477e20decdf381aae7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:54 +0100 Subject: [PATCH 0259/2760] vfio: Move VFIOHostDMAWindow definition into spapr.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VFIOHostDMAWindow is only used in file "spapr.c". Move it there. Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-9-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-10-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/spapr.c | 7 +++++++ include/hw/vfio/vfio-common.h | 7 ------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 7e5cb95f6a..f21955a344 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -22,6 +22,13 @@ #include "qapi/error.h" #include "trace.h" +typedef struct VFIOHostDMAWindow { + hwaddr min_iova; + hwaddr max_iova; + uint64_t iova_pgsizes; + QLIST_ENTRY(VFIOHostDMAWindow) hostwin_next; +} VFIOHostDMAWindow; + typedef struct VFIOSpaprContainer { VFIOContainer container; MemoryListener prereg_listener; diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 528eafadf9..83b1f7be80 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -69,13 +69,6 @@ typedef struct VFIOContainer { OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_IOMMU_LEGACY); -typedef struct VFIOHostDMAWindow { - hwaddr min_iova; - hwaddr max_iova; - uint64_t iova_pgsizes; - QLIST_ENTRY(VFIOHostDMAWindow) hostwin_next; -} VFIOHostDMAWindow; - typedef struct IOMMUFDBackend IOMMUFDBackend; typedef struct VFIOIOASHwpt { From d4a8f286e991c468489b19e45b959a1920d6890c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:55 +0100 Subject: [PATCH 0260/2760] vfio: Introduce a new header file for VFIOIOMMUFD declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all VFIOIOMMUFD related declarations introduced by commits 5ee3dc7af785 ("vfio/iommufd: Implement the iommufd backend") and 5b1e96e65403 ("vfio/iommufd: Introduce auto domain creation") into "vfio-iommufd.h". This to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". Cc: Joao Martins Cc: Yi Liu Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-10-clg@redhat.com Reviewed-by: Joao Martins Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-11-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/iommufd.c | 1 + hw/vfio/vfio-iommufd.h | 34 ++++++++++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 21 +++------------------ 3 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 hw/vfio/vfio-iommufd.h diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 42c8412bbf..7196c40801 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -25,6 +25,7 @@ #include "qemu/cutils.h" #include "qemu/chardev_open.h" #include "pci.h" +#include "vfio-iommufd.h" static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova, ram_addr_t size, void *vaddr, bool readonly) diff --git a/hw/vfio/vfio-iommufd.h b/hw/vfio/vfio-iommufd.h new file mode 100644 index 0000000000..07ea0f4304 --- /dev/null +++ b/hw/vfio/vfio-iommufd.h @@ -0,0 +1,34 @@ +/* + * VFIO iommufd + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_IOMMUFD_H +#define HW_VFIO_VFIO_IOMMUFD_H + +#include "hw/vfio/vfio-container-base.h" + +typedef struct VFIODevice VFIODevice; + +typedef struct VFIOIOASHwpt { + uint32_t hwpt_id; + uint32_t hwpt_flags; + QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOIOASHwpt) next; +} VFIOIOASHwpt; + +typedef struct IOMMUFDBackend IOMMUFDBackend; + +typedef struct VFIOIOMMUFDContainer { + VFIOContainerBase bcontainer; + IOMMUFDBackend *be; + uint32_t ioas_id; + QLIST_HEAD(, VFIOIOASHwpt) hwpt_list; +} VFIOIOMMUFDContainer; + +OBJECT_DECLARE_SIMPLE_TYPE(VFIOIOMMUFDContainer, VFIO_IOMMU_IOMMUFD); + +#endif /* HW_VFIO_VFIO_IOMMUFD_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 83b1f7be80..9ec90fbac0 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -69,27 +69,12 @@ typedef struct VFIOContainer { OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_IOMMU_LEGACY); -typedef struct IOMMUFDBackend IOMMUFDBackend; - -typedef struct VFIOIOASHwpt { - uint32_t hwpt_id; - uint32_t hwpt_flags; - QLIST_HEAD(, VFIODevice) device_list; - QLIST_ENTRY(VFIOIOASHwpt) next; -} VFIOIOASHwpt; - -typedef struct VFIOIOMMUFDContainer { - VFIOContainerBase bcontainer; - IOMMUFDBackend *be; - uint32_t ioas_id; - QLIST_HEAD(, VFIOIOASHwpt) hwpt_list; -} VFIOIOMMUFDContainer; - -OBJECT_DECLARE_SIMPLE_TYPE(VFIOIOMMUFDContainer, VFIO_IOMMU_IOMMUFD); - typedef struct VFIODeviceOps VFIODeviceOps; typedef struct VFIOMigration VFIOMigration; +typedef struct IOMMUFDBackend IOMMUFDBackend; +typedef struct VFIOIOASHwpt VFIOIOASHwpt; + typedef struct VFIODevice { QLIST_ENTRY(VFIODevice) next; QLIST_ENTRY(VFIODevice) container_next; From 499e53cce9445d23ee1bf54562de558562fc8d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:56 +0100 Subject: [PATCH 0261/2760] vfio: Introduce new files for VFIORegion definitions and declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all VFIORegion related declarations and definitions into their own files to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". They were introduced for 'vfio-platform' support in commits db0da029a185 ("vfio: Generalize region support") and a664477db8da ("hw/vfio/pci: Introduce VFIORegion"). To be noted that the 'vfio-platform' devices have been deprecated and will be removed in QEMU 10.2. Until then, make the declarations available externally for 'sysbus-fdt.c'. Cc: Eric Auger Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-12-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/core/sysbus-fdt.c | 1 + hw/vfio/helpers.c | 363 ----------------------------- hw/vfio/meson.build | 1 + hw/vfio/pci.h | 1 + hw/vfio/platform.c | 1 + hw/vfio/region.c | 394 ++++++++++++++++++++++++++++++++ hw/vfio/trace-events | 16 +- hw/vfio/vfio-display.h | 1 + include/hw/vfio/vfio-common.h | 32 +-- include/hw/vfio/vfio-platform.h | 2 + include/hw/vfio/vfio-region.h | 47 ++++ 11 files changed, 458 insertions(+), 401 deletions(-) create mode 100644 hw/vfio/region.c create mode 100644 include/hw/vfio/vfio-region.h diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c index e85066b905..c339a27875 100644 --- a/hw/core/sysbus-fdt.c +++ b/hw/core/sysbus-fdt.c @@ -35,6 +35,7 @@ #include "hw/vfio/vfio-platform.h" #include "hw/vfio/vfio-calxeda-xgmac.h" #include "hw/vfio/vfio-amd-xgbe.h" +#include "hw/vfio/vfio-region.h" #include "hw/display/ramfb.h" #include "hw/uefi/var-service-api.h" #include "hw/arm/fdt.h" diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 4b255d4f3a..89403943a7 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -147,118 +147,6 @@ bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, return false; } -/* - * IO Port/MMIO - Beware of the endians, VFIO is always little endian - */ -void vfio_region_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - VFIORegion *region = opaque; - VFIODevice *vbasedev = region->vbasedev; - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - uint64_t qword; - } buf; - - switch (size) { - case 1: - buf.byte = data; - break; - case 2: - buf.word = cpu_to_le16(data); - break; - case 4: - buf.dword = cpu_to_le32(data); - break; - case 8: - buf.qword = cpu_to_le64(data); - break; - default: - hw_error("vfio: unsupported write size, %u bytes", size); - break; - } - - if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 - ",%d) failed: %m", - __func__, vbasedev->name, region->nr, - addr, data, size); - } - - trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); - - /* - * A read or write to a BAR always signals an INTx EOI. This will - * do nothing if not pending (including not in INTx mode). We assume - * that a BAR access is in response to an interrupt and that BAR - * accesses will service the interrupt. Unfortunately, we don't know - * which access will service the interrupt, so we're potentially - * getting quite a few host interrupts per guest interrupt. - */ - vbasedev->ops->vfio_eoi(vbasedev); -} - -uint64_t vfio_region_read(void *opaque, - hwaddr addr, unsigned size) -{ - VFIORegion *region = opaque; - VFIODevice *vbasedev = region->vbasedev; - union { - uint8_t byte; - uint16_t word; - uint32_t dword; - uint64_t qword; - } buf; - uint64_t data = 0; - - if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { - error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", - __func__, vbasedev->name, region->nr, - addr, size); - return (uint64_t)-1; - } - switch (size) { - case 1: - data = buf.byte; - break; - case 2: - data = le16_to_cpu(buf.word); - break; - case 4: - data = le32_to_cpu(buf.dword); - break; - case 8: - data = le64_to_cpu(buf.qword); - break; - default: - hw_error("vfio: unsupported read size, %u bytes", size); - break; - } - - trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); - - /* Same as write above */ - vbasedev->ops->vfio_eoi(vbasedev); - - return data; -} - -const MemoryRegionOps vfio_region_ops = { - .read = vfio_region_read, - .write = vfio_region_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 1, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 8, - }, -}; - int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size) { vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size(); @@ -306,257 +194,6 @@ vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id) return vfio_get_cap((void *)info, info->cap_offset, id); } -static int vfio_setup_region_sparse_mmaps(VFIORegion *region, - struct vfio_region_info *info) -{ - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_sparse_mmap *sparse; - int i, j; - - hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); - if (!hdr) { - return -ENODEV; - } - - sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); - - trace_vfio_region_sparse_mmap_header(region->vbasedev->name, - region->nr, sparse->nr_areas); - - region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); - - for (i = 0, j = 0; i < sparse->nr_areas; i++) { - if (sparse->areas[i].size) { - trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, - sparse->areas[i].offset + - sparse->areas[i].size - 1); - region->mmaps[j].offset = sparse->areas[i].offset; - region->mmaps[j].size = sparse->areas[i].size; - j++; - } - } - - region->nr_mmaps = j; - region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); - - return 0; -} - -int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, - int index, const char *name) -{ - g_autofree struct vfio_region_info *info = NULL; - int ret; - - ret = vfio_get_region_info(vbasedev, index, &info); - if (ret) { - return ret; - } - - region->vbasedev = vbasedev; - region->flags = info->flags; - region->size = info->size; - region->fd_offset = info->offset; - region->nr = index; - - if (region->size) { - region->mem = g_new0(MemoryRegion, 1); - memory_region_init_io(region->mem, obj, &vfio_region_ops, - region, name, region->size); - - if (!vbasedev->no_mmap && - region->flags & VFIO_REGION_INFO_FLAG_MMAP) { - - ret = vfio_setup_region_sparse_mmaps(region, info); - - if (ret) { - region->nr_mmaps = 1; - region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); - region->mmaps[0].offset = 0; - region->mmaps[0].size = region->size; - } - } - } - - trace_vfio_region_setup(vbasedev->name, index, name, - region->flags, region->fd_offset, region->size); - return 0; -} - -static void vfio_subregion_unmap(VFIORegion *region, int index) -{ - trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), - region->mmaps[index].offset, - region->mmaps[index].offset + - region->mmaps[index].size - 1); - memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); - munmap(region->mmaps[index].mmap, region->mmaps[index].size); - object_unparent(OBJECT(®ion->mmaps[index].mem)); - region->mmaps[index].mmap = NULL; -} - -int vfio_region_mmap(VFIORegion *region) -{ - int i, ret, prot = 0; - char *name; - - if (!region->mem) { - return 0; - } - - prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; - prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; - - for (i = 0; i < region->nr_mmaps; i++) { - size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB); - void *map_base, *map_align; - - /* - * Align the mmap for more efficient mapping in the kernel. Ideally - * we'd know the PMD and PUD mapping sizes to use as discrete alignment - * intervals, but we don't. As of Linux v6.12, the largest PUD size - * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set - * on x86_64). Align by power-of-two size, capped at 1GiB. - * - * NB. qemu_memalign() and friends actually allocate memory, whereas - * the region size here can exceed host memory, therefore we manually - * create an oversized anonymous mapping and clean it up for alignment. - */ - map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (map_base == MAP_FAILED) { - ret = -errno; - goto no_mmap; - } - - map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align); - munmap(map_base, map_align - map_base); - munmap(map_align + region->mmaps[i].size, - align - (map_align - map_base)); - - region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot, - MAP_SHARED | MAP_FIXED, - region->vbasedev->fd, - region->fd_offset + - region->mmaps[i].offset); - if (region->mmaps[i].mmap == MAP_FAILED) { - ret = -errno; - goto no_mmap; - } - - name = g_strdup_printf("%s mmaps[%d]", - memory_region_name(region->mem), i); - memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, - memory_region_owner(region->mem), - name, region->mmaps[i].size, - region->mmaps[i].mmap); - g_free(name); - memory_region_add_subregion(region->mem, region->mmaps[i].offset, - ®ion->mmaps[i].mem); - - trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), - region->mmaps[i].offset, - region->mmaps[i].offset + - region->mmaps[i].size - 1); - } - - return 0; - -no_mmap: - trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, - region->fd_offset + region->mmaps[i].offset, - region->fd_offset + region->mmaps[i].offset + - region->mmaps[i].size - 1, ret); - - region->mmaps[i].mmap = NULL; - - for (i--; i >= 0; i--) { - vfio_subregion_unmap(region, i); - } - - return ret; -} - -void vfio_region_unmap(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - vfio_subregion_unmap(region, i); - } - } -} - -void vfio_region_exit(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); - } - } - - trace_vfio_region_exit(region->vbasedev->name, region->nr); -} - -void vfio_region_finalize(VFIORegion *region) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - munmap(region->mmaps[i].mmap, region->mmaps[i].size); - object_unparent(OBJECT(®ion->mmaps[i].mem)); - } - } - - object_unparent(OBJECT(region->mem)); - - g_free(region->mem); - g_free(region->mmaps); - - trace_vfio_region_finalize(region->vbasedev->name, region->nr); - - region->mem = NULL; - region->mmaps = NULL; - region->nr_mmaps = 0; - region->size = 0; - region->flags = 0; - region->nr = 0; -} - -void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) -{ - int i; - - if (!region->mem) { - return; - } - - for (i = 0; i < region->nr_mmaps; i++) { - if (region->mmaps[i].mmap) { - memory_region_set_enabled(®ion->mmaps[i].mem, enabled); - } - } - - trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), - enabled); -} - int vfio_get_region_info(VFIODevice *vbasedev, int index, struct vfio_region_info **info) { diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index a8939c8386..07010c7c9e 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -23,6 +23,7 @@ system_ss.add(when: 'CONFIG_VFIO', if_true: files( 'migration.c', 'migration-multifd.c', 'cpr.c', + 'region.c', )) system_ss.add(when: ['CONFIG_VFIO', 'CONFIG_IOMMUFD'], if_true: files( 'iommufd.c', diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 62fd5f4997..801ea445b8 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -15,6 +15,7 @@ #include "system/memory.h" #include "hw/pci/pci_device.h" #include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-region.h" #include "qemu/event_notifier.h" #include "qemu/queue.h" #include "qemu/timer.h" diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index f273ae9a51..ca6528cc56 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -37,6 +37,7 @@ #include "hw/platform-bus.h" #include "hw/qdev-properties.h" #include "system/kvm.h" +#include "hw/vfio/vfio-region.h" /* * Functions used whatever the injection method diff --git a/hw/vfio/region.c b/hw/vfio/region.c new file mode 100644 index 0000000000..08cd69e704 --- /dev/null +++ b/hw/vfio/region.c @@ -0,0 +1,394 @@ +/* + * VFIO regions + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on qemu-kvm device-assignment: + * Adapted for KVM by Qumranet. + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ + +#include "qemu/osdep.h" +#include + +#include "hw/vfio/vfio-common.h" +#include "hw/vfio/pci.h" +#include "hw/hw.h" +#include "trace.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/units.h" +#include "monitor/monitor.h" + +/* + * IO Port/MMIO - Beware of the endians, VFIO is always little endian + */ +void vfio_region_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) +{ + VFIORegion *region = opaque; + VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + + switch (size) { + case 1: + buf.byte = data; + break; + case 2: + buf.word = cpu_to_le16(data); + break; + case 4: + buf.dword = cpu_to_le32(data); + break; + case 8: + buf.qword = cpu_to_le64(data); + break; + default: + hw_error("vfio: unsupported write size, %u bytes", size); + break; + } + + if (pwrite(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + error_report("%s(%s:region%d+0x%"HWADDR_PRIx", 0x%"PRIx64 + ",%d) failed: %m", + __func__, vbasedev->name, region->nr, + addr, data, size); + } + + trace_vfio_region_write(vbasedev->name, region->nr, addr, data, size); + + /* + * A read or write to a BAR always signals an INTx EOI. This will + * do nothing if not pending (including not in INTx mode). We assume + * that a BAR access is in response to an interrupt and that BAR + * accesses will service the interrupt. Unfortunately, we don't know + * which access will service the interrupt, so we're potentially + * getting quite a few host interrupts per guest interrupt. + */ + vbasedev->ops->vfio_eoi(vbasedev); +} + +uint64_t vfio_region_read(void *opaque, + hwaddr addr, unsigned size) +{ + VFIORegion *region = opaque; + VFIODevice *vbasedev = region->vbasedev; + union { + uint8_t byte; + uint16_t word; + uint32_t dword; + uint64_t qword; + } buf; + uint64_t data = 0; + + if (pread(vbasedev->fd, &buf, size, region->fd_offset + addr) != size) { + error_report("%s(%s:region%d+0x%"HWADDR_PRIx", %d) failed: %m", + __func__, vbasedev->name, region->nr, + addr, size); + return (uint64_t)-1; + } + switch (size) { + case 1: + data = buf.byte; + break; + case 2: + data = le16_to_cpu(buf.word); + break; + case 4: + data = le32_to_cpu(buf.dword); + break; + case 8: + data = le64_to_cpu(buf.qword); + break; + default: + hw_error("vfio: unsupported read size, %u bytes", size); + break; + } + + trace_vfio_region_read(vbasedev->name, region->nr, addr, size, data); + + /* Same as write above */ + vbasedev->ops->vfio_eoi(vbasedev); + + return data; +} + +static const MemoryRegionOps vfio_region_ops = { + .read = vfio_region_read, + .write = vfio_region_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 1, + .max_access_size = 8, + }, + .impl = { + .min_access_size = 1, + .max_access_size = 8, + }, +}; + +static int vfio_setup_region_sparse_mmaps(VFIORegion *region, + struct vfio_region_info *info) +{ + struct vfio_info_cap_header *hdr; + struct vfio_region_info_cap_sparse_mmap *sparse; + int i, j; + + hdr = vfio_get_region_info_cap(info, VFIO_REGION_INFO_CAP_SPARSE_MMAP); + if (!hdr) { + return -ENODEV; + } + + sparse = container_of(hdr, struct vfio_region_info_cap_sparse_mmap, header); + + trace_vfio_region_sparse_mmap_header(region->vbasedev->name, + region->nr, sparse->nr_areas); + + region->mmaps = g_new0(VFIOMmap, sparse->nr_areas); + + for (i = 0, j = 0; i < sparse->nr_areas; i++) { + if (sparse->areas[i].size) { + trace_vfio_region_sparse_mmap_entry(i, sparse->areas[i].offset, + sparse->areas[i].offset + + sparse->areas[i].size - 1); + region->mmaps[j].offset = sparse->areas[i].offset; + region->mmaps[j].size = sparse->areas[i].size; + j++; + } + } + + region->nr_mmaps = j; + region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap)); + + return 0; +} + +int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, + int index, const char *name) +{ + g_autofree struct vfio_region_info *info = NULL; + int ret; + + ret = vfio_get_region_info(vbasedev, index, &info); + if (ret) { + return ret; + } + + region->vbasedev = vbasedev; + region->flags = info->flags; + region->size = info->size; + region->fd_offset = info->offset; + region->nr = index; + + if (region->size) { + region->mem = g_new0(MemoryRegion, 1); + memory_region_init_io(region->mem, obj, &vfio_region_ops, + region, name, region->size); + + if (!vbasedev->no_mmap && + region->flags & VFIO_REGION_INFO_FLAG_MMAP) { + + ret = vfio_setup_region_sparse_mmaps(region, info); + + if (ret) { + region->nr_mmaps = 1; + region->mmaps = g_new0(VFIOMmap, region->nr_mmaps); + region->mmaps[0].offset = 0; + region->mmaps[0].size = region->size; + } + } + } + + trace_vfio_region_setup(vbasedev->name, index, name, + region->flags, region->fd_offset, region->size); + return 0; +} + +static void vfio_subregion_unmap(VFIORegion *region, int index) +{ + trace_vfio_region_unmap(memory_region_name(®ion->mmaps[index].mem), + region->mmaps[index].offset, + region->mmaps[index].offset + + region->mmaps[index].size - 1); + memory_region_del_subregion(region->mem, ®ion->mmaps[index].mem); + munmap(region->mmaps[index].mmap, region->mmaps[index].size); + object_unparent(OBJECT(®ion->mmaps[index].mem)); + region->mmaps[index].mmap = NULL; +} + +int vfio_region_mmap(VFIORegion *region) +{ + int i, ret, prot = 0; + char *name; + + if (!region->mem) { + return 0; + } + + prot |= region->flags & VFIO_REGION_INFO_FLAG_READ ? PROT_READ : 0; + prot |= region->flags & VFIO_REGION_INFO_FLAG_WRITE ? PROT_WRITE : 0; + + for (i = 0; i < region->nr_mmaps; i++) { + size_t align = MIN(1ULL << ctz64(region->mmaps[i].size), 1 * GiB); + void *map_base, *map_align; + + /* + * Align the mmap for more efficient mapping in the kernel. Ideally + * we'd know the PMD and PUD mapping sizes to use as discrete alignment + * intervals, but we don't. As of Linux v6.12, the largest PUD size + * supporting huge pfnmap is 1GiB (ARCH_SUPPORTS_PUD_PFNMAP is only set + * on x86_64). Align by power-of-two size, capped at 1GiB. + * + * NB. qemu_memalign() and friends actually allocate memory, whereas + * the region size here can exceed host memory, therefore we manually + * create an oversized anonymous mapping and clean it up for alignment. + */ + map_base = mmap(0, region->mmaps[i].size + align, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (map_base == MAP_FAILED) { + ret = -errno; + goto no_mmap; + } + + map_align = (void *)ROUND_UP((uintptr_t)map_base, (uintptr_t)align); + munmap(map_base, map_align - map_base); + munmap(map_align + region->mmaps[i].size, + align - (map_align - map_base)); + + region->mmaps[i].mmap = mmap(map_align, region->mmaps[i].size, prot, + MAP_SHARED | MAP_FIXED, + region->vbasedev->fd, + region->fd_offset + + region->mmaps[i].offset); + if (region->mmaps[i].mmap == MAP_FAILED) { + ret = -errno; + goto no_mmap; + } + + name = g_strdup_printf("%s mmaps[%d]", + memory_region_name(region->mem), i); + memory_region_init_ram_device_ptr(®ion->mmaps[i].mem, + memory_region_owner(region->mem), + name, region->mmaps[i].size, + region->mmaps[i].mmap); + g_free(name); + memory_region_add_subregion(region->mem, region->mmaps[i].offset, + ®ion->mmaps[i].mem); + + trace_vfio_region_mmap(memory_region_name(®ion->mmaps[i].mem), + region->mmaps[i].offset, + region->mmaps[i].offset + + region->mmaps[i].size - 1); + } + + return 0; + +no_mmap: + trace_vfio_region_mmap_fault(memory_region_name(region->mem), i, + region->fd_offset + region->mmaps[i].offset, + region->fd_offset + region->mmaps[i].offset + + region->mmaps[i].size - 1, ret); + + region->mmaps[i].mmap = NULL; + + for (i--; i >= 0; i--) { + vfio_subregion_unmap(region, i); + } + + return ret; +} + +void vfio_region_unmap(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + vfio_subregion_unmap(region, i); + } + } +} + +void vfio_region_exit(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + memory_region_del_subregion(region->mem, ®ion->mmaps[i].mem); + } + } + + trace_vfio_region_exit(region->vbasedev->name, region->nr); +} + +void vfio_region_finalize(VFIORegion *region) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + munmap(region->mmaps[i].mmap, region->mmaps[i].size); + object_unparent(OBJECT(®ion->mmaps[i].mem)); + } + } + + object_unparent(OBJECT(region->mem)); + + g_free(region->mem); + g_free(region->mmaps); + + trace_vfio_region_finalize(region->vbasedev->name, region->nr); + + region->mem = NULL; + region->mmaps = NULL; + region->nr_mmaps = 0; + region->size = 0; + region->flags = 0; + region->nr = 0; +} + +void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled) +{ + int i; + + if (!region->mem) { + return; + } + + for (i = 0; i < region->nr_mmaps; i++) { + if (region->mmaps[i].mmap) { + memory_region_set_enabled(®ion->mmaps[i].mem, enabled); + } + } + + trace_vfio_region_mmaps_set_enabled(memory_region_name(region->mem), + enabled); +} diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 9347e3a5f6..81f4130100 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -90,8 +90,6 @@ vfio_pci_igd_host_bridge_enabled(const char *name) "%s" vfio_pci_igd_lpc_bridge_enabled(const char *name) "%s" # common.c -vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" -vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "iommu %s @ 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_skip(const char *name, uint64_t start, uint64_t end) "SKIPPING %s 0x%"PRIx64" - 0x%"PRIx64 vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" @@ -107,6 +105,15 @@ vfio_disconnect_container(int fd) "close container->fd=%d" vfio_put_group(int fd) "close group->fd=%d" vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" vfio_put_base_device(int fd) "close vdev->fd=%d" +vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" +vfio_legacy_dma_unmap_overflow_workaround(void) "" +vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 +vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 +vfio_reset_handler(void) "" + +# region.c +vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" +vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 vfio_region_setup(const char *dev, int index, const char *name, unsigned long flags, unsigned long offset, unsigned long size) "Device %s, region %d \"%s\", flags: 0x%lx, offset: 0x%lx, size: 0x%lx" vfio_region_mmap_fault(const char *name, int index, unsigned long offset, unsigned long size, int fault) "Region %s mmaps[%d], [0x%lx - 0x%lx], fault: %d" vfio_region_mmap(const char *name, unsigned long offset, unsigned long end) "Region %s [0x%lx - 0x%lx]" @@ -116,11 +123,6 @@ vfio_region_mmaps_set_enabled(const char *name, bool enabled) "Region %s mmaps e vfio_region_unmap(const char *name, unsigned long offset, unsigned long end) "Region %s unmap [0x%lx - 0x%lx]" vfio_region_sparse_mmap_header(const char *name, int index, int nr_areas) "Device %s region %d: %d sparse mmap entries" vfio_region_sparse_mmap_entry(int i, unsigned long start, unsigned long end) "sparse entry %d [0x%lx - 0x%lx]" -vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" -vfio_legacy_dma_unmap_overflow_workaround(void) "" -vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 -vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 -vfio_reset_handler(void) "" # platform.c vfio_platform_realize(char *name, char *compat) "vfio device %s, compat = %s" diff --git a/hw/vfio/vfio-display.h b/hw/vfio/vfio-display.h index 99b8cb67ef..2606c34b39 100644 --- a/hw/vfio/vfio-display.h +++ b/hw/vfio/vfio-display.h @@ -11,6 +11,7 @@ #include "ui/console.h" #include "hw/display/ramfb.h" +#include "hw/vfio/vfio-region.h" typedef struct VFIODMABuf { QemuDmaBuf *buf; diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 9ec90fbac0..b372033741 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -39,25 +39,6 @@ enum { VFIO_DEVICE_TYPE_CCW = 2, VFIO_DEVICE_TYPE_AP = 3, }; - -typedef struct VFIOMmap { - MemoryRegion mem; - void *mmap; - off_t offset; - size_t size; -} VFIOMmap; - -typedef struct VFIORegion { - struct VFIODevice *vbasedev; - off_t fd_offset; /* offset of region within device fd */ - MemoryRegion *mem; /* slow, read/write access */ - size_t size; - uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ - uint32_t nr_mmaps; - VFIOMmap *mmaps; - uint8_t nr; /* cache the region number for debug */ -} VFIORegion; - struct VFIOGroup; typedef struct VFIOContainer { @@ -168,17 +149,7 @@ void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, int action, int fd, Error **errp); -void vfio_region_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size); -uint64_t vfio_region_read(void *opaque, - hwaddr addr, unsigned size); -int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, - int index, const char *name); -int vfio_region_mmap(VFIORegion *region); -void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); -void vfio_region_unmap(VFIORegion *region); -void vfio_region_exit(VFIORegion *region); -void vfio_region_finalize(VFIORegion *region); + void vfio_reset_handler(void *opaque); struct vfio_device_info *vfio_get_device_info(int fd); bool vfio_device_is_mdev(VFIODevice *vbasedev); @@ -194,7 +165,6 @@ int vfio_kvm_device_del_fd(int fd, Error **errp); bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp); void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer); -extern const MemoryRegionOps vfio_region_ops; typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIOGroupList vfio_group_list; diff --git a/include/hw/vfio/vfio-platform.h b/include/hw/vfio/vfio-platform.h index c414c3dffc..3191545717 100644 --- a/include/hw/vfio/vfio-platform.h +++ b/include/hw/vfio/vfio-platform.h @@ -47,6 +47,8 @@ typedef struct VFIOINTp { /* function type for user side eventfd handler */ typedef void (*eventfd_user_side_handler_t)(VFIOINTp *intp); +typedef struct VFIORegion VFIORegion; + struct VFIOPlatformDevice { SysBusDevice sbdev; VFIODevice vbasedev; /* not a QOM object */ diff --git a/include/hw/vfio/vfio-region.h b/include/hw/vfio/vfio-region.h new file mode 100644 index 0000000000..cbffb26962 --- /dev/null +++ b/include/hw/vfio/vfio-region.h @@ -0,0 +1,47 @@ +/* + * VFIO region + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_REGION_H +#define HW_VFIO_REGION_H + +#include "system/memory.h" + +typedef struct VFIOMmap { + MemoryRegion mem; + void *mmap; + off_t offset; + size_t size; +} VFIOMmap; + +typedef struct VFIODevice VFIODevice; + +typedef struct VFIORegion { + struct VFIODevice *vbasedev; + off_t fd_offset; /* offset of region within device fd */ + MemoryRegion *mem; /* slow, read/write access */ + size_t size; + uint32_t flags; /* VFIO region flags (rd/wr/mmap) */ + uint32_t nr_mmaps; + VFIOMmap *mmaps; + uint8_t nr; /* cache the region number for debug */ +} VFIORegion; + + +void vfio_region_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size); +uint64_t vfio_region_read(void *opaque, + hwaddr addr, unsigned size); +int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, + int index, const char *name); +int vfio_region_mmap(VFIORegion *region); +void vfio_region_mmaps_set_enabled(VFIORegion *region, bool enabled); +void vfio_region_unmap(VFIORegion *region); +void vfio_region_exit(VFIORegion *region); +void vfio_region_finalize(VFIORegion *region); + +#endif /* HW_VFIO_REGION_H */ From aa90d775f0f568239f2a6bd3ead7e8d3b4a35a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:57 +0100 Subject: [PATCH 0262/2760] vfio: Introduce a new header file for VFIOcontainer declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all VFIOcontainer related declarations into "hw/vfio/vfio-container.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". These declarations were initially introduced in commit 65501a745dba ("vfio: vfio-pci device assignment driver"). They are made available externally for PPC and s390x. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-12-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-13-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/ppc/spapr_pci_vfio.c | 1 + hw/s390x/s390-pci-vfio.c | 2 +- hw/vfio/container.c | 1 + hw/vfio/spapr.c | 1 + include/hw/vfio/vfio-common.h | 19 ----------------- include/hw/vfio/vfio-container.h | 36 ++++++++++++++++++++++++++++++++ 6 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 include/hw/vfio/vfio-container.h diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 76b2a3487b..1722a5bfa3 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -25,6 +25,7 @@ #include "hw/pci/msix.h" #include "hw/pci/pci_device.h" #include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-container.h" #include "qemu/error-report.h" #include CONFIG_DEVICES /* CONFIG_VFIO_PCI */ diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index db152a6252..748a51fd8c 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -20,7 +20,7 @@ #include "hw/s390x/s390-pci-clp.h" #include "hw/s390x/s390-pci-vfio.h" #include "hw/vfio/pci.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-container.h" /* * Get the current DMA available count from vfio. Returns true if vfio is diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 812d5edbcf..bda1942662 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -32,6 +32,7 @@ #include "trace.h" #include "qapi/error.h" #include "pci.h" +#include "hw/vfio/vfio-container.h" VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index f21955a344..31e4dddc9e 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -16,6 +16,7 @@ #include "system/address-spaces.h" #include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-container.h" #include "hw/hw.h" #include "system/ram_addr.h" #include "qemu/error-report.h" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index b372033741..bcdbc9de57 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -39,16 +39,6 @@ enum { VFIO_DEVICE_TYPE_CCW = 2, VFIO_DEVICE_TYPE_AP = 3, }; -struct VFIOGroup; - -typedef struct VFIOContainer { - VFIOContainerBase bcontainer; - int fd; /* /dev/vfio/vfio, empowered by the attached groups */ - unsigned iommu_type; - QLIST_HEAD(, VFIOGroup) group_list; -} VFIOContainer; - -OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_IOMMU_LEGACY); typedef struct VFIODeviceOps VFIODeviceOps; typedef struct VFIOMigration VFIOMigration; @@ -125,15 +115,6 @@ struct VFIODeviceOps { int (*vfio_load_config)(VFIODevice *vdev, QEMUFile *f); }; -typedef struct VFIOGroup { - int fd; - int groupid; - VFIOContainer *container; - QLIST_HEAD(, VFIODevice) device_list; - QLIST_ENTRY(VFIOGroup) next; - QLIST_ENTRY(VFIOGroup) container_next; - bool ram_block_discard_allowed; -} VFIOGroup; #define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ diff --git a/include/hw/vfio/vfio-container.h b/include/hw/vfio/vfio-container.h new file mode 100644 index 0000000000..afc498da49 --- /dev/null +++ b/include/hw/vfio/vfio-container.h @@ -0,0 +1,36 @@ +/* + * VFIO container + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_CONTAINER_H +#define HW_VFIO_CONTAINER_H + +#include "hw/vfio/vfio-container-base.h" + +typedef struct VFIOContainer VFIOContainer; +typedef struct VFIODevice VFIODevice; + +typedef struct VFIOGroup { + int fd; + int groupid; + VFIOContainer *container; + QLIST_HEAD(, VFIODevice) device_list; + QLIST_ENTRY(VFIOGroup) next; + QLIST_ENTRY(VFIOGroup) container_next; + bool ram_block_discard_allowed; +} VFIOGroup; + +typedef struct VFIOContainer { + VFIOContainerBase bcontainer; + int fd; /* /dev/vfio/vfio, empowered by the attached groups */ + unsigned iommu_type; + QLIST_HEAD(, VFIOGroup) group_list; +} VFIOContainer; + +OBJECT_DECLARE_SIMPLE_TYPE(VFIOContainer, VFIO_IOMMU_LEGACY); + +#endif /* HW_VFIO_CONTAINER_H */ From 0778f9b3bef0438530e1dd0d277571405637d880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:58 +0100 Subject: [PATCH 0263/2760] vfio: Make vfio_group_list static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_group_list is only used in file "container.c". Reviewed-by: John Levon Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-13-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-14-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 3 ++- include/hw/vfio/vfio-common.h | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index bda1942662..8a216b24b5 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -34,7 +34,8 @@ #include "pci.h" #include "hw/vfio/vfio-container.h" -VFIOGroupList vfio_group_list = +typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; +static VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); static int vfio_ram_block_discard_disable(VFIOContainer *container, bool state) diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index bcdbc9de57..d806349475 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -146,9 +146,7 @@ int vfio_kvm_device_del_fd(int fd, Error **errp); bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp); void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer); -typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; -extern VFIOGroupList vfio_group_list; extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; extern int vfio_kvm_device_fd; From d158ed092332d8c79193921112ea5e7b5e62cd6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:50:59 +0100 Subject: [PATCH 0264/2760] vfio: Move VFIOAddressSpace helpers into container-base.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VFIOAddressSpace is a common object used by VFIOContainerBase which is declared in "hw/vfio/vfio-container-base.h". Move the VFIOAddressSpace related services into "container-base.c". While at it, rename : vfio_get_address_space -> vfio_address_space_get vfio_put_address_space -> vfio_address_space_put to better reflect the namespace these routines belong to. Reviewed-by: John Levon Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-15-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/ppc/spapr_pci_vfio.c | 5 ++- hw/vfio/common.c | 47 ------------------------- hw/vfio/container-base.c | 50 +++++++++++++++++++++++++++ hw/vfio/container.c | 6 ++-- hw/vfio/iommufd.c | 6 ++-- include/hw/vfio/vfio-common.h | 5 --- include/hw/vfio/vfio-container-base.h | 6 ++++ 7 files changed, 64 insertions(+), 61 deletions(-) diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 1722a5bfa3..e318d0d912 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -24,7 +24,6 @@ #include "hw/pci-host/spapr.h" #include "hw/pci/msix.h" #include "hw/pci/pci_device.h" -#include "hw/vfio/vfio-common.h" #include "hw/vfio/vfio-container.h" #include "qemu/error-report.h" #include CONFIG_DEVICES /* CONFIG_VFIO_PCI */ @@ -86,7 +85,7 @@ static int vfio_eeh_container_op(VFIOContainer *container, uint32_t op) static VFIOContainer *vfio_eeh_as_container(AddressSpace *as) { - VFIOAddressSpace *space = vfio_get_address_space(as); + VFIOAddressSpace *space = vfio_address_space_get(as); VFIOContainerBase *bcontainer = NULL; if (QLIST_EMPTY(&space->containers)) { @@ -106,7 +105,7 @@ static VFIOContainer *vfio_eeh_as_container(AddressSpace *as) } out: - vfio_put_address_space(space); + vfio_address_space_put(space); return container_of(bcontainer, VFIOContainer, bcontainer); } diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 8f55e7b212..c099d4d24d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -47,8 +47,6 @@ VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); -static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = - QLIST_HEAD_INITIALIZER(vfio_address_spaces); #ifdef CONFIG_KVM /* @@ -1392,51 +1390,6 @@ int vfio_kvm_device_del_fd(int fd, Error **errp) return 0; } -VFIOAddressSpace *vfio_get_address_space(AddressSpace *as) -{ - VFIOAddressSpace *space; - - QLIST_FOREACH(space, &vfio_address_spaces, list) { - if (space->as == as) { - return space; - } - } - - /* No suitable VFIOAddressSpace, create a new one */ - space = g_malloc0(sizeof(*space)); - space->as = as; - QLIST_INIT(&space->containers); - - if (QLIST_EMPTY(&vfio_address_spaces)) { - qemu_register_reset(vfio_reset_handler, NULL); - } - - QLIST_INSERT_HEAD(&vfio_address_spaces, space, list); - - return space; -} - -void vfio_put_address_space(VFIOAddressSpace *space) -{ - if (!QLIST_EMPTY(&space->containers)) { - return; - } - - QLIST_REMOVE(space, list); - g_free(space); - - if (QLIST_EMPTY(&vfio_address_spaces)) { - qemu_unregister_reset(vfio_reset_handler, NULL); - } -} - -void vfio_address_space_insert(VFIOAddressSpace *space, - VFIOContainerBase *bcontainer) -{ - QLIST_INSERT_HEAD(&space->containers, bcontainer, next); - bcontainer->space = space; -} - struct vfio_device_info *vfio_get_device_info(int fd) { struct vfio_device_info *info; diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 749a3fd29d..2c2d8329e3 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -14,6 +14,56 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/vfio/vfio-container-base.h" +#include "hw/vfio/vfio-common.h" /* vfio_reset_handler */ +#include "system/reset.h" + +static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = + QLIST_HEAD_INITIALIZER(vfio_address_spaces); + +VFIOAddressSpace *vfio_address_space_get(AddressSpace *as) +{ + VFIOAddressSpace *space; + + QLIST_FOREACH(space, &vfio_address_spaces, list) { + if (space->as == as) { + return space; + } + } + + /* No suitable VFIOAddressSpace, create a new one */ + space = g_malloc0(sizeof(*space)); + space->as = as; + QLIST_INIT(&space->containers); + + if (QLIST_EMPTY(&vfio_address_spaces)) { + qemu_register_reset(vfio_reset_handler, NULL); + } + + QLIST_INSERT_HEAD(&vfio_address_spaces, space, list); + + return space; +} + +void vfio_address_space_put(VFIOAddressSpace *space) +{ + if (!QLIST_EMPTY(&space->containers)) { + return; + } + + QLIST_REMOVE(space, list); + g_free(space); + + if (QLIST_EMPTY(&vfio_address_spaces)) { + qemu_unregister_reset(vfio_reset_handler, NULL); + } +} + +void vfio_address_space_insert(VFIOAddressSpace *space, + VFIOContainerBase *bcontainer) +{ + QLIST_INSERT_HEAD(&space->containers, bcontainer, next); + bcontainer->space = space; +} int vfio_container_dma_map(VFIOContainerBase *bcontainer, hwaddr iova, ram_addr_t size, diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 8a216b24b5..cc8cc0f272 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -546,7 +546,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, VFIOAddressSpace *space; VFIOIOMMUClass *vioc; - space = vfio_get_address_space(as); + space = vfio_address_space_get(as); /* * VFIO is currently incompatible with discarding of RAM insofar as the @@ -675,7 +675,7 @@ close_fd_exit: close(fd); put_space_exit: - vfio_put_address_space(space); + vfio_address_space_put(space); return false; } @@ -714,7 +714,7 @@ static void vfio_disconnect_container(VFIOGroup *group) close(container->fd); object_unref(container); - vfio_put_address_space(space); + vfio_address_space_put(space); } } diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 7196c40801..a520d40afc 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -486,7 +486,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, goto err_connect_bind; } - space = vfio_get_address_space(as); + space = vfio_address_space_get(as); /* * The HostIOMMUDevice data from legacy backend is static and doesn't need @@ -606,7 +606,7 @@ err_discard_disable: err_attach_container: iommufd_cdev_container_destroy(container); err_alloc_ioas: - vfio_put_address_space(space); + vfio_address_space_put(space); iommufd_cdev_unbind_and_disconnect(vbasedev); err_connect_bind: close(vbasedev->fd); @@ -631,7 +631,7 @@ static void iommufd_cdev_detach(VFIODevice *vbasedev) vfio_cpr_unregister_container(bcontainer); iommufd_cdev_detach_container(vbasedev, container); iommufd_cdev_container_destroy(container); - vfio_put_address_space(space); + vfio_address_space_put(space); iommufd_cdev_unbind_and_disconnect(vbasedev); close(vbasedev->fd); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index d806349475..7d78eb85da 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -120,11 +120,6 @@ struct VFIODeviceOps { #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" -VFIOAddressSpace *vfio_get_address_space(AddressSpace *as); -void vfio_put_address_space(VFIOAddressSpace *space); -void vfio_address_space_insert(VFIOAddressSpace *space, - VFIOContainerBase *bcontainer); - void vfio_disable_irqindex(VFIODevice *vbasedev, int index); void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 6aca02fb3d..e0c458d487 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -71,6 +71,11 @@ typedef struct VFIORamDiscardListener { QLIST_ENTRY(VFIORamDiscardListener) next; } VFIORamDiscardListener; +VFIOAddressSpace *vfio_address_space_get(AddressSpace *as); +void vfio_address_space_put(VFIOAddressSpace *space); +void vfio_address_space_insert(VFIOAddressSpace *space, + VFIOContainerBase *bcontainer); + int vfio_container_dma_map(VFIOContainerBase *bcontainer, hwaddr iova, ram_addr_t size, void *vaddr, bool readonly); @@ -163,4 +168,5 @@ struct VFIOIOMMUClass { MemoryRegionSection *section); void (*release)(VFIOContainerBase *bcontainer); }; + #endif /* HW_VFIO_VFIO_CONTAINER_BASE_H */ From 5cf52416e428836b1328ed47173a41948e1643bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:00 +0100 Subject: [PATCH 0265/2760] vfio: Move Host IOMMU type declarations into their respective files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These definitions don't have any use outside of their respective submodules. There is no need to expose them externally. Keep them private. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-15-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-16-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 2 ++ hw/vfio/iommufd.c | 3 +++ include/hw/vfio/vfio-common.h | 5 ----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index cc8cc0f272..6ef53ee187 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -34,6 +34,8 @@ #include "pci.h" #include "hw/vfio/vfio-container.h" +#define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" + typedef QLIST_HEAD(VFIOGroupList, VFIOGroup) VFIOGroupList; static VFIOGroupList vfio_group_list = QLIST_HEAD_INITIALIZER(vfio_group_list); diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index a520d40afc..2ec15bc269 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -27,6 +27,9 @@ #include "pci.h" #include "vfio-iommufd.h" +#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ + TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" + static int iommufd_cdev_map(const VFIOContainerBase *bcontainer, hwaddr iova, ram_addr_t size, void *vaddr, bool readonly) { diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 7d78eb85da..bb11b8215a 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -115,11 +115,6 @@ struct VFIODeviceOps { int (*vfio_load_config)(VFIODevice *vdev, QEMUFile *f); }; - -#define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" -#define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ - TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" - void vfio_disable_irqindex(VFIODevice *vbasedev, int index); void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); From ac28680d5e7a84943cd9f55a4aae245d6d7fdcae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:01 +0100 Subject: [PATCH 0266/2760] vfio: Introduce a new header file for helper services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all helper routine declarations into "vfio-helpers.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-16-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-17-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/s390x/s390-pci-vfio.c | 1 + hw/vfio/common.c | 1 + hw/vfio/container.c | 1 + hw/vfio/helpers.c | 1 + hw/vfio/pci.c | 1 + hw/vfio/region.c | 1 + hw/vfio/vfio-helpers.h | 26 ++++++++++++++++++++++++++ include/hw/vfio/vfio-common.h | 7 ------- 8 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 hw/vfio/vfio-helpers.h diff --git a/hw/s390x/s390-pci-vfio.c b/hw/s390x/s390-pci-vfio.c index 748a51fd8c..aaf91319b4 100644 --- a/hw/s390x/s390-pci-vfio.c +++ b/hw/s390x/s390-pci-vfio.c @@ -21,6 +21,7 @@ #include "hw/s390x/s390-pci-vfio.h" #include "hw/vfio/pci.h" #include "hw/vfio/vfio-container.h" +#include "hw/vfio/vfio-helpers.h" /* * Get the current DMA available count from vfio. Returns true if vfio is diff --git a/hw/vfio/common.c b/hw/vfio/common.c index c099d4d24d..18e5aacbd1 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -44,6 +44,7 @@ #include "system/tcg.h" #include "system/tpm.h" #include "vfio-migration-internal.h" +#include "vfio-helpers.h" VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 6ef53ee187..b2d72f5036 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -33,6 +33,7 @@ #include "qapi/error.h" #include "pci.h" #include "hw/vfio/vfio-container.h" +#include "vfio-helpers.h" #define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 89403943a7..054ee6e31e 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -30,6 +30,7 @@ #include "qemu/error-report.h" #include "qemu/units.h" #include "monitor/monitor.h" +#include "vfio-helpers.h" /* * Common VFIO interrupt disable diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index b0aac2f3a0..bade3b80d7 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -45,6 +45,7 @@ #include "migration/qemu-file.h" #include "system/iommufd.h" #include "vfio-migration-internal.h" +#include "vfio-helpers.h" #define TYPE_VFIO_PCI_NOHOTPLUG "vfio-pci-nohotplug" diff --git a/hw/vfio/region.c b/hw/vfio/region.c index 08cd69e704..9049143abf 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -29,6 +29,7 @@ #include "qemu/error-report.h" #include "qemu/units.h" #include "monitor/monitor.h" +#include "vfio-helpers.h" /* * IO Port/MMIO - Beware of the endians, VFIO is always little endian diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h new file mode 100644 index 0000000000..d7e4dcba51 --- /dev/null +++ b/hw/vfio/vfio-helpers.h @@ -0,0 +1,26 @@ +/* + * VFIO helpers + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_HELPERS_H +#define HW_VFIO_VFIO_HELPERS_H + +#ifdef CONFIG_LINUX +#include + +struct vfio_info_cap_header * +vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id); +struct vfio_info_cap_header * +vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); +struct vfio_info_cap_header * +vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id); + +#endif + +int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); + +#endif /* HW_VFIO_VFIO_HELPERS_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index bb11b8215a..8e465111d2 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -147,17 +147,10 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index, int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info); bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); -struct vfio_info_cap_header * -vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id); bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, unsigned int *avail); -struct vfio_info_cap_header * -vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); -struct vfio_info_cap_header * -vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id); #endif -int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); bool vfio_devices_all_dirty_tracking_started( const VFIOContainerBase *bcontainer); bool From f6d7f5d02bbb57b5b469863afe89278d64598d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:02 +0100 Subject: [PATCH 0267/2760] vfio: Move vfio_get_info_dma_avail() into helpers.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_get_info_dma_avail() is a low level routine similar to the other routines extracting capabilities from 'struct vfio_iommu_type1_info'. It belongs to file "helpers.c". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-17-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-18-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 31 ------------------------------- hw/vfio/helpers.c | 31 +++++++++++++++++++++++++++++++ hw/vfio/vfio-helpers.h | 5 ++++- include/hw/vfio/vfio-common.h | 2 -- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index b2d72f5036..3fdd5dac37 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -278,37 +278,6 @@ static int vfio_legacy_query_dirty_bitmap(const VFIOContainerBase *bcontainer, return ret; } -static struct vfio_info_cap_header * -vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) -{ - if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { - return NULL; - } - - return vfio_get_cap((void *)info, info->cap_offset, id); -} - -bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, - unsigned int *avail) -{ - struct vfio_info_cap_header *hdr; - struct vfio_iommu_type1_info_dma_avail *cap; - - /* If the capability cannot be found, assume no DMA limiting */ - hdr = vfio_get_iommu_type1_info_cap(info, - VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL); - if (!hdr) { - return false; - } - - if (avail != NULL) { - cap = (void *) hdr; - *avail = cap->avail; - } - - return true; -} - static bool vfio_get_info_iova_range(struct vfio_iommu_type1_info *info, VFIOContainerBase *bcontainer) { diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 054ee6e31e..1a584ba5f0 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -222,6 +222,37 @@ retry: return 0; } +struct vfio_info_cap_header * +vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) +{ + if (!(info->flags & VFIO_IOMMU_INFO_CAPS)) { + return NULL; + } + + return vfio_get_cap((void *)info, info->cap_offset, id); +} + +bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + unsigned int *avail) +{ + struct vfio_info_cap_header *hdr; + struct vfio_iommu_type1_info_dma_avail *cap; + + /* If the capability cannot be found, assume no DMA limiting */ + hdr = vfio_get_iommu_type1_info_cap(info, + VFIO_IOMMU_TYPE1_INFO_DMA_AVAIL); + if (!hdr) { + return false; + } + + if (avail != NULL) { + cap = (void *) hdr; + *avail = cap->avail; + } + + return true; +} + int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info) { diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h index d7e4dcba51..9af43878b8 100644 --- a/hw/vfio/vfio-helpers.h +++ b/hw/vfio/vfio-helpers.h @@ -18,7 +18,10 @@ struct vfio_info_cap_header * vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id); struct vfio_info_cap_header * vfio_get_region_info_cap(struct vfio_region_info *info, uint16_t id); - +struct vfio_info_cap_header * +vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id); +bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, + unsigned int *avail); #endif int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 8e465111d2..be2558f7e4 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -147,8 +147,6 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index, int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info); bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); -bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, - unsigned int *avail); #endif bool vfio_devices_all_dirty_tracking_started( From 545256134fdcac6c342f8e7f45eb591e3b12c700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:03 +0100 Subject: [PATCH 0268/2760] vfio: Move vfio_kvm_device_add/del_fd() to helpers.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_kvm_device_add/del_fd() are low level routines. Move them with the other helpers. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-18-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-19-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 58 ---------------------------------- hw/vfio/helpers.c | 59 +++++++++++++++++++++++++++++++++++ hw/vfio/iommufd.c | 1 + hw/vfio/meson.build | 2 +- hw/vfio/vfio-helpers.h | 3 ++ include/hw/vfio/vfio-common.h | 3 -- 6 files changed, 64 insertions(+), 62 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 18e5aacbd1..2b3af051cc 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1333,64 +1333,6 @@ void vfio_reset_handler(void *opaque) } } -int vfio_kvm_device_add_fd(int fd, Error **errp) -{ -#ifdef CONFIG_KVM - struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_FILE, - .attr = KVM_DEV_VFIO_FILE_ADD, - .addr = (uint64_t)(unsigned long)&fd, - }; - - if (!kvm_enabled()) { - return 0; - } - - if (vfio_kvm_device_fd < 0) { - struct kvm_create_device cd = { - .type = KVM_DEV_TYPE_VFIO, - }; - - if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) { - error_setg_errno(errp, errno, "Failed to create KVM VFIO device"); - return -errno; - } - - vfio_kvm_device_fd = cd.fd; - } - - if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device", - fd); - return -errno; - } -#endif - return 0; -} - -int vfio_kvm_device_del_fd(int fd, Error **errp) -{ -#ifdef CONFIG_KVM - struct kvm_device_attr attr = { - .group = KVM_DEV_VFIO_FILE, - .attr = KVM_DEV_VFIO_FILE_DEL, - .addr = (uint64_t)(unsigned long)&fd, - }; - - if (vfio_kvm_device_fd < 0) { - error_setg(errp, "KVM VFIO device isn't created yet"); - return -EINVAL; - } - - if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { - error_setg_errno(errp, errno, - "Failed to remove fd %d from KVM VFIO device", fd); - return -errno; - } -#endif - return 0; -} - struct vfio_device_info *vfio_get_device_info(int fd) { struct vfio_device_info *info; diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 1a584ba5f0..e6b75baa80 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -22,6 +22,7 @@ #include "qemu/osdep.h" #include +#include "system/kvm.h" #include "hw/vfio/vfio-common.h" #include "hw/vfio/pci.h" #include "hw/hw.h" @@ -253,6 +254,64 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, return true; } +int vfio_kvm_device_add_fd(int fd, Error **errp) +{ +#ifdef CONFIG_KVM + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_FILE, + .attr = KVM_DEV_VFIO_FILE_ADD, + .addr = (uint64_t)(unsigned long)&fd, + }; + + if (!kvm_enabled()) { + return 0; + } + + if (vfio_kvm_device_fd < 0) { + struct kvm_create_device cd = { + .type = KVM_DEV_TYPE_VFIO, + }; + + if (kvm_vm_ioctl(kvm_state, KVM_CREATE_DEVICE, &cd)) { + error_setg_errno(errp, errno, "Failed to create KVM VFIO device"); + return -errno; + } + + vfio_kvm_device_fd = cd.fd; + } + + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, "Failed to add fd %d to KVM VFIO device", + fd); + return -errno; + } +#endif + return 0; +} + +int vfio_kvm_device_del_fd(int fd, Error **errp) +{ +#ifdef CONFIG_KVM + struct kvm_device_attr attr = { + .group = KVM_DEV_VFIO_FILE, + .attr = KVM_DEV_VFIO_FILE_DEL, + .addr = (uint64_t)(unsigned long)&fd, + }; + + if (vfio_kvm_device_fd < 0) { + error_setg(errp, "KVM VFIO device isn't created yet"); + return -EINVAL; + } + + if (ioctl(vfio_kvm_device_fd, KVM_SET_DEVICE_ATTR, &attr)) { + error_setg_errno(errp, errno, + "Failed to remove fd %d from KVM VFIO device", fd); + return -errno; + } +#endif + return 0; +} + int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info) { diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 2ec15bc269..85b5a8146a 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -26,6 +26,7 @@ #include "qemu/chardev_open.h" #include "pci.h" #include "vfio-iommufd.h" +#include "vfio-helpers.h" #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 07010c7c9e..21795b3d19 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -2,6 +2,7 @@ vfio_ss = ss.source_set() vfio_ss.add(files( 'common.c', 'container.c', + 'helpers.c', )) vfio_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr.c')) vfio_ss.add(when: 'CONFIG_VFIO_PCI', if_true: files( @@ -18,7 +19,6 @@ specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss) system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c')) system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c')) system_ss.add(when: 'CONFIG_VFIO', if_true: files( - 'helpers.c', 'container-base.c', 'migration.c', 'migration-multifd.c', diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h index 9af43878b8..5d91e33d27 100644 --- a/hw/vfio/vfio-helpers.h +++ b/hw/vfio/vfio-helpers.h @@ -26,4 +26,7 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); +int vfio_kvm_device_add_fd(int fd, Error **errp); +int vfio_kvm_device_del_fd(int fd, Error **errp); + #endif /* HW_VFIO_VFIO_HELPERS_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index be2558f7e4..442ec287d7 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -130,9 +130,6 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev, void vfio_detach_device(VFIODevice *vbasedev); VFIODevice *vfio_get_vfio_device(Object *obj); -int vfio_kvm_device_add_fd(int fd, Error **errp); -int vfio_kvm_device_del_fd(int fd, Error **errp); - bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp); void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer); From 005b8d10450d2d41e9c1bcf8da4085f23cb85b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:04 +0100 Subject: [PATCH 0269/2760] vfio: Move vfio_get_device_info() to helpers.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_get_device_info() is a low level routine. Move it with the other helpers. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-19-clg@redhat.com Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-20-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 24 ------------------------ hw/vfio/helpers.c | 24 ++++++++++++++++++++++++ hw/vfio/vfio-helpers.h | 1 + include/hw/vfio/vfio-common.h | 1 - 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 2b3af051cc..f80c0ef229 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1333,30 +1333,6 @@ void vfio_reset_handler(void *opaque) } } -struct vfio_device_info *vfio_get_device_info(int fd) -{ - struct vfio_device_info *info; - uint32_t argsz = sizeof(*info); - - info = g_malloc0(argsz); - -retry: - info->argsz = argsz; - - if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) { - g_free(info); - return NULL; - } - - if (info->argsz > argsz) { - argsz = info->argsz; - info = g_realloc(info, argsz); - goto retry; - } - - return info; -} - bool vfio_attach_device(char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp) { diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index e6b75baa80..b7f75b47af 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -312,6 +312,30 @@ int vfio_kvm_device_del_fd(int fd, Error **errp) return 0; } +struct vfio_device_info *vfio_get_device_info(int fd) +{ + struct vfio_device_info *info; + uint32_t argsz = sizeof(*info); + + info = g_malloc0(argsz); + +retry: + info->argsz = argsz; + + if (ioctl(fd, VFIO_DEVICE_GET_INFO, info)) { + g_free(info); + return NULL; + } + + if (info->argsz > argsz) { + argsz = info->argsz; + info = g_realloc(info, argsz); + goto retry; + } + + return info; +} + int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, uint32_t subtype, struct vfio_region_info **info) { diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h index 5d91e33d27..dbcb68bbb0 100644 --- a/hw/vfio/vfio-helpers.h +++ b/hw/vfio/vfio-helpers.h @@ -25,6 +25,7 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, #endif int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size); +struct vfio_device_info *vfio_get_device_info(int fd); int vfio_kvm_device_add_fd(int fd, Error **errp); int vfio_kvm_device_del_fd(int fd, Error **errp); diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 442ec287d7..dca7a6a4b3 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -122,7 +122,6 @@ bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, int action, int fd, Error **errp); void vfio_reset_handler(void *opaque); -struct vfio_device_info *vfio_get_device_info(int fd); bool vfio_device_is_mdev(VFIODevice *vbasedev); bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp); bool vfio_attach_device(char *name, VFIODevice *vbasedev, From 68c07d76359589c9de2aa190d247afca7eb8cb8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:05 +0100 Subject: [PATCH 0270/2760] vfio: Introduce a new file for VFIODevice definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move all VFIODevice related routines of "helpers.c" into a new "device.c" file. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-21-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/device.c | 330 +++++++++++++++++++++++++++++++++++++++++++ hw/vfio/helpers.c | 303 --------------------------------------- hw/vfio/meson.build | 1 + hw/vfio/trace-events | 4 +- 4 files changed, 334 insertions(+), 304 deletions(-) create mode 100644 hw/vfio/device.c diff --git a/hw/vfio/device.c b/hw/vfio/device.c new file mode 100644 index 0000000000..21c6824430 --- /dev/null +++ b/hw/vfio/device.c @@ -0,0 +1,330 @@ +/* + * VFIO device + * + * Copyright Red Hat, Inc. 2012 + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on qemu-kvm device-assignment: + * Adapted for KVM by Qumranet. + * Copyright (c) 2007, Neocleus, Alex Novik (alex@neocleus.com) + * Copyright (c) 2007, Neocleus, Guy Zana (guy@neocleus.com) + * Copyright (C) 2008, Qumranet, Amit Shah (amit.shah@qumranet.com) + * Copyright (C) 2008, Red Hat, Amit Shah (amit.shah@redhat.com) + * Copyright (C) 2008, IBM, Muli Ben-Yehuda (muli@il.ibm.com) + */ + +#include "qemu/osdep.h" +#include + +#include "hw/vfio/vfio-common.h" +#include "hw/vfio/pci.h" +#include "hw/hw.h" +#include "trace.h" +#include "qapi/error.h" +#include "qemu/error-report.h" +#include "qemu/units.h" +#include "monitor/monitor.h" +#include "vfio-helpers.h" + +/* + * Common VFIO interrupt disable + */ +void vfio_disable_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, + .index = index, + .start = 0, + .count = 0, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, + .index = index, + .start = 0, + .count = 1, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) +{ + struct vfio_irq_set irq_set = { + .argsz = sizeof(irq_set), + .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, + .index = index, + .start = 0, + .count = 1, + }; + + ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); +} + +static inline const char *action_to_str(int action) +{ + switch (action) { + case VFIO_IRQ_SET_ACTION_MASK: + return "MASK"; + case VFIO_IRQ_SET_ACTION_UNMASK: + return "UNMASK"; + case VFIO_IRQ_SET_ACTION_TRIGGER: + return "TRIGGER"; + default: + return "UNKNOWN ACTION"; + } +} + +static const char *index_to_str(VFIODevice *vbasedev, int index) +{ + if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { + return NULL; + } + + switch (index) { + case VFIO_PCI_INTX_IRQ_INDEX: + return "INTX"; + case VFIO_PCI_MSI_IRQ_INDEX: + return "MSI"; + case VFIO_PCI_MSIX_IRQ_INDEX: + return "MSIX"; + case VFIO_PCI_ERR_IRQ_INDEX: + return "ERR"; + case VFIO_PCI_REQ_IRQ_INDEX: + return "REQ"; + default: + return NULL; + } +} + +bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, + int action, int fd, Error **errp) +{ + ERRP_GUARD(); + g_autofree struct vfio_irq_set *irq_set = NULL; + int argsz; + const char *name; + int32_t *pfd; + + argsz = sizeof(*irq_set) + sizeof(*pfd); + + irq_set = g_malloc0(argsz); + irq_set->argsz = argsz; + irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action; + irq_set->index = index; + irq_set->start = subindex; + irq_set->count = 1; + pfd = (int32_t *)&irq_set->data; + *pfd = fd; + + if (!ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { + return true; + } + + error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure"); + + name = index_to_str(vbasedev, index); + if (name) { + error_prepend(errp, "%s-%d: ", name, subindex); + } else { + error_prepend(errp, "index %d-%d: ", index, subindex); + } + error_prepend(errp, + "Failed to %s %s eventfd signaling for interrupt ", + fd < 0 ? "tear down" : "set up", action_to_str(action)); + return false; +} + +int vfio_get_region_info(VFIODevice *vbasedev, int index, + struct vfio_region_info **info) +{ + size_t argsz = sizeof(struct vfio_region_info); + + *info = g_malloc0(argsz); + + (*info)->index = index; +retry: + (*info)->argsz = argsz; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { + g_free(*info); + *info = NULL; + return -errno; + } + + if ((*info)->argsz > argsz) { + argsz = (*info)->argsz; + *info = g_realloc(*info, argsz); + + goto retry; + } + + return 0; +} + +int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, + uint32_t subtype, struct vfio_region_info **info) +{ + int i; + + for (i = 0; i < vbasedev->num_regions; i++) { + struct vfio_info_cap_header *hdr; + struct vfio_region_info_cap_type *cap_type; + + if (vfio_get_region_info(vbasedev, i, info)) { + continue; + } + + hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); + if (!hdr) { + g_free(*info); + continue; + } + + cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); + + trace_vfio_get_dev_region(vbasedev->name, i, + cap_type->type, cap_type->subtype); + + if (cap_type->type == type && cap_type->subtype == subtype) { + return 0; + } + + g_free(*info); + } + + *info = NULL; + return -ENODEV; +} + +bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +{ + g_autofree struct vfio_region_info *info = NULL; + bool ret = false; + + if (!vfio_get_region_info(vbasedev, region, &info)) { + if (vfio_get_region_info_cap(info, cap_type)) { + ret = true; + } + } + + return ret; +} + +bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp) +{ + ERRP_GUARD(); + struct stat st; + + if (vbasedev->fd < 0) { + if (stat(vbasedev->sysfsdev, &st) < 0) { + error_setg_errno(errp, errno, "no such host device"); + error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev); + return false; + } + /* User may specify a name, e.g: VFIO platform device */ + if (!vbasedev->name) { + vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); + } + } else { + if (!vbasedev->iommufd) { + error_setg(errp, "Use FD passing only with iommufd backend"); + return false; + } + /* + * Give a name with fd so any function printing out vbasedev->name + * will not break. + */ + if (!vbasedev->name) { + vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd); + } + } + + return true; +} + +void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp) +{ + ERRP_GUARD(); + int fd = monitor_fd_param(monitor_cur(), str, errp); + + if (fd < 0) { + error_prepend(errp, "Could not parse remote object fd %s:", str); + return; + } + vbasedev->fd = fd; +} + +void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops, + DeviceState *dev, bool ram_discard) +{ + vbasedev->type = type; + vbasedev->ops = ops; + vbasedev->dev = dev; + vbasedev->fd = -1; + + vbasedev->ram_block_discard_allowed = ram_discard; +} + +int vfio_device_get_aw_bits(VFIODevice *vdev) +{ + /* + * iova_ranges is a sorted list. For old kernels that support + * VFIO but not support query of iova ranges, iova_ranges is NULL, + * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned. + */ + GList *l = g_list_last(vdev->bcontainer->iova_ranges); + + if (l) { + Range *range = l->data; + return range_get_last_bit(range) + 1; + } + + return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX; +} + +bool vfio_device_is_mdev(VFIODevice *vbasedev) +{ + g_autofree char *subsys = NULL; + g_autofree char *tmp = NULL; + + if (!vbasedev->sysfsdev) { + return false; + } + + tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev); + subsys = realpath(tmp, NULL); + return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); +} + +bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp) +{ + HostIOMMUDevice *hiod = vbasedev->hiod; + + if (!hiod) { + return true; + } + + return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp); +} + +VFIODevice *vfio_get_vfio_device(Object *obj) +{ + if (object_dynamic_cast(obj, TYPE_VFIO_PCI)) { + return &VFIO_PCI(obj)->vbasedev; + } else { + return NULL; + } +} diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index b7f75b47af..7ddc9797ef 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -24,131 +24,10 @@ #include "system/kvm.h" #include "hw/vfio/vfio-common.h" -#include "hw/vfio/pci.h" #include "hw/hw.h" -#include "trace.h" #include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/units.h" -#include "monitor/monitor.h" #include "vfio-helpers.h" -/* - * Common VFIO interrupt disable - */ -void vfio_disable_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER, - .index = index, - .start = 0, - .count = 0, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK, - .index = index, - .start = 0, - .count = 1, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) -{ - struct vfio_irq_set irq_set = { - .argsz = sizeof(irq_set), - .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK, - .index = index, - .start = 0, - .count = 1, - }; - - ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); -} - -static inline const char *action_to_str(int action) -{ - switch (action) { - case VFIO_IRQ_SET_ACTION_MASK: - return "MASK"; - case VFIO_IRQ_SET_ACTION_UNMASK: - return "UNMASK"; - case VFIO_IRQ_SET_ACTION_TRIGGER: - return "TRIGGER"; - default: - return "UNKNOWN ACTION"; - } -} - -static const char *index_to_str(VFIODevice *vbasedev, int index) -{ - if (vbasedev->type != VFIO_DEVICE_TYPE_PCI) { - return NULL; - } - - switch (index) { - case VFIO_PCI_INTX_IRQ_INDEX: - return "INTX"; - case VFIO_PCI_MSI_IRQ_INDEX: - return "MSI"; - case VFIO_PCI_MSIX_IRQ_INDEX: - return "MSIX"; - case VFIO_PCI_ERR_IRQ_INDEX: - return "ERR"; - case VFIO_PCI_REQ_IRQ_INDEX: - return "REQ"; - default: - return NULL; - } -} - -bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, - int action, int fd, Error **errp) -{ - ERRP_GUARD(); - g_autofree struct vfio_irq_set *irq_set = NULL; - int argsz; - const char *name; - int32_t *pfd; - - argsz = sizeof(*irq_set) + sizeof(*pfd); - - irq_set = g_malloc0(argsz); - irq_set->argsz = argsz; - irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | action; - irq_set->index = index; - irq_set->start = subindex; - irq_set->count = 1; - pfd = (int32_t *)&irq_set->data; - *pfd = fd; - - if (!ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, irq_set)) { - return true; - } - - error_setg_errno(errp, errno, "VFIO_DEVICE_SET_IRQS failure"); - - name = index_to_str(vbasedev, index); - if (name) { - error_prepend(errp, "%s-%d: ", name, subindex); - } else { - error_prepend(errp, "index %d-%d: ", index, subindex); - } - error_prepend(errp, - "Failed to %s %s eventfd signaling for interrupt ", - fd < 0 ? "tear down" : "set up", action_to_str(action)); - return false; -} - int vfio_bitmap_alloc(VFIOBitmap *vbmap, hwaddr size) { vbmap->pages = REAL_HOST_PAGE_ALIGN(size) / qemu_real_host_page_size(); @@ -196,33 +75,6 @@ vfio_get_device_info_cap(struct vfio_device_info *info, uint16_t id) return vfio_get_cap((void *)info, info->cap_offset, id); } -int vfio_get_region_info(VFIODevice *vbasedev, int index, - struct vfio_region_info **info) -{ - size_t argsz = sizeof(struct vfio_region_info); - - *info = g_malloc0(argsz); - - (*info)->index = index; -retry: - (*info)->argsz = argsz; - - if (ioctl(vbasedev->fd, VFIO_DEVICE_GET_REGION_INFO, *info)) { - g_free(*info); - *info = NULL; - return -errno; - } - - if ((*info)->argsz > argsz) { - argsz = (*info)->argsz; - *info = g_realloc(*info, argsz); - - goto retry; - } - - return 0; -} - struct vfio_info_cap_header * vfio_get_iommu_type1_info_cap(struct vfio_iommu_type1_info *info, uint16_t id) { @@ -335,158 +187,3 @@ retry: return info; } - -int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - uint32_t subtype, struct vfio_region_info **info) -{ - int i; - - for (i = 0; i < vbasedev->num_regions; i++) { - struct vfio_info_cap_header *hdr; - struct vfio_region_info_cap_type *cap_type; - - if (vfio_get_region_info(vbasedev, i, info)) { - continue; - } - - hdr = vfio_get_region_info_cap(*info, VFIO_REGION_INFO_CAP_TYPE); - if (!hdr) { - g_free(*info); - continue; - } - - cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); - - trace_vfio_get_dev_region(vbasedev->name, i, - cap_type->type, cap_type->subtype); - - if (cap_type->type == type && cap_type->subtype == subtype) { - return 0; - } - - g_free(*info); - } - - *info = NULL; - return -ENODEV; -} - -bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) -{ - g_autofree struct vfio_region_info *info = NULL; - bool ret = false; - - if (!vfio_get_region_info(vbasedev, region, &info)) { - if (vfio_get_region_info_cap(info, cap_type)) { - ret = true; - } - } - - return ret; -} - -bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp) -{ - ERRP_GUARD(); - struct stat st; - - if (vbasedev->fd < 0) { - if (stat(vbasedev->sysfsdev, &st) < 0) { - error_setg_errno(errp, errno, "no such host device"); - error_prepend(errp, VFIO_MSG_PREFIX, vbasedev->sysfsdev); - return false; - } - /* User may specify a name, e.g: VFIO platform device */ - if (!vbasedev->name) { - vbasedev->name = g_path_get_basename(vbasedev->sysfsdev); - } - } else { - if (!vbasedev->iommufd) { - error_setg(errp, "Use FD passing only with iommufd backend"); - return false; - } - /* - * Give a name with fd so any function printing out vbasedev->name - * will not break. - */ - if (!vbasedev->name) { - vbasedev->name = g_strdup_printf("VFIO_FD%d", vbasedev->fd); - } - } - - return true; -} - -void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp) -{ - ERRP_GUARD(); - int fd = monitor_fd_param(monitor_cur(), str, errp); - - if (fd < 0) { - error_prepend(errp, "Could not parse remote object fd %s:", str); - return; - } - vbasedev->fd = fd; -} - -void vfio_device_init(VFIODevice *vbasedev, int type, VFIODeviceOps *ops, - DeviceState *dev, bool ram_discard) -{ - vbasedev->type = type; - vbasedev->ops = ops; - vbasedev->dev = dev; - vbasedev->fd = -1; - - vbasedev->ram_block_discard_allowed = ram_discard; -} - -int vfio_device_get_aw_bits(VFIODevice *vdev) -{ - /* - * iova_ranges is a sorted list. For old kernels that support - * VFIO but not support query of iova ranges, iova_ranges is NULL, - * in this case HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX(64) is returned. - */ - GList *l = g_list_last(vdev->bcontainer->iova_ranges); - - if (l) { - Range *range = l->data; - return range_get_last_bit(range) + 1; - } - - return HOST_IOMMU_DEVICE_CAP_AW_BITS_MAX; -} - -bool vfio_device_is_mdev(VFIODevice *vbasedev) -{ - g_autofree char *subsys = NULL; - g_autofree char *tmp = NULL; - - if (!vbasedev->sysfsdev) { - return false; - } - - tmp = g_strdup_printf("%s/subsystem", vbasedev->sysfsdev); - subsys = realpath(tmp, NULL); - return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); -} - -bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp) -{ - HostIOMMUDevice *hiod = vbasedev->hiod; - - if (!hiod) { - return true; - } - - return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp); -} - -VFIODevice *vfio_get_vfio_device(Object *obj) -{ - if (object_dynamic_cast(obj, TYPE_VFIO_PCI)) { - return &VFIO_PCI(obj)->vbasedev; - } else { - return NULL; - } -} diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 21795b3d19..60caa36617 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -20,6 +20,7 @@ system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c')) system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c')) system_ss.add(when: 'CONFIG_VFIO', if_true: files( 'container-base.c', + 'device.c', 'migration.c', 'migration-multifd.c', 'cpr.c', diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 81f4130100..590d9674cf 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -105,7 +105,6 @@ vfio_disconnect_container(int fd) "close container->fd=%d" vfio_put_group(int fd) "close group->fd=%d" vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" vfio_put_base_device(int fd) "close vdev->fd=%d" -vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" vfio_legacy_dma_unmap_overflow_workaround(void) "" vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 @@ -194,3 +193,6 @@ iommufd_cdev_fail_attach_existing_container(const char *msg) " %s" iommufd_cdev_alloc_ioas(int iommufd, int ioas_id) " [iommufd=%d] new IOMMUFD container with ioasid=%d" iommufd_cdev_device_info(char *name, int devfd, int num_irqs, int num_regions, int flags) " %s (%d) num_irqs=%d num_regions=%d flags=%d" iommufd_cdev_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int dev_id) "\t%04x:%02x:%02x.%x devid %d" + +# device.c +vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" From 8140d45b108c2b48960bbfb0a215f586f2d1d9e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:06 +0100 Subject: [PATCH 0271/2760] vfio: Introduce new files for CPR definitions and declarations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gather all CPR related declarations into "vfio-cpr.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". These were introduced in commit d9fa4223b30a ("vfio: register container for cpr"). Order file list in meson.build while at it. Cc: Steve Sistare Reviewed-by: Steve Sistare Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-22-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 1 + hw/vfio/cpr.c | 1 + hw/vfio/iommufd.c | 1 + hw/vfio/meson.build | 2 +- hw/vfio/vfio-cpr.h | 15 +++++++++++++++ include/hw/vfio/vfio-common.h | 3 --- 6 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 hw/vfio/vfio-cpr.h diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 3fdd5dac37..c55fe8e4be 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -34,6 +34,7 @@ #include "pci.h" #include "hw/vfio/vfio-container.h" #include "vfio-helpers.h" +#include "vfio-cpr.h" #define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" diff --git a/hw/vfio/cpr.c b/hw/vfio/cpr.c index 3d1c8d290a..696987006b 100644 --- a/hw/vfio/cpr.c +++ b/hw/vfio/cpr.c @@ -10,6 +10,7 @@ #include "migration/misc.h" #include "qapi/error.h" #include "system/runstate.h" +#include "vfio-cpr.h" static int vfio_cpr_reboot_notifier(NotifierWithReturn *notifier, MigrationEvent *e, Error **errp) diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 85b5a8146a..a5bd189a86 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -27,6 +27,7 @@ #include "pci.h" #include "vfio-iommufd.h" #include "vfio-helpers.h" +#include "vfio-cpr.h" #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 60caa36617..1f89bd28c1 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -20,10 +20,10 @@ system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c')) system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c')) system_ss.add(when: 'CONFIG_VFIO', if_true: files( 'container-base.c', + 'cpr.c', 'device.c', 'migration.c', 'migration-multifd.c', - 'cpr.c', 'region.c', )) system_ss.add(when: ['CONFIG_VFIO', 'CONFIG_IOMMUFD'], if_true: files( diff --git a/hw/vfio/vfio-cpr.h b/hw/vfio/vfio-cpr.h new file mode 100644 index 0000000000..134b83a624 --- /dev/null +++ b/hw/vfio/vfio-cpr.h @@ -0,0 +1,15 @@ +/* + * VFIO CPR + * + * Copyright (c) 2025 Oracle and/or its affiliates. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_CPR_H +#define HW_VFIO_CPR_H + +bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp); +void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer); + +#endif /* HW_VFIO_CPR_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index dca7a6a4b3..2065c2f9e4 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -129,9 +129,6 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev, void vfio_detach_device(VFIODevice *vbasedev); VFIODevice *vfio_get_vfio_device(Object *obj); -bool vfio_cpr_register_container(VFIOContainerBase *bcontainer, Error **errp); -void vfio_cpr_unregister_container(VFIOContainerBase *bcontainer); - typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; From c3fbdba15a8b3d80c1f5e6026e636030b3692437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:07 +0100 Subject: [PATCH 0272/2760] vfio: Move vfio_kvm_device_fd() into helpers.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vfio_kvm_device_add/del_fd() routines opening the VFIO pseudo device are defined in "helpers.c". Move 'vfio_kvm_device_fd' definition there and its declaration into "vfio-helpers.h" to reduce exposure of VFIO internals in "hw/vfio/vfio-common.h". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-22-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-23-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 11 ----------- hw/vfio/helpers.c | 11 +++++++++++ hw/vfio/spapr.c | 2 +- hw/vfio/vfio-helpers.h | 2 ++ include/hw/vfio/vfio-common.h | 1 - 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index f80c0ef229..84a9a37d9d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -49,17 +49,6 @@ VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); -#ifdef CONFIG_KVM -/* - * We have a single VFIO pseudo device per KVM VM. Once created it lives - * for the life of the VM. Closing the file descriptor only drops our - * reference to it and the device's reference to kvm. Therefore once - * initialized, this file descriptor is only released on QEMU exit and - * we'll re-use it should another vfio device be attached before then. - */ -int vfio_kvm_device_fd = -1; -#endif - /* * Device state interfaces */ diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 7ddc9797ef..48bd61d528 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -106,6 +106,17 @@ bool vfio_get_info_dma_avail(struct vfio_iommu_type1_info *info, return true; } +#ifdef CONFIG_KVM +/* + * We have a single VFIO pseudo device per KVM VM. Once created it lives + * for the life of the VM. Closing the file descriptor only drops our + * reference to it and the device's reference to kvm. Therefore once + * initialized, this file descriptor is only released on QEMU exit and + * we'll re-use it should another vfio device be attached before then. + */ +int vfio_kvm_device_fd = -1; +#endif + int vfio_kvm_device_add_fd(int fd, Error **errp) { #ifdef CONFIG_KVM diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 31e4dddc9e..95ccbad418 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -15,13 +15,13 @@ #include "system/hostmem.h" #include "system/address-spaces.h" -#include "hw/vfio/vfio-common.h" #include "hw/vfio/vfio-container.h" #include "hw/hw.h" #include "system/ram_addr.h" #include "qemu/error-report.h" #include "qapi/error.h" #include "trace.h" +#include "vfio-helpers.h" typedef struct VFIOHostDMAWindow { hwaddr min_iova; diff --git a/hw/vfio/vfio-helpers.h b/hw/vfio/vfio-helpers.h index dbcb68bbb0..54a327ffbc 100644 --- a/hw/vfio/vfio-helpers.h +++ b/hw/vfio/vfio-helpers.h @@ -12,6 +12,8 @@ #ifdef CONFIG_LINUX #include +extern int vfio_kvm_device_fd; + struct vfio_info_cap_header * vfio_get_cap(void *ptr, uint32_t cap_offset, uint16_t id); struct vfio_info_cap_header * diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 2065c2f9e4..06178cf282 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -132,7 +132,6 @@ VFIODevice *vfio_get_vfio_device(Object *obj); typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIODeviceList vfio_device_list; extern const MemoryListener vfio_memory_listener; -extern int vfio_kvm_device_fd; #ifdef CONFIG_LINUX int vfio_get_region_info(VFIODevice *vbasedev, int index, From a997b506e715d96549869e2d0fca28a1a9f110dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:08 +0100 Subject: [PATCH 0273/2760] vfio: Move vfio_device_list into device.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'vfio_device_list' is VFIODevice related. Move its definitions into "device.c". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-23-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-24-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 3 --- hw/vfio/device.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 84a9a37d9d..4e7d8e83ac 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -46,9 +46,6 @@ #include "vfio-migration-internal.h" #include "vfio-helpers.h" -VFIODeviceList vfio_device_list = - QLIST_HEAD_INITIALIZER(vfio_device_list); - /* * Device state interfaces */ diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 21c6824430..25fdba10a8 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -31,6 +31,9 @@ #include "monitor/monitor.h" #include "vfio-helpers.h" +VFIODeviceList vfio_device_list = + QLIST_HEAD_INITIALIZER(vfio_device_list); + /* * Common VFIO interrupt disable */ From 923b11411e0e68b460f6fd8e6a7f8ff11554e48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:09 +0100 Subject: [PATCH 0274/2760] vfio: Move vfio_de/attach_device() into device.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These routines are VFIODevice related. Move their definitions into "device.c". Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-24-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-25-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 37 ------------------------------------- hw/vfio/device.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 4e7d8e83ac..a85ed36409 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1318,40 +1318,3 @@ void vfio_reset_handler(void *opaque) } } } - -bool vfio_attach_device(char *name, VFIODevice *vbasedev, - AddressSpace *as, Error **errp) -{ - const VFIOIOMMUClass *ops = - VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY)); - HostIOMMUDevice *hiod = NULL; - - if (vbasedev->iommufd) { - ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD)); - } - - assert(ops); - - - if (!vbasedev->mdev) { - hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename)); - vbasedev->hiod = hiod; - } - - if (!ops->attach_device(name, vbasedev, as, errp)) { - object_unref(hiod); - vbasedev->hiod = NULL; - return false; - } - - return true; -} - -void vfio_detach_device(VFIODevice *vbasedev) -{ - if (!vbasedev->bcontainer) { - return; - } - object_unref(vbasedev->hiod); - VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev); -} diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 25fdba10a8..179c9fb8de 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -331,3 +331,40 @@ VFIODevice *vfio_get_vfio_device(Object *obj) return NULL; } } + +bool vfio_attach_device(char *name, VFIODevice *vbasedev, + AddressSpace *as, Error **errp) +{ + const VFIOIOMMUClass *ops = + VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY)); + HostIOMMUDevice *hiod = NULL; + + if (vbasedev->iommufd) { + ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD)); + } + + assert(ops); + + + if (!vbasedev->mdev) { + hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename)); + vbasedev->hiod = hiod; + } + + if (!ops->attach_device(name, vbasedev, as, errp)) { + object_unref(hiod); + vbasedev->hiod = NULL; + return false; + } + + return true; +} + +void vfio_detach_device(VFIODevice *vbasedev) +{ + if (!vbasedev->bcontainer) { + return; + } + object_unref(vbasedev->hiod); + VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev); +} From 819a5865c0524c4bfcf1906955c9d15952fdbcc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:10 +0100 Subject: [PATCH 0275/2760] vfio: Move vfio_reset_handler() into device.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass-through devices of a VM are not necessarily in the same group and all groups/address_spaces need to be scanned when the machine is reset. Commit f16f39c3fc97 ("Implement PCI hot reset") introduced a VM reset handler for this purpose. Move it under device.c Also reintroduce the comment which explained the context and was lost along the way. Reviewed-by: Zhenzhong Duan Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-26-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 18 ------------------ hw/vfio/device.c | 35 +++++++++++++++++++++++++++++++++++ hw/vfio/trace-events | 2 +- 3 files changed, 36 insertions(+), 19 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index a85ed36409..45ac8b7d8b 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1300,21 +1300,3 @@ const MemoryListener vfio_memory_listener = { .log_global_stop = vfio_listener_log_global_stop, .log_sync = vfio_listener_log_sync, }; - -void vfio_reset_handler(void *opaque) -{ - VFIODevice *vbasedev; - - trace_vfio_reset_handler(); - QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->dev->realized) { - vbasedev->ops->vfio_compute_needs_reset(vbasedev); - } - } - - QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { - if (vbasedev->dev->realized && vbasedev->needs_reset) { - vbasedev->ops->vfio_hot_reset_multi(vbasedev); - } - } -} diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 179c9fb8de..e122c797c2 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -34,6 +34,41 @@ VFIODeviceList vfio_device_list = QLIST_HEAD_INITIALIZER(vfio_device_list); +/* + * We want to differentiate hot reset of multiple in-use devices vs + * hot reset of a single in-use device. VFIO_DEVICE_RESET will already + * handle the case of doing hot resets when there is only a single + * device per bus. The in-use here refers to how many VFIODevices are + * affected. A hot reset that affects multiple devices, but only a + * single in-use device, means that we can call it from our bus + * ->reset() callback since the extent is effectively a single + * device. This allows us to make use of it in the hotplug path. When + * there are multiple in-use devices, we can only trigger the hot + * reset during a system reset and thus from our reset handler. We + * separate _one vs _multi here so that we don't overlap and do a + * double reset on the system reset path where both our reset handler + * and ->reset() callback are used. Calling _one() will only do a hot + * reset for the one in-use devices case, calling _multi() will do + * nothing if a _one() would have been sufficient. + */ +void vfio_reset_handler(void *opaque) +{ + VFIODevice *vbasedev; + + trace_vfio_reset_handler(); + QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->dev->realized) { + vbasedev->ops->vfio_compute_needs_reset(vbasedev); + } + } + + QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { + if (vbasedev->dev->realized && vbasedev->needs_reset) { + vbasedev->ops->vfio_hot_reset_multi(vbasedev); + } + } +} + /* * Common VFIO interrupt disable */ diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 590d9674cf..9fee7df876 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -108,7 +108,6 @@ vfio_put_base_device(int fd) "close vdev->fd=%d" vfio_legacy_dma_unmap_overflow_workaround(void) "" vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 -vfio_reset_handler(void) "" # region.c vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" @@ -196,3 +195,4 @@ iommufd_cdev_pci_hot_reset_dep_devices(int domain, int bus, int slot, int functi # device.c vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" +vfio_reset_handler(void) "" From 6b7c812972a697c412f81497999af267e0c6333a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:11 +0100 Subject: [PATCH 0276/2760] vfio: Move dirty tracking related services into container-base.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Routines of common.c : vfio_devices_all_dirty_tracking_started vfio_devices_all_device_dirty_tracking vfio_devices_query_dirty_bitmap vfio_get_dirty_bitmap are all related to dirty page tracking directly at the container level or at the container device level. Naming is a bit confusing. We will propose new names in the following changes. Reviewed-by: Joao Martins Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-27-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 130 ------------------------ hw/vfio/container-base.c | 138 ++++++++++++++++++++++++++ hw/vfio/meson.build | 2 +- hw/vfio/trace-events | 4 +- include/hw/vfio/vfio-common.h | 9 -- include/hw/vfio/vfio-container-base.h | 7 ++ 6 files changed, 149 insertions(+), 141 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 45ac8b7d8b..ed49ef88a8 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -51,27 +51,6 @@ */ -static bool vfio_devices_all_device_dirty_tracking_started( - const VFIOContainerBase *bcontainer) -{ - VFIODevice *vbasedev; - - QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { - if (!vbasedev->dirty_tracking) { - return false; - } - } - - return true; -} - -bool vfio_devices_all_dirty_tracking_started( - const VFIOContainerBase *bcontainer) -{ - return vfio_devices_all_device_dirty_tracking_started(bcontainer) || - bcontainer->dirty_pages_started; -} - static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer) { VFIODevice *vbasedev; @@ -96,22 +75,6 @@ static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer) return true; } -bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer) -{ - VFIODevice *vbasedev; - - QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { - if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) { - return false; - } - if (!vbasedev->dirty_pages_supported) { - return false; - } - } - - return true; -} - static bool vfio_listener_skipped_section(MemoryRegionSection *section) { return (!memory_region_is_ram(section->mr) && @@ -1009,99 +972,6 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) } } -static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova, - hwaddr size, void *bitmap) -{ - uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) + - sizeof(struct vfio_device_feature_dma_logging_report), - sizeof(uint64_t))] = {}; - struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; - struct vfio_device_feature_dma_logging_report *report = - (struct vfio_device_feature_dma_logging_report *)feature->data; - - report->iova = iova; - report->length = size; - report->page_size = qemu_real_host_page_size(); - report->bitmap = (uintptr_t)bitmap; - - feature->argsz = sizeof(buf); - feature->flags = VFIO_DEVICE_FEATURE_GET | - VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT; - - if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { - return -errno; - } - - return 0; -} - -int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, - VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) -{ - VFIODevice *vbasedev; - int ret; - - QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { - ret = vfio_device_dma_logging_report(vbasedev, iova, size, - vbmap->bitmap); - if (ret) { - error_setg_errno(errp, -ret, - "%s: Failed to get DMA logging report, iova: " - "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx, - vbasedev->name, iova, size); - - return ret; - } - } - - return 0; -} - -int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, - uint64_t size, ram_addr_t ram_addr, Error **errp) -{ - bool all_device_dirty_tracking = - vfio_devices_all_device_dirty_tracking(bcontainer); - uint64_t dirty_pages; - VFIOBitmap vbmap; - int ret; - - if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) { - cpu_physical_memory_set_dirty_range(ram_addr, size, - tcg_enabled() ? DIRTY_CLIENTS_ALL : - DIRTY_CLIENTS_NOCODE); - return 0; - } - - ret = vfio_bitmap_alloc(&vbmap, size); - if (ret) { - error_setg_errno(errp, -ret, - "Failed to allocate dirty tracking bitmap"); - return ret; - } - - if (all_device_dirty_tracking) { - ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, - errp); - } else { - ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size, - errp); - } - - if (ret) { - goto out; - } - - dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr, - vbmap.pages); - - trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages); -out: - g_free(vbmap.bitmap); - - return ret; -} - typedef struct { IOMMUNotifier n; VFIOGuestIOMMU *giommu; diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 2c2d8329e3..f9cf317018 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -10,12 +10,20 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ +#include +#include + #include "qemu/osdep.h" +#include "system/tcg.h" +#include "system/ram_addr.h" #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/vfio/vfio-container-base.h" #include "hw/vfio/vfio-common.h" /* vfio_reset_handler */ #include "system/reset.h" +#include "vfio-helpers.h" + +#include "trace.h" static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces = QLIST_HEAD_INITIALIZER(vfio_address_spaces); @@ -143,6 +151,136 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, errp); } +static bool vfio_devices_all_device_dirty_tracking_started( + const VFIOContainerBase *bcontainer) +{ + VFIODevice *vbasedev; + + QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { + if (!vbasedev->dirty_tracking) { + return false; + } + } + + return true; +} + +bool vfio_devices_all_dirty_tracking_started( + const VFIOContainerBase *bcontainer) +{ + return vfio_devices_all_device_dirty_tracking_started(bcontainer) || + bcontainer->dirty_pages_started; +} + +bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer) +{ + VFIODevice *vbasedev; + + QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { + if (vbasedev->device_dirty_page_tracking == ON_OFF_AUTO_OFF) { + return false; + } + if (!vbasedev->dirty_pages_supported) { + return false; + } + } + + return true; +} + +static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova, + hwaddr size, void *bitmap) +{ + uint64_t buf[DIV_ROUND_UP(sizeof(struct vfio_device_feature) + + sizeof(struct vfio_device_feature_dma_logging_report), + sizeof(uint64_t))] = {}; + struct vfio_device_feature *feature = (struct vfio_device_feature *)buf; + struct vfio_device_feature_dma_logging_report *report = + (struct vfio_device_feature_dma_logging_report *)feature->data; + + report->iova = iova; + report->length = size; + report->page_size = qemu_real_host_page_size(); + report->bitmap = (uintptr_t)bitmap; + + feature->argsz = sizeof(buf); + feature->flags = VFIO_DEVICE_FEATURE_GET | + VFIO_DEVICE_FEATURE_DMA_LOGGING_REPORT; + + if (ioctl(vbasedev->fd, VFIO_DEVICE_FEATURE, feature)) { + return -errno; + } + + return 0; +} + +int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, + VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) +{ + VFIODevice *vbasedev; + int ret; + + QLIST_FOREACH(vbasedev, &bcontainer->device_list, container_next) { + ret = vfio_device_dma_logging_report(vbasedev, iova, size, + vbmap->bitmap); + if (ret) { + error_setg_errno(errp, -ret, + "%s: Failed to get DMA logging report, iova: " + "0x%" HWADDR_PRIx ", size: 0x%" HWADDR_PRIx, + vbasedev->name, iova, size); + + return ret; + } + } + + return 0; +} + +int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, + uint64_t size, ram_addr_t ram_addr, Error **errp) +{ + bool all_device_dirty_tracking = + vfio_devices_all_device_dirty_tracking(bcontainer); + uint64_t dirty_pages; + VFIOBitmap vbmap; + int ret; + + if (!bcontainer->dirty_pages_supported && !all_device_dirty_tracking) { + cpu_physical_memory_set_dirty_range(ram_addr, size, + tcg_enabled() ? DIRTY_CLIENTS_ALL : + DIRTY_CLIENTS_NOCODE); + return 0; + } + + ret = vfio_bitmap_alloc(&vbmap, size); + if (ret) { + error_setg_errno(errp, -ret, + "Failed to allocate dirty tracking bitmap"); + return ret; + } + + if (all_device_dirty_tracking) { + ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, + errp); + } else { + ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size, + errp); + } + + if (ret) { + goto out; + } + + dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr, + vbmap.pages); + + trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages); +out: + g_free(vbmap.bitmap); + + return ret; +} + static gpointer copy_iova_range(gconstpointer src, gpointer data) { Range *source = (Range *)src; diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 1f89bd28c1..9c8a989db2 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -1,6 +1,7 @@ vfio_ss = ss.source_set() vfio_ss.add(files( 'common.c', + 'container-base.c', 'container.c', 'helpers.c', )) @@ -19,7 +20,6 @@ specific_ss.add_all(when: 'CONFIG_VFIO', if_true: vfio_ss) system_ss.add(when: 'CONFIG_VFIO_XGMAC', if_true: files('calxeda-xgmac.c')) system_ss.add(when: 'CONFIG_VFIO_AMD_XGBE', if_true: files('amd-xgbe.c')) system_ss.add(when: 'CONFIG_VFIO', if_true: files( - 'container-base.c', 'cpr.c', 'device.c', 'migration.c', diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 9fee7df876..d4cd09cb0f 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -106,9 +106,11 @@ vfio_put_group(int fd) "close group->fd=%d" vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" vfio_put_base_device(int fd) "close vdev->fd=%d" vfio_legacy_dma_unmap_overflow_workaround(void) "" -vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 +# container-base.c +vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 + # region.c vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 06178cf282..0dfae24b72 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -141,15 +141,6 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); #endif -bool vfio_devices_all_dirty_tracking_started( - const VFIOContainerBase *bcontainer); -bool -vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); -int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, - VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp); -int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, - uint64_t size, ram_addr_t ram_addr, Error **errp); - /* Returns 0 on success, or a negative errno. */ bool vfio_device_get_name(VFIODevice *vbasedev, Error **errp); void vfio_device_set_fd(VFIODevice *vbasedev, const char *str, Error **errp); diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index e0c458d487..41ca27b3f0 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -91,6 +91,13 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, bool start, Error **errp); int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp); +bool vfio_devices_all_dirty_tracking_started(const VFIOContainerBase *bcontainer); +bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); +int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, + VFIOBitmap *vbmap, hwaddr iova, hwaddr size, + Error **errp); +int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, + uint64_t size, ram_addr_t ram_addr, Error **errp); GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer); From d90aa1b8627b6a2a1e55fc559ce9082598bd47ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:12 +0100 Subject: [PATCH 0277/2760] vfio: Make vfio_devices_query_dirty_bitmap() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_devices_query_dirty_bitmap() is only used in "container-base.c". Also, rename to vfio_container_devices_query_dirty_bitmap() to reflect with the prefix 'vfio_container_devices_' that it simply loops over the container's device list. Reviewed-by: Joao Martins Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-28-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container-base.c | 6 +++--- include/hw/vfio/vfio-container-base.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index f9cf317018..eb7ab8461e 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -214,7 +214,7 @@ static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova, return 0; } -int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, +static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) { VFIODevice *vbasedev; @@ -260,8 +260,8 @@ int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, } if (all_device_dirty_tracking) { - ret = vfio_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, - errp); + ret = vfio_container_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, + errp); } else { ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size, errp); diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 41ca27b3f0..60975194a3 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -93,9 +93,6 @@ int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp); bool vfio_devices_all_dirty_tracking_started(const VFIOContainerBase *bcontainer); bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); -int vfio_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, - VFIOBitmap *vbmap, hwaddr iova, hwaddr size, - Error **errp); int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp); From 35e6d2c1d07dfd45c8b00019a98499d2cd6442ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:13 +0100 Subject: [PATCH 0278/2760] vfio: Make vfio_container_query_dirty_bitmap() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_container_query_dirty_bitmap() is only used in "container-base.c". Also, rename to vfio_container_iommu_query_dirty_bitmap() to reflect it is using the VFIO IOMMU backend device ->query_dirty_bitmap() handler. Reviewed-by: Joao Martins Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-29-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container-base.c | 24 ++++++++++++------------ include/hw/vfio/vfio-container-base.h | 2 -- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index eb7ab8461e..3c8039d52a 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -141,16 +141,6 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, return ret; } -int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, - VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) -{ - VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); - - g_assert(vioc->query_dirty_bitmap); - return vioc->query_dirty_bitmap(bcontainer, vbmap, iova, size, - errp); -} - static bool vfio_devices_all_device_dirty_tracking_started( const VFIOContainerBase *bcontainer) { @@ -214,6 +204,16 @@ static int vfio_device_dma_logging_report(VFIODevice *vbasedev, hwaddr iova, return 0; } +static int vfio_container_iommu_query_dirty_bitmap(const VFIOContainerBase *bcontainer, + VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) +{ + VFIOIOMMUClass *vioc = VFIO_IOMMU_GET_CLASS(bcontainer); + + g_assert(vioc->query_dirty_bitmap); + return vioc->query_dirty_bitmap(bcontainer, vbmap, iova, size, + errp); +} + static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bcontainer, VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp) { @@ -263,8 +263,8 @@ int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, ret = vfio_container_devices_query_dirty_bitmap(bcontainer, &vbmap, iova, size, errp); } else { - ret = vfio_container_query_dirty_bitmap(bcontainer, &vbmap, iova, size, - errp); + ret = vfio_container_iommu_query_dirty_bitmap(bcontainer, &vbmap, iova, size, + errp); } if (ret) { diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 60975194a3..69fb698bc1 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -89,8 +89,6 @@ void vfio_container_del_section_window(VFIOContainerBase *bcontainer, MemoryRegionSection *section); int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, bool start, Error **errp); -int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, - VFIOBitmap *vbmap, hwaddr iova, hwaddr size, Error **errp); bool vfio_devices_all_dirty_tracking_started(const VFIOContainerBase *bcontainer); bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, From e17c281e7c12d0bbe5de841f0a910687cdaaedd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:14 +0100 Subject: [PATCH 0279/2760] vfio: Rename vfio_devices_all_dirty_tracking_started() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also rename vfio_devices_all_device_dirty_tracking_started() while at it and use the prefix 'vfio_container_devices_' for routines simply looping over the container's device list. Reviewed-by: Joao Martins Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-30-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 2 +- hw/vfio/container-base.c | 6 +++--- hw/vfio/container.c | 2 +- include/hw/vfio/vfio-container-base.h | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index ed49ef88a8..89b7a71385 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -55,7 +55,7 @@ static bool vfio_log_sync_needed(const VFIOContainerBase *bcontainer) { VFIODevice *vbasedev; - if (!vfio_devices_all_dirty_tracking_started(bcontainer)) { + if (!vfio_container_dirty_tracking_is_started(bcontainer)) { return false; } diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 3c8039d52a..1beba37a77 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -141,7 +141,7 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, return ret; } -static bool vfio_devices_all_device_dirty_tracking_started( +static bool vfio_container_devices_dirty_tracking_is_started( const VFIOContainerBase *bcontainer) { VFIODevice *vbasedev; @@ -155,10 +155,10 @@ static bool vfio_devices_all_device_dirty_tracking_started( return true; } -bool vfio_devices_all_dirty_tracking_started( +bool vfio_container_dirty_tracking_is_started( const VFIOContainerBase *bcontainer) { - return vfio_devices_all_device_dirty_tracking_started(bcontainer) || + return vfio_container_devices_dirty_tracking_is_started(bcontainer) || bcontainer->dirty_pages_started; } diff --git a/hw/vfio/container.c b/hw/vfio/container.c index c55fe8e4be..e8cd927136 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -137,7 +137,7 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer, int ret; Error *local_err = NULL; - if (iotlb && vfio_devices_all_dirty_tracking_started(bcontainer)) { + if (iotlb && vfio_container_dirty_tracking_is_started(bcontainer)) { if (!vfio_devices_all_device_dirty_tracking(bcontainer) && bcontainer->dirty_pages_supported) { return vfio_dma_unmap_bitmap(container, iova, size, iotlb); diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 69fb698bc1..9b33e71f59 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -89,7 +89,8 @@ void vfio_container_del_section_window(VFIOContainerBase *bcontainer, MemoryRegionSection *section); int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, bool start, Error **errp); -bool vfio_devices_all_dirty_tracking_started(const VFIOContainerBase *bcontainer); +bool vfio_container_dirty_tracking_is_started( + const VFIOContainerBase *bcontainer); bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp); From 60f29d08237b6184009d0b00b933a5a788da5f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:15 +0100 Subject: [PATCH 0280/2760] vfio: Rename vfio_devices_all_device_dirty_tracking() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the prefix 'vfio_container_devices_' to reflect the routine simply loops over the container's device list. Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-31-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 4 ++-- hw/vfio/container-base.c | 5 +++-- hw/vfio/container.c | 2 +- include/hw/vfio/vfio-container-base.h | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 89b7a71385..5a7327979d 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -935,7 +935,7 @@ static bool vfio_listener_log_global_start(MemoryListener *listener, listener); bool ret; - if (vfio_devices_all_device_dirty_tracking(bcontainer)) { + if (vfio_container_devices_dirty_tracking_is_supported(bcontainer)) { ret = vfio_devices_dma_logging_start(bcontainer, errp); } else { ret = vfio_container_set_dirty_page_tracking(bcontainer, true, errp) == 0; @@ -954,7 +954,7 @@ static void vfio_listener_log_global_stop(MemoryListener *listener) Error *local_err = NULL; int ret = 0; - if (vfio_devices_all_device_dirty_tracking(bcontainer)) { + if (vfio_container_devices_dirty_tracking_is_supported(bcontainer)) { vfio_devices_dma_logging_stop(bcontainer); } else { ret = vfio_container_set_dirty_page_tracking(bcontainer, false, diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 1beba37a77..2627908e3f 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -162,7 +162,8 @@ bool vfio_container_dirty_tracking_is_started( bcontainer->dirty_pages_started; } -bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer) +bool vfio_container_devices_dirty_tracking_is_supported( + const VFIOContainerBase *bcontainer) { VFIODevice *vbasedev; @@ -240,7 +241,7 @@ int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp) { bool all_device_dirty_tracking = - vfio_devices_all_device_dirty_tracking(bcontainer); + vfio_container_devices_dirty_tracking_is_supported(bcontainer); uint64_t dirty_pages; VFIOBitmap vbmap; int ret; diff --git a/hw/vfio/container.c b/hw/vfio/container.c index e8cd927136..8e4a2cae03 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -138,7 +138,7 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer, Error *local_err = NULL; if (iotlb && vfio_container_dirty_tracking_is_started(bcontainer)) { - if (!vfio_devices_all_device_dirty_tracking(bcontainer) && + if (!vfio_container_devices_dirty_tracking_is_supported(bcontainer) && bcontainer->dirty_pages_supported) { return vfio_dma_unmap_bitmap(container, iova, size, iotlb); } diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 9b33e71f59..395ace02e4 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -91,7 +91,8 @@ int vfio_container_set_dirty_page_tracking(VFIOContainerBase *bcontainer, bool start, Error **errp); bool vfio_container_dirty_tracking_is_started( const VFIOContainerBase *bcontainer); -bool vfio_devices_all_device_dirty_tracking(const VFIOContainerBase *bcontainer); +bool vfio_container_devices_dirty_tracking_is_supported( + const VFIOContainerBase *bcontainer); int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp); From c51358bd17c324dae65f745df9c954e3a7137219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:16 +0100 Subject: [PATCH 0281/2760] vfio: Rename vfio_get_dirty_bitmap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to vfio_container_query_dirty_bitmap() to be consistent with the VFIO container routine naming scheme. Reviewed-by: Joao Martins Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-32-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/common.c | 6 +++--- hw/vfio/container-base.c | 5 +++-- hw/vfio/container.c | 2 +- hw/vfio/trace-events | 2 +- include/hw/vfio/vfio-container-base.h | 4 ++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/vfio/common.c b/hw/vfio/common.c index 5a7327979d..bde1bb3c13 100644 --- a/hw/vfio/common.c +++ b/hw/vfio/common.c @@ -1002,7 +1002,7 @@ static void vfio_iommu_map_dirty_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb) goto out_unlock; } - ret = vfio_get_dirty_bitmap(bcontainer, iova, iotlb->addr_mask + 1, + ret = vfio_container_query_dirty_bitmap(bcontainer, iova, iotlb->addr_mask + 1, translated_addr, &local_err); if (ret) { error_prepend(&local_err, @@ -1039,7 +1039,7 @@ static int vfio_ram_discard_get_dirty_bitmap(MemoryRegionSection *section, * Sync the whole mapped region (spanning multiple individual mappings) * in one go. */ - ret = vfio_get_dirty_bitmap(vrdl->bcontainer, iova, size, ram_addr, + ret = vfio_container_query_dirty_bitmap(vrdl->bcontainer, iova, size, ram_addr, &local_err); if (ret) { error_report_err(local_err); @@ -1133,7 +1133,7 @@ static int vfio_sync_dirty_bitmap(VFIOContainerBase *bcontainer, ram_addr = memory_region_get_ram_addr(section->mr) + section->offset_within_region; - return vfio_get_dirty_bitmap(bcontainer, + return vfio_container_query_dirty_bitmap(bcontainer, REAL_HOST_PAGE_ALIGN(section->offset_within_address_space), int128_get64(section->size), ram_addr, errp); } diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index 2627908e3f..fb86bc41bf 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -237,7 +237,7 @@ static int vfio_container_devices_query_dirty_bitmap(const VFIOContainerBase *bc return 0; } -int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, +int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp) { bool all_device_dirty_tracking = @@ -275,7 +275,8 @@ int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, dirty_pages = cpu_physical_memory_set_dirty_lebitmap(vbmap.bitmap, ram_addr, vbmap.pages); - trace_vfio_get_dirty_bitmap(iova, size, vbmap.size, ram_addr, dirty_pages); + trace_vfio_container_query_dirty_bitmap(iova, size, vbmap.size, ram_addr, + dirty_pages); out: g_free(vbmap.bitmap); diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 8e4a2cae03..bb3990aece 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -169,7 +169,7 @@ static int vfio_legacy_dma_unmap(const VFIOContainerBase *bcontainer, } if (need_dirty_sync) { - ret = vfio_get_dirty_bitmap(bcontainer, iova, size, + ret = vfio_container_query_dirty_bitmap(bcontainer, iova, size, iotlb->translated_addr, &local_err); if (ret) { error_report_err(local_err); diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index d4cd09cb0f..aa0ba695fa 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -109,7 +109,7 @@ vfio_legacy_dma_unmap_overflow_workaround(void) "" vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 # container-base.c -vfio_get_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 +vfio_container_query_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 # region.c vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index 395ace02e4..af63373c92 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -93,8 +93,8 @@ bool vfio_container_dirty_tracking_is_started( const VFIOContainerBase *bcontainer); bool vfio_container_devices_dirty_tracking_is_supported( const VFIOContainerBase *bcontainer); -int vfio_get_dirty_bitmap(const VFIOContainerBase *bcontainer, uint64_t iova, - uint64_t size, ram_addr_t ram_addr, Error **errp); +int vfio_container_query_dirty_bitmap(const VFIOContainerBase *bcontainer, + uint64_t iova, uint64_t size, ram_addr_t ram_addr, Error **errp); GList *vfio_container_get_iova_ranges(const VFIOContainerBase *bcontainer); From 6b62a90c24eb766b331343f9ad80104a7f16e7a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:17 +0100 Subject: [PATCH 0282/2760] vfio: Introduce new files for VFIO MemoryListener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit File "common.c" has been emptied of most of its definitions by the previous changes and the only definitions left are related to the VFIO MemoryListener handlers. Rename it to "listener.c" and introduce its associated "vfio-listener.h" header file for the declarations. Cleanup a little the includes while at it. Reviewed-by: Joao Martins Reviewed-by: John Levon Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-33-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 1 + hw/vfio/iommufd.c | 1 + hw/vfio/{common.c => listener.c} | 0 hw/vfio/meson.build | 2 +- hw/vfio/trace-events | 2 +- hw/vfio/vfio-listener.h | 14 ++++++++++++++ include/hw/vfio/vfio-common.h | 1 - 7 files changed, 18 insertions(+), 3 deletions(-) rename hw/vfio/{common.c => listener.c} (100%) create mode 100644 hw/vfio/vfio-listener.h diff --git a/hw/vfio/container.c b/hw/vfio/container.c index bb3990aece..ff540e1c59 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -35,6 +35,7 @@ #include "hw/vfio/vfio-container.h" #include "vfio-helpers.h" #include "vfio-cpr.h" +#include "vfio-listener.h" #define TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO TYPE_HOST_IOMMU_DEVICE "-legacy-vfio" diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index a5bd189a86..7488d21215 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -28,6 +28,7 @@ #include "vfio-iommufd.h" #include "vfio-helpers.h" #include "vfio-cpr.h" +#include "vfio-listener.h" #define TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO \ TYPE_HOST_IOMMU_DEVICE_IOMMUFD "-vfio" diff --git a/hw/vfio/common.c b/hw/vfio/listener.c similarity index 100% rename from hw/vfio/common.c rename to hw/vfio/listener.c diff --git a/hw/vfio/meson.build b/hw/vfio/meson.build index 9c8a989db2..bccb05098c 100644 --- a/hw/vfio/meson.build +++ b/hw/vfio/meson.build @@ -1,6 +1,6 @@ vfio_ss = ss.source_set() vfio_ss.add(files( - 'common.c', + 'listener.c', 'container-base.c', 'container.c', 'helpers.c', diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index aa0ba695fa..ddb1bcc24a 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -89,7 +89,7 @@ vfio_pci_igd_bdsm_enabled(const char *name, int size) "%s %dMB" vfio_pci_igd_host_bridge_enabled(const char *name) "%s" vfio_pci_igd_lpc_bridge_enabled(const char *name) "%s" -# common.c +# listener.c vfio_iommu_map_notify(const char *op, uint64_t iova_start, uint64_t iova_end) "iommu %s @ 0x%"PRIx64" - 0x%"PRIx64 vfio_listener_region_skip(const char *name, uint64_t start, uint64_t end) "SKIPPING %s 0x%"PRIx64" - 0x%"PRIx64 vfio_spapr_group_attach(int groupfd, int tablefd) "Attached groupfd %d to liobn fd %d" diff --git a/hw/vfio/vfio-listener.h b/hw/vfio/vfio-listener.h new file mode 100644 index 0000000000..93af6747b2 --- /dev/null +++ b/hw/vfio/vfio-listener.h @@ -0,0 +1,14 @@ +/* + * VFIO MemoryListener services + * + * Copyright Red Hat, Inc. 2025 + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_VFIO_VFIO_LISTENER_H +#define HW_VFIO_VFIO_LISTENER_H + +extern const MemoryListener vfio_memory_listener; + +#endif /* HW_VFIO_VFIO_LISTENER_H */ diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h index 0dfae24b72..92381c6160 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-common.h @@ -131,7 +131,6 @@ VFIODevice *vfio_get_vfio_device(Object *obj); typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIODeviceList vfio_device_list; -extern const MemoryListener vfio_memory_listener; #ifdef CONFIG_LINUX int vfio_get_region_info(VFIODevice *vbasedev, int index, From 74d376378e2a41392a36f34cef7d2c89ac2dfb33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:18 +0100 Subject: [PATCH 0283/2760] vfio: Rename RAM discard related services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename some routines to better reflect the namespace they belong to. Reviewed-by: Avihai Horon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-34-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/listener.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c index bde1bb3c13..70bdeb3ce7 100644 --- a/hw/vfio/listener.c +++ b/hw/vfio/listener.c @@ -242,7 +242,7 @@ static int vfio_ram_discard_notify_populate(RamDiscardListener *rdl, return 0; } -static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, +static void vfio_ram_discard_register_listener(VFIOContainerBase *bcontainer, MemoryRegionSection *section) { RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr); @@ -317,7 +317,7 @@ static void vfio_register_ram_discard_listener(VFIOContainerBase *bcontainer, } } -static void vfio_unregister_ram_discard_listener(VFIOContainerBase *bcontainer, +static void vfio_ram_discard_unregister_listener(VFIOContainerBase *bcontainer, MemoryRegionSection *section) { RamDiscardManager *rdm = memory_region_get_ram_discard_manager(section->mr); @@ -504,7 +504,7 @@ static void vfio_listener_region_add(MemoryListener *listener, * about changes. */ if (memory_region_has_ram_discard_manager(section->mr)) { - vfio_register_ram_discard_listener(bcontainer, section); + vfio_ram_discard_register_listener(bcontainer, section); return; } @@ -627,7 +627,7 @@ static void vfio_listener_region_del(MemoryListener *listener, pgmask = (1ULL << ctz64(bcontainer->pgsizes)) - 1; try_unmap = !((iova & pgmask) || (int128_get64(llsize) & pgmask)); } else if (memory_region_has_ram_discard_manager(section->mr)) { - vfio_unregister_ram_discard_listener(bcontainer, section); + vfio_ram_discard_unregister_listener(bcontainer, section); /* Unregistering will trigger an unmap. */ try_unmap = false; } @@ -1024,7 +1024,7 @@ out: } } -static int vfio_ram_discard_get_dirty_bitmap(MemoryRegionSection *section, +static int vfio_ram_discard_query_dirty_bitmap(MemoryRegionSection *section, void *opaque) { const hwaddr size = int128_get64(section->size); @@ -1071,7 +1071,7 @@ vfio_sync_ram_discard_listener_dirty_bitmap(VFIOContainerBase *bcontainer, * which correspond to populated parts. Replay all populated parts. */ return ram_discard_manager_replay_populated(rdm, section, - vfio_ram_discard_get_dirty_bitmap, + vfio_ram_discard_query_dirty_bitmap, &vrdl); } From a9183378f54969c8b11f08fdb3063925de8d77c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:19 +0100 Subject: [PATCH 0284/2760] vfio: Introduce vfio_listener_un/register() routines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This hides the MemoryListener implementation and makes the code common to both IOMMU backends, legacy and IOMMUFD. Reviewed-by: Joao Martins Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-35-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 11 +++-------- hw/vfio/iommufd.c | 9 ++------- hw/vfio/listener.c | 22 +++++++++++++++++++++- hw/vfio/vfio-listener.h | 3 ++- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index ff540e1c59..e4fcb1ad8b 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -616,12 +616,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, group->container = container; QLIST_INSERT_HEAD(&container->group_list, group, container_next); - bcontainer->listener = vfio_memory_listener; - memory_listener_register(&bcontainer->listener, bcontainer->space->as); - - if (bcontainer->error) { - error_propagate_prepend(errp, bcontainer->error, - "memory listener initialization failed: "); + if (!vfio_listener_register(bcontainer, errp)) { goto listener_release_exit; } @@ -631,7 +626,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, listener_release_exit: QLIST_REMOVE(group, container_next); vfio_kvm_device_del_group(group); - memory_listener_unregister(&bcontainer->listener); + vfio_listener_unregister(bcontainer); if (vioc->release) { vioc->release(bcontainer); } @@ -669,7 +664,7 @@ static void vfio_disconnect_container(VFIOGroup *group) * group. */ if (QLIST_EMPTY(&container->group_list)) { - memory_listener_unregister(&bcontainer->listener); + vfio_listener_unregister(bcontainer); if (vioc->release) { vioc->release(bcontainer); } diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 7488d21215..e47720247d 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -410,7 +410,7 @@ static void iommufd_cdev_container_destroy(VFIOIOMMUFDContainer *container) if (!QLIST_EMPTY(&bcontainer->device_list)) { return; } - memory_listener_unregister(&bcontainer->listener); + vfio_listener_unregister(bcontainer); iommufd_backend_free_id(container->be, container->ioas_id); object_unref(container); } @@ -562,12 +562,7 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, bcontainer->pgsizes = qemu_real_host_page_size(); } - bcontainer->listener = vfio_memory_listener; - memory_listener_register(&bcontainer->listener, bcontainer->space->as); - - if (bcontainer->error) { - error_propagate_prepend(errp, bcontainer->error, - "memory listener initialization failed: "); + if (!vfio_listener_register(bcontainer, errp)) { goto err_listener_register; } diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c index 70bdeb3ce7..d19674503c 100644 --- a/hw/vfio/listener.c +++ b/hw/vfio/listener.c @@ -45,6 +45,7 @@ #include "system/tpm.h" #include "vfio-migration-internal.h" #include "vfio-helpers.h" +#include "vfio-listener.h" /* * Device state interfaces @@ -1162,7 +1163,7 @@ static void vfio_listener_log_sync(MemoryListener *listener, } } -const MemoryListener vfio_memory_listener = { +static const MemoryListener vfio_memory_listener = { .name = "vfio", .region_add = vfio_listener_region_add, .region_del = vfio_listener_region_del, @@ -1170,3 +1171,22 @@ const MemoryListener vfio_memory_listener = { .log_global_stop = vfio_listener_log_global_stop, .log_sync = vfio_listener_log_sync, }; + +bool vfio_listener_register(VFIOContainerBase *bcontainer, Error **errp) +{ + bcontainer->listener = vfio_memory_listener; + memory_listener_register(&bcontainer->listener, bcontainer->space->as); + + if (bcontainer->error) { + error_propagate_prepend(errp, bcontainer->error, + "memory listener initialization failed: "); + return false; + } + + return true; +} + +void vfio_listener_unregister(VFIOContainerBase *bcontainer) +{ + memory_listener_unregister(&bcontainer->listener); +} diff --git a/hw/vfio/vfio-listener.h b/hw/vfio/vfio-listener.h index 93af6747b2..eb69ddd374 100644 --- a/hw/vfio/vfio-listener.h +++ b/hw/vfio/vfio-listener.h @@ -9,6 +9,7 @@ #ifndef HW_VFIO_VFIO_LISTENER_H #define HW_VFIO_VFIO_LISTENER_H -extern const MemoryListener vfio_memory_listener; +bool vfio_listener_register(VFIOContainerBase *bcontainer, Error **errp); +void vfio_listener_unregister(VFIOContainerBase *bcontainer); #endif /* HW_VFIO_VFIO_LISTENER_H */ From 11b8b9d53d8b30bf1823e9d2e303c28fe13acf34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:20 +0100 Subject: [PATCH 0285/2760] vfio: Rename vfio-common.h to vfio-device.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "hw/vfio/vfio-common.h" has been emptied of most of its declarations by the previous changes and the only declarations left are related to VFIODevice. Rename it to "hw/vfio/vfio-device.h" and make the necessary adjustments. Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-36-clg@redhat.com Signed-off-by: Cédric Le Goater --- backends/iommufd.c | 2 +- hw/vfio/ap.c | 2 +- hw/vfio/ccw.c | 2 +- hw/vfio/container-base.c | 2 +- hw/vfio/container.c | 2 +- hw/vfio/cpr.c | 2 +- hw/vfio/device.c | 2 +- hw/vfio/helpers.c | 2 +- hw/vfio/iommufd.c | 2 +- hw/vfio/listener.c | 2 +- hw/vfio/migration-multifd.c | 2 +- hw/vfio/migration-multifd.h | 2 +- hw/vfio/migration.c | 2 +- hw/vfio/pci.h | 2 +- hw/vfio/region.c | 4 ++-- include/hw/s390x/vfio-ccw.h | 2 +- include/hw/vfio/{vfio-common.h => vfio-device.h} | 2 +- include/hw/vfio/vfio-platform.h | 2 +- 18 files changed, 19 insertions(+), 19 deletions(-) rename include/hw/vfio/{vfio-common.h => vfio-device.h} (98%) diff --git a/backends/iommufd.c b/backends/iommufd.c index d57da44755..9587e4d99b 100644 --- a/backends/iommufd.c +++ b/backends/iommufd.c @@ -18,7 +18,7 @@ #include "qemu/error-report.h" #include "monitor/monitor.h" #include "trace.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include #include diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index d6575d7c44..9e2251437e 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -15,7 +15,7 @@ #include #include #include "qapi/error.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "system/iommufd.h" #include "hw/s390x/ap-device.h" #include "qemu/error-report.h" diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 29e804e122..d0713ca4c7 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -21,7 +21,7 @@ #include #include "qapi/error.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "system/iommufd.h" #include "hw/s390x/s390-ccw.h" #include "hw/s390x/vfio-ccw.h" diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index fb86bc41bf..c037bafe21 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -19,7 +19,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/vfio/vfio-container-base.h" -#include "hw/vfio/vfio-common.h" /* vfio_reset_handler */ +#include "hw/vfio/vfio-device.h" /* vfio_reset_handler */ #include "system/reset.h" #include "vfio-helpers.h" diff --git a/hw/vfio/container.c b/hw/vfio/container.c index e4fcb1ad8b..ef14046072 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -22,7 +22,7 @@ #include #include -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "system/address-spaces.h" #include "system/memory.h" #include "system/ram_addr.h" diff --git a/hw/vfio/cpr.c b/hw/vfio/cpr.c index 696987006b..3214184f97 100644 --- a/hw/vfio/cpr.c +++ b/hw/vfio/cpr.c @@ -6,7 +6,7 @@ */ #include "qemu/osdep.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "migration/misc.h" #include "qapi/error.h" #include "system/runstate.h" diff --git a/hw/vfio/device.c b/hw/vfio/device.c index e122c797c2..543750c3b1 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -21,7 +21,7 @@ #include "qemu/osdep.h" #include -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/vfio/pci.h" #include "hw/hw.h" #include "trace.h" diff --git a/hw/vfio/helpers.c b/hw/vfio/helpers.c index 48bd61d528..d0dbab1d17 100644 --- a/hw/vfio/helpers.c +++ b/hw/vfio/helpers.c @@ -23,7 +23,7 @@ #include #include "system/kvm.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/hw.h" #include "qapi/error.h" #include "vfio-helpers.h" diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index e47720247d..48db105422 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -15,7 +15,7 @@ #include #include -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "qemu/error-report.h" #include "trace.h" #include "qapi/error.h" diff --git a/hw/vfio/listener.c b/hw/vfio/listener.c index d19674503c..6f77e18a7a 100644 --- a/hw/vfio/listener.c +++ b/hw/vfio/listener.c @@ -25,7 +25,7 @@ #endif #include -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/vfio/pci.h" #include "system/address-spaces.h" #include "system/memory.h" diff --git a/hw/vfio/migration-multifd.c b/hw/vfio/migration-multifd.c index a3005226b9..850a319488 100644 --- a/hw/vfio/migration-multifd.c +++ b/hw/vfio/migration-multifd.c @@ -10,7 +10,7 @@ */ #include "qemu/osdep.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "migration/misc.h" #include "qapi/error.h" #include "qemu/bswap.h" diff --git a/hw/vfio/migration-multifd.h b/hw/vfio/migration-multifd.h index a664051eb8..0bab63211d 100644 --- a/hw/vfio/migration-multifd.h +++ b/hw/vfio/migration-multifd.h @@ -12,7 +12,7 @@ #ifndef HW_VFIO_MIGRATION_MULTIFD_H #define HW_VFIO_MIGRATION_MULTIFD_H -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" bool vfio_multifd_setup(VFIODevice *vbasedev, bool alloc_multifd, Error **errp); void vfio_multifd_cleanup(VFIODevice *vbasedev); diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 4da0526325..1dceab1b19 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -16,7 +16,7 @@ #include #include "system/runstate.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/vfio/vfio-migration.h" #include "migration/misc.h" #include "migration/savevm.h" diff --git a/hw/vfio/pci.h b/hw/vfio/pci.h index 801ea445b8..f835b1dbc2 100644 --- a/hw/vfio/pci.h +++ b/hw/vfio/pci.h @@ -14,7 +14,7 @@ #include "system/memory.h" #include "hw/pci/pci_device.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/vfio/vfio-region.h" #include "qemu/event_notifier.h" #include "qemu/queue.h" diff --git a/hw/vfio/region.c b/hw/vfio/region.c index 9049143abf..010b5241e1 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -21,8 +21,8 @@ #include "qemu/osdep.h" #include -#include "hw/vfio/vfio-common.h" -#include "hw/vfio/pci.h" +#include "hw/vfio/vfio-region.h" +#include "hw/vfio/vfio-device.h" #include "hw/hw.h" #include "trace.h" #include "qapi/error.h" diff --git a/include/hw/s390x/vfio-ccw.h b/include/hw/s390x/vfio-ccw.h index 4209d27657..1e0922dca1 100644 --- a/include/hw/s390x/vfio-ccw.h +++ b/include/hw/s390x/vfio-ccw.h @@ -14,7 +14,7 @@ #ifndef HW_VFIO_CCW_H #define HW_VFIO_CCW_H -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "hw/s390x/s390-ccw.h" #include "hw/s390x/ccw-device.h" #include "qom/object.h" diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-device.h similarity index 98% rename from include/hw/vfio/vfio-common.h rename to include/hw/vfio/vfio-device.h index 92381c6160..cfbe254e31 100644 --- a/include/hw/vfio/vfio-common.h +++ b/include/hw/vfio/vfio-device.h @@ -1,5 +1,5 @@ /* - * common header for vfio based device assignment support + * VFIO Device interface * * Copyright Red Hat, Inc. 2012 * diff --git a/include/hw/vfio/vfio-platform.h b/include/hw/vfio/vfio-platform.h index 3191545717..256d8500b7 100644 --- a/include/hw/vfio/vfio-platform.h +++ b/include/hw/vfio/vfio-platform.h @@ -17,7 +17,7 @@ #define HW_VFIO_VFIO_PLATFORM_H #include "hw/sysbus.h" -#include "hw/vfio/vfio-common.h" +#include "hw/vfio/vfio-device.h" #include "qemu/event_notifier.h" #include "qemu/queue.h" #include "qom/object.h" From e218ccf0c94b6fe26b333e2bdad87da85fe1c428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:21 +0100 Subject: [PATCH 0286/2760] vfio: Rename VFIODevice related services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename these routines : vfio_disable_irqindex -> vfio_device_irq_disable vfio_unmask_single_irqindex -> vfio_device_irq_unmask vfio_mask_single_irqindex -> vfio_device_irq_mask vfio_set_irq_signaling -> vfio_device_irq_set_signaling vfio_attach_device -> vfio_device_attach vfio_detach_device -> vfio_device_detach vfio_get_region_info -> vfio_device_get_region_info vfio_get_dev_region_info -> vfio_device_get_region_info_type vfio_has_region_cap -> vfio_device_has_region_cap vfio_reset_handler -> vfio_device_reset_hander to better reflect the namespace they belong to. Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-37-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/ap.c | 12 +++---- hw/vfio/ccw.c | 28 +++++++-------- hw/vfio/container-base.c | 6 ++-- hw/vfio/container.c | 6 ++-- hw/vfio/device.c | 36 +++++++++---------- hw/vfio/display.c | 8 ++--- hw/vfio/igd.c | 10 +++--- hw/vfio/pci.c | 68 +++++++++++++++++------------------ hw/vfio/platform.c | 14 ++++---- hw/vfio/region.c | 2 +- hw/vfio/trace-events | 8 ++--- include/hw/vfio/vfio-device.h | 26 +++++++------- 12 files changed, 112 insertions(+), 112 deletions(-) diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index 9e2251437e..be2e2927c2 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -117,8 +117,8 @@ static bool vfio_ap_register_irq_notifier(VFIOAPDevice *vapdev, fd = event_notifier_get_fd(notifier); qemu_set_fd_handler(fd, fd_read, NULL, vapdev); - if (!vfio_set_irq_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, - errp)) { + if (!vfio_device_irq_set_signaling(vdev, irq, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, + errp)) { qemu_set_fd_handler(fd, NULL, NULL, vapdev); event_notifier_cleanup(notifier); } @@ -141,8 +141,8 @@ static void vfio_ap_unregister_irq_notifier(VFIOAPDevice *vapdev, return; } - if (!vfio_set_irq_signaling(&vapdev->vdev, irq, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + if (!vfio_device_irq_set_signaling(&vapdev->vdev, irq, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { warn_reportf_err(err, VFIO_MSG_PREFIX, vapdev->vdev.name); } @@ -162,7 +162,7 @@ static void vfio_ap_realize(DeviceState *dev, Error **errp) return; } - if (!vfio_attach_device(vbasedev->name, vbasedev, + if (!vfio_device_attach(vbasedev->name, vbasedev, &address_space_memory, errp)) { goto error; } @@ -187,7 +187,7 @@ static void vfio_ap_unrealize(DeviceState *dev) VFIOAPDevice *vapdev = VFIO_AP_DEVICE(dev); vfio_ap_unregister_irq_notifier(vapdev, VFIO_AP_REQ_IRQ_INDEX); - vfio_detach_device(&vapdev->vdev); + vfio_device_detach(&vapdev->vdev); g_free(vapdev->vdev.name); } diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index d0713ca4c7..3a91efce81 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -426,8 +426,8 @@ static bool vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, fd = event_notifier_get_fd(notifier); qemu_set_fd_handler(fd, fd_read, NULL, vcdev); - if (!vfio_set_irq_signaling(vdev, irq, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { + if (!vfio_device_irq_set_signaling(vdev, irq, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { qemu_set_fd_handler(fd, NULL, NULL, vcdev); event_notifier_cleanup(notifier); } @@ -456,8 +456,8 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, return; } - if (!vfio_set_irq_signaling(&vcdev->vdev, irq, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + if (!vfio_device_irq_set_signaling(&vcdev->vdev, irq, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { warn_reportf_err(err, VFIO_MSG_PREFIX, vcdev->vdev.name); } @@ -488,7 +488,7 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) return false; } - ret = vfio_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info); + ret = vfio_device_get_region_info(vdev, VFIO_CCW_CONFIG_REGION_INDEX, &info); if (ret) { error_setg_errno(errp, -ret, "vfio: Error getting config info"); return false; @@ -505,8 +505,8 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) g_free(info); /* check for the optional async command region */ - ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, - VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info); + ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW, + VFIO_REGION_SUBTYPE_CCW_ASYNC_CMD, &info); if (!ret) { vcdev->async_cmd_region_size = info->size; if (sizeof(*vcdev->async_cmd_region) != vcdev->async_cmd_region_size) { @@ -518,8 +518,8 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) g_free(info); } - ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, - VFIO_REGION_SUBTYPE_CCW_SCHIB, &info); + ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW, + VFIO_REGION_SUBTYPE_CCW_SCHIB, &info); if (!ret) { vcdev->schib_region_size = info->size; if (sizeof(*vcdev->schib_region) != vcdev->schib_region_size) { @@ -531,8 +531,8 @@ static bool vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp) g_free(info); } - ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW, - VFIO_REGION_SUBTYPE_CCW_CRW, &info); + ret = vfio_device_get_region_info_type(vdev, VFIO_REGION_TYPE_CCW, + VFIO_REGION_SUBTYPE_CCW_CRW, &info); if (!ret) { vcdev->crw_region_size = info->size; @@ -583,7 +583,7 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) goto out_unrealize; } - if (!vfio_attach_device(cdev->mdevid, vbasedev, + if (!vfio_device_attach(cdev->mdevid, vbasedev, &address_space_memory, errp)) { goto out_attach_dev_err; } @@ -620,7 +620,7 @@ out_irq_notifier_err: out_io_notifier_err: vfio_ccw_put_region(vcdev); out_region_err: - vfio_detach_device(vbasedev); + vfio_device_detach(vbasedev); out_attach_dev_err: g_free(vbasedev->name); out_unrealize: @@ -639,7 +639,7 @@ static void vfio_ccw_unrealize(DeviceState *dev) vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); vfio_ccw_put_region(vcdev); - vfio_detach_device(&vcdev->vdev); + vfio_device_detach(&vcdev->vdev); g_free(vcdev->vdev.name); if (cdc->unrealize) { diff --git a/hw/vfio/container-base.c b/hw/vfio/container-base.c index c037bafe21..09340fd97a 100644 --- a/hw/vfio/container-base.c +++ b/hw/vfio/container-base.c @@ -19,7 +19,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "hw/vfio/vfio-container-base.h" -#include "hw/vfio/vfio-device.h" /* vfio_reset_handler */ +#include "hw/vfio/vfio-device.h" /* vfio_device_reset_handler */ #include "system/reset.h" #include "vfio-helpers.h" @@ -44,7 +44,7 @@ VFIOAddressSpace *vfio_address_space_get(AddressSpace *as) QLIST_INIT(&space->containers); if (QLIST_EMPTY(&vfio_address_spaces)) { - qemu_register_reset(vfio_reset_handler, NULL); + qemu_register_reset(vfio_device_reset_handler, NULL); } QLIST_INSERT_HEAD(&vfio_address_spaces, space, list); @@ -62,7 +62,7 @@ void vfio_address_space_put(VFIOAddressSpace *space) g_free(space); if (QLIST_EMPTY(&vfio_address_spaces)) { - qemu_unregister_reset(vfio_reset_handler, NULL); + qemu_unregister_reset(vfio_device_reset_handler, NULL); } } diff --git a/hw/vfio/container.c b/hw/vfio/container.c index ef14046072..149ea26aff 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -865,7 +865,7 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) } /* - * vfio_attach_device: attach a device to a security context + * vfio_device_attach: attach a device to a security context * @name and @vbasedev->name are likely to be different depending * on the type of the device, hence the need for passing @name */ @@ -881,7 +881,7 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, return false; } - trace_vfio_attach_device(vbasedev->name, groupid); + trace_vfio_device_attach(vbasedev->name, groupid); if (!vfio_device_hiod_realize(vbasedev, errp)) { return false; @@ -919,7 +919,7 @@ static void vfio_legacy_detach_device(VFIODevice *vbasedev) QLIST_REMOVE(vbasedev, global_next); QLIST_REMOVE(vbasedev, container_next); vbasedev->bcontainer = NULL; - trace_vfio_detach_device(vbasedev->name, group->groupid); + trace_vfio_device_detach(vbasedev->name, group->groupid); vfio_put_base_device(vbasedev); vfio_put_group(group); } diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 543750c3b1..4de6948cf4 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -51,11 +51,11 @@ VFIODeviceList vfio_device_list = * reset for the one in-use devices case, calling _multi() will do * nothing if a _one() would have been sufficient. */ -void vfio_reset_handler(void *opaque) +void vfio_device_reset_handler(void *opaque) { VFIODevice *vbasedev; - trace_vfio_reset_handler(); + trace_vfio_device_reset_handler(); QLIST_FOREACH(vbasedev, &vfio_device_list, global_next) { if (vbasedev->dev->realized) { vbasedev->ops->vfio_compute_needs_reset(vbasedev); @@ -72,7 +72,7 @@ void vfio_reset_handler(void *opaque) /* * Common VFIO interrupt disable */ -void vfio_disable_irqindex(VFIODevice *vbasedev, int index) +void vfio_device_irq_disable(VFIODevice *vbasedev, int index) { struct vfio_irq_set irq_set = { .argsz = sizeof(irq_set), @@ -85,7 +85,7 @@ void vfio_disable_irqindex(VFIODevice *vbasedev, int index) ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); } -void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) +void vfio_device_irq_unmask(VFIODevice *vbasedev, int index) { struct vfio_irq_set irq_set = { .argsz = sizeof(irq_set), @@ -98,7 +98,7 @@ void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index) ioctl(vbasedev->fd, VFIO_DEVICE_SET_IRQS, &irq_set); } -void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index) +void vfio_device_irq_mask(VFIODevice *vbasedev, int index) { struct vfio_irq_set irq_set = { .argsz = sizeof(irq_set), @@ -147,8 +147,8 @@ static const char *index_to_str(VFIODevice *vbasedev, int index) } } -bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, - int action, int fd, Error **errp) +bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex, + int action, int fd, Error **errp) { ERRP_GUARD(); g_autofree struct vfio_irq_set *irq_set = NULL; @@ -185,8 +185,8 @@ bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, return false; } -int vfio_get_region_info(VFIODevice *vbasedev, int index, - struct vfio_region_info **info) +int vfio_device_get_region_info(VFIODevice *vbasedev, int index, + struct vfio_region_info **info) { size_t argsz = sizeof(struct vfio_region_info); @@ -212,8 +212,8 @@ retry: return 0; } -int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - uint32_t subtype, struct vfio_region_info **info) +int vfio_device_get_region_info_type(VFIODevice *vbasedev, uint32_t type, + uint32_t subtype, struct vfio_region_info **info) { int i; @@ -221,7 +221,7 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, struct vfio_info_cap_header *hdr; struct vfio_region_info_cap_type *cap_type; - if (vfio_get_region_info(vbasedev, i, info)) { + if (vfio_device_get_region_info(vbasedev, i, info)) { continue; } @@ -233,8 +233,8 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, cap_type = container_of(hdr, struct vfio_region_info_cap_type, header); - trace_vfio_get_dev_region(vbasedev->name, i, - cap_type->type, cap_type->subtype); + trace_vfio_device_get_region_info_type(vbasedev->name, i, + cap_type->type, cap_type->subtype); if (cap_type->type == type && cap_type->subtype == subtype) { return 0; @@ -247,12 +247,12 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, return -ENODEV; } -bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) +bool vfio_device_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type) { g_autofree struct vfio_region_info *info = NULL; bool ret = false; - if (!vfio_get_region_info(vbasedev, region, &info)) { + if (!vfio_device_get_region_info(vbasedev, region, &info)) { if (vfio_get_region_info_cap(info, cap_type)) { ret = true; } @@ -367,7 +367,7 @@ VFIODevice *vfio_get_vfio_device(Object *obj) } } -bool vfio_attach_device(char *name, VFIODevice *vbasedev, +bool vfio_device_attach(char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp) { const VFIOIOMMUClass *ops = @@ -395,7 +395,7 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev, return true; } -void vfio_detach_device(VFIODevice *vbasedev) +void vfio_device_detach(VFIODevice *vbasedev) { if (!vbasedev->bcontainer) { return; diff --git a/hw/vfio/display.c b/hw/vfio/display.c index 70cfd685bd..f3e6581f15 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -129,10 +129,10 @@ static bool vfio_display_edid_init(VFIOPCIDevice *vdev, Error **errp) int fd = vdev->vbasedev.fd; int ret; - ret = vfio_get_dev_region_info(&vdev->vbasedev, - VFIO_REGION_TYPE_GFX, - VFIO_REGION_SUBTYPE_GFX_EDID, - &dpy->edid_info); + ret = vfio_device_get_region_info_type(&vdev->vbasedev, + VFIO_REGION_TYPE_GFX, + VFIO_REGION_SUBTYPE_GFX_EDID, + &dpy->edid_info); if (ret) { /* Failed to get GFX edid info, allow to go through without edid. */ return true; diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index 265fffc2aa..6678e0e5cd 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -200,7 +200,7 @@ static bool vfio_pci_igd_setup_opregion(VFIOPCIDevice *vdev, Error **errp) return false; } - ret = vfio_get_dev_region_info(&vdev->vbasedev, + ret = vfio_device_get_region_info_type(&vdev->vbasedev, VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION, &opregion); if (ret) { @@ -385,7 +385,7 @@ static bool vfio_pci_igd_setup_lpc_bridge(VFIOPCIDevice *vdev, Error **errp) * Check whether we have all the vfio device specific regions to * support LPC quirk (added in Linux v4.6). */ - ret = vfio_get_dev_region_info(&vdev->vbasedev, + ret = vfio_device_get_region_info_type(&vdev->vbasedev, VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, VFIO_REGION_SUBTYPE_INTEL_IGD_LPC_CFG, &lpc); if (ret) { @@ -393,7 +393,7 @@ static bool vfio_pci_igd_setup_lpc_bridge(VFIOPCIDevice *vdev, Error **errp) return false; } - ret = vfio_get_dev_region_info(&vdev->vbasedev, + ret = vfio_device_get_region_info_type(&vdev->vbasedev, VFIO_REGION_TYPE_PCI_VENDOR_TYPE | PCI_VENDOR_ID_INTEL, VFIO_REGION_SUBTYPE_INTEL_IGD_HOST_CFG, &host); if (ret) { @@ -542,8 +542,8 @@ static bool vfio_pci_igd_config_quirk(VFIOPCIDevice *vdev, Error **errp) * there's no ROM, there's no point in setting up this quirk. * NB. We only seem to get BIOS ROMs, so UEFI VM would need CSM support. */ - ret = vfio_get_region_info(&vdev->vbasedev, - VFIO_PCI_ROM_REGION_INDEX, &rom); + ret = vfio_device_get_region_info(&vdev->vbasedev, + VFIO_PCI_ROM_REGION_INDEX, &rom); if ((ret || !rom->size) && !vdev->pdev.romfile) { error_setg(&err, "Device has no ROM"); goto error; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index bade3b80d7..6fa7217db8 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -115,7 +115,7 @@ static void vfio_intx_eoi(VFIODevice *vbasedev) vdev->intx.pending = false; pci_irq_deassert(&vdev->pdev); - vfio_unmask_single_irqindex(vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_unmask(vbasedev, VFIO_PCI_INTX_IRQ_INDEX); } static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) @@ -131,7 +131,7 @@ static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) /* Get to a known interrupt state */ qemu_set_fd_handler(irq_fd, NULL, NULL, vdev); - vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_mask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; pci_irq_deassert(&vdev->pdev); @@ -149,15 +149,15 @@ static bool vfio_intx_enable_kvm(VFIOPCIDevice *vdev, Error **errp) goto fail_irqfd; } - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_UNMASK, - event_notifier_get_fd(&vdev->intx.unmask), - errp)) { + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_UNMASK, + event_notifier_get_fd(&vdev->intx.unmask), + errp)) { goto fail_vfio; } /* Let'em rip */ - vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.kvm_accel = true; @@ -172,7 +172,7 @@ fail_irqfd: event_notifier_cleanup(&vdev->intx.unmask); fail: qemu_set_fd_handler(irq_fd, vfio_intx_interrupt, NULL, vdev); - vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); return false; #else return true; @@ -190,7 +190,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) * Get to a known state, hardware masked, QEMU ready to accept new * interrupts, QEMU IRQ de-asserted. */ - vfio_mask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_mask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; pci_irq_deassert(&vdev->pdev); @@ -210,7 +210,7 @@ static void vfio_intx_disable_kvm(VFIOPCIDevice *vdev) vdev->intx.kvm_accel = false; /* If we've missed an event, let it re-fire through QEMU */ - vfio_unmask_single_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_unmask(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); trace_vfio_intx_disable_kvm(vdev->vbasedev.name); #endif @@ -299,7 +299,7 @@ static bool vfio_intx_enable(VFIOPCIDevice *vdev, Error **errp) fd = event_notifier_get_fd(&vdev->intx.interrupt); qemu_set_fd_handler(fd, vfio_intx_interrupt, NULL, vdev); - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX, 0, VFIO_IRQ_SET_ACTION_TRIGGER, fd, errp)) { qemu_set_fd_handler(fd, NULL, NULL, vdev); event_notifier_cleanup(&vdev->intx.interrupt); @@ -322,7 +322,7 @@ static void vfio_intx_disable(VFIOPCIDevice *vdev) timer_del(vdev->intx.mmap_timer); vfio_intx_disable_kvm(vdev); - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); + vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_INTX_IRQ_INDEX); vdev->intx.pending = false; pci_irq_deassert(&vdev->pdev); vfio_mmap_set_enabled(vdev, true); @@ -578,7 +578,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, if (!vdev->defer_kvm_irq_routing) { if (vdev->msix->noresize && resizing) { - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); ret = vfio_enable_vectors(vdev, true); if (ret) { error_report("vfio: failed to enable vectors, %d", ret); @@ -593,7 +593,7 @@ static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, fd = event_notifier_get_fd(&vector->interrupt); } - if (!vfio_set_irq_signaling(&vdev->vbasedev, + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, nr, VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { @@ -638,7 +638,7 @@ static void vfio_msix_vector_release(PCIDevice *pdev, unsigned int nr) int32_t fd = event_notifier_get_fd(&vector->interrupt); Error *err = NULL; - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX, nr, VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); @@ -835,7 +835,7 @@ static void vfio_msix_disable(VFIOPCIDevice *vdev) * Always clear MSI-X IRQ index. A PF device could have enabled * MSI-X with no vectors. See vfio_msix_enable(). */ - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); + vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); vfio_msi_disable_common(vdev); if (!vfio_intx_enable(vdev, &err)) { @@ -852,7 +852,7 @@ static void vfio_msi_disable(VFIOPCIDevice *vdev) { Error *err = NULL; - vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); + vfio_device_irq_disable(&vdev->vbasedev, VFIO_PCI_MSI_IRQ_INDEX); vfio_msi_disable_common(vdev); vfio_intx_enable(vdev, &err); if (err) { @@ -886,8 +886,8 @@ static void vfio_pci_load_rom(VFIOPCIDevice *vdev) off_t off = 0; ssize_t bytes; - if (vfio_get_region_info(&vdev->vbasedev, - VFIO_PCI_ROM_REGION_INDEX, ®_info)) { + if (vfio_device_get_region_info(&vdev->vbasedev, + VFIO_PCI_ROM_REGION_INDEX, ®_info)) { error_report("vfio: Error getting ROM info: %m"); return; } @@ -1380,8 +1380,8 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev) * If the host driver allows mapping of a MSIX data, we are going to * do map the entire BAR and emulate MSIX table on top of that. */ - if (vfio_has_region_cap(&vdev->vbasedev, region->nr, - VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) { + if (vfio_device_has_region_cap(&vdev->vbasedev, region->nr, + VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) { return; } @@ -2673,7 +2673,7 @@ bool vfio_populate_vga(VFIOPCIDevice *vdev, Error **errp) g_autofree struct vfio_region_info *reg_info = NULL; int ret; - ret = vfio_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, ®_info); + ret = vfio_device_get_region_info(vbasedev, VFIO_PCI_VGA_REGION_INDEX, ®_info); if (ret) { error_setg_errno(errp, -ret, "failed getting region info for VGA region index %d", @@ -2771,8 +2771,8 @@ static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) QLIST_INIT(&vdev->bars[i].quirks); } - ret = vfio_get_region_info(vbasedev, - VFIO_PCI_CONFIG_REGION_INDEX, ®_info); + ret = vfio_device_get_region_info(vbasedev, + VFIO_PCI_CONFIG_REGION_INDEX, ®_info); if (ret) { error_setg_errno(errp, -ret, "failed to get config info"); return false; @@ -2816,7 +2816,7 @@ static bool vfio_populate_device(VFIOPCIDevice *vdev, Error **errp) static void vfio_pci_put_device(VFIOPCIDevice *vdev) { - vfio_detach_device(&vdev->vbasedev); + vfio_device_detach(&vdev->vbasedev); g_free(vdev->vbasedev.name); g_free(vdev->msix); @@ -2868,8 +2868,8 @@ static void vfio_register_err_notifier(VFIOPCIDevice *vdev) fd = event_notifier_get_fd(&vdev->err_notifier); qemu_set_fd_handler(fd, vfio_err_notifier_handler, NULL, vdev); - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); qemu_set_fd_handler(fd, NULL, NULL, vdev); event_notifier_cleanup(&vdev->err_notifier); @@ -2885,8 +2885,8 @@ static void vfio_unregister_err_notifier(VFIOPCIDevice *vdev) return; } - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_ERR_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } qemu_set_fd_handler(event_notifier_get_fd(&vdev->err_notifier), @@ -2933,8 +2933,8 @@ static void vfio_register_req_notifier(VFIOPCIDevice *vdev) fd = event_notifier_get_fd(&vdev->req_notifier); qemu_set_fd_handler(fd, vfio_req_notifier_handler, NULL, vdev); - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); qemu_set_fd_handler(fd, NULL, NULL, vdev); event_notifier_cleanup(&vdev->req_notifier); @@ -2951,8 +2951,8 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) return; } - if (!vfio_set_irq_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { + if (!vfio_device_irq_set_signaling(&vdev->vbasedev, VFIO_PCI_REQ_IRQ_INDEX, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, -1, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vdev->vbasedev.name); } qemu_set_fd_handler(event_notifier_get_fd(&vdev->req_notifier), @@ -3015,7 +3015,7 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) name = g_strdup(vbasedev->name); } - if (!vfio_attach_device(name, vbasedev, + if (!vfio_device_attach(name, vbasedev, pci_device_iommu_address_space(pdev), errp)) { goto error; } diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index ca6528cc56..49cd9816c3 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -119,8 +119,8 @@ static int vfio_set_trigger_eventfd(VFIOINTp *intp, qemu_set_fd_handler(fd, (IOHandler *)handler, NULL, intp); - if (!vfio_set_irq_signaling(vbasedev, intp->pin, 0, - VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { + if (!vfio_device_irq_set_signaling(vbasedev, intp->pin, 0, + VFIO_IRQ_SET_ACTION_TRIGGER, fd, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vbasedev->name); qemu_set_fd_handler(fd, NULL, NULL, NULL); return -EINVAL; @@ -301,7 +301,7 @@ static void vfio_platform_eoi(VFIODevice *vbasedev) if (vfio_irq_is_automasked(intp)) { /* unmasks the physical level-sensitive IRQ */ - vfio_unmask_single_irqindex(vbasedev, intp->pin); + vfio_device_irq_unmask(vbasedev, intp->pin); } /* a single IRQ can be active at a time */ @@ -357,8 +357,8 @@ static int vfio_set_resample_eventfd(VFIOINTp *intp) Error *err = NULL; qemu_set_fd_handler(fd, NULL, NULL, NULL); - if (!vfio_set_irq_signaling(vbasedev, intp->pin, 0, - VFIO_IRQ_SET_ACTION_UNMASK, fd, &err)) { + if (!vfio_device_irq_set_signaling(vbasedev, intp->pin, 0, + VFIO_IRQ_SET_ACTION_UNMASK, fd, &err)) { error_reportf_err(err, VFIO_MSG_PREFIX, vbasedev->name); return -EINVAL; } @@ -546,7 +546,7 @@ static bool vfio_base_device_init(VFIODevice *vbasedev, Error **errp) return false; } - if (!vfio_attach_device(vbasedev->name, vbasedev, + if (!vfio_device_attach(vbasedev->name, vbasedev, &address_space_memory, errp)) { return false; } @@ -555,7 +555,7 @@ static bool vfio_base_device_init(VFIODevice *vbasedev, Error **errp) return true; } - vfio_detach_device(vbasedev); + vfio_device_detach(vbasedev); return false; } diff --git a/hw/vfio/region.c b/hw/vfio/region.c index 010b5241e1..04bf9eb098 100644 --- a/hw/vfio/region.c +++ b/hw/vfio/region.c @@ -185,7 +185,7 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region, g_autofree struct vfio_region_info *info = NULL; int ret; - ret = vfio_get_region_info(vbasedev, index, &info); + ret = vfio_device_get_region_info(vbasedev, index, &info); if (ret) { return ret; } diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index ddb1bcc24a..8843560576 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -37,8 +37,6 @@ vfio_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int vfio_pci_hot_reset_result(const char *name, const char *result) "%s hot reset: %s" vfio_populate_device_config(const char *name, unsigned long size, unsigned long offset, unsigned long flags) "Device '%s' config: size: 0x%lx, offset: 0x%lx, flags: 0x%lx" vfio_populate_device_get_irq_info_failure(const char *errstr) "VFIO_DEVICE_GET_IRQ_INFO failure: %s" -vfio_attach_device(const char *name, int group_id) " (%s) group %d" -vfio_detach_device(const char *name, int group_id) " (%s) group %d" vfio_mdev(const char *name, bool is_mdev) " (%s) is_mdev %d" vfio_add_ext_cap_dropped(const char *name, uint16_t cap, uint16_t offset) "%s 0x%x@0x%x" vfio_pci_reset(const char *name) " (%s)" @@ -196,5 +194,7 @@ iommufd_cdev_device_info(char *name, int devfd, int num_irqs, int num_regions, i iommufd_cdev_pci_hot_reset_dep_devices(int domain, int bus, int slot, int function, int dev_id) "\t%04x:%02x:%02x.%x devid %d" # device.c -vfio_get_dev_region(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" -vfio_reset_handler(void) "" +vfio_device_get_region_info_type(const char *name, int index, uint32_t type, uint32_t subtype) "%s index %d, %08x/%08x" +vfio_device_reset_handler(void) "" +vfio_device_attach(const char *name, int group_id) " (%s) group %d" +vfio_device_detach(const char *name, int group_id) " (%s) group %d" diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h index cfbe254e31..696ed87f01 100644 --- a/include/hw/vfio/vfio-device.h +++ b/include/hw/vfio/vfio-device.h @@ -115,29 +115,29 @@ struct VFIODeviceOps { int (*vfio_load_config)(VFIODevice *vdev, QEMUFile *f); }; -void vfio_disable_irqindex(VFIODevice *vbasedev, int index); -void vfio_unmask_single_irqindex(VFIODevice *vbasedev, int index); -void vfio_mask_single_irqindex(VFIODevice *vbasedev, int index); -bool vfio_set_irq_signaling(VFIODevice *vbasedev, int index, int subindex, - int action, int fd, Error **errp); +void vfio_device_irq_disable(VFIODevice *vbasedev, int index); +void vfio_device_irq_unmask(VFIODevice *vbasedev, int index); +void vfio_device_irq_mask(VFIODevice *vbasedev, int index); +bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex, + int action, int fd, Error **errp); -void vfio_reset_handler(void *opaque); +void vfio_device_reset_handler(void *opaque); bool vfio_device_is_mdev(VFIODevice *vbasedev); bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp); -bool vfio_attach_device(char *name, VFIODevice *vbasedev, +bool vfio_device_attach(char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp); -void vfio_detach_device(VFIODevice *vbasedev); +void vfio_device_detach(VFIODevice *vbasedev); VFIODevice *vfio_get_vfio_device(Object *obj); typedef QLIST_HEAD(VFIODeviceList, VFIODevice) VFIODeviceList; extern VFIODeviceList vfio_device_list; #ifdef CONFIG_LINUX -int vfio_get_region_info(VFIODevice *vbasedev, int index, - struct vfio_region_info **info); -int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type, - uint32_t subtype, struct vfio_region_info **info); -bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); +int vfio_device_get_region_info(VFIODevice *vbasedev, int index, + struct vfio_region_info **info); +int vfio_device_get_region_info_type(VFIODevice *vbasedev, uint32_t type, + uint32_t subtype, struct vfio_region_info **info); +bool vfio_device_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type); #endif /* Returns 0 on success, or a negative errno. */ From 7d810bb166820237f57b8e20272a366af2641f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 26 Mar 2025 08:51:22 +0100 Subject: [PATCH 0287/2760] vfio: Rename VFIOContainer related services MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename these routines : vfio_put_group -> vfio_group_put vfio_get_group -> vfio_group_get vfio_kvm_device_del_group -> vfio_group_del_kvm_device vfio_kvm_device_add_group -> vfio_group_add_kvm_device vfio_get_device -> vfio_device_get vfio_put_base_device -> vfio_device_put vfio_device_groupid -> vfio_device_get_groupid vfio_connect_container -> vfio_container_connect vfio_disconnect_container -> vfio_container_disconnect to better reflect the namespace they belong to. Reviewed-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250318095415.670319-30-clg@redhat.com Reviewed-by: Zhenzhong Duan Link: https://lore.kernel.org/qemu-devel/20250326075122.1299361-38-clg@redhat.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 52 ++++++++++++++++++++++---------------------- hw/vfio/trace-events | 12 +++++----- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 149ea26aff..7177747603 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -306,7 +306,7 @@ static bool vfio_get_info_iova_range(struct vfio_iommu_type1_info *info, return true; } -static void vfio_kvm_device_add_group(VFIOGroup *group) +static void vfio_group_add_kvm_device(VFIOGroup *group) { Error *err = NULL; @@ -315,7 +315,7 @@ static void vfio_kvm_device_add_group(VFIOGroup *group) } } -static void vfio_kvm_device_del_group(VFIOGroup *group) +static void vfio_group_del_kvm_device(VFIOGroup *group) { Error *err = NULL; @@ -511,7 +511,7 @@ static bool vfio_legacy_setup(VFIOContainerBase *bcontainer, Error **errp) return true; } -static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, +static bool vfio_container_connect(VFIOGroup *group, AddressSpace *as, Error **errp) { VFIOContainer *container; @@ -569,7 +569,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, } group->container = container; QLIST_INSERT_HEAD(&container->group_list, group, container_next); - vfio_kvm_device_add_group(group); + vfio_group_add_kvm_device(group); return true; } } @@ -609,7 +609,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, goto enable_discards_exit; } - vfio_kvm_device_add_group(group); + vfio_group_add_kvm_device(group); vfio_address_space_insert(space, bcontainer); @@ -625,7 +625,7 @@ static bool vfio_connect_container(VFIOGroup *group, AddressSpace *as, return true; listener_release_exit: QLIST_REMOVE(group, container_next); - vfio_kvm_device_del_group(group); + vfio_group_del_kvm_device(group); vfio_listener_unregister(bcontainer); if (vioc->release) { vioc->release(bcontainer); @@ -649,7 +649,7 @@ put_space_exit: return false; } -static void vfio_disconnect_container(VFIOGroup *group) +static void vfio_container_disconnect(VFIOGroup *group) { VFIOContainer *container = group->container; VFIOContainerBase *bcontainer = &container->bcontainer; @@ -678,7 +678,7 @@ static void vfio_disconnect_container(VFIOGroup *group) if (QLIST_EMPTY(&container->group_list)) { VFIOAddressSpace *space = bcontainer->space; - trace_vfio_disconnect_container(container->fd); + trace_vfio_container_disconnect(container->fd); vfio_cpr_unregister_container(bcontainer); close(container->fd); object_unref(container); @@ -687,7 +687,7 @@ static void vfio_disconnect_container(VFIOGroup *group) } } -static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) +static VFIOGroup *vfio_group_get(int groupid, AddressSpace *as, Error **errp) { ERRP_GUARD(); VFIOGroup *group; @@ -731,7 +731,7 @@ static VFIOGroup *vfio_get_group(int groupid, AddressSpace *as, Error **errp) group->groupid = groupid; QLIST_INIT(&group->device_list); - if (!vfio_connect_container(group, as, errp)) { + if (!vfio_container_connect(group, as, errp)) { error_prepend(errp, "failed to setup container for group %d: ", groupid); goto close_fd_exit; @@ -750,7 +750,7 @@ free_group_exit: return NULL; } -static void vfio_put_group(VFIOGroup *group) +static void vfio_group_put(VFIOGroup *group) { if (!group || !QLIST_EMPTY(&group->device_list)) { return; @@ -759,15 +759,15 @@ static void vfio_put_group(VFIOGroup *group) if (!group->ram_block_discard_allowed) { vfio_ram_block_discard_disable(group->container, false); } - vfio_kvm_device_del_group(group); - vfio_disconnect_container(group); + vfio_group_del_kvm_device(group); + vfio_container_disconnect(group); QLIST_REMOVE(group, next); - trace_vfio_put_group(group->fd); + trace_vfio_group_put(group->fd); close(group->fd); g_free(group); } -static bool vfio_get_device(VFIOGroup *group, const char *name, +static bool vfio_device_get(VFIOGroup *group, const char *name, VFIODevice *vbasedev, Error **errp) { g_autofree struct vfio_device_info *info = NULL; @@ -819,25 +819,25 @@ static bool vfio_get_device(VFIOGroup *group, const char *name, vbasedev->num_regions = info->num_regions; vbasedev->flags = info->flags; - trace_vfio_get_device(name, info->flags, info->num_regions, info->num_irqs); + trace_vfio_device_get(name, info->flags, info->num_regions, info->num_irqs); vbasedev->reset_works = !!(info->flags & VFIO_DEVICE_FLAGS_RESET); return true; } -static void vfio_put_base_device(VFIODevice *vbasedev) +static void vfio_device_put(VFIODevice *vbasedev) { if (!vbasedev->group) { return; } QLIST_REMOVE(vbasedev, next); vbasedev->group = NULL; - trace_vfio_put_base_device(vbasedev->fd); + trace_vfio_device_put(vbasedev->fd); close(vbasedev->fd); } -static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) +static int vfio_device_get_groupid(VFIODevice *vbasedev, Error **errp) { char *tmp, group_path[PATH_MAX]; g_autofree char *group_name = NULL; @@ -872,7 +872,7 @@ static int vfio_device_groupid(VFIODevice *vbasedev, Error **errp) static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp) { - int groupid = vfio_device_groupid(vbasedev, errp); + int groupid = vfio_device_get_groupid(vbasedev, errp); VFIODevice *vbasedev_iter; VFIOGroup *group; VFIOContainerBase *bcontainer; @@ -887,7 +887,7 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, return false; } - group = vfio_get_group(groupid, as, errp); + group = vfio_group_get(groupid, as, errp); if (!group) { return false; } @@ -895,12 +895,12 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { error_setg(errp, "device is already attached"); - vfio_put_group(group); + vfio_group_put(group); return false; } } - if (!vfio_get_device(group, name, vbasedev, errp)) { - vfio_put_group(group); + if (!vfio_device_get(group, name, vbasedev, errp)) { + vfio_group_put(group); return false; } @@ -920,8 +920,8 @@ static void vfio_legacy_detach_device(VFIODevice *vbasedev) QLIST_REMOVE(vbasedev, container_next); vbasedev->bcontainer = NULL; trace_vfio_device_detach(vbasedev->name, group->groupid); - vfio_put_base_device(vbasedev); - vfio_put_group(group); + vfio_device_put(vbasedev); + vfio_group_put(group); } static int vfio_legacy_pci_hot_reset(VFIODevice *vbasedev, bool single) diff --git a/hw/vfio/trace-events b/hw/vfio/trace-events index 8843560576..e90ec9bff8 100644 --- a/hw/vfio/trace-events +++ b/hw/vfio/trace-events @@ -99,16 +99,18 @@ vfio_listener_region_add_no_dma_map(const char *name, uint64_t iova, uint64_t si vfio_listener_region_del(uint64_t start, uint64_t end) "region_del 0x%"PRIx64" - 0x%"PRIx64 vfio_device_dirty_tracking_update(uint64_t start, uint64_t end, uint64_t min, uint64_t max) "section 0x%"PRIx64" - 0x%"PRIx64" -> update [0x%"PRIx64" - 0x%"PRIx64"]" vfio_device_dirty_tracking_start(int nr_ranges, uint64_t min32, uint64_t max32, uint64_t min64, uint64_t max64, uint64_t minpci, uint64_t maxpci) "nr_ranges %d 32:[0x%"PRIx64" - 0x%"PRIx64"], 64:[0x%"PRIx64" - 0x%"PRIx64"], pci64:[0x%"PRIx64" - 0x%"PRIx64"]" -vfio_disconnect_container(int fd) "close container->fd=%d" -vfio_put_group(int fd) "close group->fd=%d" -vfio_get_device(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" -vfio_put_base_device(int fd) "close vdev->fd=%d" -vfio_legacy_dma_unmap_overflow_workaround(void) "" vfio_iommu_map_dirty_notify(uint64_t iova_start, uint64_t iova_end) "iommu dirty @ 0x%"PRIx64" - 0x%"PRIx64 # container-base.c vfio_container_query_dirty_bitmap(uint64_t iova, uint64_t size, uint64_t bitmap_size, uint64_t start, uint64_t dirty_pages) "iova=0x%"PRIx64" size= 0x%"PRIx64" bitmap_size=0x%"PRIx64" start=0x%"PRIx64" dirty_pages=%"PRIu64 +# container.c +vfio_container_disconnect(int fd) "close container->fd=%d" +vfio_group_put(int fd) "close group->fd=%d" +vfio_device_get(const char * name, unsigned int flags, unsigned int num_regions, unsigned int num_irqs) "Device %s flags: %u, regions: %u, irqs: %u" +vfio_device_put(int fd) "close vdev->fd=%d" +vfio_legacy_dma_unmap_overflow_workaround(void) "" + # region.c vfio_region_write(const char *name, int index, uint64_t addr, uint64_t data, unsigned size) " (%s:region%d+0x%"PRIx64", 0x%"PRIx64 ", %d)" vfio_region_read(char *name, int index, uint64_t addr, unsigned size, uint64_t data) " (%s:region%d+0x%"PRIx64", %d) = 0x%"PRIx64 From 85ae745edd2815c504a3198410a545e50f583e6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Tue, 22 Apr 2025 18:29:54 +0200 Subject: [PATCH 0288/2760] MAINTAINERS: Add a maintainer for util/vfio-helpers.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The NVMe Block device driver makes use of a reduced VFIO library managing the host interface. These routines are VFIO related and do not have a maintainer. Move util/vfio-helpers.c under VFIO jurisdiction. Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/qemu-devel/20250422162954.210706-1-clg@redhat.com Signed-off-by: Cédric Le Goater --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 661a47db5a..a316907e76 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2197,6 +2197,7 @@ M: Alex Williamson M: Cédric Le Goater S: Supported F: hw/vfio/* +F: util/vfio-helpers.c F: include/hw/vfio/ F: docs/devel/migration/vfio.rst F: qapi/vfio.json From 436114cc4390ff46535229e67e43056196a971c1 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 23 Apr 2025 15:28:20 +0800 Subject: [PATCH 0289/2760] vfio/iommufd: Make a separate call to get IOMMU capabilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we depend on .realize() calling iommufd_backend_get_device_info() to get IOMMU capabilities and check for dirty page tracking support. By make a extra separate call, this dependency is removed. This happens only during device attach, it's not a hot path. Suggested-by: Cédric Le Goater Signed-off-by: Zhenzhong Duan Reviewed-by: Joao Martins Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072824.3647952-2-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/iommufd.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 48db105422..2253778b3a 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -287,7 +287,8 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev, { ERRP_GUARD(); IOMMUFDBackend *iommufd = vbasedev->iommufd; - uint32_t flags = 0; + uint32_t type, flags = 0; + uint64_t hw_caps; VFIOIOASHwpt *hwpt; uint32_t hwpt_id; int ret; @@ -324,7 +325,12 @@ static bool iommufd_cdev_autodomains_get(VFIODevice *vbasedev, * vfio_migration_realize() may decide to use VF dirty tracking * instead. */ - if (vbasedev->hiod->caps.hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) { + if (!iommufd_backend_get_device_info(vbasedev->iommufd, vbasedev->devid, + &type, NULL, 0, &hw_caps, errp)) { + return false; + } + + if (hw_caps & IOMMU_HW_CAP_DIRTY_TRACKING) { flags = IOMMU_HWPT_ALLOC_DIRTY_TRACKING; } From c45d88b8a2f25600c69748bfcf37911412c396ab Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 23 Apr 2025 15:28:21 +0800 Subject: [PATCH 0290/2760] vfio/iommufd: Move realize() after attachment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously device attaching depends on realize() getting host IOMMU capabilities to check dirty tracking support. Now we have a separate call to ioctl(IOMMU_GET_HW_INFO) to get host IOMMU capabilities and check that for dirty tracking support, there is no dependency any more, move realize() call after attachment succeed. Suggested-by: Cédric Le Goater Suggested-by: Donald Dutile Signed-off-by: Zhenzhong Duan Reviewed-by: Joao Martins Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072824.3647952-3-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/iommufd.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 2253778b3a..f273dc8712 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -500,17 +500,6 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, space = vfio_address_space_get(as); - /* - * The HostIOMMUDevice data from legacy backend is static and doesn't need - * any information from the (type1-iommu) backend to be initialized. In - * contrast however, the IOMMUFD HostIOMMUDevice data requires the iommufd - * FD to be connected and having a devid to be able to successfully call - * iommufd_backend_get_device_info(). - */ - if (!vfio_device_hiod_realize(vbasedev, errp)) { - goto err_alloc_ioas; - } - /* try to attach to an existing container in this space */ QLIST_FOREACH(bcontainer, &space->containers, next) { container = container_of(bcontainer, VFIOIOMMUFDContainer, bcontainer); @@ -585,6 +574,10 @@ found_container: goto err_listener_register; } + if (!vfio_device_hiod_realize(vbasedev, errp)) { + goto err_hiod_realize; + } + /* * TODO: examine RAM_BLOCK_DISCARD stuff, should we do group level * for discarding incompatibility check as well? @@ -606,6 +599,8 @@ found_container: vbasedev->num_regions, vbasedev->flags); return true; +err_hiod_realize: + vfio_cpr_unregister_container(bcontainer); err_listener_register: iommufd_cdev_ram_block_discard_disable(false); err_discard_disable: From 0327ffc8530e9733526fab6c790ad5f0661b008d Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 23 Apr 2025 15:28:22 +0800 Subject: [PATCH 0291/2760] vfio/container: Move realize() after attachment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To match the change for IOMMUFD backend, move realize() after attachment for legacy backend too. Suggested-by: Cédric Le Goater Suggested-by: Donald Dutile Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072824.3647952-4-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 7177747603..652a6197ce 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -883,10 +883,6 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, trace_vfio_device_attach(vbasedev->name, groupid); - if (!vfio_device_hiod_realize(vbasedev, errp)) { - return false; - } - group = vfio_group_get(groupid, as, errp); if (!group) { return false; @@ -895,13 +891,15 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, QLIST_FOREACH(vbasedev_iter, &group->device_list, next) { if (strcmp(vbasedev_iter->name, vbasedev->name) == 0) { error_setg(errp, "device is already attached"); - vfio_group_put(group); - return false; + goto group_put_exit; } } if (!vfio_device_get(group, name, vbasedev, errp)) { - vfio_group_put(group); - return false; + goto group_put_exit; + } + + if (!vfio_device_hiod_realize(vbasedev, errp)) { + goto device_put_exit; } bcontainer = &group->container->bcontainer; @@ -910,6 +908,12 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, QLIST_INSERT_HEAD(&vfio_device_list, vbasedev, global_next); return true; + +device_put_exit: + vfio_device_put(vbasedev); +group_put_exit: + vfio_group_put(group); + return false; } static void vfio_legacy_detach_device(VFIODevice *vbasedev) From 0805f829a1aa07888fa7378f9421d37c521c4193 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 23 Apr 2025 15:28:23 +0800 Subject: [PATCH 0292/2760] vfio: Cleanup host IOMMU device creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit realize() is now moved after attachment, do the same for hiod creation. Introduce a new function vfio_device_hiod_create_and_realize() to do them all in one go. Suggested-by: Cédric Le Goater Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072824.3647952-5-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 5 ++++- hw/vfio/device.c | 33 ++++++++++++++------------------- hw/vfio/iommufd.c | 4 +++- include/hw/vfio/vfio-device.h | 3 ++- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 652a6197ce..78f70e63d6 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -898,7 +898,9 @@ static bool vfio_legacy_attach_device(const char *name, VFIODevice *vbasedev, goto group_put_exit; } - if (!vfio_device_hiod_realize(vbasedev, errp)) { + if (!vfio_device_hiod_create_and_realize(vbasedev, + TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO, + errp)) { goto device_put_exit; } @@ -924,6 +926,7 @@ static void vfio_legacy_detach_device(VFIODevice *vbasedev) QLIST_REMOVE(vbasedev, container_next); vbasedev->bcontainer = NULL; trace_vfio_device_detach(vbasedev->name, group->groupid); + object_unref(vbasedev->hiod); vfio_device_put(vbasedev); vfio_group_put(group); } diff --git a/hw/vfio/device.c b/hw/vfio/device.c index 4de6948cf4..d625a7c4db 100644 --- a/hw/vfio/device.c +++ b/hw/vfio/device.c @@ -347,15 +347,24 @@ bool vfio_device_is_mdev(VFIODevice *vbasedev) return subsys && (strcmp(subsys, "/sys/bus/mdev") == 0); } -bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp) +bool vfio_device_hiod_create_and_realize(VFIODevice *vbasedev, + const char *typename, Error **errp) { - HostIOMMUDevice *hiod = vbasedev->hiod; + HostIOMMUDevice *hiod; - if (!hiod) { + if (vbasedev->mdev) { return true; } - return HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp); + hiod = HOST_IOMMU_DEVICE(object_new(typename)); + + if (!HOST_IOMMU_DEVICE_GET_CLASS(hiod)->realize(hiod, vbasedev, errp)) { + object_unref(hiod); + return false; + } + + vbasedev->hiod = hiod; + return true; } VFIODevice *vfio_get_vfio_device(Object *obj) @@ -372,7 +381,6 @@ bool vfio_device_attach(char *name, VFIODevice *vbasedev, { const VFIOIOMMUClass *ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY)); - HostIOMMUDevice *hiod = NULL; if (vbasedev->iommufd) { ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD)); @@ -380,19 +388,7 @@ bool vfio_device_attach(char *name, VFIODevice *vbasedev, assert(ops); - - if (!vbasedev->mdev) { - hiod = HOST_IOMMU_DEVICE(object_new(ops->hiod_typename)); - vbasedev->hiod = hiod; - } - - if (!ops->attach_device(name, vbasedev, as, errp)) { - object_unref(hiod); - vbasedev->hiod = NULL; - return false; - } - - return true; + return ops->attach_device(name, vbasedev, as, errp); } void vfio_device_detach(VFIODevice *vbasedev) @@ -400,6 +396,5 @@ void vfio_device_detach(VFIODevice *vbasedev) if (!vbasedev->bcontainer) { return; } - object_unref(vbasedev->hiod); VFIO_IOMMU_GET_CLASS(vbasedev->bcontainer)->detach_device(vbasedev); } diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index f273dc8712..8a010a51ea 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -574,7 +574,8 @@ found_container: goto err_listener_register; } - if (!vfio_device_hiod_realize(vbasedev, errp)) { + if (!vfio_device_hiod_create_and_realize(vbasedev, + TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO, errp)) { goto err_hiod_realize; } @@ -630,6 +631,7 @@ static void iommufd_cdev_detach(VFIODevice *vbasedev) iommufd_cdev_ram_block_discard_disable(false); } + object_unref(vbasedev->hiod); vfio_cpr_unregister_container(bcontainer); iommufd_cdev_detach_container(vbasedev, container); iommufd_cdev_container_destroy(container); diff --git a/include/hw/vfio/vfio-device.h b/include/hw/vfio/vfio-device.h index 696ed87f01..81c95bb51e 100644 --- a/include/hw/vfio/vfio-device.h +++ b/include/hw/vfio/vfio-device.h @@ -123,7 +123,8 @@ bool vfio_device_irq_set_signaling(VFIODevice *vbasedev, int index, int subindex void vfio_device_reset_handler(void *opaque); bool vfio_device_is_mdev(VFIODevice *vbasedev); -bool vfio_device_hiod_realize(VFIODevice *vbasedev, Error **errp); +bool vfio_device_hiod_create_and_realize(VFIODevice *vbasedev, + const char *typename, Error **errp); bool vfio_device_attach(char *name, VFIODevice *vbasedev, AddressSpace *as, Error **errp); void vfio_device_detach(VFIODevice *vbasedev); From fdd75967836ca1affa29ad5a50a690851d310cd9 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Wed, 23 Apr 2025 15:28:24 +0800 Subject: [PATCH 0293/2760] vfio: Remove hiod_typename property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because we handle host IOMMU device creation in each container backend, we know which type name to use, so hiod_typename property is useless now, just remove it. Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072824.3647952-6-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/container.c | 2 -- hw/vfio/iommufd.c | 2 -- include/hw/vfio/vfio-container-base.h | 3 --- 3 files changed, 7 deletions(-) diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 78f70e63d6..29170f0634 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -1103,8 +1103,6 @@ static void vfio_iommu_legacy_class_init(ObjectClass *klass, void *data) { VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); - vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_LEGACY_VFIO; - vioc->setup = vfio_legacy_setup; vioc->dma_map = vfio_legacy_dma_map; vioc->dma_unmap = vfio_legacy_dma_unmap; diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 8a010a51ea..f24054a6a5 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -795,8 +795,6 @@ static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data) { VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); - vioc->hiod_typename = TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO; - vioc->dma_map = iommufd_cdev_map; vioc->dma_unmap = iommufd_cdev_unmap; vioc->attach_device = iommufd_cdev_attach; diff --git a/include/hw/vfio/vfio-container-base.h b/include/hw/vfio/vfio-container-base.h index af63373c92..5527e02722 100644 --- a/include/hw/vfio/vfio-container-base.h +++ b/include/hw/vfio/vfio-container-base.h @@ -115,9 +115,6 @@ OBJECT_DECLARE_TYPE(VFIOContainerBase, VFIOIOMMUClass, VFIO_IOMMU) struct VFIOIOMMUClass { ObjectClass parent_class; - /* Properties */ - const char *hiod_typename; - /* basic feature */ bool (*setup)(VFIOContainerBase *bcontainer, Error **errp); int (*dma_map)(const VFIOContainerBase *bcontainer, From f3028b7d2d9895799159433ccb18180c2d4d1516 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 24 Apr 2025 14:33:55 +0800 Subject: [PATCH 0294/2760] vfio: Register/unregister container for CPR only once for each container MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vfio_cpr_register_container and vfio_cpr_unregister_container are container scoped function. Calling them for each device attaching/detaching would corrupt CPR reboot notifier list, i.e., when two VFIO devices are attached to same container and have same notifier registered twice. Fixes: d9fa4223b30a ("vfio: register container for cpr") Signed-off-by: Zhenzhong Duan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424063355.3855174-1-zhenzhong.duan@intel.com Signed-off-by: Cédric Le Goater --- hw/vfio/iommufd.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index f24054a6a5..b2f72dc8c3 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -416,6 +416,7 @@ static void iommufd_cdev_container_destroy(VFIOIOMMUFDContainer *container) if (!QLIST_EMPTY(&bcontainer->device_list)) { return; } + vfio_cpr_unregister_container(bcontainer); vfio_listener_unregister(bcontainer); iommufd_backend_free_id(container->be, container->ioas_id); object_unref(container); @@ -561,6 +562,10 @@ static bool iommufd_cdev_attach(const char *name, VFIODevice *vbasedev, goto err_listener_register; } + if (!vfio_cpr_register_container(bcontainer, errp)) { + goto err_listener_register; + } + bcontainer->initialized = true; found_container: @@ -570,13 +575,9 @@ found_container: goto err_listener_register; } - if (!vfio_cpr_register_container(bcontainer, errp)) { - goto err_listener_register; - } - if (!vfio_device_hiod_create_and_realize(vbasedev, TYPE_HOST_IOMMU_DEVICE_IOMMUFD_VFIO, errp)) { - goto err_hiod_realize; + goto err_listener_register; } /* @@ -600,8 +601,6 @@ found_container: vbasedev->num_regions, vbasedev->flags); return true; -err_hiod_realize: - vfio_cpr_unregister_container(bcontainer); err_listener_register: iommufd_cdev_ram_block_discard_disable(false); err_discard_disable: @@ -632,7 +631,6 @@ static void iommufd_cdev_detach(VFIODevice *vbasedev) } object_unref(vbasedev->hiod); - vfio_cpr_unregister_container(bcontainer); iommufd_cdev_detach_container(vbasedev, container); iommufd_cdev_container_destroy(container); vfio_address_space_put(space); From 54594b520862682d846cb6fa91705a927290eec5 Mon Sep 17 00:00:00 2001 From: John Levon Date: Wed, 9 Apr 2025 15:48:01 +0200 Subject: [PATCH 0295/2760] vfio: refactor out vfio_interrupt_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the interrupt setup code out of vfio_realize() for readability. Signed-off-by: John Levon Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250409134814.478903-2-john.levon@nutanix.com Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 55 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 6fa7217db8..27cc6426a5 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2962,6 +2962,38 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) vdev->req_enabled = false; } +static bool vfio_interrupt_setup(VFIOPCIDevice *vdev, Error **errp) +{ + PCIDevice *pdev = &vdev->pdev; + + /* QEMU emulates all of MSI & MSIX */ + if (pdev->cap_present & QEMU_PCI_CAP_MSIX) { + memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff, + MSIX_CAP_LENGTH); + } + + if (pdev->cap_present & QEMU_PCI_CAP_MSI) { + memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff, + vdev->msi_cap_size); + } + + if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { + vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, + vfio_intx_mmap_enable, vdev); + pci_device_set_intx_routing_notifier(&vdev->pdev, + vfio_intx_routing_notifier); + vdev->irqchip_change_notifier.notify = vfio_irqchip_change; + kvm_irqchip_add_change_notifier(&vdev->irqchip_change_notifier); + if (!vfio_intx_enable(vdev, errp)) { + timer_free(vdev->intx.mmap_timer); + pci_device_set_intx_routing_notifier(&vdev->pdev, NULL); + kvm_irqchip_remove_change_notifier(&vdev->irqchip_change_notifier); + return false; + } + } + return true; +} + static void vfio_realize(PCIDevice *pdev, Error **errp) { ERRP_GUARD(); @@ -3141,27 +3173,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) vfio_bar_quirk_setup(vdev, i); } - /* QEMU emulates all of MSI & MSIX */ - if (pdev->cap_present & QEMU_PCI_CAP_MSIX) { - memset(vdev->emulated_config_bits + pdev->msix_cap, 0xff, - MSIX_CAP_LENGTH); - } - - if (pdev->cap_present & QEMU_PCI_CAP_MSI) { - memset(vdev->emulated_config_bits + pdev->msi_cap, 0xff, - vdev->msi_cap_size); - } - - if (vfio_pci_read_config(&vdev->pdev, PCI_INTERRUPT_PIN, 1)) { - vdev->intx.mmap_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, - vfio_intx_mmap_enable, vdev); - pci_device_set_intx_routing_notifier(&vdev->pdev, - vfio_intx_routing_notifier); - vdev->irqchip_change_notifier.notify = vfio_irqchip_change; - kvm_irqchip_add_change_notifier(&vdev->irqchip_change_notifier); - if (!vfio_intx_enable(vdev, errp)) { - goto out_deregister; - } + if (!vfio_interrupt_setup(vdev, errp)) { + goto out_unset_idev; } if (vdev->display != ON_OFF_AUTO_OFF) { From a9d270f6b85bab40d388fe5244f02d145759cc08 Mon Sep 17 00:00:00 2001 From: John Levon Date: Wed, 9 Apr 2025 15:48:02 +0200 Subject: [PATCH 0296/2760] vfio: refactor out vfio_pci_config_setup() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the PCI config setup code out of vfio_realize() for readability. Reviewed-by: Cédric Le Goater Signed-off-by: John Levon Link: https://lore.kernel.org/qemu-devel/20250409134814.478903-3-john.levon@nutanix.com Signed-off-by: Cédric Le Goater --- hw/vfio/pci.c | 176 +++++++++++++++++++++++++++----------------------- 1 file changed, 94 insertions(+), 82 deletions(-) diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 27cc6426a5..4a9484dfbe 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -2962,6 +2962,99 @@ static void vfio_unregister_req_notifier(VFIOPCIDevice *vdev) vdev->req_enabled = false; } +static bool vfio_pci_config_setup(VFIOPCIDevice *vdev, Error **errp) +{ + PCIDevice *pdev = &vdev->pdev; + VFIODevice *vbasedev = &vdev->vbasedev; + + /* vfio emulates a lot for us, but some bits need extra love */ + vdev->emulated_config_bits = g_malloc0(vdev->config_size); + + /* QEMU can choose to expose the ROM or not */ + memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4); + /* QEMU can also add or extend BARs */ + memset(vdev->emulated_config_bits + PCI_BASE_ADDRESS_0, 0xff, 6 * 4); + + /* + * The PCI spec reserves vendor ID 0xffff as an invalid value. The + * device ID is managed by the vendor and need only be a 16-bit value. + * Allow any 16-bit value for subsystem so they can be hidden or changed. + */ + if (vdev->vendor_id != PCI_ANY_ID) { + if (vdev->vendor_id >= 0xffff) { + error_setg(errp, "invalid PCI vendor ID provided"); + return false; + } + vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); + trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); + } else { + vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); + } + + if (vdev->device_id != PCI_ANY_ID) { + if (vdev->device_id > 0xffff) { + error_setg(errp, "invalid PCI device ID provided"); + return false; + } + vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); + trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); + } else { + vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); + } + + if (vdev->sub_vendor_id != PCI_ANY_ID) { + if (vdev->sub_vendor_id > 0xffff) { + error_setg(errp, "invalid PCI subsystem vendor ID provided"); + return false; + } + vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, + vdev->sub_vendor_id, ~0); + trace_vfio_pci_emulated_sub_vendor_id(vbasedev->name, + vdev->sub_vendor_id); + } + + if (vdev->sub_device_id != PCI_ANY_ID) { + if (vdev->sub_device_id > 0xffff) { + error_setg(errp, "invalid PCI subsystem device ID provided"); + return false; + } + vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); + trace_vfio_pci_emulated_sub_device_id(vbasedev->name, + vdev->sub_device_id); + } + + /* QEMU can change multi-function devices to single function, or reverse */ + vdev->emulated_config_bits[PCI_HEADER_TYPE] = + PCI_HEADER_TYPE_MULTI_FUNCTION; + + /* Restore or clear multifunction, this is always controlled by QEMU */ + if (vdev->pdev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + vdev->pdev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; + } else { + vdev->pdev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; + } + + /* + * Clear host resource mapping info. If we choose not to register a + * BAR, such as might be the case with the option ROM, we can get + * confusing, unwritable, residual addresses from the host here. + */ + memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24); + memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4); + + vfio_pci_size_rom(vdev); + + vfio_bars_prepare(vdev); + + if (!vfio_msix_early_setup(vdev, errp)) { + return false; + } + + vfio_bars_register(vdev); + + return true; +} + static bool vfio_interrupt_setup(VFIOPCIDevice *vdev, Error **errp) { PCIDevice *pdev = &vdev->pdev; @@ -3066,91 +3159,10 @@ static void vfio_realize(PCIDevice *pdev, Error **errp) goto error; } - /* vfio emulates a lot for us, but some bits need extra love */ - vdev->emulated_config_bits = g_malloc0(vdev->config_size); - - /* QEMU can choose to expose the ROM or not */ - memset(vdev->emulated_config_bits + PCI_ROM_ADDRESS, 0xff, 4); - /* QEMU can also add or extend BARs */ - memset(vdev->emulated_config_bits + PCI_BASE_ADDRESS_0, 0xff, 6 * 4); - - /* - * The PCI spec reserves vendor ID 0xffff as an invalid value. The - * device ID is managed by the vendor and need only be a 16-bit value. - * Allow any 16-bit value for subsystem so they can be hidden or changed. - */ - if (vdev->vendor_id != PCI_ANY_ID) { - if (vdev->vendor_id >= 0xffff) { - error_setg(errp, "invalid PCI vendor ID provided"); - goto error; - } - vfio_add_emulated_word(vdev, PCI_VENDOR_ID, vdev->vendor_id, ~0); - trace_vfio_pci_emulated_vendor_id(vbasedev->name, vdev->vendor_id); - } else { - vdev->vendor_id = pci_get_word(pdev->config + PCI_VENDOR_ID); - } - - if (vdev->device_id != PCI_ANY_ID) { - if (vdev->device_id > 0xffff) { - error_setg(errp, "invalid PCI device ID provided"); - goto error; - } - vfio_add_emulated_word(vdev, PCI_DEVICE_ID, vdev->device_id, ~0); - trace_vfio_pci_emulated_device_id(vbasedev->name, vdev->device_id); - } else { - vdev->device_id = pci_get_word(pdev->config + PCI_DEVICE_ID); - } - - if (vdev->sub_vendor_id != PCI_ANY_ID) { - if (vdev->sub_vendor_id > 0xffff) { - error_setg(errp, "invalid PCI subsystem vendor ID provided"); - goto error; - } - vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_VENDOR_ID, - vdev->sub_vendor_id, ~0); - trace_vfio_pci_emulated_sub_vendor_id(vbasedev->name, - vdev->sub_vendor_id); - } - - if (vdev->sub_device_id != PCI_ANY_ID) { - if (vdev->sub_device_id > 0xffff) { - error_setg(errp, "invalid PCI subsystem device ID provided"); - goto error; - } - vfio_add_emulated_word(vdev, PCI_SUBSYSTEM_ID, vdev->sub_device_id, ~0); - trace_vfio_pci_emulated_sub_device_id(vbasedev->name, - vdev->sub_device_id); - } - - /* QEMU can change multi-function devices to single function, or reverse */ - vdev->emulated_config_bits[PCI_HEADER_TYPE] = - PCI_HEADER_TYPE_MULTI_FUNCTION; - - /* Restore or clear multifunction, this is always controlled by QEMU */ - if (vdev->pdev.cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { - vdev->pdev.config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; - } else { - vdev->pdev.config[PCI_HEADER_TYPE] &= ~PCI_HEADER_TYPE_MULTI_FUNCTION; - } - - /* - * Clear host resource mapping info. If we choose not to register a - * BAR, such as might be the case with the option ROM, we can get - * confusing, unwritable, residual addresses from the host here. - */ - memset(&vdev->pdev.config[PCI_BASE_ADDRESS_0], 0, 24); - memset(&vdev->pdev.config[PCI_ROM_ADDRESS], 0, 4); - - vfio_pci_size_rom(vdev); - - vfio_bars_prepare(vdev); - - if (!vfio_msix_early_setup(vdev, errp)) { + if (!vfio_pci_config_setup(vdev, errp)) { goto error; } - vfio_bars_register(vdev); - if (!vbasedev->mdev && !pci_device_set_iommu_device(pdev, vbasedev->hiod, errp)) { error_prepend(errp, "Failed to set vIOMMU: "); From 0a5692fecc76c6fee9a4fc86dbe8faf84ce30ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 16:09:06 +0100 Subject: [PATCH 0297/2760] cpus: Introduce CPUClass::list_cpus() callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some targets define cpu_list to a method listing their CPUs on stdout. In order to make list_cpus() generic, introduce the CPUClass::list_cpus() callback. When no callback is registered, list_cpus() defaults to the cpu_list definition. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Message-Id: <20250324185837.46506-2-philmd@linaro.org> --- cpu-target.c | 8 +++++++- include/hw/core/cpu.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cpu-target.c b/cpu-target.c index 14cd623bff..d139a18f5b 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -104,7 +104,13 @@ static void cpu_list(void) void list_cpus(void) { - cpu_list(); + CPUClass *cc = CPU_CLASS(object_class_by_name(CPU_RESOLVING_TYPE)); + + if (cc->list_cpus) { + cc->list_cpus(); + } else { + cpu_list(); + } } /* enable or disable single step mode. EXCP_DEBUG is returned by the diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index c8d6abff19..5b645df59f 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -102,6 +102,7 @@ struct SysemuCPUOps; * CPUClass: * @class_by_name: Callback to map -cpu command line model name to an * instantiatable CPU type. + * @list_cpus: list available CPU models and flags. * @parse_features: Callback to parse command line arguments. * @reset_dump_flags: #CPUDumpFlags to use for reset logging. * @memory_rw_debug: Callback for GDB memory access. @@ -148,6 +149,7 @@ struct CPUClass { /*< public >*/ ObjectClass *(*class_by_name)(const char *cpu_model); + void (*list_cpus)(void); void (*parse_features)(const char *typename, char *str, Error **errp); int (*memory_rw_debug)(CPUState *cpu, vaddr addr, From 0bc15e47f000e83f81ac5b1aeccaee1bbfaa0d40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 16:18:00 +0100 Subject: [PATCH 0298/2760] target/i386: Register CPUClass:list_cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register x86_cpu_list() as CPUClass:list_cpus callback. Reduce its scope and remove the cpu_list definition. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Message-Id: <20250324185837.46506-3-philmd@linaro.org> --- target/i386/cpu.c | 3 ++- target/i386/cpu.h | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 1f970aa4da..955295fe79 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -6319,7 +6319,7 @@ static void x86_cpu_list_entry(gpointer data, gpointer user_data) } /* list available CPU models and flags */ -void x86_cpu_list(void) +static void x86_cpu_list(void) { int i, j; GSList *list; @@ -8905,6 +8905,7 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data) cc->reset_dump_flags = CPU_DUMP_FPU | CPU_DUMP_CCOP; cc->class_by_name = x86_cpu_class_by_name; + cc->list_cpus = x86_cpu_list; cc->parse_features = x86_cpu_parse_featurestr; cc->dump_state = x86_cpu_dump_state; cc->set_pc = x86_cpu_set_pc; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 9866595cd0..54bf9639f1 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2365,7 +2365,6 @@ int x86_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int x86_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); void x86_cpu_gdb_init(CPUState *cs); -void x86_cpu_list(void); int cpu_x86_support_mca_broadcast(CPUX86State *env); #ifndef CONFIG_USER_ONLY @@ -2559,8 +2558,6 @@ uint64_t cpu_get_tsc(CPUX86State *env); #define TARGET_DEFAULT_CPU_TYPE X86_CPU_TYPE_NAME("qemu32") #endif -#define cpu_list x86_cpu_list - /* MMU modes definitions */ #define MMU_KSMAP64_IDX 0 #define MMU_KSMAP32_IDX 1 From 53c895fbb2d31b0de6a04a6f7e86e17b48324dc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 16:22:41 +0100 Subject: [PATCH 0299/2760] target/ppc: Register CPUClass:list_cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register ppc_cpu_list() as CPUClass:list_cpus callback. Reduce its scope and remove the cpu_list definition. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Message-Id: <20250324185837.46506-4-philmd@linaro.org> --- target/ppc/cpu.h | 4 ---- target/ppc/cpu_init.c | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 3c02f7f7d4..f4cc823c5c 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1610,8 +1610,6 @@ void ppc_store_dawrx1(CPUPPCState *env, uint32_t value); #endif /* !defined(CONFIG_USER_ONLY) */ void ppc_store_msr(CPUPPCState *env, target_ulong value); -void ppc_cpu_list(void); - /* Time-base and decrementer management */ uint64_t cpu_ppc_load_tbl(CPUPPCState *env); uint32_t cpu_ppc_load_tbu(CPUPPCState *env); @@ -1673,8 +1671,6 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn) int ppc_dcr_read(ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp); int ppc_dcr_write(ppc_dcr_t *dcr_env, int dcrn, uint32_t val); -#define cpu_list ppc_cpu_list - /* MMU modes definitions */ #define MMU_USER_IDX 0 static inline int ppc_env_mmu_index(CPUPPCState *env, bool ifetch) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index fde7d71fc6..077991ed53 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7177,7 +7177,7 @@ static void ppc_cpu_list_entry(gpointer data, gpointer user_data) g_free(name); } -void ppc_cpu_list(void) +static void ppc_cpu_list(void) { GSList *list; @@ -7521,6 +7521,7 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data) &pcc->parent_phases); cc->class_by_name = ppc_cpu_class_by_name; + cc->list_cpus = ppc_cpu_list; cc->dump_state = ppc_cpu_dump_state; cc->set_pc = ppc_cpu_set_pc; cc->get_pc = ppc_cpu_get_pc; From 8b54467fb61eb507651ea8be6d786b0f2b0a1524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 16:15:35 +0100 Subject: [PATCH 0300/2760] target/sparc: Register CPUClass:list_cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Register sparc_cpu_list() as CPUClass:list_cpus callback. Reduce its scope and remove the cpu_list definition. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Message-Id: <20250324185837.46506-5-philmd@linaro.org> --- target/sparc/cpu.c | 3 ++- target/sparc/cpu.h | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index f7d231c6f8..174b76f762 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -580,7 +580,7 @@ static void print_features(uint32_t features, const char *prefix) } } -void sparc_cpu_list(void) +static void sparc_cpu_list(void) { unsigned int i; @@ -1057,6 +1057,7 @@ static void sparc_cpu_class_init(ObjectClass *oc, void *data) &scc->parent_phases); cc->class_by_name = sparc_cpu_class_by_name; + cc->list_cpus = sparc_cpu_list, cc->parse_features = sparc_cpu_parse_features; cc->dump_state = sparc_cpu_dump_state; #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 83ac818933..37fd1e066e 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -595,7 +595,6 @@ G_NORETURN void cpu_raise_exception_ra(CPUSPARCState *, int, uintptr_t); /* cpu_init.c */ void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu); -void sparc_cpu_list(void); /* mmu_helper.c */ bool sparc_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, @@ -666,8 +665,6 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr, #define CPU_RESOLVING_TYPE TYPE_SPARC_CPU -#define cpu_list sparc_cpu_list - /* MMU modes definitions */ #if defined (TARGET_SPARC64) #define MMU_USER_IDX 0 From e828206a0f63867deb9eedc194c49cc40a3b249b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 24 Mar 2025 19:29:03 +0100 Subject: [PATCH 0301/2760] target/s390x: Register CPUClass:list_cpus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both s390_cpu_list() and s390_set_qemu_cpu_model() are defined in cpu_models.c, move their declarations in the related "cpu_models.h" header. Use full path to header in s390-virtio-ccw.c file. Register s390_cpu_list() as CPUClass:list_cpus callback and remove the cpu_list definition. Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Eric Farman Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250324185837.46506-6-philmd@linaro.org> --- hw/s390x/s390-virtio-ccw.c | 2 +- target/s390x/cpu.c | 1 + target/s390x/cpu.h | 7 ------- target/s390x/cpu_models.h | 3 +++ 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 52c273b3de..cf5b9974c5 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -35,7 +35,7 @@ #include "hw/s390x/css-bridge.h" #include "hw/s390x/ap-bridge.h" #include "migration/register.h" -#include "cpu_models.h" +#include "target/s390x/cpu_models.h" #include "hw/nmi.h" #include "hw/qdev-properties.h" #include "hw/s390x/tod.h" diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 41cccc1e69..43fc3194bc 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -386,6 +386,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data) &scc->parent_phases); cc->class_by_name = s390_cpu_class_by_name; + cc->list_cpus = s390_cpu_list; cc->dump_state = s390_cpu_dump_state; cc->query_cpu_fast = s390_query_cpu_fast; cc->set_pc = s390_cpu_set_pc; diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 90f64ee20c..d9ca2506e2 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -900,13 +900,6 @@ static inline uint8_t s390_cpu_get_state(S390CPU *cpu) } -/* cpu_models.c */ -void s390_cpu_list(void); -#define cpu_list s390_cpu_list -void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, - const S390FeatInit feat_init); - - /* helper.c */ #define CPU_RESOLVING_TYPE TYPE_S390_CPU diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index 71d4bc2dd4..f701bc0b53 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -113,6 +113,9 @@ static inline uint64_t s390_cpuid_from_cpu_model(const S390CPUModel *model) } S390CPUDef const *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, S390FeatBitmap features); +void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, + const S390FeatInit feat_init); +void s390_cpu_list(void); bool kvm_s390_cpu_models_supported(void); bool kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp); From edbb66bb305b7d7f9b13734d222cc5e333180948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 16:24:29 +0100 Subject: [PATCH 0302/2760] cpus: Remove #ifdef check on cpu_list definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we removed all definitions of cpu_list, the #ifdef check is always true. Remove it, inlining cpu_list(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Thomas Huth Reviewed-by: Richard Henderson Reviewed-by: Zhao Liu Message-Id: <20250324185837.46506-7-philmd@linaro.org> --- cpu-target.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index d139a18f5b..c99d208a7c 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -77,7 +77,6 @@ const char *parse_cpu_option(const char *cpu_option) return cpu_type; } -#ifndef cpu_list static void cpu_list_entry(gpointer data, gpointer user_data) { CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data)); @@ -91,17 +90,6 @@ static void cpu_list_entry(gpointer data, gpointer user_data) } } -static void cpu_list(void) -{ - GSList *list; - - list = object_class_get_list_sorted(TYPE_CPU, false); - qemu_printf("Available CPUs:\n"); - g_slist_foreach(list, cpu_list_entry, NULL); - g_slist_free(list); -} -#endif - void list_cpus(void) { CPUClass *cc = CPU_CLASS(object_class_by_name(CPU_RESOLVING_TYPE)); @@ -109,7 +97,12 @@ void list_cpus(void) if (cc->list_cpus) { cc->list_cpus(); } else { - cpu_list(); + GSList *list; + + list = object_class_get_list_sorted(TYPE_CPU, false); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, cpu_list_entry, NULL); + g_slist_free(list); } } From f605796aae42885034400c83ed6a9b07cd6d6481 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Apr 2025 11:05:27 -0400 Subject: [PATCH 0303/2760] file-posix: probe discard alignment on Linux block devices Populate the pdiscard_alignment block limit so the block layer is able align discard requests correctly. Signed-off-by: Stefan Hajnoczi Message-ID: <20250417150528.76470-2-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/file-posix.c | 67 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 56d1972d15..0d6e12f880 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1276,10 +1276,10 @@ static int get_sysfs_zoned_model(struct stat *st, BlockZoneModel *zoned) } #endif /* defined(CONFIG_BLKZONED) */ +#ifdef CONFIG_LINUX /* * Get a sysfs attribute value as a long integer. */ -#ifdef CONFIG_LINUX static long get_sysfs_long_val(struct stat *st, const char *attribute) { g_autofree char *str = NULL; @@ -1299,6 +1299,30 @@ static long get_sysfs_long_val(struct stat *st, const char *attribute) } return ret; } + +/* + * Get a sysfs attribute value as a uint32_t. + */ +static int get_sysfs_u32_val(struct stat *st, const char *attribute, + uint32_t *u32) +{ + g_autofree char *str = NULL; + const char *end; + unsigned int val; + int ret; + + ret = get_sysfs_str_val(st, attribute, &str); + if (ret < 0) { + return ret; + } + + /* The file is ended with '\n', pass 'end' to accept that. */ + ret = qemu_strtoui(str, &end, 10, &val); + if (ret == 0 && end && *end == '\0') { + *u32 = val; + } + return ret; +} #endif static int hdev_get_max_segments(int fd, struct stat *st) @@ -1318,6 +1342,23 @@ static int hdev_get_max_segments(int fd, struct stat *st) #endif } +/* + * Fills in *dalign with the discard alignment and returns 0 on success, + * -errno otherwise. + */ +static int hdev_get_pdiscard_alignment(struct stat *st, uint32_t *dalign) +{ +#ifdef CONFIG_LINUX + /* + * Note that Linux "discard_granularity" is QEMU "discard_alignment". Linux + * "discard_alignment" is something else. + */ + return get_sysfs_u32_val(st, "discard_granularity", dalign); +#else + return -ENOTSUP; +#endif +} + #if defined(CONFIG_BLKZONED) /* * If the reset_all flag is true, then the wps of zone whose state is @@ -1527,6 +1568,30 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) } } + if (S_ISBLK(st.st_mode)) { + uint32_t dalign = 0; + int ret; + + ret = hdev_get_pdiscard_alignment(&st, &dalign); + if (ret == 0) { + uint32_t ralign = bs->bl.request_alignment; + + /* Probably never happens, but handle it just in case */ + if (dalign < ralign && (ralign % dalign == 0)) { + dalign = ralign; + } + + /* The block layer requires a multiple of request_alignment */ + if (dalign % ralign != 0) { + error_setg(errp, "Invalid pdiscard_alignment limit %u is not a " + "multiple of request_alignment %u", dalign, ralign); + return; + } + + bs->bl.pdiscard_alignment = dalign; + } + } + raw_refresh_zoned_limits(bs, &st, errp); } From 4733cb0833c4b223f92ec0136980eeb5239ecb87 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Apr 2025 11:05:28 -0400 Subject: [PATCH 0304/2760] block/io: skip head/tail requests on EINVAL When guests send misaligned discard requests, the block layer breaks them up into a misaligned head, an aligned main body, and a misaligned tail. The file-posix block driver on Linux returns -EINVAL on misaligned discard requests. This causes bdrv_co_pdiscard() to fail and guests configured with werror=stop will pause. Add a special case for misaligned head/tail requests. Simply continue when EINVAL is encountered so that the aligned main body of the request can be completed and the guest is not paused. This is the best we can do when guest discard limits do not match the host discard limits. Fixes: https://issues.redhat.com/browse/RHEL-86032 Signed-off-by: Stefan Hajnoczi Reviewed-by: Hanna Czenczek Message-ID: <20250417150528.76470-3-stefanha@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/io.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/block/io.c b/block/io.c index 1ba8d1aeea..ccec11386b 100644 --- a/block/io.c +++ b/block/io.c @@ -3109,11 +3109,12 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, /* Invalidate the cached block-status data range if this discard overlaps */ bdrv_bsc_invalidate_range(bs, offset, bytes); - /* Discard is advisory, but some devices track and coalesce + /* + * Discard is advisory, but some devices track and coalesce * unaligned requests, so we must pass everything down rather than - * round here. Still, most devices will just silently ignore - * unaligned requests (by returning -ENOTSUP), so we must fragment - * the request accordingly. */ + * round here. Still, most devices reject unaligned requests with + * -EINVAL or -ENOTSUP, so we must fragment the request accordingly. + */ align = MAX(bs->bl.pdiscard_alignment, bs->bl.request_alignment); assert(align % bs->bl.request_alignment == 0); head = offset % align; @@ -3180,7 +3181,11 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, } } if (ret && ret != -ENOTSUP) { - goto out; + if (ret == -EINVAL && (offset % align != 0 || num % align != 0)) { + /* Silently skip rejected unaligned head/tail requests */ + } else { + goto out; /* bail out */ + } } offset += num; From 6970f91ac7819e186dc0e2efea08120450fb5404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 31 Mar 2025 17:15:47 +0200 Subject: [PATCH 0305/2760] hw/pci-host/designware: Use deposit/extract API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer the safer (less bug-prone) deposit/extract API to access lower/upper 32-bit of 64-bit registers. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Gustavo Romero Message-Id: <20250331152041.74533-3-philmd@linaro.org> --- hw/pci-host/designware.c | 48 ++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 5598d18f47..9c3a5f8d91 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "qemu/module.h" #include "qemu/log.h" +#include "qemu/bitops.h" #include "hw/pci/msi.h" #include "hw/pci/pci_bridge.h" #include "hw/pci/pci_host.h" @@ -162,11 +163,9 @@ designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len) break; case DESIGNWARE_PCIE_MSI_ADDR_LO: - val = root->msi.base; - break; - case DESIGNWARE_PCIE_MSI_ADDR_HI: - val = root->msi.base >> 32; + val = extract64(root->msi.base, + address == DESIGNWARE_PCIE_MSI_ADDR_LO ? 0 : 32, 32); break; case DESIGNWARE_PCIE_MSI_INTR0_ENABLE: @@ -190,19 +189,16 @@ designware_pcie_root_config_read(PCIDevice *d, uint32_t address, int len) break; case DESIGNWARE_PCIE_ATU_LOWER_BASE: - val = viewport->base; - break; - case DESIGNWARE_PCIE_ATU_UPPER_BASE: - val = viewport->base >> 32; + val = extract64(viewport->base, + address == DESIGNWARE_PCIE_ATU_LOWER_BASE ? 0 : 32, 32); break; case DESIGNWARE_PCIE_ATU_LOWER_TARGET: - val = viewport->target; - break; - case DESIGNWARE_PCIE_ATU_UPPER_TARGET: - val = viewport->target >> 32; + val = extract64(viewport->target, + address == DESIGNWARE_PCIE_ATU_LOWER_TARGET ? 0 : 32, + 32); break; case DESIGNWARE_PCIE_ATU_LIMIT: @@ -321,14 +317,10 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, break; case DESIGNWARE_PCIE_MSI_ADDR_LO: - root->msi.base &= 0xFFFFFFFF00000000ULL; - root->msi.base |= val; - designware_pcie_root_update_msi_mapping(root); - break; - case DESIGNWARE_PCIE_MSI_ADDR_HI: - root->msi.base &= 0x00000000FFFFFFFFULL; - root->msi.base |= (uint64_t)val << 32; + root->msi.base = deposit64(root->msi.base, + address == DESIGNWARE_PCIE_MSI_ADDR_LO + ? 0 : 32, 32, val); designware_pcie_root_update_msi_mapping(root); break; @@ -355,23 +347,17 @@ static void designware_pcie_root_config_write(PCIDevice *d, uint32_t address, break; case DESIGNWARE_PCIE_ATU_LOWER_BASE: - viewport->base &= 0xFFFFFFFF00000000ULL; - viewport->base |= val; - break; - case DESIGNWARE_PCIE_ATU_UPPER_BASE: - viewport->base &= 0x00000000FFFFFFFFULL; - viewport->base |= (uint64_t)val << 32; + viewport->base = deposit64(root->msi.base, + address == DESIGNWARE_PCIE_ATU_LOWER_BASE + ? 0 : 32, 32, val); break; case DESIGNWARE_PCIE_ATU_LOWER_TARGET: - viewport->target &= 0xFFFFFFFF00000000ULL; - viewport->target |= val; - break; - case DESIGNWARE_PCIE_ATU_UPPER_TARGET: - viewport->target &= 0x00000000FFFFFFFFULL; - viewport->target |= (uint64_t)val << 32; + viewport->target = deposit64(root->msi.base, + address == DESIGNWARE_PCIE_ATU_LOWER_TARGET + ? 0 : 32, 32, val); break; case DESIGNWARE_PCIE_ATU_LIMIT: From fbb23135d691d20f713bf2318e1cf6575e77cda7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Apr 2025 19:00:39 +0200 Subject: [PATCH 0306/2760] hw/misc/edu: Convert type_init() -> DEFINE_TYPES() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prefer DEFINE_TYPES() macro over type_init() to register QOM types. Initialize the .interfaces struct field as compound literal casted to InterfaceInfo type like the rest of our code base. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250424194905.82506-2-philmd@linaro.org> --- hw/misc/edu.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 504178b4a2..5723ef0ed1 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -429,21 +429,18 @@ static void edu_class_init(ObjectClass *class, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); } -static void pci_edu_register_types(void) -{ - static InterfaceInfo interfaces[] = { - { INTERFACE_CONVENTIONAL_PCI_DEVICE }, - { }, - }; - static const TypeInfo edu_info = { +static const TypeInfo edu_types[] = { + { .name = TYPE_PCI_EDU_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(EduState), .instance_init = edu_instance_init, .class_init = edu_class_init, - .interfaces = interfaces, - }; + .interfaces = (InterfaceInfo[]) { + { INTERFACE_CONVENTIONAL_PCI_DEVICE }, + { }, + }, + } +}; - type_register_static(&edu_info); -} -type_init(pci_edu_register_types) +DEFINE_TYPES(edu_types) From f1fa787b92c52d1034de164d2a26771ff969454e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 9 Feb 2025 22:15:54 +0100 Subject: [PATCH 0307/2760] qom: Have class_base_init() take a const data argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250424194905.82506-3-philmd@linaro.org> --- hw/core/machine.c | 2 +- hw/core/qdev.c | 2 +- hw/pci/pci.c | 2 +- include/qom/object.h | 2 +- qom/object.c | 2 +- rust/qemu-api/src/qom.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index abfcedd4a5..bbff84855a 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1243,7 +1243,7 @@ static void machine_class_init(ObjectClass *oc, void *data) "Memory size configuration"); } -static void machine_class_base_init(ObjectClass *oc, void *data) +static void machine_class_base_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->max_cpus = mc->max_cpus ?: 1; diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 2745b5e092..1e0f47cc84 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -693,7 +693,7 @@ static void device_finalize(Object *obj) g_free(dev->id); } -static void device_class_base_init(ObjectClass *class, void *data) +static void device_class_base_init(ObjectClass *class, const void *data) { DeviceClass *klass = DEVICE_CLASS(class); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 2844ec5556..475b97c649 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2809,7 +2809,7 @@ static void pci_device_class_init(ObjectClass *klass, void *data) "access to indirect DMA memory"); } -static void pci_device_class_base_init(ObjectClass *klass, void *data) +static void pci_device_class_base_init(ObjectClass *klass, const void *data) { if (!object_class_is_abstract(klass)) { ObjectClass *conventional = diff --git a/include/qom/object.h b/include/qom/object.h index 9192265db7..7bb14ca706 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -487,7 +487,7 @@ struct TypeInfo size_t class_size; void (*class_init)(ObjectClass *klass, void *data); - void (*class_base_init)(ObjectClass *klass, void *data); + void (*class_base_init)(ObjectClass *klass, const void *data); void *class_data; InterfaceInfo *interfaces; diff --git a/qom/object.c b/qom/object.c index 01618d06bd..dfd59502d1 100644 --- a/qom/object.c +++ b/qom/object.c @@ -55,7 +55,7 @@ struct TypeImpl size_t instance_align; void (*class_init)(ObjectClass *klass, void *data); - void (*class_base_init)(ObjectClass *klass, void *data); + void (*class_base_init)(ObjectClass *klass, const void *data); void *class_data; diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 34d7bc0ef9..03fe6247ff 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -492,7 +492,7 @@ pub trait ObjectImpl: ObjectType + IsA { /// the effects of copying the contents of the parent's class struct /// to the descendants. const CLASS_BASE_INIT: Option< - unsafe extern "C" fn(klass: *mut ObjectClass, data: *mut c_void), + unsafe extern "C" fn(klass: *mut ObjectClass, data: *const c_void), > = None; const TYPE_INFO: TypeInfo = TypeInfo { From 12d1a768bdfea6e27a3a829228840d72507613a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 9 Feb 2025 23:47:35 +0100 Subject: [PATCH 0308/2760] qom: Have class_init() take a const data argument MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mechanical change using gsed, then style manually adapted to pass checkpatch.pl script. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250424194905.82506-4-philmd@linaro.org> --- accel/hvf/hvf-accel-ops.c | 4 +- accel/kvm/kvm-accel-ops.c | 2 +- accel/kvm/kvm-all.c | 2 +- accel/qtest/qtest.c | 4 +- accel/tcg/tcg-accel-ops.c | 2 +- accel/tcg/tcg-all.c | 2 +- accel/xen/xen-all.c | 4 +- authz/list.c | 2 +- authz/listfile.c | 2 +- authz/pamacct.c | 2 +- authz/simple.c | 2 +- backends/confidential-guest-support.c | 3 +- backends/cryptodev-builtin.c | 2 +- backends/cryptodev-lkcf.c | 2 +- backends/cryptodev-vhost-user.c | 2 +- backends/cryptodev.c | 2 +- backends/dbus-vmstate.c | 2 +- backends/host_iommu_device.c | 2 +- backends/hostmem-epc.c | 2 +- backends/hostmem-file.c | 2 +- backends/hostmem-memfd.c | 2 +- backends/hostmem-ram.c | 2 +- backends/hostmem-shm.c | 2 +- backends/hostmem.c | 2 +- backends/iommufd.c | 4 +- backends/rng-builtin.c | 2 +- backends/rng-egd.c | 2 +- backends/rng-random.c | 2 +- backends/rng.c | 2 +- backends/tpm/tpm_emulator.c | 2 +- backends/tpm/tpm_passthrough.c | 2 +- backends/vhost-user.c | 2 +- block/throttle-groups.c | 3 +- chardev/baum.c | 2 +- chardev/char-console.c | 2 +- chardev/char-fd.c | 2 +- chardev/char-file.c | 2 +- chardev/char-hub.c | 2 +- chardev/char-mux.c | 2 +- chardev/char-null.c | 2 +- chardev/char-parallel.c | 2 +- chardev/char-pipe.c | 2 +- chardev/char-pty.c | 2 +- chardev/char-ringbuf.c | 2 +- chardev/char-serial.c | 2 +- chardev/char-socket.c | 2 +- chardev/char-stdio.c | 2 +- chardev/char-udp.c | 2 +- chardev/char-win-stdio.c | 2 +- chardev/char-win.c | 2 +- chardev/char.c | 2 +- chardev/msmouse.c | 2 +- chardev/spice.c | 6 +- chardev/testdev.c | 2 +- chardev/wctablet.c | 2 +- crypto/secret.c | 2 +- crypto/secret_common.c | 2 +- crypto/secret_keyring.c | 2 +- crypto/tls-cipher-suites.c | 3 +- crypto/tlscreds.c | 2 +- crypto/tlscredsanon.c | 2 +- crypto/tlscredspsk.c | 2 +- crypto/tlscredsx509.c | 2 +- docs/devel/qom.rst | 8 +- docs/devel/reset.rst | 2 +- docs/devel/virtio-backends.rst | 2 +- event-loop-base.c | 3 +- gdbstub/system.c | 2 +- hw/9pfs/virtio-9p-device.c | 2 +- hw/acpi/erst.c | 2 +- hw/acpi/generic_event_device.c | 2 +- hw/acpi/pci.c | 4 +- hw/acpi/piix4.c | 2 +- hw/acpi/vmclock.c | 2 +- hw/acpi/vmgenid.c | 2 +- hw/adc/aspeed_adc.c | 10 +-- hw/adc/npcm7xx_adc.c | 2 +- hw/adc/stm32f2xx_adc.c | 2 +- hw/adc/zynq-xadc.c | 2 +- hw/alpha/typhoon.c | 2 +- hw/arm/allwinner-a10.c | 2 +- hw/arm/allwinner-h3.c | 2 +- hw/arm/allwinner-r40.c | 2 +- hw/arm/armsse.c | 2 +- hw/arm/armv7m.c | 4 +- hw/arm/aspeed.c | 59 +++++++----- hw/arm/aspeed_ast10x0.c | 2 +- hw/arm/aspeed_ast2400.c | 4 +- hw/arm/aspeed_ast2600.c | 2 +- hw/arm/aspeed_ast27x0.c | 4 +- hw/arm/aspeed_soc_common.c | 2 +- hw/arm/b-l475e-iot01a.c | 2 +- hw/arm/bcm2835_peripherals.c | 2 +- hw/arm/bcm2836.c | 8 +- hw/arm/bcm2838.c | 2 +- hw/arm/bcm2838_peripherals.c | 2 +- hw/arm/collie.c | 2 +- hw/arm/digic.c | 2 +- hw/arm/exynos4210.c | 2 +- hw/arm/exynos4_boards.c | 4 +- hw/arm/fby35.c | 2 +- hw/arm/fsl-imx25.c | 2 +- hw/arm/fsl-imx31.c | 2 +- hw/arm/fsl-imx6.c | 2 +- hw/arm/fsl-imx6ul.c | 2 +- hw/arm/fsl-imx7.c | 2 +- hw/arm/fsl-imx8mp.c | 2 +- hw/arm/highbank.c | 6 +- hw/arm/integratorcp.c | 6 +- hw/arm/microbit.c | 2 +- hw/arm/mps2-tz.c | 10 +-- hw/arm/mps2.c | 10 +-- hw/arm/mps3r.c | 4 +- hw/arm/msf2-soc.c | 2 +- hw/arm/musca.c | 6 +- hw/arm/musicpal.c | 14 +-- hw/arm/npcm7xx.c | 6 +- hw/arm/npcm7xx_boards.c | 12 +-- hw/arm/npcm8xx.c | 2 +- hw/arm/npcm8xx_boards.c | 4 +- hw/arm/nrf51_soc.c | 2 +- hw/arm/omap_sx1.c | 4 +- hw/arm/raspi.c | 10 +-- hw/arm/raspi4b.c | 2 +- hw/arm/realview.c | 8 +- hw/arm/sbsa-ref.c | 2 +- hw/arm/smmu-common.c | 2 +- hw/arm/smmuv3.c | 4 +- hw/arm/stellaris.c | 10 +-- hw/arm/stm32f100_soc.c | 2 +- hw/arm/stm32f205_soc.c | 2 +- hw/arm/stm32f405_soc.c | 2 +- hw/arm/stm32l4x5_soc.c | 8 +- hw/arm/strongarm.c | 13 +-- hw/arm/versatilepb.c | 6 +- hw/arm/vexpress.c | 6 +- hw/arm/virt.c | 4 +- hw/arm/xen-pvh.c | 2 +- hw/arm/xilinx_zynq.c | 2 +- hw/arm/xlnx-versal-virt.c | 2 +- hw/arm/xlnx-versal.c | 2 +- hw/arm/xlnx-zcu102.c | 2 +- hw/arm/xlnx-zynqmp.c | 2 +- hw/audio/ac97.c | 2 +- hw/audio/adlib.c | 2 +- hw/audio/asc.c | 2 +- hw/audio/cs4231.c | 2 +- hw/audio/cs4231a.c | 2 +- hw/audio/es1370.c | 2 +- hw/audio/gus.c | 2 +- hw/audio/hda-codec.c | 8 +- hw/audio/intel-hda.c | 8 +- hw/audio/marvell_88w8618.c | 2 +- hw/audio/pcspk.c | 2 +- hw/audio/pl041.c | 2 +- hw/audio/sb16.c | 2 +- hw/audio/via-ac97.c | 4 +- hw/audio/virtio-snd-pci.c | 2 +- hw/audio/virtio-snd.c | 2 +- hw/audio/wm8750.c | 2 +- hw/avr/arduino.c | 10 +-- hw/avr/atmega.c | 10 +-- hw/block/fdc-isa.c | 2 +- hw/block/fdc-sysbus.c | 6 +- hw/block/fdc.c | 2 +- hw/block/m25p80.c | 4 +- hw/block/nand.c | 2 +- hw/block/pflash_cfi01.c | 2 +- hw/block/pflash_cfi02.c | 2 +- hw/block/swim.c | 4 +- hw/block/vhost-user-blk.c | 2 +- hw/block/virtio-blk.c | 2 +- hw/block/xen-block.c | 6 +- hw/char/avr_usart.c | 2 +- hw/char/bcm2835_aux.c | 2 +- hw/char/cadence_uart.c | 2 +- hw/char/cmsdk-apb-uart.c | 2 +- hw/char/debugcon.c | 2 +- hw/char/digic-uart.c | 2 +- hw/char/diva-gsp.c | 4 +- hw/char/escc.c | 2 +- hw/char/exynos4210_uart.c | 2 +- hw/char/goldfish_tty.c | 2 +- hw/char/grlib_apbuart.c | 2 +- hw/char/ibex_uart.c | 2 +- hw/char/imx_serial.c | 2 +- hw/char/ipoctal232.c | 2 +- hw/char/mcf_uart.c | 2 +- hw/char/mchp_pfsoc_mmuart.c | 2 +- hw/char/nrf51_uart.c | 2 +- hw/char/parallel.c | 2 +- hw/char/pl011.c | 2 +- hw/char/renesas_sci.c | 2 +- hw/char/sclpconsole-lm.c | 2 +- hw/char/sclpconsole.c | 2 +- hw/char/serial-isa.c | 2 +- hw/char/serial-mm.c | 2 +- hw/char/serial-pci-multi.c | 6 +- hw/char/serial-pci.c | 2 +- hw/char/serial.c | 2 +- hw/char/sh_serial.c | 2 +- hw/char/shakti_uart.c | 2 +- hw/char/sifive_uart.c | 2 +- hw/char/spapr_vty.c | 2 +- hw/char/stm32f2xx_usart.c | 2 +- hw/char/stm32l4x5_usart.c | 9 +- hw/char/terminal3270.c | 2 +- hw/char/virtio-console.c | 4 +- hw/char/virtio-serial-bus.c | 6 +- hw/char/xen_console.c | 2 +- hw/char/xilinx_uartlite.c | 2 +- hw/core/bus.c | 2 +- hw/core/clock.c | 2 +- hw/core/cpu-common.c | 2 +- hw/core/generic-loader.c | 2 +- hw/core/guest-loader.c | 2 +- hw/core/machine.c | 2 +- hw/core/or-irq.c | 2 +- hw/core/platform-bus.c | 2 +- hw/core/qdev.c | 2 +- hw/core/register.c | 2 +- hw/core/reset.c | 2 +- hw/core/resetcontainer.c | 3 +- hw/core/split-irq.c | 2 +- hw/core/sysbus.c | 7 +- hw/cpu/a15mpcore.c | 2 +- hw/cpu/a9mpcore.c | 2 +- hw/cpu/arm11mpcore.c | 2 +- hw/cpu/cluster.c | 2 +- hw/cpu/core.c | 2 +- hw/cpu/realview_mpcore.c | 2 +- hw/cxl/switch-mailbox-cci.c | 2 +- hw/display/apple-gfx-mmio.m | 2 +- hw/display/apple-gfx-pci.m | 2 +- hw/display/artist.c | 2 +- hw/display/ati.c | 2 +- hw/display/bcm2835_fb.c | 2 +- hw/display/bochs-display.c | 2 +- hw/display/cg3.c | 2 +- hw/display/cirrus_vga.c | 2 +- hw/display/cirrus_vga_isa.c | 2 +- hw/display/dm163.c | 2 +- hw/display/dpcd.c | 2 +- hw/display/exynos4210_fimd.c | 2 +- hw/display/g364fb.c | 2 +- hw/display/i2c-ddc.c | 2 +- hw/display/jazz_led.c | 2 +- hw/display/macfb.c | 4 +- hw/display/next-fb.c | 2 +- hw/display/pl110.c | 2 +- hw/display/qxl.c | 6 +- hw/display/ramfb-standalone.c | 2 +- hw/display/sii9022.c | 2 +- hw/display/sm501.c | 4 +- hw/display/ssd0303.c | 2 +- hw/display/ssd0323.c | 2 +- hw/display/tcx.c | 2 +- hw/display/vga-isa.c | 2 +- hw/display/vga-mmio.c | 2 +- hw/display/vga-pci.c | 6 +- hw/display/vhost-user-gpu.c | 2 +- hw/display/virtio-gpu-base.c | 2 +- hw/display/virtio-gpu-gl.c | 2 +- hw/display/virtio-gpu-pci.c | 2 +- hw/display/virtio-gpu-rutabaga.c | 2 +- hw/display/virtio-gpu.c | 2 +- hw/display/virtio-vga.c | 2 +- hw/display/vmware_vga.c | 2 +- hw/display/xlnx_dp.c | 2 +- hw/dma/bcm2835_dma.c | 2 +- hw/dma/i82374.c | 2 +- hw/dma/i8257.c | 2 +- hw/dma/pl080.c | 2 +- hw/dma/pl330.c | 2 +- hw/dma/rc4030.c | 4 +- hw/dma/sifive_pdma.c | 2 +- hw/dma/sparc32_dma.c | 10 ++- hw/dma/xilinx_axidma.c | 5 +- hw/dma/xlnx-zdma.c | 2 +- hw/dma/xlnx-zynq-devcfg.c | 2 +- hw/dma/xlnx_csu_dma.c | 2 +- hw/dma/xlnx_dpdma.c | 2 +- hw/fsi/aspeed_apb2opb.c | 2 +- hw/fsi/cfam.c | 2 +- hw/fsi/fsi-master.c | 2 +- hw/fsi/fsi.c | 2 +- hw/fsi/lbus.c | 2 +- hw/gpio/aspeed_gpio.c | 16 ++-- hw/gpio/bcm2835_gpio.c | 2 +- hw/gpio/bcm2838_gpio.c | 2 +- hw/gpio/gpio_key.c | 2 +- hw/gpio/imx_gpio.c | 2 +- hw/gpio/mpc8xxx.c | 2 +- hw/gpio/npcm7xx_gpio.c | 2 +- hw/gpio/nrf51_gpio.c | 2 +- hw/gpio/omap_gpio.c | 2 +- hw/gpio/pca9552.c | 4 +- hw/gpio/pca9554.c | 2 +- hw/gpio/pcf8574.c | 2 +- hw/gpio/pl061.c | 2 +- hw/gpio/sifive_gpio.c | 2 +- hw/gpio/stm32l4x5_gpio.c | 2 +- hw/gpio/zaurus.c | 2 +- hw/hppa/machine.c | 4 +- hw/hyperv/hv-balloon.c | 2 +- hw/hyperv/hyperv.c | 2 +- hw/hyperv/hyperv_testdev.c | 2 +- hw/hyperv/syndbg.c | 2 +- hw/hyperv/vmbus.c | 6 +- hw/i2c/allwinner-i2c.c | 2 +- hw/i2c/aspeed_i2c.c | 17 ++-- hw/i2c/bcm2835_i2c.c | 2 +- hw/i2c/bitbang_i2c.c | 2 +- hw/i2c/core.c | 2 +- hw/i2c/exynos4210_i2c.c | 2 +- hw/i2c/i2c_mux_pca954x.c | 6 +- hw/i2c/imx_i2c.c | 2 +- hw/i2c/microbit_i2c.c | 2 +- hw/i2c/mpc_i2c.c | 2 +- hw/i2c/npcm7xx_smbus.c | 2 +- hw/i2c/omap_i2c.c | 2 +- hw/i2c/pmbus_device.c | 2 +- hw/i2c/ppc4xx_i2c.c | 2 +- hw/i2c/smbus_eeprom.c | 2 +- hw/i2c/smbus_ich9.c | 2 +- hw/i2c/smbus_slave.c | 2 +- hw/i386/amd_iommu.c | 7 +- hw/i386/intel_iommu.c | 4 +- hw/i386/kvm/apic.c | 2 +- hw/i386/kvm/clock.c | 2 +- hw/i386/kvm/i8254.c | 2 +- hw/i386/kvm/i8259.c | 2 +- hw/i386/kvm/ioapic.c | 2 +- hw/i386/kvm/xen_evtchn.c | 2 +- hw/i386/kvm/xen_gnttab.c | 2 +- hw/i386/kvm/xen_overlay.c | 2 +- hw/i386/kvm/xen_primary_console.c | 2 +- hw/i386/kvm/xen_xenstore.c | 2 +- hw/i386/microvm.c | 2 +- hw/i386/nitro_enclave.c | 2 +- hw/i386/pc.c | 2 +- hw/i386/port92.c | 2 +- hw/i386/sgx-epc.c | 2 +- hw/i386/vapic.c | 2 +- hw/i386/vmmouse.c | 2 +- hw/i386/vmport.c | 2 +- hw/i386/x86-iommu.c | 2 +- hw/i386/x86.c | 2 +- hw/i386/xen/xen-pvh.c | 2 +- hw/i386/xen/xen_apic.c | 2 +- hw/i386/xen/xen_platform.c | 2 +- hw/i386/xen/xen_pvdevice.c | 2 +- hw/ide/ahci-allwinner.c | 2 +- hw/ide/ahci-sysbus.c | 2 +- hw/ide/cf.c | 2 +- hw/ide/cmd646.c | 2 +- hw/ide/ich.c | 2 +- hw/ide/ide-bus.c | 2 +- hw/ide/ide-dev.c | 6 +- hw/ide/isa.c | 2 +- hw/ide/macio.c | 2 +- hw/ide/mmio.c | 2 +- hw/ide/piix.c | 4 +- hw/ide/sii3112.c | 2 +- hw/ide/via.c | 2 +- hw/input/adb-kbd.c | 2 +- hw/input/adb-mouse.c | 2 +- hw/input/adb.c | 4 +- hw/input/lasips2.c | 8 +- hw/input/pckbd.c | 4 +- hw/input/pl050.c | 6 +- hw/input/ps2.c | 6 +- hw/input/stellaris_gamepad.c | 2 +- hw/input/virtio-input-hid.c | 6 +- hw/input/virtio-input-host.c | 2 +- hw/input/virtio-input.c | 2 +- hw/intc/allwinner-a10-pic.c | 2 +- hw/intc/apic.c | 2 +- hw/intc/apic_common.c | 2 +- hw/intc/arm_gic.c | 2 +- hw/intc/arm_gic_common.c | 2 +- hw/intc/arm_gic_kvm.c | 2 +- hw/intc/arm_gicv2m.c | 2 +- hw/intc/arm_gicv3.c | 2 +- hw/intc/arm_gicv3_common.c | 2 +- hw/intc/arm_gicv3_its.c | 2 +- hw/intc/arm_gicv3_its_common.c | 2 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_kvm.c | 2 +- hw/intc/armv7m_nvic.c | 2 +- hw/intc/aspeed_intc.c | 6 +- hw/intc/aspeed_vic.c | 2 +- hw/intc/bcm2835_ic.c | 2 +- hw/intc/bcm2836_control.c | 2 +- hw/intc/exynos4210_combiner.c | 2 +- hw/intc/exynos4210_gic.c | 2 +- hw/intc/goldfish_pic.c | 2 +- hw/intc/grlib_irqmp.c | 2 +- hw/intc/heathrow_pic.c | 2 +- hw/intc/i8259.c | 2 +- hw/intc/i8259_common.c | 2 +- hw/intc/imx_avic.c | 2 +- hw/intc/imx_gpcv2.c | 2 +- hw/intc/ioapic.c | 2 +- hw/intc/ioapic_common.c | 2 +- hw/intc/loongarch_extioi.c | 2 +- hw/intc/loongarch_extioi_common.c | 3 +- hw/intc/loongarch_ipi.c | 2 +- hw/intc/loongarch_pch_msi.c | 2 +- hw/intc/loongarch_pch_pic.c | 2 +- hw/intc/loongarch_pic_common.c | 3 +- hw/intc/loongson_ipi.c | 2 +- hw/intc/loongson_ipi_common.c | 2 +- hw/intc/m68k_irqc.c | 2 +- hw/intc/mips_gic.c | 2 +- hw/intc/omap_intc.c | 2 +- hw/intc/ompic.c | 2 +- hw/intc/openpic.c | 2 +- hw/intc/openpic_kvm.c | 2 +- hw/intc/pl190.c | 2 +- hw/intc/pnv_xive.c | 2 +- hw/intc/pnv_xive2.c | 2 +- hw/intc/ppc-uic.c | 2 +- hw/intc/realview_gic.c | 2 +- hw/intc/riscv_aclint.c | 4 +- hw/intc/riscv_aplic.c | 2 +- hw/intc/riscv_imsic.c | 2 +- hw/intc/rx_icu.c | 2 +- hw/intc/s390_flic.c | 4 +- hw/intc/s390_flic_kvm.c | 2 +- hw/intc/sifive_plic.c | 2 +- hw/intc/slavio_intctl.c | 2 +- hw/intc/spapr_xive.c | 2 +- hw/intc/xics.c | 4 +- hw/intc/xics_pnv.c | 2 +- hw/intc/xics_spapr.c | 2 +- hw/intc/xilinx_intc.c | 2 +- hw/intc/xive.c | 8 +- hw/intc/xive2.c | 4 +- hw/intc/xlnx-pmu-iomod-intc.c | 2 +- hw/intc/xlnx-zynqmp-ipi.c | 2 +- hw/ipack/ipack.c | 2 +- hw/ipack/tpci200.c | 2 +- hw/ipmi/ipmi.c | 4 +- hw/ipmi/ipmi_bmc_extern.c | 2 +- hw/ipmi/ipmi_bmc_sim.c | 2 +- hw/ipmi/isa_ipmi_bt.c | 2 +- hw/ipmi/isa_ipmi_kcs.c | 2 +- hw/ipmi/pci_ipmi_bt.c | 2 +- hw/ipmi/pci_ipmi_kcs.c | 2 +- hw/ipmi/smbus_ipmi.c | 2 +- hw/isa/fdc37m81x-superio.c | 2 +- hw/isa/i82378.c | 2 +- hw/isa/isa-bus.c | 6 +- hw/isa/isa-superio.c | 2 +- hw/isa/lpc_ich9.c | 2 +- hw/isa/pc87312.c | 2 +- hw/isa/piix.c | 6 +- hw/isa/smc37c669-superio.c | 2 +- hw/isa/vt82c686.c | 12 +-- hw/loongarch/virt.c | 2 +- hw/m68k/mcf5206.c | 2 +- hw/m68k/mcf_intc.c | 2 +- hw/m68k/next-cube.c | 8 +- hw/m68k/next-kbd.c | 2 +- hw/m68k/q800-glue.c | 2 +- hw/m68k/q800.c | 2 +- hw/m68k/virt.c | 4 +- hw/mem/cxl_type3.c | 2 +- hw/mem/npcm7xx_mc.c | 2 +- hw/mem/nvdimm.c | 2 +- hw/mem/pc-dimm.c | 2 +- hw/mem/sparse-mem.c | 2 +- hw/microblaze/petalogix_s3adsp1800_mmu.c | 3 +- hw/microblaze/xlnx-zynqmp-pmu.c | 2 +- hw/mips/cps.c | 2 +- hw/mips/jazz.c | 4 +- hw/mips/loongson3_virt.c | 2 +- hw/misc/a9scu.c | 2 +- hw/misc/allwinner-a10-ccm.c | 2 +- hw/misc/allwinner-a10-dramc.c | 2 +- hw/misc/allwinner-cpucfg.c | 2 +- hw/misc/allwinner-h3-ccu.c | 2 +- hw/misc/allwinner-h3-dramc.c | 2 +- hw/misc/allwinner-h3-sysctrl.c | 3 +- hw/misc/allwinner-r40-ccu.c | 2 +- hw/misc/allwinner-r40-dramc.c | 2 +- hw/misc/allwinner-sid.c | 2 +- hw/misc/allwinner-sramc.c | 4 +- hw/misc/applesmc.c | 2 +- hw/misc/arm11scu.c | 2 +- hw/misc/arm_l2x0.c | 2 +- hw/misc/arm_sysctl.c | 2 +- hw/misc/armsse-cpu-pwrctrl.c | 2 +- hw/misc/armsse-cpuid.c | 2 +- hw/misc/armsse-mhu.c | 2 +- hw/misc/armv7m_ras.c | 2 +- hw/misc/aspeed_hace.c | 12 +-- hw/misc/aspeed_i3c.c | 4 +- hw/misc/aspeed_lpc.c | 2 +- hw/misc/aspeed_peci.c | 2 +- hw/misc/aspeed_sbc.c | 4 +- hw/misc/aspeed_scu.c | 14 +-- hw/misc/aspeed_sdmc.c | 10 +-- hw/misc/aspeed_sli.c | 6 +- hw/misc/aspeed_xdma.c | 8 +- hw/misc/auxbus.c | 6 +- hw/misc/avr_power.c | 2 +- hw/misc/axp2xx.c | 6 +- hw/misc/bcm2835_cprman.c | 10 +-- hw/misc/bcm2835_mbox.c | 2 +- hw/misc/bcm2835_mphi.c | 2 +- hw/misc/bcm2835_powermgt.c | 2 +- hw/misc/bcm2835_property.c | 2 +- hw/misc/bcm2835_rng.c | 2 +- hw/misc/bcm2835_thermal.c | 2 +- hw/misc/debugexit.c | 2 +- hw/misc/djmemc.c | 2 +- hw/misc/eccmemctl.c | 2 +- hw/misc/edu.c | 2 +- hw/misc/empty_slot.c | 2 +- hw/misc/exynos4210_clk.c | 2 +- hw/misc/exynos4210_pmu.c | 2 +- hw/misc/exynos4210_rng.c | 2 +- hw/misc/grlib_ahb_apb_pnp.c | 4 +- hw/misc/i2c-echo.c | 2 +- hw/misc/imx25_ccm.c | 2 +- hw/misc/imx31_ccm.c | 2 +- hw/misc/imx6_ccm.c | 2 +- hw/misc/imx6_src.c | 2 +- hw/misc/imx6ul_ccm.c | 2 +- hw/misc/imx7_ccm.c | 4 +- hw/misc/imx7_gpr.c | 2 +- hw/misc/imx7_snvs.c | 2 +- hw/misc/imx7_src.c | 2 +- hw/misc/imx8mp_analog.c | 2 +- hw/misc/imx8mp_ccm.c | 2 +- hw/misc/imx_rngc.c | 2 +- hw/misc/iosb.c | 2 +- hw/misc/iotkit-secctl.c | 2 +- hw/misc/iotkit-sysctl.c | 2 +- hw/misc/iotkit-sysinfo.c | 2 +- hw/misc/ivshmem-flat.c | 2 +- hw/misc/ivshmem-pci.c | 6 +- hw/misc/lasi.c | 2 +- hw/misc/led.c | 2 +- hw/misc/mac_via.c | 4 +- hw/misc/macio/cuda.c | 4 +- hw/misc/macio/gpio.c | 2 +- hw/misc/macio/mac_dbdma.c | 2 +- hw/misc/macio/macio.c | 6 +- hw/misc/macio/pmu.c | 4 +- hw/misc/mchp_pfsoc_dmc.c | 5 +- hw/misc/mchp_pfsoc_ioscb.c | 2 +- hw/misc/mchp_pfsoc_sysreg.c | 2 +- hw/misc/mips_cmgcr.c | 2 +- hw/misc/mips_cpc.c | 2 +- hw/misc/mips_itu.c | 2 +- hw/misc/mos6522.c | 2 +- hw/misc/mps2-fpgaio.c | 2 +- hw/misc/mps2-scc.c | 2 +- hw/misc/msf2-sysreg.c | 2 +- hw/misc/npcm7xx_mft.c | 2 +- hw/misc/npcm7xx_pwm.c | 2 +- hw/misc/npcm7xx_rng.c | 2 +- hw/misc/npcm_clk.c | 12 +-- hw/misc/npcm_gcr.c | 6 +- hw/misc/nrf51_rng.c | 2 +- hw/misc/pc-testdev.c | 2 +- hw/misc/pci-testdev.c | 2 +- hw/misc/pvpanic-isa.c | 2 +- hw/misc/pvpanic-mmio.c | 2 +- hw/misc/pvpanic-pci.c | 2 +- hw/misc/sbsa_ec.c | 2 +- hw/misc/sifive_e_aon.c | 2 +- hw/misc/sifive_u_otp.c | 2 +- hw/misc/sifive_u_prci.c | 2 +- hw/misc/slavio_misc.c | 2 +- hw/misc/stm32_rcc.c | 2 +- hw/misc/stm32f2xx_syscfg.c | 2 +- hw/misc/stm32f4xx_exti.c | 2 +- hw/misc/stm32f4xx_syscfg.c | 2 +- hw/misc/stm32l4x5_exti.c | 2 +- hw/misc/stm32l4x5_rcc.c | 6 +- hw/misc/stm32l4x5_syscfg.c | 2 +- hw/misc/tz-mpc.c | 4 +- hw/misc/tz-msc.c | 2 +- hw/misc/tz-ppc.c | 2 +- hw/misc/unimp.c | 2 +- hw/misc/virt_ctrl.c | 2 +- hw/misc/vmcoreinfo.c | 2 +- hw/misc/xlnx-versal-cframe-reg.c | 4 +- hw/misc/xlnx-versal-cfu.c | 6 +- hw/misc/xlnx-versal-crl.c | 2 +- hw/misc/xlnx-versal-pmc-iou-slcr.c | 3 +- hw/misc/xlnx-versal-trng.c | 2 +- hw/misc/xlnx-versal-xramc.c | 2 +- hw/misc/xlnx-zynqmp-apu-ctrl.c | 2 +- hw/misc/xlnx-zynqmp-crf.c | 2 +- hw/misc/zynq_slcr.c | 2 +- hw/net/allwinner-sun8i-emac.c | 3 +- hw/net/allwinner_emac.c | 2 +- hw/net/cadence_gem.c | 2 +- hw/net/can/can_kvaser_pci.c | 2 +- hw/net/can/can_mioe3680_pci.c | 2 +- hw/net/can/can_pcm3680_pci.c | 2 +- hw/net/can/ctucan_pci.c | 2 +- hw/net/can/xlnx-versal-canfd.c | 2 +- hw/net/can/xlnx-zynqmp-can.c | 2 +- hw/net/dp8393x.c | 2 +- hw/net/e1000.c | 2 +- hw/net/e1000e.c | 2 +- hw/net/eepro100.c | 2 +- hw/net/fsl_etsec/etsec.c | 2 +- hw/net/ftgmac100.c | 4 +- hw/net/igb.c | 2 +- hw/net/igbvf.c | 2 +- hw/net/imx_fec.c | 2 +- hw/net/lan9118.c | 2 +- hw/net/lan9118_phy.c | 2 +- hw/net/lance.c | 2 +- hw/net/lasi_i82596.c | 2 +- hw/net/mcf_fec.c | 2 +- hw/net/mipsnet.c | 2 +- hw/net/msf2-emac.c | 2 +- hw/net/mv88w8618_eth.c | 2 +- hw/net/ne2000-isa.c | 2 +- hw/net/ne2000-pci.c | 2 +- hw/net/npcm7xx_emc.c | 2 +- hw/net/npcm_gmac.c | 2 +- hw/net/npcm_pcs.c | 2 +- hw/net/opencores_eth.c | 2 +- hw/net/pcnet-pci.c | 2 +- hw/net/rocker/rocker.c | 2 +- hw/net/rtl8139.c | 2 +- hw/net/smc91c111.c | 2 +- hw/net/spapr_llan.c | 2 +- hw/net/stellaris_enet.c | 2 +- hw/net/sungem.c | 2 +- hw/net/sunhme.c | 2 +- hw/net/tulip.c | 2 +- hw/net/virtio-net.c | 2 +- hw/net/vmxnet3.c | 2 +- hw/net/xen_nic.c | 2 +- hw/net/xgmac.c | 2 +- hw/net/xilinx_axienet.c | 7 +- hw/net/xilinx_ethlite.c | 2 +- hw/nubus/mac-nubus-bridge.c | 2 +- hw/nubus/nubus-bridge.c | 2 +- hw/nubus/nubus-bus.c | 2 +- hw/nubus/nubus-device.c | 2 +- hw/nubus/nubus-virtio-mmio.c | 2 +- hw/nvme/ctrl.c | 2 +- hw/nvme/ns.c | 2 +- hw/nvme/subsys.c | 2 +- hw/nvram/bcm2835_otp.c | 2 +- hw/nvram/ds1225y.c | 2 +- hw/nvram/eeprom_at24c.c | 2 +- hw/nvram/fw_cfg.c | 6 +- hw/nvram/mac_nvram.c | 2 +- hw/nvram/npcm7xx_otp.c | 6 +- hw/nvram/nrf51_nvm.c | 2 +- hw/nvram/spapr_nvram.c | 2 +- hw/nvram/xlnx-bbram.c | 2 +- hw/nvram/xlnx-efuse.c | 2 +- hw/nvram/xlnx-versal-efuse-cache.c | 2 +- hw/nvram/xlnx-versal-efuse-ctrl.c | 2 +- hw/nvram/xlnx-zynqmp-efuse.c | 2 +- hw/openrisc/openrisc_sim.c | 2 +- hw/openrisc/virt.c | 2 +- hw/pci-bridge/cxl_downstream.c | 2 +- hw/pci-bridge/cxl_root_port.c | 2 +- hw/pci-bridge/cxl_upstream.c | 2 +- hw/pci-bridge/gen_pcie_root_port.c | 2 +- hw/pci-bridge/i82801b11.c | 2 +- hw/pci-bridge/ioh3420.c | 2 +- hw/pci-bridge/pci_bridge_dev.c | 4 +- hw/pci-bridge/pci_expander_bridge.c | 12 +-- hw/pci-bridge/pcie_pci_bridge.c | 2 +- hw/pci-bridge/pcie_root_port.c | 2 +- hw/pci-bridge/simba.c | 2 +- hw/pci-bridge/xio3130_downstream.c | 2 +- hw/pci-bridge/xio3130_upstream.c | 2 +- hw/pci-host/articia.c | 6 +- hw/pci-host/astro.c | 6 +- hw/pci-host/bonito.c | 4 +- hw/pci-host/designware.c | 9 +- hw/pci-host/dino.c | 2 +- hw/pci-host/fsl_imx8m_phy.c | 2 +- hw/pci-host/gpex.c | 4 +- hw/pci-host/grackle.c | 4 +- hw/pci-host/gt64120.c | 4 +- hw/pci-host/i440fx.c | 4 +- hw/pci-host/mv64361.c | 6 +- hw/pci-host/pnv_phb.c | 4 +- hw/pci-host/pnv_phb3.c | 6 +- hw/pci-host/pnv_phb3_msi.c | 2 +- hw/pci-host/pnv_phb3_pbcq.c | 2 +- hw/pci-host/pnv_phb4.c | 6 +- hw/pci-host/pnv_phb4_pec.c | 4 +- hw/pci-host/ppc440_pcix.c | 2 +- hw/pci-host/ppc4xx_pci.c | 4 +- hw/pci-host/ppce500.c | 4 +- hw/pci-host/q35.c | 4 +- hw/pci-host/raven.c | 4 +- hw/pci-host/remote.c | 2 +- hw/pci-host/sabre.c | 4 +- hw/pci-host/sh_pci.c | 4 +- hw/pci-host/uninorth.c | 19 ++-- hw/pci-host/versatile.c | 4 +- hw/pci-host/xen_igd_pt.c | 3 +- hw/pci-host/xilinx-pcie.c | 4 +- hw/pci/pci.c | 6 +- hw/pci/pci_bridge.c | 2 +- hw/pci/pci_host.c | 2 +- hw/pci/pcie_port.c | 4 +- hw/ppc/amigaone.c | 2 +- hw/ppc/e500plat.c | 2 +- hw/ppc/mac_newworld.c | 2 +- hw/ppc/mac_oldworld.c | 2 +- hw/ppc/mpc8544ds.c | 2 +- hw/ppc/pef.c | 2 +- hw/ppc/pegasos2.c | 2 +- hw/ppc/pnv.c | 25 +++--- hw/ppc/pnv_adu.c | 2 +- hw/ppc/pnv_chiptod.c | 6 +- hw/ppc/pnv_core.c | 14 +-- hw/ppc/pnv_homer.c | 8 +- hw/ppc/pnv_i2c.c | 2 +- hw/ppc/pnv_lpc.c | 8 +- hw/ppc/pnv_n1_chiplet.c | 2 +- hw/ppc/pnv_nest_pervasive.c | 2 +- hw/ppc/pnv_occ.c | 8 +- hw/ppc/pnv_pnor.c | 2 +- hw/ppc/pnv_psi.c | 8 +- hw/ppc/pnv_sbe.c | 6 +- hw/ppc/ppc440_uc.c | 2 +- hw/ppc/ppc4xx_devs.c | 8 +- hw/ppc/ppc4xx_sdram.c | 4 +- hw/ppc/ppce500_spin.c | 2 +- hw/ppc/prep_systemio.c | 2 +- hw/ppc/rs6000_mc.c | 2 +- hw/ppc/spapr.c | 4 +- hw/ppc/spapr_cpu_core.c | 2 +- hw/ppc/spapr_drc.c | 16 ++-- hw/ppc/spapr_iommu.c | 5 +- hw/ppc/spapr_nvdimm.c | 2 +- hw/ppc/spapr_pci.c | 2 +- hw/ppc/spapr_rng.c | 2 +- hw/ppc/spapr_rtc.c | 2 +- hw/ppc/spapr_tpm_proxy.c | 2 +- hw/ppc/spapr_vio.c | 6 +- hw/remote/machine.c | 2 +- hw/remote/proxy.c | 2 +- hw/remote/remote-obj.c | 2 +- hw/remote/vfio-user-obj.c | 2 +- hw/riscv/microchip_pfsoc.c | 5 +- hw/riscv/opentitan.c | 4 +- hw/riscv/riscv-iommu-pci.c | 2 +- hw/riscv/riscv-iommu-sys.c | 2 +- hw/riscv/riscv-iommu.c | 4 +- hw/riscv/riscv_hart.c | 2 +- hw/riscv/shakti_c.c | 4 +- hw/riscv/sifive_e.c | 4 +- hw/riscv/sifive_u.c | 4 +- hw/riscv/spike.c | 2 +- hw/riscv/virt.c | 2 +- hw/rtc/allwinner-rtc.c | 8 +- hw/rtc/aspeed_rtc.c | 2 +- hw/rtc/ds1338.c | 2 +- hw/rtc/exynos4210_rtc.c | 2 +- hw/rtc/goldfish_rtc.c | 2 +- hw/rtc/ls7a_rtc.c | 2 +- hw/rtc/m41t80.c | 2 +- hw/rtc/m48t59-isa.c | 4 +- hw/rtc/m48t59.c | 5 +- hw/rtc/mc146818rtc.c | 2 +- hw/rtc/pl031.c | 2 +- hw/rtc/rs5c372.c | 2 +- hw/rtc/sun4v-rtc.c | 2 +- hw/rtc/xlnx-zynqmp-rtc.c | 2 +- hw/rx/rx-gdbsim.c | 6 +- hw/rx/rx62n.c | 6 +- hw/s390x/3270-ccw.c | 2 +- hw/s390x/ap-bridge.c | 4 +- hw/s390x/ap-device.c | 2 +- hw/s390x/ccw-device.c | 2 +- hw/s390x/css-bridge.c | 4 +- hw/s390x/event-facility.c | 4 +- hw/s390x/ipl.c | 2 +- hw/s390x/s390-ccw.c | 2 +- hw/s390x/s390-pci-bus.c | 7 +- hw/s390x/s390-skeys-kvm.c | 2 +- hw/s390x/s390-skeys.c | 4 +- hw/s390x/s390-stattrib-kvm.c | 2 +- hw/s390x/s390-stattrib.c | 4 +- hw/s390x/s390-virtio-ccw.c | 4 +- hw/s390x/sclp.c | 2 +- hw/s390x/sclpcpu.c | 2 +- hw/s390x/sclpquiesce.c | 2 +- hw/s390x/tod-kvm.c | 2 +- hw/s390x/tod-tcg.c | 2 +- hw/s390x/tod.c | 2 +- hw/s390x/vhost-scsi-ccw.c | 2 +- hw/s390x/vhost-user-fs-ccw.c | 2 +- hw/s390x/vhost-vsock-ccw.c | 2 +- hw/s390x/virtio-ccw-9p.c | 2 +- hw/s390x/virtio-ccw-balloon.c | 2 +- hw/s390x/virtio-ccw-blk.c | 2 +- hw/s390x/virtio-ccw-crypto.c | 2 +- hw/s390x/virtio-ccw-gpu.c | 2 +- hw/s390x/virtio-ccw-input.c | 2 +- hw/s390x/virtio-ccw-mem.c | 2 +- hw/s390x/virtio-ccw-net.c | 2 +- hw/s390x/virtio-ccw-rng.c | 2 +- hw/s390x/virtio-ccw-scsi.c | 2 +- hw/s390x/virtio-ccw-serial.c | 2 +- hw/s390x/virtio-ccw.c | 4 +- hw/scsi/esp-pci.c | 4 +- hw/scsi/esp.c | 4 +- hw/scsi/lsi53c895a.c | 4 +- hw/scsi/megasas.c | 2 +- hw/scsi/mptsas.c | 2 +- hw/scsi/scsi-bus.c | 4 +- hw/scsi/scsi-disk.c | 8 +- hw/scsi/scsi-generic.c | 2 +- hw/scsi/spapr_vscsi.c | 2 +- hw/scsi/vhost-scsi.c | 2 +- hw/scsi/vhost-user-scsi.c | 2 +- hw/scsi/virtio-scsi.c | 4 +- hw/scsi/vmw_pvscsi.c | 2 +- hw/sd/allwinner-sdhost.c | 15 ++-- hw/sd/aspeed_sdhci.c | 10 +-- hw/sd/bcm2835_sdhost.c | 2 +- hw/sd/cadence_sdhci.c | 2 +- hw/sd/npcm7xx_sdhci.c | 2 +- hw/sd/omap_mmc.c | 2 +- hw/sd/pl181.c | 4 +- hw/sd/sd.c | 8 +- hw/sd/sdhci-pci.c | 2 +- hw/sd/sdhci.c | 4 +- hw/sd/ssi-sd.c | 2 +- hw/sensor/adm1266.c | 2 +- hw/sensor/adm1272.c | 2 +- hw/sensor/dps310.c | 2 +- hw/sensor/emc141x.c | 4 +- hw/sensor/isl_pmbus_vr.c | 8 +- hw/sensor/lsm303dlhc_mag.c | 2 +- hw/sensor/max31785.c | 2 +- hw/sensor/max34451.c | 2 +- hw/sensor/tmp105.c | 2 +- hw/sensor/tmp421.c | 2 +- hw/sparc/sun4m.c | 28 +++--- hw/sparc/sun4m_iommu.c | 5 +- hw/sparc64/niagara.c | 2 +- hw/sparc64/sun4u.c | 12 +-- hw/sparc64/sun4u_iommu.c | 5 +- hw/ssi/allwinner-a10-spi.c | 2 +- hw/ssi/aspeed_smc.c | 36 ++++---- hw/ssi/bcm2835_spi.c | 2 +- hw/ssi/ibex_spi_host.c | 2 +- hw/ssi/imx_spi.c | 2 +- hw/ssi/mss-spi.c | 2 +- hw/ssi/npcm7xx_fiu.c | 2 +- hw/ssi/npcm_pspi.c | 2 +- hw/ssi/pl022.c | 2 +- hw/ssi/pnv_spi.c | 2 +- hw/ssi/sifive_spi.c | 2 +- hw/ssi/ssi.c | 4 +- hw/ssi/stm32f2xx_spi.c | 2 +- hw/ssi/xilinx_spi.c | 2 +- hw/ssi/xilinx_spips.c | 6 +- hw/ssi/xlnx-versal-ospi.c | 2 +- hw/timer/a9gtimer.c | 2 +- hw/timer/allwinner-a10-pit.c | 2 +- hw/timer/arm_mptimer.c | 2 +- hw/timer/arm_timer.c | 2 +- hw/timer/armv7m_systick.c | 2 +- hw/timer/aspeed_timer.c | 12 +-- hw/timer/avr_timer16.c | 2 +- hw/timer/bcm2835_systmr.c | 2 +- hw/timer/cadence_ttc.c | 2 +- hw/timer/cmsdk-apb-dualtimer.c | 2 +- hw/timer/cmsdk-apb-timer.c | 2 +- hw/timer/digic-timer.c | 2 +- hw/timer/exynos4210_mct.c | 2 +- hw/timer/exynos4210_pwm.c | 2 +- hw/timer/grlib_gptimer.c | 2 +- hw/timer/hpet.c | 2 +- hw/timer/i8254.c | 2 +- hw/timer/i8254_common.c | 2 +- hw/timer/ibex_timer.c | 2 +- hw/timer/imx_epit.c | 2 +- hw/timer/imx_gpt.c | 2 +- hw/timer/mss-timer.c | 2 +- hw/timer/npcm7xx_timer.c | 2 +- hw/timer/nrf51_timer.c | 2 +- hw/timer/pxa2xx_timer.c | 4 +- hw/timer/renesas_cmt.c | 2 +- hw/timer/renesas_tmr.c | 2 +- hw/timer/sifive_pwm.c | 2 +- hw/timer/slavio_timer.c | 2 +- hw/timer/sse-counter.c | 2 +- hw/timer/sse-timer.c | 2 +- hw/timer/stellaris-gptm.c | 2 +- hw/timer/stm32f2xx_timer.c | 2 +- hw/timer/xilinx_timer.c | 2 +- hw/tpm/tpm_crb.c | 2 +- hw/tpm/tpm_spapr.c | 2 +- hw/tpm/tpm_tis_i2c.c | 2 +- hw/tpm/tpm_tis_isa.c | 2 +- hw/tpm/tpm_tis_sysbus.c | 2 +- hw/tricore/tc27x_soc.c | 4 +- hw/tricore/triboard.c | 2 +- hw/tricore/tricore_testdevice.c | 2 +- hw/uefi/var-service-sysbus.c | 4 +- hw/ufs/lu.c | 2 +- hw/ufs/ufs.c | 4 +- hw/usb/bus.c | 4 +- hw/usb/canokey.c | 2 +- hw/usb/ccid-card-emulated.c | 2 +- hw/usb/ccid-card-passthru.c | 2 +- hw/usb/chipidea.c | 2 +- hw/usb/dev-audio.c | 2 +- hw/usb/dev-hid.c | 8 +- hw/usb/dev-hub.c | 2 +- hw/usb/dev-mtp.c | 2 +- hw/usb/dev-network.c | 2 +- hw/usb/dev-serial.c | 6 +- hw/usb/dev-smartcard-reader.c | 4 +- hw/usb/dev-storage-bot.c | 2 +- hw/usb/dev-storage-classic.c | 2 +- hw/usb/dev-storage.c | 2 +- hw/usb/dev-uas.c | 2 +- hw/usb/dev-wacom.c | 2 +- hw/usb/hcd-dwc2.c | 2 +- hw/usb/hcd-dwc3.c | 2 +- hw/usb/hcd-ehci-pci.c | 4 +- hw/usb/hcd-ehci-sysbus.c | 16 ++-- hw/usb/hcd-ohci-pci.c | 2 +- hw/usb/hcd-ohci-sysbus.c | 2 +- hw/usb/hcd-uhci.c | 4 +- hw/usb/hcd-uhci.h | 2 +- hw/usb/hcd-xhci-nec.c | 2 +- hw/usb/hcd-xhci-pci.c | 4 +- hw/usb/hcd-xhci-sysbus.c | 2 +- hw/usb/hcd-xhci.c | 2 +- hw/usb/host-libusb.c | 2 +- hw/usb/imx-usb-phy.c | 2 +- hw/usb/redirect.c | 2 +- hw/usb/u2f-emulated.c | 2 +- hw/usb/u2f-passthru.c | 2 +- hw/usb/u2f.c | 2 +- hw/usb/xlnx-usb-subsystem.c | 2 +- hw/usb/xlnx-versal-usb2-ctrl-regs.c | 2 +- hw/vfio/amd-xgbe.c | 2 +- hw/vfio/ap.c | 2 +- hw/vfio/calxeda-xgmac.c | 2 +- hw/vfio/ccw.c | 2 +- hw/vfio/container.c | 4 +- hw/vfio/igd.c | 3 +- hw/vfio/iommufd.c | 4 +- hw/vfio/pci.c | 5 +- hw/vfio/platform.c | 2 +- hw/vfio/spapr.c | 2 +- hw/virtio/vdpa-dev-pci.c | 3 +- hw/virtio/vdpa-dev.c | 2 +- hw/virtio/vhost-scsi-pci.c | 2 +- hw/virtio/vhost-user-base.c | 2 +- hw/virtio/vhost-user-blk-pci.c | 2 +- hw/virtio/vhost-user-device-pci.c | 3 +- hw/virtio/vhost-user-device.c | 2 +- hw/virtio/vhost-user-fs-pci.c | 2 +- hw/virtio/vhost-user-fs.c | 2 +- hw/virtio/vhost-user-gpio-pci.c | 2 +- hw/virtio/vhost-user-gpio.c | 2 +- hw/virtio/vhost-user-i2c-pci.c | 2 +- hw/virtio/vhost-user-i2c.c | 2 +- hw/virtio/vhost-user-input.c | 2 +- hw/virtio/vhost-user-rng-pci.c | 2 +- hw/virtio/vhost-user-rng.c | 2 +- hw/virtio/vhost-user-scmi-pci.c | 2 +- hw/virtio/vhost-user-scmi.c | 2 +- hw/virtio/vhost-user-scsi-pci.c | 2 +- hw/virtio/vhost-user-snd-pci.c | 2 +- hw/virtio/vhost-user-snd.c | 2 +- hw/virtio/vhost-user-vsock-pci.c | 3 +- hw/virtio/vhost-user-vsock.c | 2 +- hw/virtio/vhost-vsock-common.c | 2 +- hw/virtio/vhost-vsock-pci.c | 2 +- hw/virtio/vhost-vsock.c | 2 +- hw/virtio/virtio-9p-pci.c | 2 +- hw/virtio/virtio-balloon-pci.c | 2 +- hw/virtio/virtio-balloon.c | 2 +- hw/virtio/virtio-blk-pci.c | 2 +- hw/virtio/virtio-bus.c | 2 +- hw/virtio/virtio-crypto-pci.c | 2 +- hw/virtio/virtio-crypto.c | 2 +- hw/virtio/virtio-input-pci.c | 7 +- hw/virtio/virtio-iommu-pci.c | 2 +- hw/virtio/virtio-iommu.c | 4 +- hw/virtio/virtio-mem-pci.c | 2 +- hw/virtio/virtio-mem.c | 5 +- hw/virtio/virtio-mmio.c | 4 +- hw/virtio/virtio-net-pci.c | 2 +- hw/virtio/virtio-nsm-pci.c | 2 +- hw/virtio/virtio-nsm.c | 2 +- hw/virtio/virtio-pci.c | 8 +- hw/virtio/virtio-pmem-pci.c | 2 +- hw/virtio/virtio-pmem.c | 2 +- hw/virtio/virtio-rng-pci.c | 2 +- hw/virtio/virtio-rng.c | 2 +- hw/virtio/virtio-scsi-pci.c | 2 +- hw/virtio/virtio-serial-pci.c | 2 +- hw/virtio/virtio.c | 2 +- hw/vmapple/aes.c | 2 +- hw/vmapple/bdif.c | 2 +- hw/vmapple/cfg.c | 2 +- hw/vmapple/virtio-blk.c | 5 +- hw/vmapple/vmapple.c | 2 +- hw/watchdog/allwinner-wdt.c | 6 +- hw/watchdog/cmsdk-apb-watchdog.c | 2 +- hw/watchdog/sbsa_gwdt.c | 2 +- hw/watchdog/spapr_watchdog.c | 2 +- hw/watchdog/wdt_aspeed.c | 12 +-- hw/watchdog/wdt_diag288.c | 2 +- hw/watchdog/wdt_i6300esb.c | 2 +- hw/watchdog/wdt_ib700.c | 2 +- hw/watchdog/wdt_imx2.c | 2 +- hw/xen/xen-bus.c | 4 +- hw/xen/xen-legacy-backend.c | 4 +- hw/xen/xen-pvh-common.c | 2 +- hw/xen/xen_pt.c | 2 +- hw/xen/xen_pt_graphics.c | 2 +- hw/xtensa/xtfpga.c | 16 ++-- include/hw/boards.h | 2 +- include/hw/i386/pc.h | 5 +- include/hw/virtio/virtio-pci.h | 2 +- include/qom/object.h | 4 +- io/channel-buffer.c | 2 +- io/channel-command.c | 2 +- io/channel-file.c | 2 +- io/channel-null.c | 2 +- io/channel-socket.c | 2 +- io/channel-tls.c | 2 +- io/channel-websock.c | 2 +- iothread.c | 2 +- migration/channel-block.c | 2 +- migration/migration.c | 2 +- migration/rdma.c | 2 +- net/can/can_core.c | 2 +- net/can/can_host.c | 2 +- net/can/can_socketcan.c | 2 +- net/colo-compare.c | 2 +- net/dump.c | 2 +- net/filter-buffer.c | 2 +- net/filter-mirror.c | 4 +- net/filter-replay.c | 2 +- net/filter-rewriter.c | 2 +- net/filter.c | 2 +- qom/object.c | 4 +- rust/qemu-api/src/qom.rs | 2 +- .../codeconverter/qom_type_info.py | 3 +- scsi/pr-manager-helper.c | 2 +- system/qtest.c | 2 +- target/alpha/cpu.c | 2 +- target/arm/cpu.c | 4 +- target/arm/cpu.h | 2 +- target/arm/cpu64.c | 4 +- target/arm/tcg/cpu-v7m.c | 2 +- target/avr/cpu.c | 2 +- target/hexagon/cpu.c | 2 +- target/hppa/cpu.c | 2 +- target/i386/confidential-guest.c | 2 +- target/i386/cpu.c | 8 +- target/i386/host-cpu.c | 2 +- target/i386/hvf/hvf-cpu.c | 2 +- target/i386/kvm/kvm-cpu.c | 2 +- target/i386/nvmm/nvmm-accel-ops.c | 2 +- target/i386/nvmm/nvmm-all.c | 2 +- target/i386/sev.c | 6 +- target/i386/tcg/tcg-cpu.c | 2 +- target/i386/whpx/whpx-accel-ops.c | 2 +- target/i386/whpx/whpx-all.c | 2 +- target/i386/whpx/whpx-apic.c | 2 +- target/loongarch/cpu.c | 6 +- target/m68k/cpu.c | 6 +- target/microblaze/cpu.c | 2 +- target/mips/cpu.c | 4 +- target/openrisc/cpu.c | 2 +- target/ppc/cpu-models.c | 2 +- target/ppc/cpu.h | 3 +- target/ppc/cpu_init.c | 90 +++++++++---------- target/ppc/kvm.c | 4 +- target/riscv/cpu.c | 4 +- target/riscv/kvm/kvm-cpu.c | 4 +- target/riscv/tcg/tcg-cpu.c | 2 +- target/rx/cpu.c | 2 +- target/s390x/cpu.c | 2 +- target/s390x/cpu_models.c | 10 +-- target/s390x/kvm/pv.c | 2 +- target/sh4/cpu.c | 8 +- target/sparc/cpu.c | 4 +- target/tricore/cpu.c | 2 +- target/xtensa/cpu.c | 2 +- target/xtensa/helper.c | 2 +- tests/unit/check-qom-interface.c | 2 +- tests/unit/check-qom-proplist.c | 6 +- tests/unit/test-qdev-global-props.c | 8 +- tests/unit/test-smp-parse.c | 23 ++--- ui/console-vc.c | 6 +- ui/console.c | 4 +- ui/dbus-chardev.c | 2 +- ui/dbus.c | 4 +- ui/gtk.c | 2 +- ui/input-barrier.c | 2 +- ui/input-linux.c | 2 +- ui/spice-app.c | 2 +- ui/vdagent.c | 2 +- util/main-loop.c | 2 +- util/thread-context.c | 2 +- 1121 files changed, 1774 insertions(+), 1707 deletions(-) diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 601c3bc0ac..5375de7bcf 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -355,7 +355,7 @@ static inline int hvf_gdbstub_sstep_flags(void) return SSTEP_ENABLE | SSTEP_NOIRQ; } -static void hvf_accel_class_init(ObjectClass *oc, void *data) +static void hvf_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "HVF"; @@ -578,7 +578,7 @@ static void hvf_remove_all_breakpoints(CPUState *cpu) } } -static void hvf_accel_ops_class_init(ObjectClass *oc, void *data) +static void hvf_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/accel/kvm/kvm-accel-ops.c b/accel/kvm/kvm-accel-ops.c index 54ea60909e..e5c15449aa 100644 --- a/accel/kvm/kvm-accel-ops.c +++ b/accel/kvm/kvm-accel-ops.c @@ -90,7 +90,7 @@ static int kvm_update_guest_debug_ops(CPUState *cpu) } #endif -static void kvm_accel_ops_class_init(ObjectClass *oc, void *data) +static void kvm_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index cba9c78d2f..b8c68c7819 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -3964,7 +3964,7 @@ static int kvm_gdbstub_sstep_flags(void) return kvm_sstep_flags; } -static void kvm_accel_class_init(ObjectClass *oc, void *data) +static void kvm_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "KVM"; diff --git a/accel/qtest/qtest.c b/accel/qtest/qtest.c index 7fae80f6a1..92bed9264c 100644 --- a/accel/qtest/qtest.c +++ b/accel/qtest/qtest.c @@ -42,7 +42,7 @@ static int qtest_init_accel(MachineState *ms) return 0; } -static void qtest_accel_class_init(ObjectClass *oc, void *data) +static void qtest_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "QTest"; @@ -59,7 +59,7 @@ static const TypeInfo qtest_accel_type = { }; module_obj(TYPE_QTEST_ACCEL); -static void qtest_accel_ops_class_init(ObjectClass *oc, void *data) +static void qtest_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c index ccdb781eef..b24d6a7562 100644 --- a/accel/tcg/tcg-accel-ops.c +++ b/accel/tcg/tcg-accel-ops.c @@ -224,7 +224,7 @@ static void tcg_accel_ops_init(AccelOpsClass *ops) ops->remove_all_breakpoints = tcg_remove_all_breakpoints; } -static void tcg_accel_ops_class_init(ObjectClass *oc, void *data) +static void tcg_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index b0d4e3e136..40d7364979 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -237,7 +237,7 @@ static int tcg_gdbstub_supported_sstep_flags(void) } } -static void tcg_accel_class_init(ObjectClass *oc, void *data) +static void tcg_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "tcg"; diff --git a/accel/xen/xen-all.c b/accel/xen/xen-all.c index 7aa28b9ab9..de52a8f882 100644 --- a/accel/xen/xen-all.c +++ b/accel/xen/xen-all.c @@ -116,7 +116,7 @@ static int xen_init(MachineState *ms) return 0; } -static void xen_accel_class_init(ObjectClass *oc, void *data) +static void xen_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); static GlobalProperty compat[] = { @@ -147,7 +147,7 @@ static const TypeInfo xen_accel_type = { .class_init = xen_accel_class_init, }; -static void xen_accel_ops_class_init(ObjectClass *oc, void *data) +static void xen_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/authz/list.c b/authz/list.c index 0e17eed897..bbd99f2b7f 100644 --- a/authz/list.c +++ b/authz/list.c @@ -116,7 +116,7 @@ qauthz_list_finalize(Object *obj) static void -qauthz_list_class_init(ObjectClass *oc, void *data) +qauthz_list_class_init(ObjectClass *oc, const void *data) { QAuthZClass *authz = QAUTHZ_CLASS(oc); diff --git a/authz/listfile.c b/authz/listfile.c index d31d9103f7..b58d4ebd1d 100644 --- a/authz/listfile.c +++ b/authz/listfile.c @@ -220,7 +220,7 @@ qauthz_list_file_finalize(Object *obj) static void -qauthz_list_file_class_init(ObjectClass *oc, void *data) +qauthz_list_file_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); QAuthZClass *authz = QAUTHZ_CLASS(oc); diff --git a/authz/pamacct.c b/authz/pamacct.c index c862d9ff39..07b8aad497 100644 --- a/authz/pamacct.c +++ b/authz/pamacct.c @@ -103,7 +103,7 @@ qauthz_pam_finalize(Object *obj) static void -qauthz_pam_class_init(ObjectClass *oc, void *data) +qauthz_pam_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); QAuthZClass *authz = QAUTHZ_CLASS(oc); diff --git a/authz/simple.c b/authz/simple.c index 0597dcd8ea..f6985b840e 100644 --- a/authz/simple.c +++ b/authz/simple.c @@ -78,7 +78,7 @@ qauthz_simple_complete(UserCreatable *uc, Error **errp) static void -qauthz_simple_class_init(ObjectClass *oc, void *data) +qauthz_simple_class_init(ObjectClass *oc, const void *data) { QAuthZClass *authz = QAUTHZ_CLASS(oc); UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/backends/confidential-guest-support.c b/backends/confidential-guest-support.c index 1cd9bed505..8ff7bfa857 100644 --- a/backends/confidential-guest-support.c +++ b/backends/confidential-guest-support.c @@ -20,7 +20,8 @@ OBJECT_DEFINE_ABSTRACT_TYPE(ConfidentialGuestSupport, CONFIDENTIAL_GUEST_SUPPORT, OBJECT) -static void confidential_guest_support_class_init(ObjectClass *oc, void *data) +static void confidential_guest_support_class_init(ObjectClass *oc, + const void *data) { } diff --git a/backends/cryptodev-builtin.c b/backends/cryptodev-builtin.c index 764cee4311..0414c01e06 100644 --- a/backends/cryptodev-builtin.c +++ b/backends/cryptodev-builtin.c @@ -608,7 +608,7 @@ static void cryptodev_builtin_cleanup( } static void -cryptodev_builtin_class_init(ObjectClass *oc, void *data) +cryptodev_builtin_class_init(ObjectClass *oc, const void *data) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); diff --git a/backends/cryptodev-lkcf.c b/backends/cryptodev-lkcf.c index 352c3e8958..bb7a81d5d0 100644 --- a/backends/cryptodev-lkcf.c +++ b/backends/cryptodev-lkcf.c @@ -619,7 +619,7 @@ static int cryptodev_lkcf_close_session(CryptoDevBackend *backend, return 0; } -static void cryptodev_lkcf_class_init(ObjectClass *oc, void *data) +static void cryptodev_lkcf_class_init(ObjectClass *oc, const void *data) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); diff --git a/backends/cryptodev-vhost-user.c b/backends/cryptodev-vhost-user.c index 3295c6198a..cb04e68b02 100644 --- a/backends/cryptodev-vhost-user.c +++ b/backends/cryptodev-vhost-user.c @@ -393,7 +393,7 @@ static void cryptodev_vhost_user_finalize(Object *obj) } static void -cryptodev_vhost_user_class_init(ObjectClass *oc, void *data) +cryptodev_vhost_user_class_init(ObjectClass *oc, const void *data) { CryptoDevBackendClass *bc = CRYPTODEV_BACKEND_CLASS(oc); diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 1187b08dac..51bbe5ce40 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -608,7 +608,7 @@ static void cryptodev_backend_schemas_cb(StatsSchemaList **result, } static void -cryptodev_backend_class_init(ObjectClass *oc, void *data) +cryptodev_backend_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index be6c4d8e0a..8c2deef43d 100644 --- a/backends/dbus-vmstate.c +++ b/backends/dbus-vmstate.c @@ -485,7 +485,7 @@ dbus_vmstate_get_id(VMStateIf *vmif) } static void -dbus_vmstate_class_init(ObjectClass *oc, void *data) +dbus_vmstate_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); VMStateIfClass *vc = VMSTATE_IF_CLASS(oc); diff --git a/backends/host_iommu_device.c b/backends/host_iommu_device.c index cea76c6925..f6965e4027 100644 --- a/backends/host_iommu_device.c +++ b/backends/host_iommu_device.c @@ -17,7 +17,7 @@ OBJECT_DEFINE_ABSTRACT_TYPE(HostIOMMUDevice, HOST_IOMMU_DEVICE, OBJECT) -static void host_iommu_device_class_init(ObjectClass *oc, void *data) +static void host_iommu_device_class_init(ObjectClass *oc, const void *data) { } diff --git a/backends/hostmem-epc.c b/backends/hostmem-epc.c index 1fa2d031e4..ab20b18233 100644 --- a/backends/hostmem-epc.c +++ b/backends/hostmem-epc.c @@ -50,7 +50,7 @@ static void sgx_epc_backend_instance_init(Object *obj) m->dump = false; } -static void sgx_epc_backend_class_init(ObjectClass *oc, void *data) +static void sgx_epc_backend_class_init(ObjectClass *oc, const void *data) { HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); diff --git a/backends/hostmem-file.c b/backends/hostmem-file.c index 691a827819..8e3219c061 100644 --- a/backends/hostmem-file.c +++ b/backends/hostmem-file.c @@ -270,7 +270,7 @@ static void file_backend_unparent(Object *obj) } static void -file_backend_class_init(ObjectClass *oc, void *data) +file_backend_class_init(ObjectClass *oc, const void *data) { HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); diff --git a/backends/hostmem-memfd.c b/backends/hostmem-memfd.c index 85daa1432c..923239f9cf 100644 --- a/backends/hostmem-memfd.c +++ b/backends/hostmem-memfd.c @@ -133,7 +133,7 @@ memfd_backend_instance_init(Object *obj) } static void -memfd_backend_class_init(ObjectClass *oc, void *data) +memfd_backend_class_init(ObjectClass *oc, const void *data) { HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); diff --git a/backends/hostmem-ram.c b/backends/hostmem-ram.c index 868ae6ca80..062b1abb11 100644 --- a/backends/hostmem-ram.c +++ b/backends/hostmem-ram.c @@ -37,7 +37,7 @@ ram_backend_memory_alloc(HostMemoryBackend *backend, Error **errp) } static void -ram_backend_class_init(ObjectClass *oc, void *data) +ram_backend_class_init(ObjectClass *oc, const void *data) { HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); diff --git a/backends/hostmem-shm.c b/backends/hostmem-shm.c index f67ad2740b..f66211a2ec 100644 --- a/backends/hostmem-shm.c +++ b/backends/hostmem-shm.c @@ -69,7 +69,7 @@ shm_backend_instance_init(Object *obj) } static void -shm_backend_class_init(ObjectClass *oc, void *data) +shm_backend_class_init(ObjectClass *oc, const void *data) { HostMemoryBackendClass *bc = MEMORY_BACKEND_CLASS(oc); diff --git a/backends/hostmem.c b/backends/hostmem.c index bceca1a8d9..195f37fa44 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -501,7 +501,7 @@ host_memory_backend_set_use_canonical_path(Object *obj, bool value, } static void -host_memory_backend_class_init(ObjectClass *oc, void *data) +host_memory_backend_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/backends/iommufd.c b/backends/iommufd.c index d57da44755..17f7ae3809 100644 --- a/backends/iommufd.c +++ b/backends/iommufd.c @@ -64,7 +64,7 @@ static bool iommufd_backend_can_be_deleted(UserCreatable *uc) return !be->users; } -static void iommufd_backend_class_init(ObjectClass *oc, void *data) +static void iommufd_backend_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); @@ -326,7 +326,7 @@ static int hiod_iommufd_get_cap(HostIOMMUDevice *hiod, int cap, Error **errp) } } -static void hiod_iommufd_class_init(ObjectClass *oc, void *data) +static void hiod_iommufd_class_init(ObjectClass *oc, const void *data) { HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc); diff --git a/backends/rng-builtin.c b/backends/rng-builtin.c index 4cfa7e578b..41b7bfaa27 100644 --- a/backends/rng-builtin.c +++ b/backends/rng-builtin.c @@ -55,7 +55,7 @@ static void rng_builtin_finalize(Object *obj) qemu_bh_delete(s->bh); } -static void rng_builtin_class_init(ObjectClass *klass, void *data) +static void rng_builtin_class_init(ObjectClass *klass, const void *data) { RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); diff --git a/backends/rng-egd.c b/backends/rng-egd.c index 82da46365d..9fd3393ede 100644 --- a/backends/rng-egd.c +++ b/backends/rng-egd.c @@ -143,7 +143,7 @@ static void rng_egd_finalize(Object *obj) g_free(s->chr_name); } -static void rng_egd_class_init(ObjectClass *klass, void *data) +static void rng_egd_class_init(ObjectClass *klass, const void *data) { RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); diff --git a/backends/rng-random.c b/backends/rng-random.c index 3ce6cc9b4a..820bf48c9b 100644 --- a/backends/rng-random.c +++ b/backends/rng-random.c @@ -121,7 +121,7 @@ static void rng_random_finalize(Object *obj) g_free(s->filename); } -static void rng_random_class_init(ObjectClass *klass, void *data) +static void rng_random_class_init(ObjectClass *klass, const void *data) { RngBackendClass *rbc = RNG_BACKEND_CLASS(klass); diff --git a/backends/rng.c b/backends/rng.c index 1f6fb106ae..b3480d27a1 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -99,7 +99,7 @@ static void rng_backend_finalize(Object *obj) rng_backend_free_requests(s); } -static void rng_backend_class_init(ObjectClass *oc, void *data) +static void rng_backend_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c index 00fe015a94..43d350e895 100644 --- a/backends/tpm/tpm_emulator.c +++ b/backends/tpm/tpm_emulator.c @@ -1056,7 +1056,7 @@ static void tpm_emulator_inst_finalize(Object *obj) vmstate_unregister(NULL, &vmstate_tpm_emulator, obj); } -static void tpm_emulator_class_init(ObjectClass *klass, void *data) +static void tpm_emulator_class_init(ObjectClass *klass, const void *data) { TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c index 09a6abf02d..b7c7074c2a 100644 --- a/backends/tpm/tpm_passthrough.c +++ b/backends/tpm/tpm_passthrough.c @@ -364,7 +364,7 @@ static void tpm_passthrough_inst_finalize(Object *obj) qapi_free_TPMPassthroughOptions(tpm_pt->options); } -static void tpm_passthrough_class_init(ObjectClass *klass, void *data) +static void tpm_passthrough_class_init(ObjectClass *klass, const void *data) { TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass); diff --git a/backends/vhost-user.c b/backends/vhost-user.c index d0e4d71a63..94274a619d 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -163,7 +163,7 @@ static char *get_chardev(Object *obj, Error **errp) return NULL; } -static void vhost_user_backend_class_init(ObjectClass *oc, void *data) +static void vhost_user_backend_class_init(ObjectClass *oc, const void *data) { object_class_property_add_str(oc, "chardev", get_chardev, set_chardev); } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 9f4d252c74..9720cafb96 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -933,7 +933,8 @@ static bool throttle_group_can_be_deleted(UserCreatable *uc) return OBJECT(uc)->ref == 1; } -static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data) +static void throttle_group_obj_class_init(ObjectClass *klass, + const void *class_data) { size_t i = 0; UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); diff --git a/chardev/baum.c b/chardev/baum.c index a1d9784d92..f3e8cd27f0 100644 --- a/chardev/baum.c +++ b/chardev/baum.c @@ -668,7 +668,7 @@ static void baum_chr_open(Chardev *chr, qemu_set_fd_handler(baum->brlapi_fd, baum_chr_read, NULL, baum); } -static void char_braille_class_init(ObjectClass *oc, void *data) +static void char_braille_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-console.c b/chardev/char-console.c index 6c4ce5dbce..7e1bf642eb 100644 --- a/chardev/char-console.c +++ b/chardev/char-console.c @@ -34,7 +34,7 @@ static void qemu_chr_open_win_con(Chardev *chr, win_chr_set_file(chr, GetStdHandle(STD_OUTPUT_HANDLE), true); } -static void char_console_class_init(ObjectClass *oc, void *data) +static void char_console_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-fd.c b/chardev/char-fd.c index d2c4923359..23bfe3c0b1 100644 --- a/chardev/char-fd.c +++ b/chardev/char-fd.c @@ -238,7 +238,7 @@ void qemu_chr_open_fd(Chardev *chr, } } -static void char_fd_class_init(ObjectClass *oc, void *data) +static void char_fd_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-file.c b/chardev/char-file.c index 263e6da563..a9e8c5e0d7 100644 --- a/chardev/char-file.c +++ b/chardev/char-file.c @@ -123,7 +123,7 @@ static void qemu_chr_parse_file_out(QemuOpts *opts, ChardevBackend *backend, file->append = qemu_opt_get_bool(opts, "append", false); } -static void char_file_class_init(ObjectClass *oc, void *data) +static void char_file_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-hub.c b/chardev/char-hub.c index 3a4aae3289..16ffee2017 100644 --- a/chardev/char-hub.c +++ b/chardev/char-hub.c @@ -272,7 +272,7 @@ static void qemu_chr_parse_hub(QemuOpts *opts, ChardevBackend *backend, } } -static void char_hub_class_init(ObjectClass *oc, void *data) +static void char_hub_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-mux.c b/chardev/char-mux.c index d5f7e1a9cf..6b36290e2c 100644 --- a/chardev/char-mux.c +++ b/chardev/char-mux.c @@ -447,7 +447,7 @@ void resume_mux_open(void) chardev_options_parsed_cb, NULL); } -static void char_mux_class_init(ObjectClass *oc, void *data) +static void char_mux_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-null.c b/chardev/char-null.c index 1c6a2900f9..89cb85da79 100644 --- a/chardev/char-null.c +++ b/chardev/char-null.c @@ -34,7 +34,7 @@ static void null_chr_open(Chardev *chr, *be_opened = false; } -static void char_null_class_init(ObjectClass *oc, void *data) +static void char_null_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-parallel.c b/chardev/char-parallel.c index 78697d7522..62a44b2f96 100644 --- a/chardev/char-parallel.c +++ b/chardev/char-parallel.c @@ -270,7 +270,7 @@ static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, parallel->device = g_strdup(device); } -static void char_parallel_class_init(ObjectClass *oc, void *data) +static void char_parallel_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-pipe.c b/chardev/char-pipe.c index 5ad30bcc59..3d1b0ce2d2 100644 --- a/chardev/char-pipe.c +++ b/chardev/char-pipe.c @@ -171,7 +171,7 @@ static void qemu_chr_parse_pipe(QemuOpts *opts, ChardevBackend *backend, dev->device = g_strdup(device); } -static void char_pipe_class_init(ObjectClass *oc, void *data) +static void char_pipe_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-pty.c b/chardev/char-pty.c index 6a2c1dc13a..c28554e6e0 100644 --- a/chardev/char-pty.c +++ b/chardev/char-pty.c @@ -390,7 +390,7 @@ static void char_pty_parse(QemuOpts *opts, ChardevBackend *backend, pty->path = g_strdup(path); } -static void char_pty_class_init(ObjectClass *oc, void *data) +static void char_pty_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-ringbuf.c b/chardev/char-ringbuf.c index d40d21d3cf..98aadb6acf 100644 --- a/chardev/char-ringbuf.c +++ b/chardev/char-ringbuf.c @@ -223,7 +223,7 @@ static void qemu_chr_parse_ringbuf(QemuOpts *opts, ChardevBackend *backend, } } -static void char_ringbuf_class_init(ObjectClass *oc, void *data) +static void char_ringbuf_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-serial.c b/chardev/char-serial.c index 4b0b83d5b4..0a68b4b4e0 100644 --- a/chardev/char-serial.c +++ b/chardev/char-serial.c @@ -298,7 +298,7 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, serial->device = g_strdup(device); } -static void char_serial_class_init(ObjectClass *oc, void *data) +static void char_serial_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 2f842f9f88..e8dd2931dc 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1581,7 +1581,7 @@ char_socket_get_connected(Object *obj, Error **errp) return s->state == TCP_CHARDEV_STATE_CONNECTED; } -static void char_socket_class_init(ObjectClass *oc, void *data) +static void char_socket_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-stdio.c b/chardev/char-stdio.c index b960ddd4e4..48db8d2f30 100644 --- a/chardev/char-stdio.c +++ b/chardev/char-stdio.c @@ -136,7 +136,7 @@ static void qemu_chr_parse_stdio(QemuOpts *opts, ChardevBackend *backend, stdio->signal = qemu_opt_get_bool(opts, "signal", true); } -static void char_stdio_class_init(ObjectClass *oc, void *data) +static void char_stdio_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-udp.c b/chardev/char-udp.c index 3d9a2d5e77..572fab0ad1 100644 --- a/chardev/char-udp.c +++ b/chardev/char-udp.c @@ -219,7 +219,7 @@ static void qmp_chardev_open_udp(Chardev *chr, *be_opened = false; } -static void char_udp_class_init(ObjectClass *oc, void *data) +static void char_udp_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-win-stdio.c b/chardev/char-win-stdio.c index 13325ca967..fb802a00b1 100644 --- a/chardev/char-win-stdio.c +++ b/chardev/char-win-stdio.c @@ -256,7 +256,7 @@ static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len) return len - len1; } -static void char_win_stdio_class_init(ObjectClass *oc, void *data) +static void char_win_stdio_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char-win.c b/chardev/char-win.c index d4fb44c4dc..fef45e83aa 100644 --- a/chardev/char-win.c +++ b/chardev/char-win.c @@ -220,7 +220,7 @@ void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open) s->file = file; } -static void char_win_class_init(ObjectClass *oc, void *data) +static void char_win_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/char.c b/chardev/char.c index 5a9e9762ad..bbebd246c3 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -295,7 +295,7 @@ static int null_chr_write(Chardev *chr, const uint8_t *buf, int len) return len; } -static void char_class_init(ObjectClass *oc, void *data) +static void char_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/msmouse.c b/chardev/msmouse.c index 2279694cfa..1a55755d39 100644 --- a/chardev/msmouse.c +++ b/chardev/msmouse.c @@ -267,7 +267,7 @@ static void msmouse_chr_open(Chardev *chr, fifo8_create(&mouse->outbuf, MSMOUSE_BUF_SZ); } -static void char_msmouse_class_init(ObjectClass *oc, void *data) +static void char_msmouse_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/spice.c b/chardev/spice.c index e843d961a7..db53b49da2 100644 --- a/chardev/spice.c +++ b/chardev/spice.c @@ -347,7 +347,7 @@ static void qemu_chr_parse_spice_port(QemuOpts *opts, ChardevBackend *backend, spiceport->fqdn = g_strdup(name); } -static void char_spice_class_init(ObjectClass *oc, void *data) +static void char_spice_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -366,7 +366,7 @@ static const TypeInfo char_spice_type_info = { }; module_obj(TYPE_CHARDEV_SPICE); -static void char_spicevmc_class_init(ObjectClass *oc, void *data) +static void char_spicevmc_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); @@ -382,7 +382,7 @@ static const TypeInfo char_spicevmc_type_info = { }; module_obj(TYPE_CHARDEV_SPICEVMC); -static void char_spiceport_class_init(ObjectClass *oc, void *data) +static void char_spiceport_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/testdev.c b/chardev/testdev.c index a92caca3c3..e91f4e8343 100644 --- a/chardev/testdev.c +++ b/chardev/testdev.c @@ -110,7 +110,7 @@ static int testdev_chr_write(Chardev *chr, const uint8_t *buf, int len) return orig_len; } -static void char_testdev_class_init(ObjectClass *oc, void *data) +static void char_testdev_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/chardev/wctablet.c b/chardev/wctablet.c index f4008bf35b..0dc6ef08f5 100644 --- a/chardev/wctablet.c +++ b/chardev/wctablet.c @@ -342,7 +342,7 @@ static void wctablet_chr_open(Chardev *chr, &wctablet_handler); } -static void wctablet_chr_class_init(ObjectClass *oc, void *data) +static void wctablet_chr_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/crypto/secret.c b/crypto/secret.c index 44eaff16f6..61a4584286 100644 --- a/crypto/secret.c +++ b/crypto/secret.c @@ -117,7 +117,7 @@ qcrypto_secret_finalize(Object *obj) } static void -qcrypto_secret_class_init(ObjectClass *oc, void *data) +qcrypto_secret_class_init(ObjectClass *oc, const void *data) { QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); sic->load_data = qcrypto_secret_load_data; diff --git a/crypto/secret_common.c b/crypto/secret_common.c index dbda998940..2399ce412b 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -263,7 +263,7 @@ qcrypto_secret_finalize(Object *obj) } static void -qcrypto_secret_class_init(ObjectClass *oc, void *data) +qcrypto_secret_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/crypto/secret_keyring.c b/crypto/secret_keyring.c index 1b7edec84a..78d7f09b3b 100644 --- a/crypto/secret_keyring.c +++ b/crypto/secret_keyring.c @@ -103,7 +103,7 @@ qcrypto_secret_prop_get_key(Object *obj, Visitor *v, static void -qcrypto_secret_keyring_class_init(ObjectClass *oc, void *data) +qcrypto_secret_keyring_class_init(ObjectClass *oc, const void *data) { QCryptoSecretCommonClass *sic = QCRYPTO_SECRET_COMMON_CLASS(oc); sic->load_data = qcrypto_secret_keyring_load_data; diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c index d0df4badc0..e546cc7c0e 100644 --- a/crypto/tls-cipher-suites.c +++ b/crypto/tls-cipher-suites.c @@ -102,7 +102,8 @@ static GByteArray *qcrypto_tls_cipher_suites_fw_cfg_gen_data(Object *obj, errp); } -static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, void *data) +static void qcrypto_tls_cipher_suites_class_init(ObjectClass *oc, + const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); FWCfgDataGeneratorClass *fwgc = FW_CFG_DATA_GENERATOR_CLASS(oc); diff --git a/crypto/tlscreds.c b/crypto/tlscreds.c index 084ce0d51a..9e59594d67 100644 --- a/crypto/tlscreds.c +++ b/crypto/tlscreds.c @@ -223,7 +223,7 @@ qcrypto_tls_creds_prop_get_endpoint(Object *obj, static void -qcrypto_tls_creds_class_init(ObjectClass *oc, void *data) +qcrypto_tls_creds_class_init(ObjectClass *oc, const void *data) { object_class_property_add_bool(oc, "verify-peer", qcrypto_tls_creds_prop_get_verify, diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 476cf89c96..0e2d133821 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -137,7 +137,7 @@ qcrypto_tls_creds_anon_finalize(Object *obj) static void -qcrypto_tls_creds_anon_class_init(ObjectClass *oc, void *data) +qcrypto_tls_creds_anon_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index aa270d7988..287c2a3c96 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -236,7 +236,7 @@ qcrypto_tls_creds_psk_prop_get_username(Object *obj, } static void -qcrypto_tls_creds_psk_class_init(ObjectClass *oc, void *data) +qcrypto_tls_creds_psk_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 24ec584922..143993f539 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -802,7 +802,7 @@ qcrypto_tls_creds_x509_finalize(Object *obj) static void -qcrypto_tls_creds_x509_class_init(ObjectClass *oc, void *data) +qcrypto_tls_creds_x509_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); QCryptoTLSCredsClass *ctcc = QCRYPTO_TLS_CREDS_CLASS(oc); diff --git a/docs/devel/qom.rst b/docs/devel/qom.rst index 0889ca949c..5870745ba2 100644 --- a/docs/devel/qom.rst +++ b/docs/devel/qom.rst @@ -147,7 +147,7 @@ to introduce an overridden virtual function: #include "qdev.h" - void my_device_class_init(ObjectClass *klass, void *class_data) + void my_device_class_init(ObjectClass *klass, const void *class_data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = my_device_reset; @@ -249,7 +249,7 @@ class, which someone might choose to change at some point. // do something } - static void my_class_init(ObjectClass *oc, void *data) + static void my_class_init(ObjectClass *oc, const void *data) { MyClass *mc = MY_CLASS(oc); @@ -279,7 +279,7 @@ class, which someone might choose to change at some point. // do something else here } - static void derived_class_init(ObjectClass *oc, void *data) + static void derived_class_init(ObjectClass *oc, const void *data) { MyClass *mc = MY_CLASS(oc); DerivedClass *dc = DERIVED_CLASS(oc); @@ -363,7 +363,7 @@ This is equivalent to the following: :caption: Expansion from defining a simple type static void my_device_finalize(Object *obj); - static void my_device_class_init(ObjectClass *oc, void *data); + static void my_device_class_init(ObjectClass *oc, const void *data); static void my_device_init(Object *obj); static const TypeInfo my_device_info = { diff --git a/docs/devel/reset.rst b/docs/devel/reset.rst index 0b8b2fa5f4..c02fe0a405 100644 --- a/docs/devel/reset.rst +++ b/docs/devel/reset.rst @@ -216,7 +216,7 @@ in reset. ResettablePhases parent_phases; } MyDevClass; - static void mydev_class_init(ObjectClass *class, void *data) + static void mydev_class_init(ObjectClass *class, const void *data) { MyDevClass *myclass = MYDEV_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); diff --git a/docs/devel/virtio-backends.rst b/docs/devel/virtio-backends.rst index 679d7544b8..ebddc3b9f5 100644 --- a/docs/devel/virtio-backends.rst +++ b/docs/devel/virtio-backends.rst @@ -119,7 +119,7 @@ manually instantiated: qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } - static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) + static void virtio_blk_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/event-loop-base.c b/event-loop-base.c index ddf8400a6b..733c54486c 100644 --- a/event-loop-base.c +++ b/event-loop-base.c @@ -97,7 +97,8 @@ static bool event_loop_base_can_be_deleted(UserCreatable *uc) return true; } -static void event_loop_base_class_init(ObjectClass *klass, void *class_data) +static void event_loop_base_class_init(ObjectClass *klass, + const void *class_data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass); ucc->complete = event_loop_base_complete; diff --git a/gdbstub/system.c b/gdbstub/system.c index dd22ff0fb3..8a32d8e1a1 100644 --- a/gdbstub/system.c +++ b/gdbstub/system.c @@ -243,7 +243,7 @@ static void gdb_monitor_open(Chardev *chr, ChardevBackend *backend, *be_opened = false; } -static void char_gdb_class_init(ObjectClass *oc, void *data) +static void char_gdb_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index bb2843da0f..81b91e47c6 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -248,7 +248,7 @@ static const Property virtio_9p_properties[] = { DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id), }; -static void virtio_9p_class_init(ObjectClass *klass, void *data) +static void virtio_9p_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index 2e49b551f2..90148ec9dc 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -1018,7 +1018,7 @@ static const Property erst_properties[] = { default_record_size, ERST_RECORD_SIZE), }; -static void erst_class_init(ObjectClass *klass, void *data) +static void erst_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index c85d97ca37..f589e79a2b 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -469,7 +469,7 @@ static void acpi_ged_initfn(Object *obj) sysbus_init_mmio(sbd, &ged_st->regs); } -static void acpi_ged_class_init(ObjectClass *class, void *data) +static void acpi_ged_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(class); diff --git a/hw/acpi/pci.c b/hw/acpi/pci.c index f88f450af3..d511a85029 100644 --- a/hw/acpi/pci.c +++ b/hw/acpi/pci.c @@ -133,7 +133,7 @@ static void acpi_generic_initiator_set_node(Object *obj, Visitor *v, ms->numa_state->nodes[gi->node].has_gi = true; } -static void acpi_generic_initiator_class_init(ObjectClass *oc, void *data) +static void acpi_generic_initiator_class_init(ObjectClass *oc, const void *data) { object_class_property_add_str(oc, "pci-dev", NULL, acpi_generic_initiator_set_pci_device); @@ -247,7 +247,7 @@ static void acpi_generic_port_set_node(Object *obj, Visitor *v, gp->node = value; } -static void acpi_generic_port_class_init(ObjectClass *oc, void *data) +static void acpi_generic_port_class_init(ObjectClass *oc, const void *data) { object_class_property_add_str(oc, "pci-bus", NULL, acpi_generic_port_set_pci_bus); diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 6d023e595b..5860e8408b 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -619,7 +619,7 @@ static const Property piix4_pm_properties[] = { not_migrate_acpi_index, false), }; -static void piix4_pm_class_init(ObjectClass *klass, void *data) +static void piix4_pm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/acpi/vmclock.c b/hw/acpi/vmclock.c index 7387e5c9ca..c582c0c1f8 100644 --- a/hw/acpi/vmclock.c +++ b/hw/acpi/vmclock.c @@ -154,7 +154,7 @@ static void vmclock_realize(DeviceState *dev, Error **errp) vmclock_update_guest(vms); } -static void vmclock_device_class_init(ObjectClass *klass, void *data) +static void vmclock_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/acpi/vmgenid.c b/hw/acpi/vmgenid.c index 008768e036..fac3d6d97e 100644 --- a/hw/acpi/vmgenid.c +++ b/hw/acpi/vmgenid.c @@ -218,7 +218,7 @@ static const Property vmgenid_device_properties[] = { DEFINE_PROP_UUID(VMGENID_GUID, VmGenIdState, guid), }; -static void vmgenid_device_class_init(ObjectClass *klass, void *data) +static void vmgenid_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/adc/aspeed_adc.c b/hw/adc/aspeed_adc.c index 1cc554f179..3e820cae1e 100644 --- a/hw/adc/aspeed_adc.c +++ b/hw/adc/aspeed_adc.c @@ -291,7 +291,7 @@ static const Property aspeed_adc_engine_properties[] = { DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0), }; -static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data) +static void aspeed_adc_engine_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -369,7 +369,7 @@ static void aspeed_adc_realize(DeviceState *dev, Error **errp) } } -static void aspeed_adc_class_init(ObjectClass *klass, void *data) +static void aspeed_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); @@ -379,7 +379,7 @@ static void aspeed_adc_class_init(ObjectClass *klass, void *data) aac->nr_engines = 1; } -static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); @@ -388,7 +388,7 @@ static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data) aac->nr_engines = 2; } -static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); @@ -397,7 +397,7 @@ static void aspeed_1030_adc_class_init(ObjectClass *klass, void *data) aac->nr_engines = 2; } -static void aspeed_2700_adc_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedADCClass *aac = ASPEED_ADC_CLASS(klass); diff --git a/hw/adc/npcm7xx_adc.c b/hw/adc/npcm7xx_adc.c index 0a83d28605..ddb219d456 100644 --- a/hw/adc/npcm7xx_adc.c +++ b/hw/adc/npcm7xx_adc.c @@ -271,7 +271,7 @@ static const Property npcm7xx_timer_properties[] = { DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF), }; -static void npcm7xx_adc_class_init(ObjectClass *klass, void *data) +static void npcm7xx_adc_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/adc/stm32f2xx_adc.c b/hw/adc/stm32f2xx_adc.c index e3b21f9077..a490ae640d 100644 --- a/hw/adc/stm32f2xx_adc.c +++ b/hw/adc/stm32f2xx_adc.c @@ -284,7 +284,7 @@ static void stm32f2xx_adc_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } -static void stm32f2xx_adc_class_init(ObjectClass *klass, void *data) +static void stm32f2xx_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/adc/zynq-xadc.c b/hw/adc/zynq-xadc.c index 26d9a7b9a5..748a51ba78 100644 --- a/hw/adc/zynq-xadc.c +++ b/hw/adc/zynq-xadc.c @@ -281,7 +281,7 @@ static const VMStateDescription vmstate_zynq_xadc = { } }; -static void zynq_xadc_class_init(ObjectClass *klass, void *data) +static void zynq_xadc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/alpha/typhoon.c b/hw/alpha/typhoon.c index 9718e1a579..4c56f981d7 100644 --- a/hw/alpha/typhoon.c +++ b/hw/alpha/typhoon.c @@ -935,7 +935,7 @@ static const TypeInfo typhoon_pcihost_info = { }; static void typhoon_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/arm/allwinner-a10.c b/hw/arm/allwinner-a10.c index f1b399759a..dc910d4177 100644 --- a/hw/arm/allwinner-a10.c +++ b/hw/arm/allwinner-a10.c @@ -208,7 +208,7 @@ static void aw_a10_realize(DeviceState *dev, Error **errp) sysbus_mmio_map_overlap(SYS_BUS_DEVICE(&s->wdt), 0, AW_A10_WDT_BASE, 1); } -static void aw_a10_class_init(ObjectClass *oc, void *data) +static void aw_a10_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/allwinner-h3.c b/hw/arm/allwinner-h3.c index 1b1afa4fb6..edffc21dd8 100644 --- a/hw/arm/allwinner-h3.c +++ b/hw/arm/allwinner-h3.c @@ -466,7 +466,7 @@ static void allwinner_h3_realize(DeviceState *dev, Error **errp) } } -static void allwinner_h3_class_init(ObjectClass *oc, void *data) +static void allwinner_h3_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/allwinner-r40.c b/hw/arm/allwinner-r40.c index cef6e4d18c..0bf700865c 100644 --- a/hw/arm/allwinner-r40.c +++ b/hw/arm/allwinner-r40.c @@ -539,7 +539,7 @@ static void allwinner_r40_realize(DeviceState *dev, Error **errp) } } -static void allwinner_r40_class_init(ObjectClass *oc, void *data) +static void allwinner_r40_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index ffd732f806..d65a46b8d8 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -1691,7 +1691,7 @@ static void armsse_reset(DeviceState *dev) s->nsccfg = 0; } -static void armsse_class_init(ObjectClass *klass, void *data) +static void armsse_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(klass); diff --git a/hw/arm/armv7m.c b/hw/arm/armv7m.c index 64009174b9..cea3eb49ee 100644 --- a/hw/arm/armv7m.c +++ b/hw/arm/armv7m.c @@ -565,7 +565,7 @@ static const VMStateDescription vmstate_armv7m = { } }; -static void armv7m_class_init(ObjectClass *klass, void *data) +static void armv7m_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -636,7 +636,7 @@ static const Property bitband_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void bitband_class_init(ObjectClass *klass, void *data) +static void bitband_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 82f42582fa..20f418fb63 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -1227,7 +1227,7 @@ static void aspeed_machine_ast2600_class_emmc_init(ObjectClass *oc) "Set or unset boot from EMMC"); } -static void aspeed_machine_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1243,7 +1243,8 @@ static void aspeed_machine_class_init(ObjectClass *oc, void *data) aspeed_machine_class_props_init(oc); } -static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_palmetto_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1260,7 +1261,8 @@ static void aspeed_machine_palmetto_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1278,7 +1280,7 @@ static void aspeed_machine_quanta_q71l_class_init(ObjectClass *oc, void *data) } static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1297,7 +1299,7 @@ static void aspeed_machine_supermicrox11_bmc_class_init(ObjectClass *oc, } static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1315,7 +1317,8 @@ static void aspeed_machine_supermicro_x11spi_bmc_class_init(ObjectClass *oc, aspeed_machine_class_init_cpus_defaults(mc); } -static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1332,7 +1335,8 @@ static void aspeed_machine_ast2500_evb_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1350,7 +1354,8 @@ static void aspeed_machine_yosemitev2_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_romulus_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1367,7 +1372,8 @@ static void aspeed_machine_romulus_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1385,7 +1391,8 @@ static void aspeed_machine_tiogapass_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1402,7 +1409,8 @@ static void aspeed_machine_sonorapass_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1419,7 +1427,8 @@ static void aspeed_machine_witherspoon_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1441,7 +1450,7 @@ static void aspeed_machine_ast2600_evb_class_init(ObjectClass *oc, void *data) aspeed_machine_ast2600_class_emmc_init(oc); }; -static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_g220a_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1459,7 +1468,8 @@ static void aspeed_machine_g220a_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1477,7 +1487,7 @@ static void aspeed_machine_fp5280g2_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); }; -static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_rainier_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1499,7 +1509,7 @@ static void aspeed_machine_rainier_class_init(ObjectClass *oc, void *data) #define FUJI_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) -static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_fuji_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1521,7 +1531,8 @@ static void aspeed_machine_fuji_class_init(ObjectClass *oc, void *data) #define BLETCHLEY_BMC_RAM_SIZE ASPEED_RAM_SIZE(2 * GiB) -static void aspeed_machine_bletchley_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_bletchley_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1566,7 +1577,7 @@ static void fby35_reset(MachineState *state, ResetType type) object_property_set_bool(OBJECT(gpio), "gpioB5", false, &error_fatal); } -static void aspeed_machine_fby35_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_fby35_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1644,7 +1655,7 @@ static void ast1030_evb_i2c_init(AspeedMachineState *bmc) } static void aspeed_minibmc_machine_ast1030_evb_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1673,7 +1684,8 @@ static void ast2700_evb_i2c_init(AspeedMachineState *bmc) TYPE_TMP105, 0x4d); } -static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1694,7 +1706,8 @@ static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc, void *data) aspeed_machine_class_init_cpus_defaults(mc); } -static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc, void *data) +static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1716,7 +1729,7 @@ static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc, void *data) #endif static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); @@ -1736,7 +1749,7 @@ static void aspeed_machine_qcom_dc_scm_v1_class_init(ObjectClass *oc, }; static void aspeed_machine_qcom_firework_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); AspeedMachineClass *amc = ASPEED_MACHINE_CLASS(oc); diff --git a/hw/arm/aspeed_ast10x0.c b/hw/arm/aspeed_ast10x0.c index 21ffab10f3..e6e1ee63c1 100644 --- a/hw/arm/aspeed_ast10x0.c +++ b/hw/arm/aspeed_ast10x0.c @@ -415,7 +415,7 @@ static void aspeed_soc_ast1030_realize(DeviceState *dev_soc, Error **errp) sc->memmap[ASPEED_DEV_JTAG1], 0x20); } -static void aspeed_soc_ast1030_class_init(ObjectClass *klass, void *data) +static void aspeed_soc_ast1030_class_init(ObjectClass *klass, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */ diff --git a/hw/arm/aspeed_ast2400.c b/hw/arm/aspeed_ast2400.c index 0158f6e9c2..c7b0f21887 100644 --- a/hw/arm/aspeed_ast2400.c +++ b/hw/arm/aspeed_ast2400.c @@ -502,7 +502,7 @@ static void aspeed_ast2400_soc_realize(DeviceState *dev, Error **errp) aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); } -static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_ast2400_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("arm926"), @@ -530,7 +530,7 @@ static void aspeed_soc_ast2400_class_init(ObjectClass *oc, void *data) sc->get_irq = aspeed_soc_ast2400_get_irq; } -static void aspeed_soc_ast2500_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_ast2500_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("arm1176"), diff --git a/hw/arm/aspeed_ast2600.c b/hw/arm/aspeed_ast2600.c index 1f994ba26c..d12707f0ab 100644 --- a/hw/arm/aspeed_ast2600.c +++ b/hw/arm/aspeed_ast2600.c @@ -653,7 +653,7 @@ static bool aspeed_soc_ast2600_boot_from_emmc(AspeedSoCState *s) return !!(hw_strap1 & SCU_AST2600_HW_STRAP_BOOT_SRC_EMMC); } -static void aspeed_soc_ast2600_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_ast2600_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a7"), diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index dce7255a2c..63a366f7e8 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -883,7 +883,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) create_unimplemented_device("ast2700.io", 0x0, 0x4000000); } -static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a35"), @@ -910,7 +910,7 @@ static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, void *data) sc->get_irq = aspeed_soc_ast2700_get_irq; } -static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a35"), diff --git a/hw/arm/aspeed_soc_common.c b/hw/arm/aspeed_soc_common.c index 1ddcb26c1e..1c4ac93a0f 100644 --- a/hw/arm/aspeed_soc_common.c +++ b/hw/arm/aspeed_soc_common.c @@ -146,7 +146,7 @@ static const Property aspeed_soc_properties[] = { MemoryRegion *), }; -static void aspeed_soc_class_init(ObjectClass *oc, void *data) +static void aspeed_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); AspeedSoCClass *sc = ASPEED_SOC_CLASS(oc); diff --git a/hw/arm/b-l475e-iot01a.c b/hw/arm/b-l475e-iot01a.c index c9a5209216..34ed2e0851 100644 --- a/hw/arm/b-l475e-iot01a.c +++ b/hw/arm/b-l475e-iot01a.c @@ -110,7 +110,7 @@ static void bl475e_init(MachineState *machine) } } -static void bl475e_machine_init(ObjectClass *oc, void *data) +static void bl475e_machine_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); static const char *machine_valid_cpu_types[] = { diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index adc9730c2e..8a1e72dfab 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -520,7 +520,7 @@ void bcm_soc_peripherals_common_realize(DeviceState *dev, Error **errp) create_unimp(s, &s->sdramc, "bcm2835-sdramc", SDRAMC_OFFSET, 0x100); } -static void bcm2835_peripherals_class_init(ObjectClass *oc, void *data) +static void bcm2835_peripherals_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCMSocPeripheralBaseClass *bc = BCM_SOC_PERIPHERALS_BASE_CLASS(oc); diff --git a/hw/arm/bcm2836.c b/hw/arm/bcm2836.c index 95e16806fa..cd61ba1505 100644 --- a/hw/arm/bcm2836.c +++ b/hw/arm/bcm2836.c @@ -163,7 +163,7 @@ static void bcm2836_realize(DeviceState *dev, Error **errp) } } -static void bcm283x_base_class_init(ObjectClass *oc, void *data) +static void bcm283x_base_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -171,7 +171,7 @@ static void bcm283x_base_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; } -static void bcm2835_class_init(ObjectClass *oc, void *data) +static void bcm2835_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc); @@ -182,7 +182,7 @@ static void bcm2835_class_init(ObjectClass *oc, void *data) dc->realize = bcm2835_realize; }; -static void bcm2836_class_init(ObjectClass *oc, void *data) +static void bcm2836_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc); @@ -196,7 +196,7 @@ static void bcm2836_class_init(ObjectClass *oc, void *data) }; #ifdef TARGET_AARCH64 -static void bcm2837_class_init(ObjectClass *oc, void *data) +static void bcm2837_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCM283XBaseClass *bc = BCM283X_BASE_CLASS(oc); diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c index ddb7c5f757..22aa754613 100644 --- a/hw/arm/bcm2838.c +++ b/hw/arm/bcm2838.c @@ -233,7 +233,7 @@ static void bcm2838_realize(DeviceState *dev, Error **errp) qdev_pass_gpios(DEVICE(&s->gic), DEVICE(&s->peripherals), NULL); } -static void bcm2838_class_init(ObjectClass *oc, void *data) +static void bcm2838_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCM283XBaseClass *bc_base = BCM283X_BASE_CLASS(oc); diff --git a/hw/arm/bcm2838_peripherals.c b/hw/arm/bcm2838_peripherals.c index e28bef4a37..812b5b8480 100644 --- a/hw/arm/bcm2838_peripherals.c +++ b/hw/arm/bcm2838_peripherals.c @@ -196,7 +196,7 @@ static void bcm2838_peripherals_realize(DeviceState *dev, Error **errp) create_unimp(s_base, &s->asb, "bcm2838-asb", BRDG_OFFSET, 0x24); } -static void bcm2838_peripherals_class_init(ObjectClass *oc, void *data) +static void bcm2838_peripherals_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); BCM2838PeripheralClass *bc = BCM2838_PERIPHERALS_CLASS(oc); diff --git a/hw/arm/collie.c b/hw/arm/collie.c index e83aee58c6..93bb190f1f 100644 --- a/hw/arm/collie.c +++ b/hw/arm/collie.c @@ -69,7 +69,7 @@ static void collie_init(MachineState *machine) arm_load_kernel(cms->sa1110->cpu, machine, &collie_binfo); } -static void collie_machine_class_init(ObjectClass *oc, void *data) +static void collie_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/digic.c b/hw/arm/digic.c index 5836619d9f..d831bc974d 100644 --- a/hw/arm/digic.c +++ b/hw/arm/digic.c @@ -79,7 +79,7 @@ static void digic_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sbd, 0, DIGIC_UART_BASE); } -static void digic_class_init(ObjectClass *oc, void *data) +static void digic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/exynos4210.c b/hw/arm/exynos4210.c index 0c27588116..76001ff0df 100644 --- a/hw/arm/exynos4210.c +++ b/hw/arm/exynos4210.c @@ -842,7 +842,7 @@ static void exynos4210_init(Object *obj) TYPE_EXYNOS4210_COMBINER); } -static void exynos4210_class_init(ObjectClass *klass, void *data) +static void exynos4210_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/exynos4_boards.c b/hw/arm/exynos4_boards.c index 2d8f2d7326..7304974131 100644 --- a/hw/arm/exynos4_boards.c +++ b/hw/arm/exynos4_boards.c @@ -154,7 +154,7 @@ static const char * const valid_cpu_types[] = { NULL }; -static void nuri_class_init(ObjectClass *oc, void *data) +static void nuri_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -174,7 +174,7 @@ static const TypeInfo nuri_type = { .class_init = nuri_class_init, }; -static void smdkc210_class_init(ObjectClass *oc, void *data) +static void smdkc210_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c index 6d3663f14a..e123fa69e1 100644 --- a/hw/arm/fby35.c +++ b/hw/arm/fby35.c @@ -162,7 +162,7 @@ static void fby35_instance_init(Object *obj) FBY35(obj)->mmio_exec = false; } -static void fby35_class_init(ObjectClass *oc, void *data) +static void fby35_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c index 02214ca1a1..7aad6359ea 100644 --- a/hw/arm/fsl-imx25.c +++ b/hw/arm/fsl-imx25.c @@ -311,7 +311,7 @@ static const Property fsl_imx25_properties[] = { DEFINE_PROP_UINT32("fec-phy-num", FslIMX25State, phy_num, 0), }; -static void fsl_imx25_class_init(ObjectClass *oc, void *data) +static void fsl_imx25_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c index 2a8ffb15f7..e9f70ad94b 100644 --- a/hw/arm/fsl-imx31.c +++ b/hw/arm/fsl-imx31.c @@ -218,7 +218,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp) &s->iram_alias); } -static void fsl_imx31_class_init(ObjectClass *oc, void *data) +static void fsl_imx31_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/fsl-imx6.c b/hw/arm/fsl-imx6.c index a114dc0d63..f3a60022d8 100644 --- a/hw/arm/fsl-imx6.c +++ b/hw/arm/fsl-imx6.c @@ -484,7 +484,7 @@ static const Property fsl_imx6_properties[] = { DEFINE_PROP_UINT32("fec-phy-num", FslIMX6State, phy_num, 0), }; -static void fsl_imx6_class_init(ObjectClass *oc, void *data) +static void fsl_imx6_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/fsl-imx6ul.c b/hw/arm/fsl-imx6ul.c index ce8d3ef535..883c7fc534 100644 --- a/hw/arm/fsl-imx6ul.c +++ b/hw/arm/fsl-imx6ul.c @@ -715,7 +715,7 @@ static const Property fsl_imx6ul_properties[] = { true), }; -static void fsl_imx6ul_class_init(ObjectClass *oc, void *data) +static void fsl_imx6ul_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/fsl-imx7.c b/hw/arm/fsl-imx7.c index ed1f10bca2..02f7602077 100644 --- a/hw/arm/fsl-imx7.c +++ b/hw/arm/fsl-imx7.c @@ -748,7 +748,7 @@ static const Property fsl_imx7_properties[] = { true), }; -static void fsl_imx7_class_init(ObjectClass *oc, void *data) +static void fsl_imx7_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/fsl-imx8mp.c b/hw/arm/fsl-imx8mp.c index af7a7e6745..23e662c16c 100644 --- a/hw/arm/fsl-imx8mp.c +++ b/hw/arm/fsl-imx8mp.c @@ -689,7 +689,7 @@ static const Property fsl_imx8mp_properties[] = { DEFINE_PROP_BOOL("fec1-phy-connected", FslImx8mpState, phy_connected, true), }; -static void fsl_imx8mp_class_init(ObjectClass *oc, void *data) +static void fsl_imx8mp_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/arm/highbank.c b/hw/arm/highbank.c index 0f3c207d54..3ae26ebebd 100644 --- a/hw/arm/highbank.c +++ b/hw/arm/highbank.c @@ -139,7 +139,7 @@ static void highbank_regs_init(Object *obj) sysbus_init_mmio(dev, &s->iomem); } -static void highbank_regs_class_init(ObjectClass *klass, void *data) +static void highbank_regs_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -341,7 +341,7 @@ static void midway_init(MachineState *machine) calxeda_init(machine, CALXEDA_MIDWAY); } -static void highbank_class_init(ObjectClass *oc, void *data) +static void highbank_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a9"), @@ -365,7 +365,7 @@ static const TypeInfo highbank_type = { .class_init = highbank_class_init, }; -static void midway_class_init(ObjectClass *oc, void *data) +static void midway_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a15"), diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c index ac0c6c6096..b1d8fbd470 100644 --- a/hw/arm/integratorcp.c +++ b/hw/arm/integratorcp.c @@ -699,7 +699,7 @@ static const Property core_properties[] = { DEFINE_PROP_UINT32("memsz", IntegratorCMState, memsz, 0), }; -static void core_class_init(ObjectClass *klass, void *data) +static void core_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -708,14 +708,14 @@ static void core_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_integratorcm; } -static void icp_pic_class_init(ObjectClass *klass, void *data) +static void icp_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_icp_pic; } -static void icp_control_class_init(ObjectClass *klass, void *data) +static void icp_control_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c index ade363daaa..525443fdb9 100644 --- a/hw/arm/microbit.c +++ b/hw/arm/microbit.c @@ -60,7 +60,7 @@ static void microbit_init(MachineState *machine) 0, s->nrf51.flash_size); } -static void microbit_machine_class_init(ObjectClass *oc, void *data) +static void microbit_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index b0633a5a69..8474549f5f 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -1267,7 +1267,7 @@ static void mps2_machine_reset(MachineState *machine, ResetType type) qemu_devices_reset(type); } -static void mps2tz_class_init(ObjectClass *oc, void *data) +static void mps2tz_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); IDAUInterfaceClass *iic = IDAU_INTERFACE_CLASS(oc); @@ -1304,7 +1304,7 @@ static void mps2tz_set_default_ram_info(MPS2TZMachineClass *mmc) g_assert_not_reached(); } -static void mps2tz_an505_class_init(ObjectClass *oc, void *data) +static void mps2tz_an505_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); @@ -1338,7 +1338,7 @@ static void mps2tz_an505_class_init(ObjectClass *oc, void *data) mps2tz_set_default_ram_info(mmc); } -static void mps2tz_an521_class_init(ObjectClass *oc, void *data) +static void mps2tz_an521_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); @@ -1372,7 +1372,7 @@ static void mps2tz_an521_class_init(ObjectClass *oc, void *data) mps2tz_set_default_ram_info(mmc); } -static void mps3tz_an524_class_init(ObjectClass *oc, void *data) +static void mps3tz_an524_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); @@ -1411,7 +1411,7 @@ static void mps3tz_an524_class_init(ObjectClass *oc, void *data) "are BRAM (default) and QSPI."); } -static void mps3tz_an547_class_init(ObjectClass *oc, void *data) +static void mps3tz_an547_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2TZMachineClass *mmc = MPS2TZ_MACHINE_CLASS(oc); diff --git a/hw/arm/mps2.c b/hw/arm/mps2.c index 6958485a66..58efb41e6d 100644 --- a/hw/arm/mps2.c +++ b/hw/arm/mps2.c @@ -464,7 +464,7 @@ static void mps2_common_init(MachineState *machine) 0, 0x400000); } -static void mps2_class_init(ObjectClass *oc, void *data) +static void mps2_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -474,7 +474,7 @@ static void mps2_class_init(ObjectClass *oc, void *data) mc->default_ram_id = "mps.ram"; } -static void mps2_an385_class_init(ObjectClass *oc, void *data) +static void mps2_an385_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); @@ -493,7 +493,7 @@ static void mps2_an385_class_init(ObjectClass *oc, void *data) mmc->has_block_ram = true; } -static void mps2_an386_class_init(ObjectClass *oc, void *data) +static void mps2_an386_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); @@ -512,7 +512,7 @@ static void mps2_an386_class_init(ObjectClass *oc, void *data) mmc->has_block_ram = true; } -static void mps2_an500_class_init(ObjectClass *oc, void *data) +static void mps2_an500_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); @@ -531,7 +531,7 @@ static void mps2_an500_class_init(ObjectClass *oc, void *data) mmc->has_block_ram = false; } -static void mps2_an511_class_init(ObjectClass *oc, void *data) +static void mps2_an511_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS2MachineClass *mmc = MPS2_MACHINE_CLASS(oc); diff --git a/hw/arm/mps3r.c b/hw/arm/mps3r.c index 4dd1e8a718..48c73acc62 100644 --- a/hw/arm/mps3r.c +++ b/hw/arm/mps3r.c @@ -583,14 +583,14 @@ static void mps3r_set_default_ram_info(MPS3RMachineClass *mmc) g_assert_not_reached(); } -static void mps3r_class_init(ObjectClass *oc, void *data) +static void mps3r_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->init = mps3r_common_init; } -static void mps3r_an536_class_init(ObjectClass *oc, void *data) +static void mps3r_an536_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MPS3RMachineClass *mmc = MPS3R_MACHINE_CLASS(oc); diff --git a/hw/arm/msf2-soc.c b/hw/arm/msf2-soc.c index bc9b419e37..c5e9c7175a 100644 --- a/hw/arm/msf2-soc.c +++ b/hw/arm/msf2-soc.c @@ -236,7 +236,7 @@ static const Property m2sxxx_soc_properties[] = { DEFINE_PROP_UINT8("apb1div", MSF2State, apb1div, 2), }; -static void m2sxxx_soc_class_init(ObjectClass *klass, void *data) +static void m2sxxx_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/musca.c b/hw/arm/musca.c index a4f43f1992..250b3b5bf8 100644 --- a/hw/arm/musca.c +++ b/hw/arm/musca.c @@ -594,7 +594,7 @@ static void musca_init(MachineState *machine) 0, 0x2000000); } -static void musca_class_init(ObjectClass *oc, void *data) +static void musca_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); static const char * const valid_cpu_types[] = { @@ -609,7 +609,7 @@ static void musca_class_init(ObjectClass *oc, void *data) mc->init = musca_init; } -static void musca_a_class_init(ObjectClass *oc, void *data) +static void musca_a_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc); @@ -623,7 +623,7 @@ static void musca_a_class_init(ObjectClass *oc, void *data) mmc->num_mpcs = ARRAY_SIZE(a_mpc_info); } -static void musca_b1_class_init(ObjectClass *oc, void *data) +static void musca_b1_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MuscaMachineClass *mmc = MUSCA_MACHINE_CLASS(oc); diff --git a/hw/arm/musicpal.c b/hw/arm/musicpal.c index 48a32c2407..329b162eb2 100644 --- a/hw/arm/musicpal.c +++ b/hw/arm/musicpal.c @@ -286,7 +286,7 @@ static const VMStateDescription musicpal_lcd_vmsd = { } }; -static void musicpal_lcd_class_init(ObjectClass *klass, void *data) +static void musicpal_lcd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -407,7 +407,7 @@ static const VMStateDescription mv88w8618_pic_vmsd = { } }; -static void mv88w8618_pic_class_init(ObjectClass *klass, void *data) +static void mv88w8618_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -601,7 +601,7 @@ static const VMStateDescription mv88w8618_pit_vmsd = { } }; -static void mv88w8618_pit_class_init(ObjectClass *klass, void *data) +static void mv88w8618_pit_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -687,7 +687,7 @@ static const VMStateDescription mv88w8618_flashcfg_vmsd = { } }; -static void mv88w8618_flashcfg_class_init(ObjectClass *klass, void *data) +static void mv88w8618_flashcfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1026,7 +1026,7 @@ static const VMStateDescription musicpal_gpio_vmsd = { } }; -static void musicpal_gpio_class_init(ObjectClass *klass, void *data) +static void musicpal_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1171,7 +1171,7 @@ static const VMStateDescription musicpal_key_vmsd = { } }; -static void musicpal_key_class_init(ObjectClass *klass, void *data) +static void musicpal_key_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1348,7 +1348,7 @@ static void musicpal_machine_init(MachineClass *mc) DEFINE_MACHINE("musicpal", musicpal_machine_init) -static void mv88w8618_wlan_class_init(ObjectClass *klass, void *data) +static void mv88w8618_wlan_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/npcm7xx.c b/hw/arm/npcm7xx.c index 2d6e08b72b..2f30c49df5 100644 --- a/hw/arm/npcm7xx.c +++ b/hw/arm/npcm7xx.c @@ -821,7 +821,7 @@ static const Property npcm7xx_properties[] = { MemoryRegion *), }; -static void npcm7xx_class_init(ObjectClass *oc, void *data) +static void npcm7xx_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -830,7 +830,7 @@ static void npcm7xx_class_init(ObjectClass *oc, void *data) device_class_set_props(dc, npcm7xx_properties); } -static void npcm730_class_init(ObjectClass *oc, void *data) +static void npcm730_class_init(ObjectClass *oc, const void *data) { NPCM7xxClass *nc = NPCM7XX_CLASS(oc); @@ -839,7 +839,7 @@ static void npcm730_class_init(ObjectClass *oc, void *data) nc->num_cpus = 2; } -static void npcm750_class_init(ObjectClass *oc, void *data) +static void npcm750_class_init(ObjectClass *oc, const void *data) { NPCM7xxClass *nc = NPCM7XX_CLASS(oc); diff --git a/hw/arm/npcm7xx_boards.c b/hw/arm/npcm7xx_boards.c index eb28b97ad8..465a0e5ace 100644 --- a/hw/arm/npcm7xx_boards.c +++ b/hw/arm/npcm7xx_boards.c @@ -453,7 +453,7 @@ static void npcm7xx_set_soc_type(NPCM7xxMachineClass *nmc, const char *type) mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus; } -static void npcm7xx_machine_class_init(ObjectClass *oc, void *data) +static void npcm7xx_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); static const char * const valid_cpu_types[] = { @@ -472,7 +472,7 @@ static void npcm7xx_machine_class_init(ObjectClass *oc, void *data) * Schematics: * https://github.com/Nuvoton-Israel/nuvoton-info/blob/master/npcm7xx-poleg/evaluation-board/board_deliverables/NPCM750x_EB_ver.A1.1_COMPLETE.pdf */ -static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data) +static void npcm750_evb_machine_class_init(ObjectClass *oc, const void *data) { NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); @@ -485,7 +485,7 @@ static void npcm750_evb_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * MiB; }; -static void gsj_machine_class_init(ObjectClass *oc, void *data) +static void gsj_machine_class_init(ObjectClass *oc, const void *data) { NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); @@ -498,7 +498,7 @@ static void gsj_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * MiB; }; -static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data) +static void gbs_bmc_machine_class_init(ObjectClass *oc, const void *data) { NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); @@ -511,7 +511,7 @@ static void gbs_bmc_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 1 * GiB; } -static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data) +static void kudo_bmc_machine_class_init(ObjectClass *oc, const void *data) { NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); @@ -524,7 +524,7 @@ static void kudo_bmc_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 1 * GiB; }; -static void mori_bmc_machine_class_init(ObjectClass *oc, void *data) +static void mori_bmc_machine_class_init(ObjectClass *oc, const void *data) { NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c index f182accc47..5cc67b132f 100644 --- a/hw/arm/npcm8xx.c +++ b/hw/arm/npcm8xx.c @@ -779,7 +779,7 @@ static const Property npcm8xx_properties[] = { MemoryRegion *), }; -static void npcm8xx_class_init(ObjectClass *oc, void *data) +static void npcm8xx_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); NPCM8xxClass *nc = NPCM8XX_CLASS(oc); diff --git a/hw/arm/npcm8xx_boards.c b/hw/arm/npcm8xx_boards.c index 3fb8478e72..9d9f6d0c9a 100644 --- a/hw/arm/npcm8xx_boards.c +++ b/hw/arm/npcm8xx_boards.c @@ -209,7 +209,7 @@ static void npcm8xx_set_soc_type(NPCM8xxMachineClass *nmc, const char *type) mc->default_cpus = mc->min_cpus = mc->max_cpus = sc->num_cpus; } -static void npcm8xx_machine_class_init(ObjectClass *oc, void *data) +static void npcm8xx_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); static const char * const valid_cpu_types[] = { @@ -224,7 +224,7 @@ static void npcm8xx_machine_class_init(ObjectClass *oc, void *data) mc->valid_cpu_types = valid_cpu_types; } -static void npcm845_evb_machine_class_init(ObjectClass *oc, void *data) +static void npcm845_evb_machine_class_init(ObjectClass *oc, const void *data) { NPCM8xxMachineClass *nmc = NPCM8XX_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/nrf51_soc.c b/hw/arm/nrf51_soc.c index dee06ab565..d8cc3214ed 100644 --- a/hw/arm/nrf51_soc.c +++ b/hw/arm/nrf51_soc.c @@ -216,7 +216,7 @@ static const Property nrf51_soc_properties[] = { NRF51822_FLASH_SIZE), }; -static void nrf51_soc_class_init(ObjectClass *klass, void *data) +static void nrf51_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index aa1e96b3ad..1d89a202bb 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -202,7 +202,7 @@ static void sx1_init_v2(MachineState *machine) sx1_init(machine, 2); } -static void sx1_machine_v2_class_init(ObjectClass *oc, void *data) +static void sx1_machine_v2_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -221,7 +221,7 @@ static const TypeInfo sx1_machine_v2_type = { .class_init = sx1_machine_v2_class_init, }; -static void sx1_machine_v1_class_init(ObjectClass *oc, void *data) +static void sx1_machine_v1_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/raspi.c b/hw/arm/raspi.c index dce35ca11a..9d9af63d65 100644 --- a/hw/arm/raspi.c +++ b/hw/arm/raspi.c @@ -337,7 +337,7 @@ static void raspi_machine_class_init(MachineClass *mc, mc->init = raspi_machine_init; }; -static void raspi0_machine_class_init(ObjectClass *oc, void *data) +static void raspi0_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); @@ -347,7 +347,7 @@ static void raspi0_machine_class_init(ObjectClass *oc, void *data) raspi_machine_class_init(mc, rmc->board_rev); }; -static void raspi1ap_machine_class_init(ObjectClass *oc, void *data) +static void raspi1ap_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); @@ -357,7 +357,7 @@ static void raspi1ap_machine_class_init(ObjectClass *oc, void *data) raspi_machine_class_init(mc, rmc->board_rev); }; -static void raspi2b_machine_class_init(ObjectClass *oc, void *data) +static void raspi2b_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); @@ -368,7 +368,7 @@ static void raspi2b_machine_class_init(ObjectClass *oc, void *data) }; #ifdef TARGET_AARCH64 -static void raspi3ap_machine_class_init(ObjectClass *oc, void *data) +static void raspi3ap_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); @@ -378,7 +378,7 @@ static void raspi3ap_machine_class_init(ObjectClass *oc, void *data) raspi_machine_class_init(mc, rmc->board_rev); }; -static void raspi3b_machine_class_init(ObjectClass *oc, void *data) +static void raspi3b_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); diff --git a/hw/arm/raspi4b.c b/hw/arm/raspi4b.c index f6de103a3e..20082d5266 100644 --- a/hw/arm/raspi4b.c +++ b/hw/arm/raspi4b.c @@ -107,7 +107,7 @@ static void raspi4b_machine_init(MachineState *machine) raspi_base_machine_init(machine, &soc->parent_obj); } -static void raspi4b_machine_class_init(ObjectClass *oc, void *data) +static void raspi4b_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); RaspiBaseMachineClass *rmc = RASPI_BASE_MACHINE_CLASS(oc); diff --git a/hw/arm/realview.c b/hw/arm/realview.c index 008eeaf049..5c9050490b 100644 --- a/hw/arm/realview.c +++ b/hw/arm/realview.c @@ -413,7 +413,7 @@ static void realview_pbx_a9_init(MachineState *machine) realview_init(machine, BOARD_PBX_A9); } -static void realview_eb_class_init(ObjectClass *oc, void *data) +static void realview_eb_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -433,7 +433,7 @@ static const TypeInfo realview_eb_type = { .class_init = realview_eb_class_init, }; -static void realview_eb_mpcore_class_init(ObjectClass *oc, void *data) +static void realview_eb_mpcore_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -454,7 +454,7 @@ static const TypeInfo realview_eb_mpcore_type = { .class_init = realview_eb_mpcore_class_init, }; -static void realview_pb_a8_class_init(ObjectClass *oc, void *data) +static void realview_pb_a8_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -473,7 +473,7 @@ static const TypeInfo realview_pb_a8_type = { .class_init = realview_pb_a8_class_init, }; -static void realview_pbx_a9_class_init(ObjectClass *oc, void *data) +static void realview_pbx_a9_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/sbsa-ref.c b/hw/arm/sbsa-ref.c index aa09d7a091..deae5cf986 100644 --- a/hw/arm/sbsa-ref.c +++ b/hw/arm/sbsa-ref.c @@ -880,7 +880,7 @@ static void sbsa_ref_instance_init(Object *obj) sbsa_flash_create(sms); } -static void sbsa_ref_class_init(ObjectClass *oc, void *data) +static void sbsa_ref_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); static const char * const valid_cpu_types[] = { diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c index 1aa2eabfbd..f39b99e526 100644 --- a/hw/arm/smmu-common.c +++ b/hw/arm/smmu-common.c @@ -965,7 +965,7 @@ static const Property smmu_dev_properties[] = { TYPE_PCI_BUS, PCIBus *), }; -static void smmu_base_class_init(ObjectClass *klass, void *data) +static void smmu_base_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c index 4362ae6aa1..ab67972353 100644 --- a/hw/arm/smmuv3.c +++ b/hw/arm/smmuv3.c @@ -1984,7 +1984,7 @@ static void smmuv3_instance_init(Object *obj) /* Nothing much to do here as of now */ } -static void smmuv3_class_init(ObjectClass *klass, void *data) +static void smmuv3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -2031,7 +2031,7 @@ static int smmuv3_notify_flag_changed(IOMMUMemoryRegion *iommu, } static void smmuv3_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/arm/stellaris.c b/hw/arm/stellaris.c index cbe914c93e..031ea3a24e 100644 --- a/hw/arm/stellaris.c +++ b/hw/arm/stellaris.c @@ -1413,7 +1413,7 @@ static void lm3s6965evb_init(MachineState *machine) * Stellaris LM3S811 Evaluation Board Schematics: * https://www.ti.com/lit/ug/symlink/spmu030.pdf */ -static void lm3s811evb_class_init(ObjectClass *oc, void *data) +static void lm3s811evb_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1433,7 +1433,7 @@ static const TypeInfo lm3s811evb_type = { * Stellaris: LM3S6965 Evaluation Board Schematics: * https://www.ti.com/lit/ug/symlink/spmu029.pdf */ -static void lm3s6965evb_class_init(ObjectClass *oc, void *data) +static void lm3s6965evb_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1458,7 +1458,7 @@ static void stellaris_machine_init(void) type_init(stellaris_machine_init) -static void stellaris_i2c_class_init(ObjectClass *klass, void *data) +static void stellaris_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1477,7 +1477,7 @@ static const TypeInfo stellaris_i2c_info = { .class_init = stellaris_i2c_class_init, }; -static void stellaris_adc_class_init(ObjectClass *klass, void *data) +static void stellaris_adc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1494,7 +1494,7 @@ static const TypeInfo stellaris_adc_info = { .class_init = stellaris_adc_class_init, }; -static void stellaris_sys_class_init(ObjectClass *klass, void *data) +static void stellaris_sys_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/arm/stm32f100_soc.c b/hw/arm/stm32f100_soc.c index 0eabaf8d9b..0702d51cc3 100644 --- a/hw/arm/stm32f100_soc.c +++ b/hw/arm/stm32f100_soc.c @@ -181,7 +181,7 @@ static void stm32f100_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("CRC", 0x40023000, 0x400); } -static void stm32f100_soc_class_init(ObjectClass *klass, void *data) +static void stm32f100_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c index 32e96912f0..229af7fb10 100644 --- a/hw/arm/stm32f205_soc.c +++ b/hw/arm/stm32f205_soc.c @@ -202,7 +202,7 @@ static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp) } } -static void stm32f205_soc_class_init(ObjectClass *klass, void *data) +static void stm32f205_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/stm32f405_soc.c b/hw/arm/stm32f405_soc.c index bba9060daf..c8684e2b4c 100644 --- a/hw/arm/stm32f405_soc.c +++ b/hw/arm/stm32f405_soc.c @@ -298,7 +298,7 @@ static void stm32f405_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("RNG", 0x50060800, 0x400); } -static void stm32f405_soc_class_init(ObjectClass *klass, void *data) +static void stm32f405_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/stm32l4x5_soc.c b/hw/arm/stm32l4x5_soc.c index 6278d354c8..64da5559c0 100644 --- a/hw/arm/stm32l4x5_soc.c +++ b/hw/arm/stm32l4x5_soc.c @@ -435,7 +435,7 @@ static void stm32l4x5_soc_realize(DeviceState *dev_soc, Error **errp) create_unimplemented_device("QUADSPI", 0xA0001000, 0x400); } -static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -446,21 +446,21 @@ static void stm32l4x5_soc_class_init(ObjectClass *klass, void *data) /* No vmstate or reset required: device has no internal state */ } -static void stm32l4x5xc_soc_class_init(ObjectClass *oc, void *data) +static void stm32l4x5xc_soc_class_init(ObjectClass *oc, const void *data) { Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); ssc->flash_size = 256 * KiB; } -static void stm32l4x5xe_soc_class_init(ObjectClass *oc, void *data) +static void stm32l4x5xe_soc_class_init(ObjectClass *oc, const void *data) { Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); ssc->flash_size = 512 * KiB; } -static void stm32l4x5xg_soc_class_init(ObjectClass *oc, void *data) +static void stm32l4x5xg_soc_class_init(ObjectClass *oc, const void *data) { Stm32l4x5SocClass *ssc = STM32L4X5_SOC_CLASS(oc); diff --git a/hw/arm/strongarm.c b/hw/arm/strongarm.c index a31f4b4c65..229c98ddd9 100644 --- a/hw/arm/strongarm.c +++ b/hw/arm/strongarm.c @@ -215,7 +215,7 @@ static const VMStateDescription vmstate_strongarm_pic_regs = { }, }; -static void strongarm_pic_class_init(ObjectClass *klass, void *data) +static void strongarm_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -448,7 +448,8 @@ static const VMStateDescription vmstate_strongarm_rtc_regs = { }, }; -static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, void *data) +static void strongarm_rtc_sysbus_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -693,7 +694,7 @@ static const VMStateDescription vmstate_strongarm_gpio_regs = { }, }; -static void strongarm_gpio_class_init(ObjectClass *klass, void *data) +static void strongarm_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -865,7 +866,7 @@ static const VMStateDescription vmstate_strongarm_ppc_regs = { }, }; -static void strongarm_ppc_class_init(ObjectClass *klass, void *data) +static void strongarm_ppc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1336,7 +1337,7 @@ static const Property strongarm_uart_properties[] = { DEFINE_PROP_CHR("chardev", StrongARMUARTState, chr), }; -static void strongarm_uart_class_init(ObjectClass *klass, void *data) +static void strongarm_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1589,7 +1590,7 @@ static const VMStateDescription vmstate_strongarm_ssp_regs = { }, }; -static void strongarm_ssp_class_init(ObjectClass *klass, void *data) +static void strongarm_ssp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c index 35766445fa..5cf1a70d10 100644 --- a/hw/arm/versatilepb.c +++ b/hw/arm/versatilepb.c @@ -412,7 +412,7 @@ static void vab_init(MachineState *machine) versatile_init(machine, 0x25e); } -static void versatilepb_class_init(ObjectClass *oc, void *data) +static void versatilepb_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -433,7 +433,7 @@ static const TypeInfo versatilepb_type = { .class_init = versatilepb_class_init, }; -static void versatileab_class_init(ObjectClass *oc, void *data) +static void versatileab_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -462,7 +462,7 @@ static void versatile_machine_init(void) type_init(versatile_machine_init) -static void vpb_sic_class_init(ObjectClass *klass, void *data) +static void vpb_sic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c index 76c6107766..35f8d05ea1 100644 --- a/hw/arm/vexpress.c +++ b/hw/arm/vexpress.c @@ -777,7 +777,7 @@ static void vexpress_a9_instance_init(Object *obj) vms->virt = false; } -static void vexpress_class_init(ObjectClass *oc, void *data) +static void vexpress_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -795,7 +795,7 @@ static void vexpress_class_init(ObjectClass *oc, void *data) "Security Extensions (TrustZone)"); } -static void vexpress_a9_class_init(ObjectClass *oc, void *data) +static void vexpress_a9_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a9"), @@ -811,7 +811,7 @@ static void vexpress_a9_class_init(ObjectClass *oc, void *data) vmc->daughterboard = &a9_daughterboard; } -static void vexpress_a15_class_init(ObjectClass *oc, void *data) +static void vexpress_a15_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a15"), diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 3e72adaa91..17faf34aae 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -107,7 +107,7 @@ static void arm_virt_compat_set(MachineClass *mc) #define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \ static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \ ObjectClass *oc, \ - void *data) \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ arm_virt_compat_set(mc); \ @@ -3124,7 +3124,7 @@ static int virt_hvf_get_physical_address_range(MachineState *ms) return requested_ipa_size; } -static void virt_machine_class_init(ObjectClass *oc, void *data) +static void virt_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/arm/xen-pvh.c b/hw/arm/xen-pvh.c index d1509bd235..4b26bcff7a 100644 --- a/hw/arm/xen-pvh.c +++ b/hw/arm/xen-pvh.c @@ -49,7 +49,7 @@ static void xen_pvh_set_pci_intx_irq(void *opaque, int intx_irq, int level) } } -static void xen_arm_machine_class_init(ObjectClass *oc, void *data) +static void xen_arm_machine_class_init(ObjectClass *oc, const void *data) { XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/xilinx_zynq.c b/hw/arm/xilinx_zynq.c index b8916665ed..0372cd0ac4 100644 --- a/hw/arm/xilinx_zynq.c +++ b/hw/arm/xilinx_zynq.c @@ -453,7 +453,7 @@ static void zynq_init(MachineState *machine) arm_load_kernel(zynq_machine->cpu[0], machine, &zynq_binfo); } -static void zynq_machine_class_init(ObjectClass *oc, void *data) +static void zynq_machine_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { ARM_CPU_TYPE_NAME("cortex-a9"), diff --git a/hw/arm/xlnx-versal-virt.c b/hw/arm/xlnx-versal-virt.c index 0c6f0359e3..adadbb7290 100644 --- a/hw/arm/xlnx-versal-virt.c +++ b/hw/arm/xlnx-versal-virt.c @@ -808,7 +808,7 @@ static void versal_virt_machine_finalize(Object *obj) g_free(s->ospi_model); } -static void versal_virt_machine_class_init(ObjectClass *oc, void *data) +static void versal_virt_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index f0b383b29e..a42b9e7140 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -975,7 +975,7 @@ static const Property versal_properties[] = { TYPE_CAN_BUS, CanBusState *), }; -static void versal_class_init(ObjectClass *klass, void *data) +static void versal_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/arm/xlnx-zcu102.c b/hw/arm/xlnx-zcu102.c index 4fdb153e4d..14b6641a71 100644 --- a/hw/arm/xlnx-zcu102.c +++ b/hw/arm/xlnx-zcu102.c @@ -267,7 +267,7 @@ static void xlnx_zcu102_machine_instance_init(Object *obj) 0); } -static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data) +static void xlnx_zcu102_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c index ec2b3a41ed..ec96a46eec 100644 --- a/hw/arm/xlnx-zynqmp.c +++ b/hw/arm/xlnx-zynqmp.c @@ -853,7 +853,7 @@ static const Property xlnx_zynqmp_props[] = { CanBusState *), }; -static void xlnx_zynqmp_class_init(ObjectClass *oc, void *data) +static void xlnx_zynqmp_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 05c573776e..7454cc60de 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1328,7 +1328,7 @@ static const Property ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(AC97LinkState, card), }; -static void ac97_class_init(ObjectClass *klass, void *data) +static void ac97_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c index 8c9767b537..1f29a7e319 100644 --- a/hw/audio/adlib.c +++ b/hw/audio/adlib.c @@ -303,7 +303,7 @@ static const Property adlib_properties[] = { DEFINE_PROP_UINT32 ("freq", AdlibState, freq, 44100), }; -static void adlib_class_initfn (ObjectClass *klass, void *data) +static void adlib_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS (klass); diff --git a/hw/audio/asc.c b/hw/audio/asc.c index cea7a1c053..18382ccf6a 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -699,7 +699,7 @@ static const Property asc_properties[] = { DEFINE_PROP_UINT8("asctype", ASCState, type, ASC_TYPE_ASC), }; -static void asc_class_init(ObjectClass *oc, void *data) +static void asc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/audio/cs4231.c b/hw/audio/cs4231.c index 8321f89c88..97cceb44d8 100644 --- a/hw/audio/cs4231.c +++ b/hw/audio/cs4231.c @@ -160,7 +160,7 @@ static void cs4231_init(Object *obj) sysbus_init_irq(dev, &s->irq); } -static void cs4231_class_init(ObjectClass *klass, void *data) +static void cs4231_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/audio/cs4231a.c b/hw/audio/cs4231a.c index 5a9be80ba3..06b44da869 100644 --- a/hw/audio/cs4231a.c +++ b/hw/audio/cs4231a.c @@ -696,7 +696,7 @@ static const Property cs4231a_properties[] = { DEFINE_PROP_UINT32 ("dma", CSState, dma, 3), }; -static void cs4231a_class_initfn (ObjectClass *klass, void *data) +static void cs4231a_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS (klass); diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 75f71e5d78..322b779814 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -872,7 +872,7 @@ static const Property es1370_properties[] = { DEFINE_AUDIO_PROPERTIES(ES1370State, card), }; -static void es1370_class_init (ObjectClass *klass, void *data) +static void es1370_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS (klass); PCIDeviceClass *k = PCI_DEVICE_CLASS (klass); diff --git a/hw/audio/gus.c b/hw/audio/gus.c index e718c1183e..87e8634893 100644 --- a/hw/audio/gus.c +++ b/hw/audio/gus.c @@ -298,7 +298,7 @@ static const Property gus_properties[] = { DEFINE_PROP_UINT32 ("dma", GUSState, emu.gusdma, 3), }; -static void gus_class_initfn (ObjectClass *klass, void *data) +static void gus_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS (klass); diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c index 6f3a8f691b..66edad280f 100644 --- a/hw/audio/hda-codec.c +++ b/hw/audio/hda-codec.c @@ -900,7 +900,7 @@ static void hda_audio_init_micro(HDACodecDevice *hda, Error **errp) hda_audio_init(hda, desc, errp); } -static void hda_audio_base_class_init(ObjectClass *klass, void *data) +static void hda_audio_base_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); @@ -922,7 +922,7 @@ static const TypeInfo hda_audio_info = { .abstract = true, }; -static void hda_audio_output_class_init(ObjectClass *klass, void *data) +static void hda_audio_output_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); @@ -937,7 +937,7 @@ static const TypeInfo hda_audio_output_info = { .class_init = hda_audio_output_class_init, }; -static void hda_audio_duplex_class_init(ObjectClass *klass, void *data) +static void hda_audio_duplex_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); @@ -952,7 +952,7 @@ static const TypeInfo hda_audio_duplex_info = { .class_init = hda_audio_duplex_class_init, }; -static void hda_audio_micro_class_init(ObjectClass *klass, void *data) +static void hda_audio_micro_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass); diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 3214992ddc..2f1b08e9c1 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1220,7 +1220,7 @@ static const Property intel_hda_properties[] = { DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false), }; -static void intel_hda_class_init(ObjectClass *klass, void *data) +static void intel_hda_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1234,7 +1234,7 @@ static void intel_hda_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, intel_hda_properties); } -static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) +static void intel_hda_class_init_ich6(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1245,7 +1245,7 @@ static void intel_hda_class_init_ich6(ObjectClass *klass, void *data) dc->desc = "Intel HD Audio Controller (ich6)"; } -static void intel_hda_class_init_ich9(ObjectClass *klass, void *data) +static void intel_hda_class_init_ich9(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1280,7 +1280,7 @@ static const TypeInfo intel_hda_info_ich9 = { .class_init = intel_hda_class_init_ich9, }; -static void hda_codec_device_class_init(ObjectClass *klass, void *data) +static void hda_codec_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = hda_codec_dev_realize; diff --git a/hw/audio/marvell_88w8618.c b/hw/audio/marvell_88w8618.c index 28f9af320d..6d3ebbb0c8 100644 --- a/hw/audio/marvell_88w8618.c +++ b/hw/audio/marvell_88w8618.c @@ -287,7 +287,7 @@ static const VMStateDescription mv88w8618_audio_vmsd = { } }; -static void mv88w8618_audio_class_init(ObjectClass *klass, void *data) +static void mv88w8618_audio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/audio/pcspk.c b/hw/audio/pcspk.c index 17be185547..a419161b5b 100644 --- a/hw/audio/pcspk.c +++ b/hw/audio/pcspk.c @@ -221,7 +221,7 @@ static const Property pcspk_properties[] = { DEFINE_PROP_BOOL("migrate", PCSpkState, migrate, true), }; -static void pcspk_class_initfn(ObjectClass *klass, void *data) +static void pcspk_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/audio/pl041.c b/hw/audio/pl041.c index f771d725fa..5d9d6c1178 100644 --- a/hw/audio/pl041.c +++ b/hw/audio/pl041.c @@ -632,7 +632,7 @@ static const Property pl041_device_properties[] = { DEFAULT_FIFO_DEPTH), }; -static void pl041_device_class_init(ObjectClass *klass, void *data) +static void pl041_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c index 0c661b4947..19fd3b9020 100644 --- a/hw/audio/sb16.c +++ b/hw/audio/sb16.c @@ -1449,7 +1449,7 @@ static const Property sb16_properties[] = { DEFINE_PROP_UINT32 ("dma16", SB16State, hdma, 5), }; -static void sb16_class_initfn (ObjectClass *klass, void *data) +static void sb16_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS (klass); diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c index 4e115e011e..5feef663d8 100644 --- a/hw/audio/via-ac97.c +++ b/hw/audio/via-ac97.c @@ -463,7 +463,7 @@ static const Property via_ac97_properties[] = { DEFINE_AUDIO_PROPERTIES(ViaAC97State, card), }; -static void via_ac97_class_init(ObjectClass *klass, void *data) +static void via_ac97_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -501,7 +501,7 @@ static void via_mc97_realize(PCIDevice *pci_dev, Error **errp) pci_set_long(pci_dev->config + PCI_INTERRUPT_PIN, 0x03); } -static void via_mc97_class_init(ObjectClass *klass, void *data) +static void via_mc97_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/audio/virtio-snd-pci.c b/hw/audio/virtio-snd-pci.c index 74d93f4e9c..9eb0007392 100644 --- a/hw/audio/virtio-snd-pci.c +++ b/hw/audio/virtio-snd-pci.c @@ -42,7 +42,7 @@ static void virtio_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_snd_pci_class_init(ObjectClass *klass, void *data) +static void virtio_snd_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *vpciklass = VIRTIO_PCI_CLASS(klass); diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c index 0b47741f01..eca3319e59 100644 --- a/hw/audio/virtio-snd.c +++ b/hw/audio/virtio-snd.c @@ -1361,7 +1361,7 @@ static void virtio_snd_reset(VirtIODevice *vdev) } } -static void virtio_snd_class_init(ObjectClass *klass, void *data) +static void virtio_snd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/audio/wm8750.c b/hw/audio/wm8750.c index 8d381dbc65..2846b55fe2 100644 --- a/hw/audio/wm8750.c +++ b/hw/audio/wm8750.c @@ -710,7 +710,7 @@ static const Property wm8750_properties[] = { DEFINE_AUDIO_PROPERTIES(WM8750State, card), }; -static void wm8750_class_init(ObjectClass *klass, void *data) +static void wm8750_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); diff --git a/hw/avr/arduino.c b/hw/avr/arduino.c index 48ef478346..e166ca18e1 100644 --- a/hw/avr/arduino.c +++ b/hw/avr/arduino.c @@ -56,7 +56,7 @@ static void arduino_machine_init(MachineState *machine) } } -static void arduino_machine_class_init(ObjectClass *oc, void *data) +static void arduino_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -69,7 +69,7 @@ static void arduino_machine_class_init(ObjectClass *oc, void *data) mc->no_parallel = 1; } -static void arduino_duemilanove_class_init(ObjectClass *oc, void *data) +static void arduino_duemilanove_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); @@ -84,7 +84,7 @@ static void arduino_duemilanove_class_init(ObjectClass *oc, void *data) amc->xtal_hz = 16 * 1000 * 1000; }; -static void arduino_uno_class_init(ObjectClass *oc, void *data) +static void arduino_uno_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); @@ -99,7 +99,7 @@ static void arduino_uno_class_init(ObjectClass *oc, void *data) amc->xtal_hz = 16 * 1000 * 1000; }; -static void arduino_mega_class_init(ObjectClass *oc, void *data) +static void arduino_mega_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); @@ -114,7 +114,7 @@ static void arduino_mega_class_init(ObjectClass *oc, void *data) amc->xtal_hz = 16 * 1000 * 1000; }; -static void arduino_mega2560_class_init(ObjectClass *oc, void *data) +static void arduino_mega2560_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); ArduinoMachineClass *amc = ARDUINO_MACHINE_CLASS(oc); diff --git a/hw/avr/atmega.c b/hw/avr/atmega.c index c105d2a97c..95b6da5e34 100644 --- a/hw/avr/atmega.c +++ b/hw/avr/atmega.c @@ -386,7 +386,7 @@ static const Property atmega_props[] = { xtal_freq_hz, 0), }; -static void atmega_class_init(ObjectClass *oc, void *data) +static void atmega_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -396,7 +396,7 @@ static void atmega_class_init(ObjectClass *oc, void *data) dc->user_creatable = false; } -static void atmega168_class_init(ObjectClass *oc, void *data) +static void atmega168_class_init(ObjectClass *oc, const void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); @@ -411,7 +411,7 @@ static void atmega168_class_init(ObjectClass *oc, void *data) amc->dev = dev168_328; }; -static void atmega328_class_init(ObjectClass *oc, void *data) +static void atmega328_class_init(ObjectClass *oc, const void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); @@ -426,7 +426,7 @@ static void atmega328_class_init(ObjectClass *oc, void *data) amc->dev = dev168_328; }; -static void atmega1280_class_init(ObjectClass *oc, void *data) +static void atmega1280_class_init(ObjectClass *oc, const void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); @@ -441,7 +441,7 @@ static void atmega1280_class_init(ObjectClass *oc, void *data) amc->dev = dev1280_2560; }; -static void atmega2560_class_init(ObjectClass *oc, void *data) +static void atmega2560_class_init(ObjectClass *oc, const void *data) { AtmegaMcuClass *amc = ATMEGA_MCU_CLASS(oc); diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c index 561cfa47c1..fbba2ab629 100644 --- a/hw/block/fdc-isa.c +++ b/hw/block/fdc-isa.c @@ -298,7 +298,7 @@ static const Property isa_fdc_properties[] = { FloppyDriveType), }; -static void isabus_fdc_class_init(ObjectClass *klass, void *data) +static void isabus_fdc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/block/fdc-sysbus.c b/hw/block/fdc-sysbus.c index 4955e478cd..956860ab29 100644 --- a/hw/block/fdc-sysbus.c +++ b/hw/block/fdc-sysbus.c @@ -176,7 +176,7 @@ static const VMStateDescription vmstate_sysbus_fdc = { } }; -static void sysbus_fdc_common_class_init(ObjectClass *klass, void *data) +static void sysbus_fdc_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -208,7 +208,7 @@ static const Property sysbus_fdc_properties[] = { FloppyDriveType), }; -static void sysbus_fdc_class_init(ObjectClass *klass, void *data) +static void sysbus_fdc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -231,7 +231,7 @@ static const Property sun4m_fdc_properties[] = { FloppyDriveType), }; -static void sun4m_fdc_class_init(ObjectClass *klass, void *data) +static void sun4m_fdc_class_init(ObjectClass *klass, const void *data) { FDCtrlSysBusClass *sbdc = SYSBUS_FDC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/block/fdc.c b/hw/block/fdc.c index 2df941d3f4..d0f08c7be5 100644 --- a/hw/block/fdc.c +++ b/hw/block/fdc.c @@ -553,7 +553,7 @@ static void floppy_drive_realize(DeviceState *qdev, Error **errp) fd_revalidate(drive); } -static void floppy_drive_class_init(ObjectClass *klass, void *data) +static void floppy_drive_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = floppy_drive_realize; diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 0887c103e4..75b9d71251 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -528,7 +528,7 @@ struct Flash { struct M25P80Class { SSIPeripheralClass parent_class; - FlashPartInfo *pi; + const FlashPartInfo *pi; }; OBJECT_DECLARE_TYPE(Flash, M25P80Class, M25P80) @@ -1857,7 +1857,7 @@ static const VMStateDescription vmstate_m25p80 = { } }; -static void m25p80_class_init(ObjectClass *klass, void *data) +static void m25p80_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); diff --git a/hw/block/nand.c b/hw/block/nand.c index e98c55b729..c80bf78fe5 100644 --- a/hw/block/nand.c +++ b/hw/block/nand.c @@ -451,7 +451,7 @@ static const Property nand_properties[] = { DEFINE_PROP_DRIVE("drive", NANDFlashState, blk), }; -static void nand_class_init(ObjectClass *klass, void *data) +static void nand_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c index b5ea927f36..168101d8df 100644 --- a/hw/block/pflash_cfi01.c +++ b/hw/block/pflash_cfi01.c @@ -934,7 +934,7 @@ static const Property pflash_cfi01_properties[] = { old_multiple_chip_handling, false), }; -static void pflash_cfi01_class_init(ObjectClass *klass, void *data) +static void pflash_cfi01_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c index 315a53629a..3244b699b9 100644 --- a/hw/block/pflash_cfi02.c +++ b/hw/block/pflash_cfi02.c @@ -968,7 +968,7 @@ static void pflash_cfi02_unrealize(DeviceState *dev) g_free(pfl->sector_erase_map); } -static void pflash_cfi02_class_init(ObjectClass *klass, void *data) +static void pflash_cfi02_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/block/swim.c b/hw/block/swim.c index 4645468dcf..ad047362f8 100644 --- a/hw/block/swim.c +++ b/hw/block/swim.c @@ -253,7 +253,7 @@ static void swim_drive_realize(DeviceState *qdev, Error **errp) blk_set_dev_ops(drive->blk, &swim_block_ops, drive); } -static void swim_drive_class_init(ObjectClass *klass, void *data) +static void swim_drive_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = swim_drive_realize; @@ -550,7 +550,7 @@ static const VMStateDescription vmstate_sysbus_swim = { } }; -static void sysbus_swim_class_init(ObjectClass *oc, void *data) +static void sysbus_swim_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index ae42327cf8..4bb5ed299e 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -583,7 +583,7 @@ static const Property vhost_user_blk_properties[] = { VIRTIO_BLK_F_WRITE_ZEROES, true), }; -static void vhost_user_blk_class_init(ObjectClass *klass, void *data) +static void vhost_user_blk_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 5077793e5e..b54d01d3a2 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1886,7 +1886,7 @@ static const Property virtio_blk_properties[] = { conf.x_enable_wce_if_config_wce, true), }; -static void virtio_blk_class_init(ObjectClass *klass, void *data) +static void virtio_blk_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index ec04102b66..74de897c79 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -679,7 +679,7 @@ static const Property xen_block_props[] = { TYPE_IOTHREAD, IOThread *), }; -static void xen_block_class_init(ObjectClass *class, void *data) +static void xen_block_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); @@ -724,7 +724,7 @@ static void xen_disk_realize(XenBlockDevice *blockdev, Error **errp) blockdev->info = blk_supports_write_perm(conf->blk) ? 0 : VDISK_READONLY; } -static void xen_disk_class_init(ObjectClass *class, void *data) +static void xen_disk_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); @@ -771,7 +771,7 @@ static void xen_cdrom_realize(XenBlockDevice *blockdev, Error **errp) blockdev->info = VDISK_READONLY | VDISK_CDROM; } -static void xen_cdrom_class_init(ObjectClass *class, void *data) +static void xen_cdrom_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenBlockDeviceClass *blockdev_class = XEN_BLOCK_DEVICE_CLASS(class); diff --git a/hw/char/avr_usart.c b/hw/char/avr_usart.c index e8012cae3a..fae15217e9 100644 --- a/hw/char/avr_usart.c +++ b/hw/char/avr_usart.c @@ -295,7 +295,7 @@ static void avr_usart_realize(DeviceState *dev, Error **errp) avr_usart_reset(dev); } -static void avr_usart_class_init(ObjectClass *klass, void *data) +static void avr_usart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/bcm2835_aux.c b/hw/char/bcm2835_aux.c index 9b073fc330..2b397f2ff3 100644 --- a/hw/char/bcm2835_aux.c +++ b/hw/char/bcm2835_aux.c @@ -296,7 +296,7 @@ static const Property bcm2835_aux_props[] = { DEFINE_PROP_CHR("chardev", BCM2835AuxState, chr), }; -static void bcm2835_aux_class_init(ObjectClass *oc, void *data) +static void bcm2835_aux_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index ebd846a083..0dfa356b6d 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -621,7 +621,7 @@ static const Property cadence_uart_properties[] = { DEFINE_PROP_CHR("chardev", CadenceUARTState, chr), }; -static void cadence_uart_class_init(ObjectClass *klass, void *data) +static void cadence_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/char/cmsdk-apb-uart.c b/hw/char/cmsdk-apb-uart.c index 0506500215..32090f3516 100644 --- a/hw/char/cmsdk-apb-uart.c +++ b/hw/char/cmsdk-apb-uart.c @@ -382,7 +382,7 @@ static const Property cmsdk_apb_uart_properties[] = { DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBUART, pclk_frq, 0), }; -static void cmsdk_apb_uart_class_init(ObjectClass *klass, void *data) +static void cmsdk_apb_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/debugcon.c b/hw/char/debugcon.c index 1bc3bf85fe..bf44aaf9e4 100644 --- a/hw/char/debugcon.c +++ b/hw/char/debugcon.c @@ -120,7 +120,7 @@ static const Property debugcon_isa_properties[] = { DEFINE_PROP_UINT32("readback", ISADebugconState, state.readback, 0xe9), }; -static void debugcon_isa_class_initfn(ObjectClass *klass, void *data) +static void debugcon_isa_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/digic-uart.c b/hw/char/digic-uart.c index b0b0714e0f..0f6af51bb7 100644 --- a/hw/char/digic-uart.c +++ b/hw/char/digic-uart.c @@ -176,7 +176,7 @@ static const Property digic_uart_properties[] = { DEFINE_PROP_CHR("chardev", DigicUartState, chr), }; -static void digic_uart_class_init(ObjectClass *klass, void *data) +static void digic_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c index ecec1f7bb1..9a623d680b 100644 --- a/hw/char/diva-gsp.c +++ b/hw/char/diva-gsp.c @@ -183,7 +183,7 @@ static const Property diva_serial_properties[] = { PCI_DEVICE_ID_HP_DIVA_TOSCA1), }; -static void diva_serial_class_initfn(ObjectClass *klass, void *data) +static void diva_serial_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); @@ -242,7 +242,7 @@ static void diva_aux_exit(PCIDevice *dev) qemu_free_irq(pci->irq); } -static void diva_aux_class_initfn(ObjectClass *klass, void *data) +static void diva_aux_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); diff --git a/hw/char/escc.c b/hw/char/escc.c index a5fdd8f698..afe4ca483e 100644 --- a/hw/char/escc.c +++ b/hw/char/escc.c @@ -1101,7 +1101,7 @@ static const Property escc_properties[] = { DEFINE_PROP_STRING("chnA-sunkbd-layout", ESCCState, chn[1].sunkbd_layout), }; -static void escc_class_init(ObjectClass *klass, void *data) +static void escc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/exynos4210_uart.c b/hw/char/exynos4210_uart.c index a1a9a12caf..6521b4cedd 100644 --- a/hw/char/exynos4210_uart.c +++ b/hw/char/exynos4210_uart.c @@ -711,7 +711,7 @@ static const Property exynos4210_uart_properties[] = { DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16), }; -static void exynos4210_uart_class_init(ObjectClass *klass, void *data) +static void exynos4210_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/goldfish_tty.c b/hw/char/goldfish_tty.c index f0891ffa4d..a37408adae 100644 --- a/hw/char/goldfish_tty.c +++ b/hw/char/goldfish_tty.c @@ -256,7 +256,7 @@ static void goldfish_tty_instance_init(Object *obj) sysbus_init_irq(dev, &s->irq); } -static void goldfish_tty_class_init(ObjectClass *oc, void *data) +static void goldfish_tty_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/grlib_apbuart.c b/hw/char/grlib_apbuart.c index db6bcdad41..81c26e3389 100644 --- a/hw/char/grlib_apbuart.c +++ b/hw/char/grlib_apbuart.c @@ -281,7 +281,7 @@ static const Property grlib_apbuart_properties[] = { DEFINE_PROP_CHR("chrdev", UART, chr), }; -static void grlib_apbuart_class_init(ObjectClass *klass, void *data) +static void grlib_apbuart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/ibex_uart.c b/hw/char/ibex_uart.c index 392375ad55..d6f0d18c77 100644 --- a/hw/char/ibex_uart.c +++ b/hw/char/ibex_uart.c @@ -542,7 +542,7 @@ static void ibex_uart_realize(DeviceState *dev, Error **errp) s, NULL, true); } -static void ibex_uart_class_init(ObjectClass *klass, void *data) +static void ibex_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/imx_serial.c b/hw/char/imx_serial.c index 6f14f8403a..509b0141d0 100644 --- a/hw/char/imx_serial.c +++ b/hw/char/imx_serial.c @@ -467,7 +467,7 @@ static const Property imx_serial_properties[] = { DEFINE_PROP_CHR("chardev", IMXSerialState, chr), }; -static void imx_serial_class_init(ObjectClass *klass, void *data) +static void imx_serial_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/ipoctal232.c b/hw/char/ipoctal232.c index a2879977fb..752c6c818a 100644 --- a/hw/char/ipoctal232.c +++ b/hw/char/ipoctal232.c @@ -569,7 +569,7 @@ static const Property ipoctal_properties[] = { DEFINE_PROP_CHR("chardev7", IPOctalState, ch[7].dev), }; -static void ipoctal_class_init(ObjectClass *klass, void *data) +static void ipoctal_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IPackDeviceClass *ic = IPACK_DEVICE_CLASS(klass); diff --git a/hw/char/mcf_uart.c b/hw/char/mcf_uart.c index 529c26be93..87bfcbebdc 100644 --- a/hw/char/mcf_uart.c +++ b/hw/char/mcf_uart.c @@ -322,7 +322,7 @@ static const Property mcf_uart_properties[] = { DEFINE_PROP_CHR("chardev", mcf_uart_state, chr), }; -static void mcf_uart_class_init(ObjectClass *oc, void *data) +static void mcf_uart_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c index 3c3224c05d..6149f9d204 100644 --- a/hw/char/mchp_pfsoc_mmuart.c +++ b/hw/char/mchp_pfsoc_mmuart.c @@ -121,7 +121,7 @@ static const VMStateDescription mchp_pfsoc_mmuart_vmstate = { } }; -static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, void *data) +static void mchp_pfsoc_mmuart_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/nrf51_uart.c b/hw/char/nrf51_uart.c index 82a61ee95f..41d423446f 100644 --- a/hw/char/nrf51_uart.c +++ b/hw/char/nrf51_uart.c @@ -308,7 +308,7 @@ static const Property nrf51_uart_properties[] = { DEFINE_PROP_CHR("chardev", NRF51UARTState, chr), }; -static void nrf51_uart_class_init(ObjectClass *klass, void *data) +static void nrf51_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/parallel.c b/hw/char/parallel.c index e1651d52a4..217ddaf2e3 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -610,7 +610,7 @@ static const Property parallel_isa_properties[] = { DEFINE_PROP_CHR("chardev", ISAParallelState, state.chr), }; -static void parallel_isa_class_initfn(ObjectClass *klass, void *data) +static void parallel_isa_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/char/pl011.c b/hw/char/pl011.c index 0e9ec1301d..01335d9437 100644 --- a/hw/char/pl011.c +++ b/hw/char/pl011.c @@ -669,7 +669,7 @@ static void pl011_reset(DeviceState *dev) pl011_reset_tx_fifo(s); } -static void pl011_class_init(ObjectClass *oc, void *data) +static void pl011_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/renesas_sci.c b/hw/char/renesas_sci.c index ea94494932..b9d0ed1c89 100644 --- a/hw/char/renesas_sci.c +++ b/hw/char/renesas_sci.c @@ -324,7 +324,7 @@ static const Property rsci_properties[] = { DEFINE_PROP_CHR("chardev", RSCIState, chr), }; -static void rsci_class_init(ObjectClass *klass, void *data) +static void rsci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c index ddb9a726d5..e9580aacba 100644 --- a/hw/char/sclpconsole-lm.c +++ b/hw/char/sclpconsole-lm.c @@ -339,7 +339,7 @@ static const Property console_properties[] = { DEFINE_PROP_BOOL("echo", SCLPConsoleLM, echo, true), }; -static void console_class_init(ObjectClass *klass, void *data) +static void console_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c index 01233b933d..95e3045178 100644 --- a/hw/char/sclpconsole.c +++ b/hw/char/sclpconsole.c @@ -255,7 +255,7 @@ static const Property console_properties[] = { DEFINE_PROP_CHR("chardev", SCLPConsole, chr), }; -static void console_class_init(ObjectClass *klass, void *data) +static void console_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCLPEventClass *ec = SCLP_EVENT_CLASS(klass); diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index 3d913891dc..fe7fb1625b 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -119,7 +119,7 @@ static const Property serial_isa_properties[] = { DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), }; -static void serial_isa_class_initfn(ObjectClass *klass, void *data) +static void serial_isa_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/char/serial-mm.c b/hw/char/serial-mm.c index 6338e7c0ba..13aba780ec 100644 --- a/hw/char/serial-mm.c +++ b/hw/char/serial-mm.c @@ -134,7 +134,7 @@ static const Property serial_mm_properties[] = { DEFINE_PROP_UINT8("endianness", SerialMM, endianness, DEVICE_NATIVE_ENDIAN), }; -static void serial_mm_class_init(ObjectClass *oc, void *data) +static void serial_mm_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index 718ae25131..ee1c0f7dc4 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -144,7 +144,8 @@ static const Property multi_4x_serial_pci_properties[] = { DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), }; -static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) +static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); @@ -159,7 +160,8 @@ static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } -static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, void *data) +static void multi_4x_serial_pci_class_initfn(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 6659cef5d4..bd38c7428c 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -85,7 +85,7 @@ static const Property serial_pci_properties[] = { DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), }; -static void serial_pci_class_initfn(ObjectClass *klass, void *data) +static void serial_pci_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); diff --git a/hw/char/serial.c b/hw/char/serial.c index 70044e14a0..03fec3fe75 100644 --- a/hw/char/serial.c +++ b/hw/char/serial.c @@ -970,7 +970,7 @@ static const Property serial_properties[] = { DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false), }; -static void serial_class_init(ObjectClass *klass, void* data) +static void serial_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/sh_serial.c b/hw/char/sh_serial.c index 41c8175a63..6abd80386f 100644 --- a/hw/char/sh_serial.c +++ b/hw/char/sh_serial.c @@ -450,7 +450,7 @@ static const Property sh_serial_properties[] = { DEFINE_PROP_UINT8("features", SHSerialState, feat, 0), }; -static void sh_serial_class_init(ObjectClass *oc, void *data) +static void sh_serial_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/char/shakti_uart.c b/hw/char/shakti_uart.c index 09975d9d34..6e216edb0f 100644 --- a/hw/char/shakti_uart.c +++ b/hw/char/shakti_uart.c @@ -161,7 +161,7 @@ static const Property shakti_uart_properties[] = { DEFINE_PROP_CHR("chardev", ShaktiUartState, chr), }; -static void shakti_uart_class_init(ObjectClass *klass, void *data) +static void shakti_uart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_legacy_reset(dc, shakti_uart_reset); diff --git a/hw/char/sifive_uart.c b/hw/char/sifive_uart.c index b45e6c098c..0fc89e76d1 100644 --- a/hw/char/sifive_uart.c +++ b/hw/char/sifive_uart.c @@ -334,7 +334,7 @@ static const VMStateDescription vmstate_sifive_uart = { }; -static void sifive_uart_class_init(ObjectClass *oc, void *data) +static void sifive_uart_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/char/spapr_vty.c b/hw/char/spapr_vty.c index 6451d010ac..fc8ea604f8 100644 --- a/hw/char/spapr_vty.c +++ b/hw/char/spapr_vty.c @@ -182,7 +182,7 @@ static const VMStateDescription vmstate_spapr_vty = { }, }; -static void spapr_vty_class_init(ObjectClass *klass, void *data) +static void spapr_vty_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c index 87882daa71..45c30643a7 100644 --- a/hw/char/stm32f2xx_usart.c +++ b/hw/char/stm32f2xx_usart.c @@ -220,7 +220,7 @@ static void stm32f2xx_usart_realize(DeviceState *dev, Error **errp) s, NULL, true); } -static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data) +static void stm32f2xx_usart_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/char/stm32l4x5_usart.c b/hw/char/stm32l4x5_usart.c index bcc310bd97..afbe4bab29 100644 --- a/hw/char/stm32l4x5_usart.c +++ b/hw/char/stm32l4x5_usart.c @@ -594,7 +594,8 @@ static void stm32l4x5_usart_base_realize(DeviceState *dev, Error **errp) s, NULL, true); } -static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_usart_base_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -605,21 +606,21 @@ static void stm32l4x5_usart_base_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_stm32l4x5_usart_base; } -static void stm32l4x5_usart_class_init(ObjectClass *oc, void *data) +static void stm32l4x5_usart_class_init(ObjectClass *oc, const void *data) { Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); subc->type = STM32L4x5_USART; } -static void stm32l4x5_uart_class_init(ObjectClass *oc, void *data) +static void stm32l4x5_uart_class_init(ObjectClass *oc, const void *data) { Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); subc->type = STM32L4x5_UART; } -static void stm32l4x5_lpuart_class_init(ObjectClass *oc, void *data) +static void stm32l4x5_lpuart_class_init(ObjectClass *oc, const void *data) { Stm32l4x5UsartBaseClass *subc = STM32L4X5_USART_BASE_CLASS(oc); diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c index 04ee26dcbd..d950c17292 100644 --- a/hw/char/terminal3270.c +++ b/hw/char/terminal3270.c @@ -292,7 +292,7 @@ static const VMStateDescription terminal3270_vmstate = { .unmigratable = 1, }; -static void terminal_class_init(ObjectClass *klass, void *data) +static void terminal_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass); diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index aa6d611a47..0932a3572b 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -261,7 +261,7 @@ static void virtconsole_unrealize(DeviceState *dev) } } -static void virtconsole_class_init(ObjectClass *klass, void *data) +static void virtconsole_class_init(ObjectClass *klass, const void *data) { VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); @@ -278,7 +278,7 @@ static const Property virtserialport_properties[] = { DEFINE_PROP_CHR("chardev", VirtConsole, chr), }; -static void virtserialport_class_init(ObjectClass *klass, void *data) +static void virtserialport_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOSerialPortClass *k = VIRTIO_SERIAL_PORT_CLASS(klass); diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index b6d2743a9c..00572873d2 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -840,7 +840,7 @@ static const Property virtser_props[] = { DEFINE_PROP_STRING("name", VirtIOSerialPort, name), }; -static void virtser_bus_class_init(ObjectClass *klass, void *data) +static void virtser_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); k->print_dev = virtser_bus_dev_print; @@ -1092,7 +1092,7 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp) QLIST_INSERT_HEAD(&vserdevices.devices, vser, next); } -static void virtio_serial_port_class_init(ObjectClass *klass, void *data) +static void virtio_serial_port_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -1159,7 +1159,7 @@ static const Property virtio_serial_properties[] = { VIRTIO_CONSOLE_F_EMERG_WRITE, true), }; -static void virtio_serial_class_init(ObjectClass *klass, void *data) +static void virtio_serial_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/char/xen_console.c b/hw/char/xen_console.c index d03c188d1d..9c34a554bf 100644 --- a/hw/char/xen_console.c +++ b/hw/char/xen_console.c @@ -492,7 +492,7 @@ static const Property xen_console_properties[] = { DEFINE_PROP_INT32("idx", XenConsole, dev, -1), }; -static void xen_console_class_init(ObjectClass *class, void *data) +static void xen_console_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); diff --git a/hw/char/xilinx_uartlite.c b/hw/char/xilinx_uartlite.c index 4037c937ee..8008171eea 100644 --- a/hw/char/xilinx_uartlite.c +++ b/hw/char/xilinx_uartlite.c @@ -241,7 +241,7 @@ static void xilinx_uartlite_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } -static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) +static void xilinx_uartlite_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/bus.c b/hw/core/bus.c index b9d89495cd..c3b431a014 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -232,7 +232,7 @@ static char *default_bus_get_fw_dev_path(DeviceState *dev) return g_strdup(object_get_typename(OBJECT(dev))); } -static void bus_class_init(ObjectClass *class, void *data) +static void bus_class_init(ObjectClass *class, const void *data) { BusClass *bc = BUS_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); diff --git a/hw/core/clock.c b/hw/core/clock.c index a81f888e62..9c906761e1 100644 --- a/hw/core/clock.c +++ b/hw/core/clock.c @@ -206,7 +206,7 @@ static void clock_finalizefn(Object *obj) g_free(clk->canonical_path); } -static void clock_class_init(ObjectClass *klass, void *data) +static void clock_class_init(ObjectClass *klass, const void *data) { klass->unparent = clock_unparent; } diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 9064dd24f8..1fb6ea3892 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -320,7 +320,7 @@ static int64_t cpu_common_get_arch_id(CPUState *cpu) return cpu->cpu_index; } -static void cpu_common_class_init(ObjectClass *klass, void *data) +static void cpu_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/core/generic-loader.c b/hw/core/generic-loader.c index d3a426a1a2..e72bbde2a2 100644 --- a/hw/core/generic-loader.c +++ b/hw/core/generic-loader.c @@ -182,7 +182,7 @@ static const Property generic_loader_props[] = { DEFINE_PROP_STRING("file", GenericLoaderState, file), }; -static void generic_loader_class_init(ObjectClass *klass, void *data) +static void generic_loader_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/guest-loader.c b/hw/core/guest-loader.c index 76271df9f5..3db89d7a2e 100644 --- a/hw/core/guest-loader.c +++ b/hw/core/guest-loader.c @@ -118,7 +118,7 @@ static const Property guest_loader_props[] = { DEFINE_PROP_STRING("initrd", GuestLoaderState, initrd), }; -static void guest_loader_class_init(ObjectClass *klass, void *data) +static void guest_loader_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/machine.c b/hw/core/machine.c index bbff84855a..ed01798d37 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -1100,7 +1100,7 @@ out: return r; } -static void machine_class_init(ObjectClass *oc, void *data) +static void machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c index 4d0d3cabf1..3942c70993 100644 --- a/hw/core/or-irq.c +++ b/hw/core/or-irq.c @@ -119,7 +119,7 @@ static const Property or_irq_properties[] = { DEFINE_PROP_UINT16("num-lines", OrIRQState, num_lines, 1), }; -static void or_irq_class_init(ObjectClass *klass, void *data) +static void or_irq_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/platform-bus.c b/hw/core/platform-bus.c index 1d00c4d36d..6950063de4 100644 --- a/hw/core/platform-bus.c +++ b/hw/core/platform-bus.c @@ -209,7 +209,7 @@ static const Property platform_bus_properties[] = { DEFINE_PROP_UINT32("mmio_size", PlatformBusDevice, mmio_size, 0), }; -static void platform_bus_class_init(ObjectClass *klass, void *data) +static void platform_bus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 1e0f47cc84..4a3760c101 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -731,7 +731,7 @@ device_vmstate_if_get_id(VMStateIf *obj) return qdev_get_dev_path(dev); } -static void device_class_init(ObjectClass *class, void *data) +static void device_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); VMStateIfClass *vc = VMSTATE_IF_CLASS(class); diff --git a/hw/core/register.c b/hw/core/register.c index 95b0150c0a..8f63d9f227 100644 --- a/hw/core/register.c +++ b/hw/core/register.c @@ -319,7 +319,7 @@ void register_finalize_block(RegisterInfoArray *r_array) g_free(r_array); } -static void register_class_init(ObjectClass *oc, void *data) +static void register_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/core/reset.c b/hw/core/reset.c index 8a3e0e518f..65f82fa43d 100644 --- a/hw/core/reset.c +++ b/hw/core/reset.c @@ -84,7 +84,7 @@ static void legacy_reset_finalize(Object *obj) { } -static void legacy_reset_class_init(ObjectClass *klass, void *data) +static void legacy_reset_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/core/resetcontainer.c b/hw/core/resetcontainer.c index e4ece68e83..5ff17002e7 100644 --- a/hw/core/resetcontainer.c +++ b/hw/core/resetcontainer.c @@ -68,7 +68,8 @@ static void resettable_container_finalize(Object *obj) { } -static void resettable_container_class_init(ObjectClass *klass, void *data) +static void resettable_container_class_init(ObjectClass *klass, + const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/core/split-irq.c b/hw/core/split-irq.c index fc12274811..f8b48750c5 100644 --- a/hw/core/split-irq.c +++ b/hw/core/split-irq.c @@ -63,7 +63,7 @@ static const Property split_irq_properties[] = { DEFINE_PROP_UINT16("num-lines", SplitIRQ, num_lines, 1), }; -static void split_irq_class_init(ObjectClass *klass, void *data) +static void split_irq_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c index 6eb4c0f15a..e71367adfb 100644 --- a/hw/core/sysbus.c +++ b/hw/core/sysbus.c @@ -71,7 +71,7 @@ void foreach_dynamic_sysbus_device(FindSysbusDeviceFunc *func, void *opaque) } -static void system_bus_class_init(ObjectClass *klass, void *data) +static void system_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -280,7 +280,7 @@ static char *sysbus_get_fw_dev_path(DeviceState *dev) return g_strdup(qdev_fw_name(dev)); } -static void sysbus_device_class_init(ObjectClass *klass, void *data) +static void sysbus_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = sysbus_device_realize; @@ -320,7 +320,8 @@ BusState *sysbus_get_default(void) return main_system_bus; } -static void dynamic_sysbus_device_class_init(ObjectClass *klass, void *data) +static void dynamic_sysbus_device_class_init(ObjectClass *klass, + const void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c index 676f65a0af..bd36dd94d4 100644 --- a/hw/cpu/a15mpcore.c +++ b/hw/cpu/a15mpcore.c @@ -161,7 +161,7 @@ static const Property a15mp_priv_properties[] = { DEFINE_PROP_UINT32("num-irq", A15MPPrivState, num_irq, 0), }; -static void a15mp_priv_class_init(ObjectClass *klass, void *data) +static void a15mp_priv_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/cpu/a9mpcore.c b/hw/cpu/a9mpcore.c index 1b9f2bef93..64bebbd19c 100644 --- a/hw/cpu/a9mpcore.c +++ b/hw/cpu/a9mpcore.c @@ -175,7 +175,7 @@ static const Property a9mp_priv_properties[] = { DEFINE_PROP_UINT32("num-irq", A9MPPrivState, num_irq, 0), }; -static void a9mp_priv_class_init(ObjectClass *klass, void *data) +static void a9mp_priv_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/cpu/arm11mpcore.c b/hw/cpu/arm11mpcore.c index b56bee6d54..01772e7f77 100644 --- a/hw/cpu/arm11mpcore.c +++ b/hw/cpu/arm11mpcore.c @@ -144,7 +144,7 @@ static const Property mpcore_priv_properties[] = { DEFINE_PROP_UINT32("num-irq", ARM11MPCorePriveState, num_irq, 64), }; -static void mpcore_priv_class_init(ObjectClass *klass, void *data) +static void mpcore_priv_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/cpu/cluster.c b/hw/cpu/cluster.c index 9da5221f88..ef3b3d1e94 100644 --- a/hw/cpu/cluster.c +++ b/hw/cpu/cluster.c @@ -72,7 +72,7 @@ static void cpu_cluster_realize(DeviceState *dev, Error **errp) assert(cbdata.cpu_count > 0); } -static void cpu_cluster_class_init(ObjectClass *klass, void *data) +static void cpu_cluster_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/cpu/core.c b/hw/cpu/core.c index 495a5c30ff..5cb2e9a7f5 100644 --- a/hw/cpu/core.c +++ b/hw/cpu/core.c @@ -77,7 +77,7 @@ static void cpu_core_instance_init(Object *obj) } } -static void cpu_core_class_init(ObjectClass *oc, void *data) +static void cpu_core_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/cpu/realview_mpcore.c b/hw/cpu/realview_mpcore.c index b140888618..099b71a9ef 100644 --- a/hw/cpu/realview_mpcore.c +++ b/hw/cpu/realview_mpcore.c @@ -107,7 +107,7 @@ static void mpcore_rirq_init(Object *obj) } } -static void mpcore_rirq_class_init(ObjectClass *klass, void *data) +static void mpcore_rirq_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/cxl/switch-mailbox-cci.c b/hw/cxl/switch-mailbox-cci.c index 833b824619..b92bbeb16e 100644 --- a/hw/cxl/switch-mailbox-cci.c +++ b/hw/cxl/switch-mailbox-cci.c @@ -72,7 +72,7 @@ static const Property cxl_switch_cci_props[] = { target, TYPE_CXL_USP, PCIDevice *), }; -static void cswmbcci_class_init(ObjectClass *oc, void *data) +static void cswmbcci_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); diff --git a/hw/display/apple-gfx-mmio.m b/hw/display/apple-gfx-mmio.m index b2e0e7a30f..b0b6e2993e 100644 --- a/hw/display/apple-gfx-mmio.m +++ b/hw/display/apple-gfx-mmio.m @@ -261,7 +261,7 @@ static const Property apple_gfx_mmio_properties[] = { qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode), }; -static void apple_gfx_mmio_class_init(ObjectClass *klass, void *data) +static void apple_gfx_mmio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m index b939bb9b23..2f0d24f7fe 100644 --- a/hw/display/apple-gfx-pci.m +++ b/hw/display/apple-gfx-pci.m @@ -121,7 +121,7 @@ static const Property apple_gfx_pci_properties[] = { qdev_prop_apple_gfx_display_mode, AppleGFXDisplayMode), }; -static void apple_gfx_pci_class_init(ObjectClass *klass, void *data) +static void apple_gfx_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pci = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/artist.c b/hw/display/artist.c index f24c1d83dd..3fafc8a222 100644 --- a/hw/display/artist.c +++ b/hw/display/artist.c @@ -1487,7 +1487,7 @@ static void artist_reset(DeviceState *qdev) { } -static void artist_class_init(ObjectClass *klass, void *data) +static void artist_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/ati.c b/hw/display/ati.c index 864fa4fc2c..4e88d09943 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -1049,7 +1049,7 @@ static const Property ati_vga_properties[] = { DEFINE_PROP_UINT8("x-pixman", ATIVGAState, use_pixman, DEFAULT_X_PIXMAN), }; -static void ati_vga_class_init(ObjectClass *klass, void *data) +static void ati_vga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/bcm2835_fb.c b/hw/display/bcm2835_fb.c index a5bded5156..820e67ac8b 100644 --- a/hw/display/bcm2835_fb.c +++ b/hw/display/bcm2835_fb.c @@ -442,7 +442,7 @@ static const Property bcm2835_fb_props[] = { initial_config.alpha, 2), /* alpha ignored */ }; -static void bcm2835_fb_class_init(ObjectClass *klass, void *data) +static void bcm2835_fb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 086f7a0f06..1d329fc9cc 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -351,7 +351,7 @@ static const Property bochs_display_properties[] = { DEFINE_EDID_PROPERTIES(BochsDisplayState, edid_info), }; -static void bochs_display_class_init(ObjectClass *klass, void *data) +static void bochs_display_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/cg3.c b/hw/display/cg3.c index 3f971d875f..daeef15217 100644 --- a/hw/display/cg3.c +++ b/hw/display/cg3.c @@ -368,7 +368,7 @@ static const Property cg3_properties[] = { DEFINE_PROP_UINT16("depth", CG3State, depth, -1), }; -static void cg3_class_init(ObjectClass *klass, void *data) +static void cg3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 76124d3656..4e5ae04af0 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -2991,7 +2991,7 @@ static const Property pci_vga_cirrus_properties[] = { cirrus_vga.vga.global_vmstate, false), }; -static void cirrus_vga_class_init(ObjectClass *klass, void *data) +static void cirrus_vga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/cirrus_vga_isa.c b/hw/display/cirrus_vga_isa.c index 60b7fd20f1..4b55c48eff 100644 --- a/hw/display/cirrus_vga_isa.c +++ b/hw/display/cirrus_vga_isa.c @@ -76,7 +76,7 @@ static const Property isa_cirrus_vga_properties[] = { cirrus_vga.enable_blitter, true), }; -static void isa_cirrus_vga_class_init(ObjectClass *klass, void *data) +static void isa_cirrus_vga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/dm163.c b/hw/display/dm163.c index f6f0ec0c63..f8340d8275 100644 --- a/hw/display/dm163.c +++ b/hw/display/dm163.c @@ -325,7 +325,7 @@ static void dm163_realize(DeviceState *dev, Error **errp) RGB_MATRIX_NUM_ROWS * LED_SQUARE_SIZE); } -static void dm163_class_init(ObjectClass *klass, void *data) +static void dm163_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c index 108faf7887..a157dc64e7 100644 --- a/hw/display/dpcd.c +++ b/hw/display/dpcd.c @@ -141,7 +141,7 @@ static const VMStateDescription vmstate_dpcd = { } }; -static void dpcd_class_init(ObjectClass *oc, void *data) +static void dpcd_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 04c864a308..c61e0280a7 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -1958,7 +1958,7 @@ static void exynos4210_fimd_realize(DeviceState *dev, Error **errp) s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s); } -static void exynos4210_fimd_class_init(ObjectClass *klass, void *data) +static void exynos4210_fimd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/g364fb.c b/hw/display/g364fb.c index 30b5ea67f2..a6ddc21d3e 100644 --- a/hw/display/g364fb.c +++ b/hw/display/g364fb.c @@ -526,7 +526,7 @@ static const VMStateDescription vmstate_g364fb_sysbus = { } }; -static void g364fb_sysbus_class_init(ObjectClass *klass, void *data) +static void g364fb_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/i2c-ddc.c b/hw/display/i2c-ddc.c index d8ab9eee40..2adfc1a147 100644 --- a/hw/display/i2c-ddc.c +++ b/hw/display/i2c-ddc.c @@ -99,7 +99,7 @@ static const Property i2c_ddc_properties[] = { DEFINE_EDID_PROPERTIES(I2CDDCState, edid_info), }; -static void i2c_ddc_class_init(ObjectClass *oc, void *data) +static void i2c_ddc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); diff --git a/hw/display/jazz_led.c b/hw/display/jazz_led.c index 1448488d06..90e82b58be 100644 --- a/hw/display/jazz_led.c +++ b/hw/display/jazz_led.c @@ -294,7 +294,7 @@ static void jazz_led_reset(DeviceState *d) qemu_console_resize(s->con, 60, 80); } -static void jazz_led_class_init(ObjectClass *klass, void *data) +static void jazz_led_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/macfb.c b/hw/display/macfb.c index b08eb06cbd..574d667173 100644 --- a/hw/display/macfb.c +++ b/hw/display/macfb.c @@ -793,7 +793,7 @@ static const VMStateDescription vmstate_macfb_nubus = { } }; -static void macfb_sysbus_class_init(ObjectClass *klass, void *data) +static void macfb_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -804,7 +804,7 @@ static void macfb_sysbus_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, macfb_sysbus_properties); } -static void macfb_nubus_class_init(ObjectClass *klass, void *data) +static void macfb_nubus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); MacfbNubusDeviceClass *ndc = NUBUS_MACFB_CLASS(klass); diff --git a/hw/display/next-fb.c b/hw/display/next-fb.c index 8446ff3c00..ec81b766a7 100644 --- a/hw/display/next-fb.c +++ b/hw/display/next-fb.c @@ -119,7 +119,7 @@ static void nextfb_realize(DeviceState *dev, Error **errp) qemu_console_resize(s->con, s->cols, s->rows); } -static void nextfb_class_init(ObjectClass *oc, void *data) +static void nextfb_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/display/pl110.c b/hw/display/pl110.c index 4d4f477b94..09c3c59e0e 100644 --- a/hw/display/pl110.c +++ b/hw/display/pl110.c @@ -580,7 +580,7 @@ static void pl111_init(Object *obj) s->version = VERSION_PL111; } -static void pl110_class_init(ObjectClass *klass, void *data) +static void pl110_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/qxl.c b/hw/display/qxl.c index da14da5209..6c820bcdb5 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2498,7 +2498,7 @@ static const Property qxl_properties[] = { DEFINE_PROP_BOOL("global-vmstate", PCIQXLDevice, vga.global_vmstate, false), }; -static void qxl_pci_class_init(ObjectClass *klass, void *data) +static void qxl_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -2523,7 +2523,7 @@ static const TypeInfo qxl_pci_type_info = { }, }; -static void qxl_primary_class_init(ObjectClass *klass, void *data) +static void qxl_primary_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -2543,7 +2543,7 @@ static const TypeInfo qxl_primary_info = { module_obj("qxl-vga"); module_kconfig(QXL); -static void qxl_secondary_class_init(ObjectClass *klass, void *data) +static void qxl_secondary_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/ramfb-standalone.c b/hw/display/ramfb-standalone.c index 1be106b57f..08f2d5db4e 100644 --- a/hw/display/ramfb-standalone.c +++ b/hw/display/ramfb-standalone.c @@ -64,7 +64,7 @@ static const Property ramfb_properties[] = { DEFINE_PROP_BOOL("x-migrate", RAMFBStandaloneState, migrate, true), }; -static void ramfb_class_initfn(ObjectClass *klass, void *data) +static void ramfb_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/sii9022.c b/hw/display/sii9022.c index 16f8cb487c..d00d3e9fc5 100644 --- a/hw/display/sii9022.c +++ b/hw/display/sii9022.c @@ -167,7 +167,7 @@ static void sii9022_realize(DeviceState *dev, Error **errp) i2c_slave_create_simple(bus, TYPE_I2CDDC, 0x50); } -static void sii9022_class_init(ObjectClass *klass, void *data) +static void sii9022_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/display/sm501.c b/hw/display/sm501.c index 09edcf86f8..dcff1e978e 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -2077,7 +2077,7 @@ static const VMStateDescription vmstate_sm501_sysbus = { } }; -static void sm501_sysbus_class_init(ObjectClass *klass, void *data) +static void sm501_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2167,7 +2167,7 @@ static const VMStateDescription vmstate_sm501_pci = { } }; -static void sm501_pci_class_init(ObjectClass *klass, void *data) +static void sm501_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/ssd0303.c b/hw/display/ssd0303.c index e292cff44e..87781438cd 100644 --- a/hw/display/ssd0303.c +++ b/hw/display/ssd0303.c @@ -311,7 +311,7 @@ static void ssd0303_realize(DeviceState *dev, Error **errp) qemu_console_resize(s->con, 96 * MAGNIFY, 16 * MAGNIFY); } -static void ssd0303_class_init(ObjectClass *klass, void *data) +static void ssd0303_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/display/ssd0323.c b/hw/display/ssd0323.c index 96cf0dc662..af5ff4fecd 100644 --- a/hw/display/ssd0323.c +++ b/hw/display/ssd0323.c @@ -361,7 +361,7 @@ static void ssd0323_realize(SSIPeripheral *d, Error **errp) qdev_init_gpio_in(dev, ssd0323_cd, 1); } -static void ssd0323_class_init(ObjectClass *klass, void *data) +static void ssd0323_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); diff --git a/hw/display/tcx.c b/hw/display/tcx.c index 5968d33e48..4853c5e142 100644 --- a/hw/display/tcx.c +++ b/hw/display/tcx.c @@ -885,7 +885,7 @@ static const Property tcx_properties[] = { DEFINE_PROP_UINT16("depth", TCXState, depth, -1), }; -static void tcx_class_init(ObjectClass *klass, void *data) +static void tcx_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/vga-isa.c b/hw/display/vga-isa.c index 2920628f78..3618913b3b 100644 --- a/hw/display/vga-isa.c +++ b/hw/display/vga-isa.c @@ -92,7 +92,7 @@ static const Property vga_isa_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", ISAVGAState, state.vram_size_mb, 8), }; -static void vga_isa_class_initfn(ObjectClass *klass, void *data) +static void vga_isa_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/vga-mmio.c b/hw/display/vga-mmio.c index 1e0c2dbf74..33263856b7 100644 --- a/hw/display/vga-mmio.c +++ b/hw/display/vga-mmio.c @@ -116,7 +116,7 @@ static const Property vga_mmio_properties[] = { DEFINE_PROP_UINT32("vgamem_mb", VGAMmioState, vga.vram_size_mb, 8), }; -static void vga_mmio_class_initfn(ObjectClass *klass, void *data) +static void vga_mmio_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index dd084c20b1..a860197274 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -350,7 +350,7 @@ static const Property secondary_pci_properties[] = { DEFINE_EDID_PROPERTIES(PCIVGAState, edid_info), }; -static void vga_pci_class_init(ObjectClass *klass, void *data) +static void vga_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -376,7 +376,7 @@ static const TypeInfo vga_pci_type_info = { }, }; -static void vga_class_init(ObjectClass *klass, void *data) +static void vga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -392,7 +392,7 @@ static void vga_class_init(ObjectClass *klass, void *data) vga_get_big_endian_fb, vga_set_big_endian_fb); } -static void secondary_class_init(ObjectClass *klass, void *data) +static void secondary_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 2aed6243f6..06c4e7e190 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -658,7 +658,7 @@ static const Property vhost_user_gpu_properties[] = { }; static void -vhost_user_gpu_class_init(ObjectClass *klass, void *data) +vhost_user_gpu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/display/virtio-gpu-base.c b/hw/display/virtio-gpu-base.c index 321a6f4998..9eb806b71f 100644 --- a/hw/display/virtio-gpu-base.c +++ b/hw/display/virtio-gpu-base.c @@ -262,7 +262,7 @@ virtio_gpu_base_device_unrealize(DeviceState *qdev) } static void -virtio_gpu_base_class_init(ObjectClass *klass, void *data) +virtio_gpu_base_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/display/virtio-gpu-gl.c b/hw/display/virtio-gpu-gl.c index 683fad3bf8..c06a078fb3 100644 --- a/hw/display/virtio-gpu-gl.c +++ b/hw/display/virtio-gpu-gl.c @@ -182,7 +182,7 @@ static void virtio_gpu_gl_device_unrealize(DeviceState *qdev) g_array_unref(g->capset_ids); } -static void virtio_gpu_gl_class_init(ObjectClass *klass, void *data) +static void virtio_gpu_gl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/display/virtio-gpu-pci.c b/hw/display/virtio-gpu-pci.c index 6d789701a3..c0d71b6254 100644 --- a/hw/display/virtio-gpu-pci.c +++ b/hw/display/virtio-gpu-pci.c @@ -57,7 +57,7 @@ static void virtio_gpu_pci_base_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_gpu_pci_base_class_init(ObjectClass *klass, void *data) +static void virtio_gpu_pci_base_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c index f6eb29472e..ed5ae52acb 100644 --- a/hw/display/virtio-gpu-rutabaga.c +++ b/hw/display/virtio-gpu-rutabaga.c @@ -1110,7 +1110,7 @@ static const Property virtio_gpu_rutabaga_properties[] = { DEFINE_PROP_STRING("wsi", VirtIOGPURutabaga, wsi), }; -static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, void *data) +static void virtio_gpu_rutabaga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 11a7a85750..0a1a625b0e 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -1684,7 +1684,7 @@ static const Property virtio_gpu_properties[] = { DEFINE_PROP_UINT8("x-scanout-vmstate-version", VirtIOGPU, scanout_vmstate_version, 2), }; -static void virtio_gpu_class_init(ObjectClass *klass, void *data) +static void virtio_gpu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/display/virtio-vga.c b/hw/display/virtio-vga.c index fefbdb61e1..40e60f70fc 100644 --- a/hw/display/virtio-vga.c +++ b/hw/display/virtio-vga.c @@ -213,7 +213,7 @@ static const Property virtio_vga_base_properties[] = { DEFINE_VIRTIO_GPU_PCI_PROPERTIES(VirtIOPCIProxy), }; -static void virtio_vga_base_class_init(ObjectClass *klass, void *data) +static void virtio_vga_base_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 2dd661e3c1..7777deb17d 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1339,7 +1339,7 @@ static const Property vga_vmware_properties[] = { chip.vga.global_vmstate, false), }; -static void vmsvga_class_init(ObjectClass *klass, void *data) +static void vmsvga_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c index 1272da0133..7c980ee642 100644 --- a/hw/display/xlnx_dp.c +++ b/hw/display/xlnx_dp.c @@ -1391,7 +1391,7 @@ static const Property xlnx_dp_device_properties[] = { DEFINE_AUDIO_PROPERTIES(XlnxDPState, aud_card), }; -static void xlnx_dp_class_init(ObjectClass *oc, void *data) +static void xlnx_dp_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/dma/bcm2835_dma.c b/hw/dma/bcm2835_dma.c index 9b2fca2c7c..a2771ddcb5 100644 --- a/hw/dma/bcm2835_dma.c +++ b/hw/dma/bcm2835_dma.c @@ -385,7 +385,7 @@ static void bcm2835_dma_realize(DeviceState *dev, Error **errp) bcm2835_dma_reset(dev); } -static void bcm2835_dma_class_init(ObjectClass *klass, void *data) +static void bcm2835_dma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/i82374.c b/hw/dma/i82374.c index 0bf69ef399..e226eda6d1 100644 --- a/hw/dma/i82374.c +++ b/hw/dma/i82374.c @@ -143,7 +143,7 @@ static const Property i82374_properties[] = { DEFINE_PROP_UINT32("iobase", I82374State, iobase, 0x400), }; -static void i82374_class_init(ObjectClass *klass, void *data) +static void i82374_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index 74c38d2ee8..1d67e50536 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -592,7 +592,7 @@ static const Property i8257_properties[] = { DEFINE_PROP_INT32("dshift", I8257State, dshift, 0), }; -static void i8257_class_init(ObjectClass *klass, void *data) +static void i8257_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IsaDmaClass *idc = ISADMA_CLASS(klass); diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index 8a9b073b24..277d934322 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -413,7 +413,7 @@ static const Property pl080_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void pl080_class_init(ObjectClass *oc, void *data) +static void pl080_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/dma/pl330.c b/hw/dma/pl330.c index 545aa44e45..a570bb08ec 100644 --- a/hw/dma/pl330.c +++ b/hw/dma/pl330.c @@ -1671,7 +1671,7 @@ static const Property pl330_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void pl330_class_init(ObjectClass *klass, void *data) +static void pl330_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/rc4030.c b/hw/dma/rc4030.c index 6842e7d491..b6ed1d4643 100644 --- a/hw/dma/rc4030.c +++ b/hw/dma/rc4030.c @@ -701,7 +701,7 @@ static void rc4030_unrealize(DeviceState *dev) object_unparent(OBJECT(&s->dma_mr)); } -static void rc4030_class_init(ObjectClass *klass, void *class_data) +static void rc4030_class_init(ObjectClass *klass, const void *class_data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -720,7 +720,7 @@ static const TypeInfo rc4030_info = { }; static void rc4030_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/dma/sifive_pdma.c b/hw/dma/sifive_pdma.c index a115af8d60..48de3a2478 100644 --- a/hw/dma/sifive_pdma.c +++ b/hw/dma/sifive_pdma.c @@ -464,7 +464,7 @@ static void sifive_pdma_realize(DeviceState *dev, Error **errp) } } -static void sifive_pdma_class_init(ObjectClass *klass, void *data) +static void sifive_pdma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 280b747521..60c23b69e5 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -274,7 +274,7 @@ static void sparc32_dma_device_init(Object *obj) qdev_init_gpio_out(dev, s->gpio, 2); } -static void sparc32_dma_device_class_init(ObjectClass *klass, void *data) +static void sparc32_dma_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -316,7 +316,8 @@ static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(sysbus), &error_fatal); } -static void sparc32_espdma_device_class_init(ObjectClass *klass, void *data) +static void sparc32_espdma_device_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -351,7 +352,8 @@ static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(lance), &error_fatal); } -static void sparc32_ledma_device_class_init(ObjectClass *klass, void *data) +static void sparc32_ledma_device_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -426,7 +428,7 @@ static void sparc32_dma_init(Object *obj) TYPE_SPARC32_LEDMA_DEVICE); } -static void sparc32_dma_class_init(ObjectClass *klass, void *data) +static void sparc32_dma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index 22fe35751a..bf1b523ac8 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -621,7 +621,7 @@ static const Property axidma_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void axidma_class_init(ObjectClass *klass, void *data) +static void axidma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -639,7 +639,8 @@ static StreamSinkClass xilinx_axidma_control_stream_class = { .push = xilinx_axidma_control_stream_push, }; -static void xilinx_axidma_stream_class_init(ObjectClass *klass, void *data) +static void xilinx_axidma_stream_class_init(ObjectClass *klass, + const void *data) { StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); diff --git a/hw/dma/xlnx-zdma.c b/hw/dma/xlnx-zdma.c index bb27cb2e64..0c075e7d0d 100644 --- a/hw/dma/xlnx-zdma.c +++ b/hw/dma/xlnx-zdma.c @@ -816,7 +816,7 @@ static const Property zdma_props[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void zdma_class_init(ObjectClass *klass, void *data) +static void zdma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/xlnx-zynq-devcfg.c b/hw/dma/xlnx-zynq-devcfg.c index 0fd0d23f57..26845713ee 100644 --- a/hw/dma/xlnx-zynq-devcfg.c +++ b/hw/dma/xlnx-zynq-devcfg.c @@ -380,7 +380,7 @@ static void xlnx_zynq_devcfg_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, void *data) +static void xlnx_zynq_devcfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 1afaa0bf51..6943c927d0 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -712,7 +712,7 @@ static const Property xlnx_csu_dma_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data) +static void xlnx_csu_dma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c index 2657808d37..3d88ccc8da 100644 --- a/hw/dma/xlnx_dpdma.c +++ b/hw/dma/xlnx_dpdma.c @@ -593,7 +593,7 @@ static void xlnx_dpdma_reset(DeviceState *dev) } } -static void xlnx_dpdma_class_init(ObjectClass *oc, void *data) +static void xlnx_dpdma_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/fsi/aspeed_apb2opb.c b/hw/fsi/aspeed_apb2opb.c index 0e2cc143f1..172ba16b0c 100644 --- a/hw/fsi/aspeed_apb2opb.c +++ b/hw/fsi/aspeed_apb2opb.c @@ -320,7 +320,7 @@ static void fsi_aspeed_apb2opb_reset(DeviceState *dev) memcpy(s->regs, aspeed_apb2opb_reset, ASPEED_APB2OPB_NR_REGS); } -static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, void *data) +static void fsi_aspeed_apb2opb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/fsi/cfam.c b/hw/fsi/cfam.c index c62f0f78de..e2145c5934 100644 --- a/hw/fsi/cfam.c +++ b/hw/fsi/cfam.c @@ -145,7 +145,7 @@ static void fsi_cfam_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(&cfam->lbus.mr, 0, &fsi_dev->iomem); } -static void fsi_cfam_class_init(ObjectClass *klass, void *data) +static void fsi_cfam_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->bus_type = TYPE_FSI_BUS; diff --git a/hw/fsi/fsi-master.c b/hw/fsi/fsi-master.c index 50fb1cd467..083a5507ab 100644 --- a/hw/fsi/fsi-master.c +++ b/hw/fsi/fsi-master.c @@ -144,7 +144,7 @@ static void fsi_master_reset(DeviceState *dev) s->regs[FSI_MVER] = 0xe0050101; } -static void fsi_master_class_init(ObjectClass *klass, void *data) +static void fsi_master_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/fsi/fsi.c b/hw/fsi/fsi.c index 83ddb17ae6..6c52d5e745 100644 --- a/hw/fsi/fsi.c +++ b/hw/fsi/fsi.c @@ -76,7 +76,7 @@ static void fsi_slave_init(Object *o) s, TYPE_FSI_SLAVE, 0x400); } -static void fsi_slave_class_init(ObjectClass *klass, void *data) +static void fsi_slave_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/fsi/lbus.c b/hw/fsi/lbus.c index 4f87b28a22..8ec7f5fd78 100644 --- a/hw/fsi/lbus.c +++ b/hw/fsi/lbus.c @@ -91,7 +91,7 @@ static void fsi_scratchpad_reset(DeviceState *dev) memset(s->regs, 0, sizeof(s->regs)); } -static void fsi_scratchpad_class_init(ObjectClass *klass, void *data) +static void fsi_scratchpad_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/aspeed_gpio.c b/hw/gpio/aspeed_gpio.c index aedaf5238b..609a556908 100644 --- a/hw/gpio/aspeed_gpio.c +++ b/hw/gpio/aspeed_gpio.c @@ -1473,7 +1473,7 @@ static const VMStateDescription vmstate_aspeed_gpio = { } }; -static void aspeed_gpio_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1483,7 +1483,7 @@ static void aspeed_gpio_class_init(ObjectClass *klass, void *data) dc->vmsd = &vmstate_aspeed_gpio; } -static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); @@ -1496,7 +1496,7 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data) agc->reg_ops = &aspeed_gpio_ops; } -static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_2500_class_init(ObjectClass *klass, const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); @@ -1509,7 +1509,8 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data) agc->reg_ops = &aspeed_gpio_ops; } -static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, + const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); @@ -1522,7 +1523,8 @@ static void aspeed_gpio_ast2600_3_3v_class_init(ObjectClass *klass, void *data) agc->reg_ops = &aspeed_gpio_ops; } -static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, + const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); @@ -1535,7 +1537,7 @@ static void aspeed_gpio_ast2600_1_8v_class_init(ObjectClass *klass, void *data) agc->reg_ops = &aspeed_gpio_ops; } -static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_1030_class_init(ObjectClass *klass, const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); @@ -1548,7 +1550,7 @@ static void aspeed_gpio_1030_class_init(ObjectClass *klass, void *data) agc->reg_ops = &aspeed_gpio_ops; } -static void aspeed_gpio_2700_class_init(ObjectClass *klass, void *data) +static void aspeed_gpio_2700_class_init(ObjectClass *klass, const void *data) { AspeedGPIOClass *agc = ASPEED_GPIO_CLASS(klass); diff --git a/hw/gpio/bcm2835_gpio.c b/hw/gpio/bcm2835_gpio.c index 5a5f1df5e8..dfb5d5cb57 100644 --- a/hw/gpio/bcm2835_gpio.c +++ b/hw/gpio/bcm2835_gpio.c @@ -319,7 +319,7 @@ static void bcm2835_gpio_realize(DeviceState *dev, Error **errp) s->sdbus_sdhost = SD_BUS(obj); } -static void bcm2835_gpio_class_init(ObjectClass *klass, void *data) +static void bcm2835_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/bcm2838_gpio.c b/hw/gpio/bcm2838_gpio.c index 53be8f2d23..1069e7811b 100644 --- a/hw/gpio/bcm2838_gpio.c +++ b/hw/gpio/bcm2838_gpio.c @@ -364,7 +364,7 @@ static void bcm2838_gpio_realize(DeviceState *dev, Error **errp) s->sdbus_sdhost = SD_BUS(obj); } -static void bcm2838_gpio_class_init(ObjectClass *klass, void *data) +static void bcm2838_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/gpio_key.c b/hw/gpio/gpio_key.c index 2fcab9ead6..40c028bed9 100644 --- a/hw/gpio/gpio_key.c +++ b/hw/gpio/gpio_key.c @@ -85,7 +85,7 @@ static void gpio_key_realize(DeviceState *dev, Error **errp) s->timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, gpio_key_timer_expired, s); } -static void gpio_key_class_init(ObjectClass *klass, void *data) +static void gpio_key_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c index 8c8299c4c4..f23c52af26 100644 --- a/hw/gpio/imx_gpio.c +++ b/hw/gpio/imx_gpio.c @@ -321,7 +321,7 @@ static void imx_gpio_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } -static void imx_gpio_class_init(ObjectClass *klass, void *data) +static void imx_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/mpc8xxx.c b/hw/gpio/mpc8xxx.c index a3c1d2fbf4..257497af58 100644 --- a/hw/gpio/mpc8xxx.c +++ b/hw/gpio/mpc8xxx.c @@ -199,7 +199,7 @@ static void mpc8xxx_gpio_initfn(Object *obj) qdev_init_gpio_out(dev, s->out, 32); } -static void mpc8xxx_gpio_class_init(ObjectClass *klass, void *data) +static void mpc8xxx_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/npcm7xx_gpio.c b/hw/gpio/npcm7xx_gpio.c index 2916056fae..66f8256a7a 100644 --- a/hw/gpio/npcm7xx_gpio.c +++ b/hw/gpio/npcm7xx_gpio.c @@ -396,7 +396,7 @@ static const Property npcm7xx_gpio_properties[] = { DEFINE_PROP_UINT32("reset-odsc", NPCM7xxGPIOState, reset_odsc, 0), }; -static void npcm7xx_gpio_class_init(ObjectClass *klass, void *data) +static void npcm7xx_gpio_class_init(ObjectClass *klass, const void *data) { ResettableClass *reset = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c index d08c254e36..d94c0c47da 100644 --- a/hw/gpio/nrf51_gpio.c +++ b/hw/gpio/nrf51_gpio.c @@ -304,7 +304,7 @@ static void nrf51_gpio_init(Object *obj) qdev_init_gpio_out_named(DEVICE(s), &s->detect, "detect", 1); } -static void nrf51_gpio_class_init(ObjectClass *klass, void *data) +static void nrf51_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index 8a9f14ba15..61ea7862af 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -229,7 +229,7 @@ static const Property omap_gpio_properties[] = { DEFINE_PROP_INT32("mpu_model", Omap1GpioState, mpu_model, 0), }; -static void omap_gpio_class_init(ObjectClass *klass, void *data) +static void omap_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/pca9552.c b/hw/gpio/pca9552.c index 1ac0cf6c46..d65c0a2e90 100644 --- a/hw/gpio/pca9552.c +++ b/hw/gpio/pca9552.c @@ -432,7 +432,7 @@ static const Property pca955x_properties[] = { DEFINE_PROP_STRING("description", PCA955xState, description), }; -static void pca955x_class_init(ObjectClass *klass, void *data) +static void pca955x_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); @@ -454,7 +454,7 @@ static const TypeInfo pca955x_info = { .abstract = true, }; -static void pca9552_class_init(ObjectClass *oc, void *data) +static void pca9552_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCA955xClass *pc = PCA955X_CLASS(oc); diff --git a/hw/gpio/pca9554.c b/hw/gpio/pca9554.c index 7301fce934..de3f883aee 100644 --- a/hw/gpio/pca9554.c +++ b/hw/gpio/pca9554.c @@ -292,7 +292,7 @@ static const Property pca9554_properties[] = { DEFINE_PROP_STRING("description", PCA9554State, description), }; -static void pca9554_class_init(ObjectClass *klass, void *data) +static void pca9554_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/gpio/pcf8574.c b/hw/gpio/pcf8574.c index 208efe69ea..274b44bb61 100644 --- a/hw/gpio/pcf8574.c +++ b/hw/gpio/pcf8574.c @@ -138,7 +138,7 @@ static void pcf8574_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out_named(dev, &s->intrq, "nINT", 1); } -static void pcf8574_class_init(ObjectClass *klass, void *data) +static void pcf8574_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c index 2e69785f2a..1acca3f2f8 100644 --- a/hw/gpio/pl061.c +++ b/hw/gpio/pl061.c @@ -566,7 +566,7 @@ static const Property pl061_props[] = { DEFINE_PROP_UINT32("pulldowns", PL061State, pulldowns, 0x0), }; -static void pl061_class_init(ObjectClass *klass, void *data) +static void pl061_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/gpio/sifive_gpio.c b/hw/gpio/sifive_gpio.c index 0d5206ae6b..5831647b4d 100644 --- a/hw/gpio/sifive_gpio.c +++ b/hw/gpio/sifive_gpio.c @@ -370,7 +370,7 @@ static void sifive_gpio_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio); } -static void sifive_gpio_class_init(ObjectClass *klass, void *data) +static void sifive_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/gpio/stm32l4x5_gpio.c b/hw/gpio/stm32l4x5_gpio.c index f69fc1db4f..414ce83039 100644 --- a/hw/gpio/stm32l4x5_gpio.c +++ b/hw/gpio/stm32l4x5_gpio.c @@ -454,7 +454,7 @@ static const Property stm32l4x5_gpio_properties[] = { DEFINE_PROP_UINT32("pupd-reset", Stm32l4x5GpioState, pupdr_reset, 0), }; -static void stm32l4x5_gpio_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c index 7342440b95..b8d27f5973 100644 --- a/hw/gpio/zaurus.c +++ b/hw/gpio/zaurus.c @@ -243,7 +243,7 @@ static const VMStateDescription vmstate_scoop_regs = { }, }; -static void scoop_sysbus_class_init(ObjectClass *klass, void *data) +static void scoop_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index c430bf28dd..1812276678 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -683,7 +683,7 @@ static void hppa_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data) +static void HP_B160L_machine_init_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { TYPE_HPPA_CPU, @@ -719,7 +719,7 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = { }, }; -static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data) +static void HP_C3700_machine_init_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { TYPE_HPPA64_CPU, diff --git a/hw/hyperv/hv-balloon.c b/hw/hyperv/hv-balloon.c index acabff2c4a..94b0abbd68 100644 --- a/hw/hyperv/hv-balloon.c +++ b/hw/hyperv/hv-balloon.c @@ -1743,7 +1743,7 @@ static const Property hv_balloon_properties[] = { DEFINE_PROP_UINT64(HV_BALLOON_ADDR_PROP, HvBalloon, addr, 0), }; -static void hv_balloon_class_init(ObjectClass *klass, void *data) +static void hv_balloon_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VMBusDeviceClass *vdc = VMBUS_DEVICE_CLASS(klass); diff --git a/hw/hyperv/hyperv.c b/hw/hyperv/hyperv.c index 8f193fd0bd..0271cfd271 100644 --- a/hw/hyperv/hyperv.c +++ b/hw/hyperv/hyperv.c @@ -133,7 +133,7 @@ static void synic_reset(DeviceState *dev) assert(QLIST_EMPTY(&synic->sint_routes)); } -static void synic_class_init(ObjectClass *klass, void *data) +static void synic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/hyperv/hyperv_testdev.c b/hw/hyperv/hyperv_testdev.c index a630ca7047..2d4a63693b 100644 --- a/hw/hyperv/hyperv_testdev.c +++ b/hw/hyperv/hyperv_testdev.c @@ -303,7 +303,7 @@ static void hv_test_dev_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(io, 0x3000, &dev->sint_control); } -static void hv_test_dev_class_init(ObjectClass *klass, void *data) +static void hv_test_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/hyperv/syndbg.c b/hw/hyperv/syndbg.c index a410b55b9a..ca291826a0 100644 --- a/hw/hyperv/syndbg.c +++ b/hw/hyperv/syndbg.c @@ -373,7 +373,7 @@ static const Property hv_syndbg_properties[] = { DEFINE_PROP_BOOL("use_hcalls", HvSynDbg, use_hcalls, false), }; -static void hv_syndbg_class_init(ObjectClass *klass, void *data) +static void hv_syndbg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/hyperv/vmbus.c b/hw/hyperv/vmbus.c index 98ea968e51..b147ea06d8 100644 --- a/hw/hyperv/vmbus.c +++ b/hw/hyperv/vmbus.c @@ -2351,7 +2351,7 @@ static const Property vmbus_dev_props[] = { }; -static void vmbus_dev_class_init(ObjectClass *klass, void *data) +static void vmbus_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *kdev = DEVICE_CLASS(klass); device_class_set_props(kdev, vmbus_dev_props); @@ -2469,7 +2469,7 @@ static char *vmbus_get_fw_dev_path(DeviceState *dev) return g_strdup_printf("%s@%s", qdev_fw_name(dev), uuid); } -static void vmbus_class_init(ObjectClass *klass, void *data) +static void vmbus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -2656,7 +2656,7 @@ static const Property vmbus_bridge_props[] = { DEFINE_PROP_UINT8("irq", VMBusBridge, irq, 7), }; -static void vmbus_bridge_class_init(ObjectClass *klass, void *data) +static void vmbus_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); SysBusDeviceClass *sk = SYS_BUS_DEVICE_CLASS(klass); diff --git a/hw/i2c/allwinner-i2c.c b/hw/i2c/allwinner-i2c.c index 66d6431c50..fe887e1c6a 100644 --- a/hw/i2c/allwinner-i2c.c +++ b/hw/i2c/allwinner-i2c.c @@ -438,7 +438,7 @@ static void allwinner_i2c_realize(DeviceState *dev, Error **errp) s->bus = i2c_init_bus(dev, "i2c"); } -static void allwinner_i2c_class_init(ObjectClass *klass, void *data) +static void allwinner_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/i2c/aspeed_i2c.c b/hw/i2c/aspeed_i2c.c index a8fbb9f44a..83fb906bdc 100644 --- a/hw/i2c/aspeed_i2c.c +++ b/hw/i2c/aspeed_i2c.c @@ -1263,7 +1263,7 @@ static const Property aspeed_i2c_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void aspeed_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1390,7 +1390,8 @@ static void aspeed_i2c_bus_slave_send_async(I2CSlave *slave, uint8_t data) aspeed_i2c_bus_raise_interrupt(bus); } -static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, void *data) +static void aspeed_i2c_bus_slave_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); @@ -1451,7 +1452,7 @@ static const Property aspeed_i2c_bus_properties[] = { AspeedI2CState *), }; -static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data) +static void aspeed_i2c_bus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1483,7 +1484,7 @@ static uint8_t *aspeed_2400_i2c_bus_pool_base(AspeedI2CBus *bus) return &pool_page[ARRAY_FIELD_EX32(bus->regs, I2CD_POOL_CTRL, OFFSET)]; } -static void aspeed_2400_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); @@ -1517,7 +1518,7 @@ static uint8_t *aspeed_2500_i2c_bus_pool_base(AspeedI2CBus *bus) return bus->pool; } -static void aspeed_2500_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); @@ -1547,7 +1548,7 @@ static qemu_irq aspeed_2600_i2c_bus_get_irq(AspeedI2CBus *bus) return bus->irq; } -static void aspeed_2600_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); @@ -1571,7 +1572,7 @@ static const TypeInfo aspeed_2600_i2c_info = { .class_init = aspeed_2600_i2c_class_init, }; -static void aspeed_1030_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); @@ -1595,7 +1596,7 @@ static const TypeInfo aspeed_1030_i2c_info = { .class_init = aspeed_1030_i2c_class_init, }; -static void aspeed_2700_i2c_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedI2CClass *aic = ASPEED_I2C_CLASS(klass); diff --git a/hw/i2c/bcm2835_i2c.c b/hw/i2c/bcm2835_i2c.c index 67bfdef3b4..be11cca2a9 100644 --- a/hw/i2c/bcm2835_i2c.c +++ b/hw/i2c/bcm2835_i2c.c @@ -258,7 +258,7 @@ static const VMStateDescription vmstate_bcm2835_i2c = { } }; -static void bcm2835_i2c_class_init(ObjectClass *klass, void *data) +static void bcm2835_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c index de5f5aacf5..e020f314e2 100644 --- a/hw/i2c/bitbang_i2c.c +++ b/hw/i2c/bitbang_i2c.c @@ -222,7 +222,7 @@ static void gpio_i2c_init(Object *obj) qdev_init_gpio_out(dev, &s->out, 1); } -static void gpio_i2c_class_init(ObjectClass *klass, void *data) +static void gpio_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/core.c b/hw/i2c/core.c index 26bb18514a..4b6345b588 100644 --- a/hw/i2c/core.c +++ b/hw/i2c/core.c @@ -401,7 +401,7 @@ static bool i2c_slave_match(I2CSlave *candidate, uint8_t address, return false; } -static void i2c_slave_class_init(ObjectClass *klass, void *data) +static void i2c_slave_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c index b1d00096ee..9d0c1cdaa8 100644 --- a/hw/i2c/exynos4210_i2c.c +++ b/hw/i2c/exynos4210_i2c.c @@ -309,7 +309,7 @@ static void exynos4210_i2c_init(Object *obj) s->bus = i2c_init_bus(dev, "i2c"); } -static void exynos4210_i2c_class_init(ObjectClass *klass, void *data) +static void exynos4210_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/i2c_mux_pca954x.c b/hw/i2c/i2c_mux_pca954x.c index 779cc4e66e..a8ef640cd2 100644 --- a/hw/i2c/i2c_mux_pca954x.c +++ b/hw/i2c/i2c_mux_pca954x.c @@ -172,13 +172,13 @@ I2CBus *pca954x_i2c_get_bus(I2CSlave *mux, uint8_t channel) return pca954x->bus[channel]; } -static void pca9546_class_init(ObjectClass *klass, void *data) +static void pca9546_class_init(ObjectClass *klass, const void *data) { Pca954xClass *s = PCA954X_CLASS(klass); s->nchans = PCA9546_CHANNEL_COUNT; } -static void pca9548_class_init(ObjectClass *klass, void *data) +static void pca9548_class_init(ObjectClass *klass, const void *data) { Pca954xClass *s = PCA954X_CLASS(klass); s->nchans = PCA9548_CHANNEL_COUNT; @@ -215,7 +215,7 @@ static const Property pca954x_props[] = { DEFINE_PROP_STRING("name", Pca954xState, name), }; -static void pca954x_class_init(ObjectClass *klass, void *data) +static void pca954x_class_init(ObjectClass *klass, const void *data) { I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/i2c/imx_i2c.c b/hw/i2c/imx_i2c.c index d62213b9e0..91f84c2ad7 100644 --- a/hw/i2c/imx_i2c.c +++ b/hw/i2c/imx_i2c.c @@ -297,7 +297,7 @@ static void imx_i2c_realize(DeviceState *dev, Error **errp) s->bus = i2c_init_bus(dev, NULL); } -static void imx_i2c_class_init(ObjectClass *klass, void *data) +static void imx_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/microbit_i2c.c b/hw/i2c/microbit_i2c.c index 06fbd18a78..2291d6370e 100644 --- a/hw/i2c/microbit_i2c.c +++ b/hw/i2c/microbit_i2c.c @@ -105,7 +105,7 @@ static void microbit_i2c_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void microbit_i2c_class_init(ObjectClass *klass, void *data) +static void microbit_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/mpc_i2c.c b/hw/i2c/mpc_i2c.c index 913d044ac1..25f91b7bc8 100644 --- a/hw/i2c/mpc_i2c.c +++ b/hw/i2c/mpc_i2c.c @@ -334,7 +334,7 @@ static void mpc_i2c_realize(DeviceState *dev, Error **errp) i2c->bus = i2c_init_bus(dev, "i2c"); } -static void mpc_i2c_class_init(ObjectClass *klass, void *data) +static void mpc_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/npcm7xx_smbus.c b/hw/i2c/npcm7xx_smbus.c index 22d68fc67d..179852a4fd 100644 --- a/hw/i2c/npcm7xx_smbus.c +++ b/hw/i2c/npcm7xx_smbus.c @@ -1075,7 +1075,7 @@ static const VMStateDescription vmstate_npcm7xx_smbus = { }, }; -static void npcm7xx_smbus_class_init(ObjectClass *klass, void *data) +static void npcm7xx_smbus_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c index a641db2348..2e45266e74 100644 --- a/hw/i2c/omap_i2c.c +++ b/hw/i2c/omap_i2c.c @@ -515,7 +515,7 @@ static const Property omap_i2c_properties[] = { DEFINE_PROP_UINT8("revision", OMAPI2CState, revision, 0), }; -static void omap_i2c_class_init(ObjectClass *klass, void *data) +static void omap_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/pmbus_device.c b/hw/i2c/pmbus_device.c index ba1d2fd716..853dc4b434 100644 --- a/hw/i2c/pmbus_device.c +++ b/hw/i2c/pmbus_device.c @@ -1902,7 +1902,7 @@ static void pmbus_device_finalize(Object *obj) g_free(pmdev->pages); } -static void pmbus_device_class_init(ObjectClass *klass, void *data) +static void pmbus_device_class_init(ObjectClass *klass, const void *data) { SMBusDeviceClass *k = SMBUS_DEVICE_CLASS(klass); diff --git a/hw/i2c/ppc4xx_i2c.c b/hw/i2c/ppc4xx_i2c.c index 7b124a7e33..09d4c49d65 100644 --- a/hw/i2c/ppc4xx_i2c.c +++ b/hw/i2c/ppc4xx_i2c.c @@ -354,7 +354,7 @@ static void ppc4xx_i2c_init(Object *o) bitbang_i2c_init(&s->bitbang, s->bus); } -static void ppc4xx_i2c_class_init(ObjectClass *klass, void *data) +static void ppc4xx_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i2c/smbus_eeprom.c b/hw/i2c/smbus_eeprom.c index e3e96d4a2d..0a1088fbb0 100644 --- a/hw/i2c/smbus_eeprom.c +++ b/hw/i2c/smbus_eeprom.c @@ -137,7 +137,7 @@ static void smbus_eeprom_realize(DeviceState *dev, Error **errp) } } -static void smbus_eeprom_class_initfn(ObjectClass *klass, void *data) +static void smbus_eeprom_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SMBusDeviceClass *sc = SMBUS_DEVICE_CLASS(klass); diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index 208f263ac5..f1fca30fea 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -118,7 +118,7 @@ static void build_ich9_smb_aml(AcpiDevAmlIf *adev, Aml *scope) qbus_build_aml(bus, scope); } -static void ich9_smb_class_init(ObjectClass *klass, void *data) +static void ich9_smb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/i2c/smbus_slave.c b/hw/i2c/smbus_slave.c index 9f9afc25a4..cfb61c879e 100644 --- a/hw/i2c/smbus_slave.c +++ b/hw/i2c/smbus_slave.c @@ -201,7 +201,7 @@ static int smbus_i2c_send(I2CSlave *s, uint8_t data) return 0; } -static void smbus_device_class_init(ObjectClass *klass, void *data) +static void smbus_device_class_init(ObjectClass *klass, const void *data) { I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 5f9b952799..b94802e21a 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1677,7 +1677,7 @@ static void amdvi_sysbus_instance_init(Object *klass) object_initialize(&s->pci, sizeof(s->pci), TYPE_AMD_IOMMU_PCI); } -static void amdvi_sysbus_class_init(ObjectClass *klass, void *data) +static void amdvi_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); X86IOMMUClass *dc_class = X86_IOMMU_DEVICE_CLASS(klass); @@ -1700,7 +1700,7 @@ static const TypeInfo amdvi_sysbus = { .class_init = amdvi_sysbus_class_init }; -static void amdvi_pci_class_init(ObjectClass *klass, void *data) +static void amdvi_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1725,7 +1725,8 @@ static const TypeInfo amdvi_pci = { }, }; -static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void amdvi_iommu_memory_region_class_init(ObjectClass *klass, + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 0608aec8c5..5f8ed1243d 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4859,7 +4859,7 @@ static void vtd_realize(DeviceState *dev, Error **errp) qemu_add_machine_init_done_notifier(&vtd_machine_done_notify); } -static void vtd_class_init(ObjectClass *klass, void *data) +static void vtd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); X86IOMMUClass *x86_class = X86_IOMMU_DEVICE_CLASS(klass); @@ -4887,7 +4887,7 @@ static const TypeInfo vtd_info = { }; static void vtd_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 7575106000..39035db042 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -240,7 +240,7 @@ static void kvm_apic_unrealize(DeviceState *dev) { } -static void kvm_apic_class_init(ObjectClass *klass, void *data) +static void kvm_apic_class_init(ObjectClass *klass, const void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c index 17443552e9..f56382717f 100644 --- a/hw/i386/kvm/clock.c +++ b/hw/i386/kvm/clock.c @@ -309,7 +309,7 @@ static const Property kvmclock_properties[] = { mach_use_reliable_get_clock, true), }; -static void kvmclock_class_init(ObjectClass *klass, void *data) +static void kvmclock_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/i8254.c b/hw/i386/kvm/i8254.c index 3b92771c79..14b78f30a8 100644 --- a/hw/i386/kvm/i8254.c +++ b/hw/i386/kvm/i8254.c @@ -292,7 +292,7 @@ static const Property kvm_pit_properties[] = { lost_tick_policy, LOST_TICK_POLICY_DELAY), }; -static void kvm_pit_class_init(ObjectClass *klass, void *data) +static void kvm_pit_class_init(ObjectClass *klass, const void *data) { KVMPITClass *kpc = KVM_PIT_CLASS(klass); PITCommonClass *k = PIT_COMMON_CLASS(klass); diff --git a/hw/i386/kvm/i8259.c b/hw/i386/kvm/i8259.c index 272c04df0b..8a72d6e4dd 100644 --- a/hw/i386/kvm/i8259.c +++ b/hw/i386/kvm/i8259.c @@ -139,7 +139,7 @@ qemu_irq *kvm_i8259_init(ISABus *bus) return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS); } -static void kvm_i8259_class_init(ObjectClass *klass, void *data) +static void kvm_i8259_class_init(ObjectClass *klass, const void *data) { KVMPICClass *kpc = KVM_PIC_CLASS(klass); PICCommonClass *k = PIC_COMMON_CLASS(klass); diff --git a/hw/i386/kvm/ioapic.c b/hw/i386/kvm/ioapic.c index 5419e191b5..693ee978a1 100644 --- a/hw/i386/kvm/ioapic.c +++ b/hw/i386/kvm/ioapic.c @@ -137,7 +137,7 @@ static const Property kvm_ioapic_properties[] = { DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0), }; -static void kvm_ioapic_class_init(ObjectClass *klass, void *data) +static void kvm_ioapic_class_init(ObjectClass *klass, const void *data) { IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index f9223ef1a1..b5190549a8 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -271,7 +271,7 @@ static const VMStateDescription xen_evtchn_vmstate = { } }; -static void xen_evtchn_class_init(ObjectClass *klass, void *data) +static void xen_evtchn_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/xen_gnttab.c b/hw/i386/kvm/xen_gnttab.c index 430ba62896..4b9e272c5e 100644 --- a/hw/i386/kvm/xen_gnttab.c +++ b/hw/i386/kvm/xen_gnttab.c @@ -135,7 +135,7 @@ static const VMStateDescription xen_gnttab_vmstate = { } }; -static void xen_gnttab_class_init(ObjectClass *klass, void *data) +static void xen_gnttab_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/xen_overlay.c b/hw/i386/kvm/xen_overlay.c index a2b26e9906..3cb7361937 100644 --- a/hw/i386/kvm/xen_overlay.c +++ b/hw/i386/kvm/xen_overlay.c @@ -151,7 +151,7 @@ static void xen_overlay_reset(DeviceState *dev) kvm_xen_soft_reset(); } -static void xen_overlay_class_init(ObjectClass *klass, void *data) +static void xen_overlay_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/xen_primary_console.c b/hw/i386/kvm/xen_primary_console.c index 8ad2363d18..6e9d6417c3 100644 --- a/hw/i386/kvm/xen_primary_console.c +++ b/hw/i386/kvm/xen_primary_console.c @@ -67,7 +67,7 @@ static void xen_primary_console_realize(DeviceState *dev, Error **errp) xen_primary_console_singleton = s; } -static void xen_primary_console_class_init(ObjectClass *klass, void *data) +static void xen_primary_console_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/kvm/xen_xenstore.c b/hw/i386/kvm/xen_xenstore.c index 227ad7ace3..42955cccd9 100644 --- a/hw/i386/kvm/xen_xenstore.c +++ b/hw/i386/kvm/xen_xenstore.c @@ -259,7 +259,7 @@ static const VMStateDescription xen_xenstore_vmstate = { } }; -static void xen_xenstore_class_init(ObjectClass *klass, void *data) +static void xen_xenstore_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index d0a236c74f..14a918a531 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -635,7 +635,7 @@ GlobalProperty microvm_properties[] = { { "pcie-root-port", "io-reserve", "0" }, }; -static void microvm_class_init(ObjectClass *oc, void *data) +static void microvm_class_init(ObjectClass *oc, const void *data) { X86MachineClass *x86mc = X86_MACHINE_CLASS(oc); MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc); diff --git a/hw/i386/nitro_enclave.c b/hw/i386/nitro_enclave.c index 4b69f265cc..5ee50f3b85 100644 --- a/hw/i386/nitro_enclave.c +++ b/hw/i386/nitro_enclave.c @@ -293,7 +293,7 @@ static void nitro_enclave_set_parent_id(Object *obj, const char *value, nems->parent_id = g_strdup(value); } -static void nitro_enclave_class_init(ObjectClass *oc, void *data) +static void nitro_enclave_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); MicrovmMachineClass *mmc = MICROVM_MACHINE_CLASS(oc); diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 5481fe40be..49753bf0b3 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1766,7 +1766,7 @@ static bool pc_hotplug_allowed(MachineState *ms, DeviceState *dev, Error **errp) return true; } -static void pc_machine_class_init(ObjectClass *oc, void *data) +static void pc_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); X86MachineClass *x86mc = X86_MACHINE_CLASS(oc); diff --git a/hw/i386/port92.c b/hw/i386/port92.c index 1ba3f32887..39b6f3178f 100644 --- a/hw/i386/port92.c +++ b/hw/i386/port92.c @@ -97,7 +97,7 @@ static void port92_realizefn(DeviceState *dev, Error **errp) isa_register_ioport(isadev, &s->io, 0x92); } -static void port92_class_initfn(ObjectClass *klass, void *data) +static void port92_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c index 00b220d4d6..8fb80900b7 100644 --- a/hw/i386/sgx-epc.c +++ b/hw/i386/sgx-epc.c @@ -147,7 +147,7 @@ static void sgx_epc_md_fill_device_info(const MemoryDeviceState *md, info->type = MEMORY_DEVICE_INFO_KIND_SGX_EPC; } -static void sgx_epc_class_init(ObjectClass *oc, void *data) +static void sgx_epc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); diff --git a/hw/i386/vapic.c b/hw/i386/vapic.c index 347431eeef..0c1c92c479 100644 --- a/hw/i386/vapic.c +++ b/hw/i386/vapic.c @@ -847,7 +847,7 @@ static const VMStateDescription vmstate_vapic = { } }; -static void vapic_class_init(ObjectClass *klass, void *data) +static void vapic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c index 3e07d12512..3896159b05 100644 --- a/hw/i386/vmmouse.c +++ b/hw/i386/vmmouse.c @@ -321,7 +321,7 @@ static const Property vmmouse_properties[] = { DEFINE_PROP_LINK("i8042", VMMouseState, i8042, TYPE_I8042, ISAKBDState *), }; -static void vmmouse_class_initfn(ObjectClass *klass, void *data) +static void vmmouse_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/vmport.c b/hw/i386/vmport.c index 2f19b970b5..6d93457c52 100644 --- a/hw/i386/vmport.c +++ b/hw/i386/vmport.c @@ -286,7 +286,7 @@ static const Property vmport_properties[] = { DEFINE_PROP_UINT8("vmware-vmx-type", VMPortState, vmware_vmx_type, 2), }; -static void vmport_class_initfn(ObjectClass *klass, void *data) +static void vmport_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/i386/x86-iommu.c b/hw/i386/x86-iommu.c index 5cdd165af0..d34a6849f4 100644 --- a/hw/i386/x86-iommu.c +++ b/hw/i386/x86-iommu.c @@ -132,7 +132,7 @@ static const Property x86_iommu_properties[] = { DEFINE_PROP_BOOL("pt", X86IOMMUState, pt_supported, true), }; -static void x86_iommu_class_init(ObjectClass *klass, void *data) +static void x86_iommu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = x86_iommu_realize; diff --git a/hw/i386/x86.c b/hw/i386/x86.c index 69bfc00b9a..c8e2551b2b 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -372,7 +372,7 @@ static void x86_machine_initfn(Object *obj) x86ms->above_4g_mem_start = 4 * GiB; } -static void x86_machine_class_init(ObjectClass *oc, void *data) +static void x86_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); X86MachineClass *x86mc = X86_MACHINE_CLASS(oc); diff --git a/hw/i386/xen/xen-pvh.c b/hw/i386/xen/xen-pvh.c index f6356f2a7e..067f73e977 100644 --- a/hw/i386/xen/xen-pvh.c +++ b/hw/i386/xen/xen-pvh.c @@ -76,7 +76,7 @@ static void xen_pvh_set_pci_intx_irq(void *opaque, int irq, int level) } } -static void xen_pvh_machine_class_init(ObjectClass *oc, void *data) +static void xen_pvh_machine_class_init(ObjectClass *oc, const void *data) { XenPVHMachineClass *xpc = XEN_PVH_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c index a94e9005cb..f30398fa4a 100644 --- a/hw/i386/xen/xen_apic.c +++ b/hw/i386/xen/xen_apic.c @@ -76,7 +76,7 @@ static void xen_send_msi(MSIMessage *msi) xen_hvm_inject_msi(msi->address, msi->data); } -static void xen_apic_class_init(ObjectClass *klass, void *data) +static void xen_apic_class_init(ObjectClass *klass, const void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index dd648a2ee9..7c0d345f96 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -581,7 +581,7 @@ static void platform_reset(DeviceState *dev) platform_fixed_ioport_reset(s); } -static void xen_platform_class_init(ObjectClass *klass, void *data) +static void xen_platform_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index 9453da97bd..65868bd5e5 100644 --- a/hw/i386/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c @@ -122,7 +122,7 @@ static const Property xen_pv_props[] = { DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000), }; -static void xen_pv_class_init(ObjectClass *klass, void *data) +static void xen_pv_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/ide/ahci-allwinner.c b/hw/ide/ahci-allwinner.c index 575be36fc5..bc7a116a89 100644 --- a/hw/ide/ahci-allwinner.c +++ b/hw/ide/ahci-allwinner.c @@ -103,7 +103,7 @@ static const VMStateDescription vmstate_allwinner_ahci = { } }; -static void allwinner_ahci_class_init(ObjectClass *klass, void *data) +static void allwinner_ahci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ide/ahci-sysbus.c b/hw/ide/ahci-sysbus.c index 3c1935d81c..210818d047 100644 --- a/hw/ide/ahci-sysbus.c +++ b/hw/ide/ahci-sysbus.c @@ -66,7 +66,7 @@ static const Property sysbus_ahci_properties[] = { DEFINE_PROP_UINT32("num-ports", SysbusAHCIState, ahci.ports, 1), }; -static void sysbus_ahci_class_init(ObjectClass *klass, void *data) +static void sysbus_ahci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ide/cf.c b/hw/ide/cf.c index cfb4394f80..f87cd413b6 100644 --- a/hw/ide/cf.c +++ b/hw/ide/cf.c @@ -31,7 +31,7 @@ static const Property ide_cf_properties[] = { IDEDrive, dev.chs_trans, BIOS_ATA_TRANSLATION_AUTO), }; -static void ide_cf_class_init(ObjectClass *klass, void *data) +static void ide_cf_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c index 8e568e4c35..2a59516a9d 100644 --- a/hw/ide/cmd646.c +++ b/hw/ide/cmd646.c @@ -317,7 +317,7 @@ static const Property cmd646_ide_properties[] = { DEFINE_PROP_UINT32("secondary", PCIIDEState, secondary, 0), }; -static void cmd646_ide_class_init(ObjectClass *klass, void *data) +static void cmd646_ide_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/ide/ich.c b/hw/ide/ich.c index a83128465f..f2773ab462 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -175,7 +175,7 @@ static void pci_ich9_uninit(PCIDevice *dev) ahci_uninit(&d->ahci); } -static void ich_ahci_class_init(ObjectClass *klass, void *data) +static void ich_ahci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/ide/ide-bus.c b/hw/ide/ide-bus.c index 437502b5b4..b24e4d17b4 100644 --- a/hw/ide/ide-bus.c +++ b/hw/ide/ide-bus.c @@ -29,7 +29,7 @@ static char *idebus_get_fw_dev_path(DeviceState *dev); static void idebus_unrealize(BusState *qdev); -static void ide_bus_class_init(ObjectClass *klass, void *data) +static void ide_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); diff --git a/hw/ide/ide-dev.c b/hw/ide/ide-dev.c index 26f0517019..5d478588c6 100644 --- a/hw/ide/ide-dev.c +++ b/hw/ide/ide-dev.c @@ -198,7 +198,7 @@ static const Property ide_hd_properties[] = { DEFINE_PROP_UINT16("rotation_rate", IDEDrive, dev.rotation_rate, 0), }; -static void ide_hd_class_init(ObjectClass *klass, void *data) +static void ide_hd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); @@ -220,7 +220,7 @@ static const Property ide_cd_properties[] = { DEFINE_IDE_DEV_PROPERTIES(), }; -static void ide_cd_class_init(ObjectClass *klass, void *data) +static void ide_cd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IDEDeviceClass *k = IDE_DEVICE_CLASS(klass); @@ -238,7 +238,7 @@ static const TypeInfo ide_cd_info = { .class_init = ide_cd_class_init, }; -static void ide_device_class_init(ObjectClass *klass, void *data) +static void ide_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = ide_qdev_realize; diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 4863ad8080..5f418413c1 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -107,7 +107,7 @@ static const Property isa_ide_properties[] = { DEFINE_PROP_UINT32("irq", ISAIDEState, irqnum, 14), }; -static void isa_ide_class_initfn(ObjectClass *klass, void *data) +static void isa_ide_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ide/macio.c b/hw/ide/macio.c index c8e8e44cc9..c23bf32d2b 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -463,7 +463,7 @@ static const Property macio_ide_properties[] = { DEFINE_PROP_UINT32("addr", MACIOIDEState, addr, -1), }; -static void macio_ide_class_init(ObjectClass *oc, void *data) +static void macio_ide_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ide/mmio.c b/hw/ide/mmio.c index 13f16170ff..699874db78 100644 --- a/hw/ide/mmio.c +++ b/hw/ide/mmio.c @@ -145,7 +145,7 @@ static const Property mmio_ide_properties[] = { DEFINE_PROP_UINT32("shift", MMIOIDEState, shift, 0), }; -static void mmio_ide_class_init(ObjectClass *oc, void *data) +static void mmio_ide_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 818ff60d6f..a0f2709c69 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -178,7 +178,7 @@ static void pci_piix_ide_exitfn(PCIDevice *dev) } /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */ -static void piix3_ide_class_init(ObjectClass *klass, void *data) +static void piix3_ide_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -201,7 +201,7 @@ static const TypeInfo piix3_ide_info = { }; /* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */ -static void piix4_ide_class_init(ObjectClass *klass, void *data) +static void piix4_ide_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c index ce8a1e4cba..9b28c691fd 100644 --- a/hw/ide/sii3112.c +++ b/hw/ide/sii3112.c @@ -290,7 +290,7 @@ static void sii3112_pci_realize(PCIDevice *dev, Error **errp) } } -static void sii3112_pci_class_init(ObjectClass *klass, void *data) +static void sii3112_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pd = PCI_DEVICE_CLASS(klass); diff --git a/hw/ide/via.c b/hw/ide/via.c index 89fd28f646..dedc2674c0 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -245,7 +245,7 @@ static void via_ide_exitfn(PCIDevice *dev) } } -static void via_ide_class_init(ObjectClass *klass, void *data) +static void via_ide_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/input/adb-kbd.c b/hw/input/adb-kbd.c index 3649d03ef2..507557deec 100644 --- a/hw/input/adb-kbd.c +++ b/hw/input/adb-kbd.c @@ -375,7 +375,7 @@ static void adb_kbd_initfn(Object *obj) d->devaddr = ADB_DEVID_KEYBOARD; } -static void adb_kbd_class_init(ObjectClass *oc, void *data) +static void adb_kbd_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); diff --git a/hw/input/adb-mouse.c b/hw/input/adb-mouse.c index 77b280d242..373ef3f953 100644 --- a/hw/input/adb-mouse.c +++ b/hw/input/adb-mouse.c @@ -287,7 +287,7 @@ static void adb_mouse_initfn(Object *obj) d->devaddr = ADB_DEVID_MOUSE; } -static void adb_mouse_class_init(ObjectClass *oc, void *data) +static void adb_mouse_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); diff --git a/hw/input/adb.c b/hw/input/adb.c index aff7130fd0..bcb11edca3 100644 --- a/hw/input/adb.c +++ b/hw/input/adb.c @@ -259,7 +259,7 @@ static void adb_bus_unrealize(BusState *qbus) vmstate_unregister(NULL, &vmstate_adb_bus, adb_bus); } -static void adb_bus_class_init(ObjectClass *klass, void *data) +static void adb_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -299,7 +299,7 @@ static void adb_device_realizefn(DeviceState *dev, Error **errp) bus->devices[bus->nb_devices++] = d; } -static void adb_device_class_init(ObjectClass *oc, void *data) +static void adb_device_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/input/lasips2.c b/hw/input/lasips2.c index 987034efd3..de625723c7 100644 --- a/hw/input/lasips2.c +++ b/hw/input/lasips2.c @@ -306,7 +306,7 @@ static void lasips2_init(Object *obj) "lasips2-port-input-irq", 2); } -static void lasips2_class_init(ObjectClass *klass, void *data) +static void lasips2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -347,7 +347,7 @@ static void lasips2_port_init(Object *obj) "ps2-input-irq", 1); } -static void lasips2_port_class_init(ObjectClass *klass, void *data) +static void lasips2_port_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -397,7 +397,7 @@ static void lasips2_kbd_port_init(Object *obj) lp->lasips2 = container_of(s, LASIPS2State, kbd_port); } -static void lasips2_kbd_port_class_init(ObjectClass *klass, void *data) +static void lasips2_kbd_port_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass); @@ -447,7 +447,7 @@ static void lasips2_mouse_port_init(Object *obj) lp->lasips2 = container_of(s, LASIPS2State, mouse_port); } -static void lasips2_mouse_port_class_init(ObjectClass *klass, void *data) +static void lasips2_mouse_port_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass); diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index fa0c549eb9..83930dd50c 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -750,7 +750,7 @@ static const VMStateDescription vmstate_kbd_mmio = { } }; -static void i8042_mmio_class_init(ObjectClass *klass, void *data) +static void i8042_mmio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -939,7 +939,7 @@ static const Property i8042_properties[] = { DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12), }; -static void i8042_class_initfn(ObjectClass *klass, void *data) +static void i8042_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/input/pl050.c b/hw/input/pl050.c index 6519e260ed..c5f4a3fa84 100644 --- a/hw/input/pl050.c +++ b/hw/input/pl050.c @@ -203,7 +203,7 @@ static void pl050_mouse_init(Object *obj) object_initialize_child(obj, "mouse", &s->mouse, TYPE_PS2_MOUSE_DEVICE); } -static void pl050_kbd_class_init(ObjectClass *oc, void *data) +static void pl050_kbd_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PL050DeviceClass *pdc = PL050_CLASS(oc); @@ -220,7 +220,7 @@ static const TypeInfo pl050_kbd_info = { .class_init = pl050_kbd_class_init, }; -static void pl050_mouse_class_init(ObjectClass *oc, void *data) +static void pl050_mouse_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PL050DeviceClass *pdc = PL050_CLASS(oc); @@ -249,7 +249,7 @@ static void pl050_init(Object *obj) qdev_init_gpio_in_named(DEVICE(obj), pl050_set_irq, "ps2-input-irq", 1); } -static void pl050_class_init(ObjectClass *oc, void *data) +static void pl050_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/input/ps2.c b/hw/input/ps2.c index 6a41b024c8..7f7b1fce2e 100644 --- a/hw/input/ps2.c +++ b/hw/input/ps2.c @@ -1254,7 +1254,7 @@ static void ps2_mouse_realize(DeviceState *dev, Error **errp) qemu_input_handler_register(dev, &ps2_mouse_handler); } -static void ps2_kbd_class_init(ObjectClass *klass, void *data) +static void ps2_kbd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1273,7 +1273,7 @@ static const TypeInfo ps2_kbd_info = { .class_init = ps2_kbd_class_init }; -static void ps2_mouse_class_init(ObjectClass *klass, void *data) +static void ps2_mouse_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1299,7 +1299,7 @@ static void ps2_init(Object *obj) qdev_init_gpio_out(DEVICE(obj), &s->irq, 1); } -static void ps2_class_init(ObjectClass *klass, void *data) +static void ps2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/input/stellaris_gamepad.c b/hw/input/stellaris_gamepad.c index 98382a0e15..fec1161c9c 100644 --- a/hw/input/stellaris_gamepad.c +++ b/hw/input/stellaris_gamepad.c @@ -82,7 +82,7 @@ static const Property stellaris_gamepad_properties[] = { keycodes, qdev_prop_uint32, uint32_t), }; -static void stellaris_gamepad_class_init(ObjectClass *klass, void *data) +static void stellaris_gamepad_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/input/virtio-input-hid.c b/hw/input/virtio-input-hid.c index 812faaef8f..d986c3c16e 100644 --- a/hw/input/virtio-input-hid.c +++ b/hw/input/virtio-input-hid.c @@ -242,7 +242,7 @@ static const Property virtio_input_hid_properties[] = { DEFINE_PROP_UINT32("head", VirtIOInputHID, head, 0), }; -static void virtio_input_hid_class_init(ObjectClass *klass, void *data) +static void virtio_input_hid_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); @@ -383,7 +383,7 @@ static const Property virtio_mouse_properties[] = { DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true), }; -static void virtio_mouse_class_init(ObjectClass *klass, void *data) +static void virtio_mouse_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -507,7 +507,7 @@ static const Property virtio_tablet_properties[] = { DEFINE_PROP_BOOL("wheel-axis", VirtIOInputHID, wheel_axis, true), }; -static void virtio_tablet_class_init(ObjectClass *klass, void *data) +static void virtio_tablet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/input/virtio-input-host.c b/hw/input/virtio-input-host.c index b21a79046e..bbfee9d3b9 100644 --- a/hw/input/virtio-input-host.c +++ b/hw/input/virtio-input-host.c @@ -224,7 +224,7 @@ static const Property virtio_input_host_properties[] = { DEFINE_PROP_STRING("evdev", VirtIOInputHost, evdev), }; -static void virtio_input_host_class_init(ObjectClass *klass, void *data) +static void virtio_input_host_class_init(ObjectClass *klass, const void *data) { VirtIOInputClass *vic = VIRTIO_INPUT_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 1394d99c6b..1818cbddc7 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -304,7 +304,7 @@ static const Property virtio_input_properties[] = { DEFINE_PROP_STRING("serial", VirtIOInput, serial), }; -static void virtio_input_class_init(ObjectClass *klass, void *data) +static void virtio_input_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/intc/allwinner-a10-pic.c b/hw/intc/allwinner-a10-pic.c index 93a604f7a0..0409734155 100644 --- a/hw/intc/allwinner-a10-pic.c +++ b/hw/intc/allwinner-a10-pic.c @@ -187,7 +187,7 @@ static void aw_a10_pic_reset(DeviceState *d) } } -static void aw_a10_pic_class_init(ObjectClass *klass, void *data) +static void aw_a10_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/apic.c b/hw/intc/apic.c index d18c1dbf2c..bcb103560c 100644 --- a/hw/intc/apic.c +++ b/hw/intc/apic.c @@ -1176,7 +1176,7 @@ static void apic_unrealize(DeviceState *dev) local_apics[s->initial_apic_id] = NULL; } -static void apic_class_init(ObjectClass *klass, void *data) +static void apic_class_init(ObjectClass *klass, const void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c index 2a3e878c4d..37a7a7019d 100644 --- a/hw/intc/apic_common.c +++ b/hw/intc/apic_common.c @@ -466,7 +466,7 @@ static void apic_common_initfn(Object *obj) apic_common_set_id, NULL, NULL); } -static void apic_common_class_init(ObjectClass *klass, void *data) +static void apic_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index 3581ff8e8a..d18bef40fc 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -2162,7 +2162,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) } -static void arm_gic_class_init(ObjectClass *klass, void *data) +static void arm_gic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ARMGICClass *agc = ARM_GIC_CLASS(klass); diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index 5ac56e3389..f61d1c1fe6 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -362,7 +362,7 @@ static const Property arm_gic_common_properties[] = { DEFINE_PROP_UINT32("num-priority-bits", GICState, n_prio_bits, 8), }; -static void arm_gic_common_class_init(ObjectClass *klass, void *data) +static void arm_gic_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gic_kvm.c b/hw/intc/arm_gic_kvm.c index 40adb02865..1e9232f47c 100644 --- a/hw/intc/arm_gic_kvm.c +++ b/hw/intc/arm_gic_kvm.c @@ -584,7 +584,7 @@ static void kvm_arm_gic_realize(DeviceState *dev, Error **errp) } } -static void kvm_arm_gic_class_init(ObjectClass *klass, void *data) +static void kvm_arm_gic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gicv2m.c b/hw/intc/arm_gicv2m.c index 3a8c62698c..cef0688221 100644 --- a/hw/intc/arm_gicv2m.c +++ b/hw/intc/arm_gicv2m.c @@ -175,7 +175,7 @@ static const Property gicv2m_properties[] = { DEFINE_PROP_UINT32("num-spi", ARMGICv2mState, num_spi, 64), }; -static void gicv2m_class_init(ObjectClass *klass, void *data) +static void gicv2m_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c index 58e18fff54..6059ce926a 100644 --- a/hw/intc/arm_gicv3.c +++ b/hw/intc/arm_gicv3.c @@ -452,7 +452,7 @@ static void arm_gic_realize(DeviceState *dev, Error **errp) gicv3_init_cpuif(s); } -static void arm_gicv3_class_init(ObjectClass *klass, void *data) +static void arm_gicv3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ARMGICv3CommonClass *agcc = ARM_GICV3_COMMON_CLASS(klass); diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index 76b2283c92..dd86a50300 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -623,7 +623,7 @@ static const Property arm_gicv3_common_properties[] = { MemoryRegion *), }; -static void arm_gicv3_common_class_init(ObjectClass *klass, void *data) +static void arm_gicv3_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index 936368c901..577b445405 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -2007,7 +2007,7 @@ static const Property gicv3_its_props[] = { GICv3State *), }; -static void gicv3_its_class_init(ObjectClass *klass, void *data) +static void gicv3_its_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gicv3_its_common.c b/hw/intc/arm_gicv3_its_common.c index 70dbee83a6..e946e3fb87 100644 --- a/hw/intc/arm_gicv3_its_common.c +++ b/hw/intc/arm_gicv3_its_common.c @@ -135,7 +135,7 @@ static void gicv3_its_common_reset_hold(Object *obj, ResetType type) memset(&s->baser, 0, sizeof(s->baser)); } -static void gicv3_its_common_class_init(ObjectClass *klass, void *data) +static void gicv3_its_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c index e198974560..9812d50859 100644 --- a/hw/intc/arm_gicv3_its_kvm.c +++ b/hw/intc/arm_gicv3_its_kvm.c @@ -239,7 +239,7 @@ static const Property kvm_arm_its_props[] = { GICv3State *), }; -static void kvm_arm_its_class_init(ObjectClass *klass, void *data) +static void kvm_arm_its_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/arm_gicv3_kvm.c b/hw/intc/arm_gicv3_kvm.c index 8e17cab2a0..3be3bf6c28 100644 --- a/hw/intc/arm_gicv3_kvm.c +++ b/hw/intc/arm_gicv3_kvm.c @@ -893,7 +893,7 @@ static void kvm_arm_gicv3_realize(DeviceState *dev, Error **errp) } } -static void kvm_arm_gicv3_class_init(ObjectClass *klass, void *data) +static void kvm_arm_gicv3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/armv7m_nvic.c b/hw/intc/armv7m_nvic.c index 7212c87c68..83ff74f899 100644 --- a/hw/intc/armv7m_nvic.c +++ b/hw/intc/armv7m_nvic.c @@ -2730,7 +2730,7 @@ static void armv7m_nvic_instance_init(Object *obj) qdev_init_gpio_in_named(dev, nvic_nmi_trigger, "NMI", 1); } -static void armv7m_nvic_class_init(ObjectClass *klass, void *data) +static void armv7m_nvic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index bae7dc95ea..be7f516a3b 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -583,7 +583,7 @@ static void aspeed_intc_unrealize(DeviceState *dev) s->regs = NULL; } -static void aspeed_intc_class_init(ObjectClass *klass, void *data) +static void aspeed_intc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); @@ -620,7 +620,7 @@ static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = { {9, 18, 1, R_GICINT136_EN, R_GICINT136_STATUS}, }; -static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_intc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); @@ -651,7 +651,7 @@ static AspeedINTCIRQ aspeed_2700_intcio_irqs[ASPEED_INTC_MAX_INPINS] = { {5, 5, 1, R_GICINT197_EN, R_GICINT197_STATUS}, }; -static void aspeed_2700_intcio_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_intcio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); diff --git a/hw/intc/aspeed_vic.c b/hw/intc/aspeed_vic.c index 55fe51a667..7120088454 100644 --- a/hw/intc/aspeed_vic.c +++ b/hw/intc/aspeed_vic.c @@ -339,7 +339,7 @@ static const VMStateDescription vmstate_aspeed_vic = { } }; -static void aspeed_vic_class_init(ObjectClass *klass, void *data) +static void aspeed_vic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = aspeed_vic_realize; diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c index 4a42fcf60d..55e0a5a503 100644 --- a/hw/intc/bcm2835_ic.c +++ b/hw/intc/bcm2835_ic.c @@ -219,7 +219,7 @@ static const VMStateDescription vmstate_bcm2835_ic = { } }; -static void bcm2835_ic_class_init(ObjectClass *klass, void *data) +static void bcm2835_ic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/bcm2836_control.c b/hw/intc/bcm2836_control.c index 197a0e2ccf..1c02853669 100644 --- a/hw/intc/bcm2836_control.c +++ b/hw/intc/bcm2836_control.c @@ -384,7 +384,7 @@ static const VMStateDescription vmstate_bcm2836_control = { } }; -static void bcm2836_control_class_init(ObjectClass *klass, void *data) +static void bcm2836_control_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index 6ddbcd4c6d..ebbe23436f 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -329,7 +329,7 @@ static const Property exynos4210_combiner_properties[] = { DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0), }; -static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) +static void exynos4210_combiner_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/exynos4210_gic.c b/hw/intc/exynos4210_gic.c index 01a53936d3..7e2d79d00c 100644 --- a/hw/intc/exynos4210_gic.c +++ b/hw/intc/exynos4210_gic.c @@ -115,7 +115,7 @@ static const Property exynos4210_gic_properties[] = { DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1), }; -static void exynos4210_gic_class_init(ObjectClass *klass, void *data) +static void exynos4210_gic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c index aa5162c18f..b80538cdeb 100644 --- a/hw/intc/goldfish_pic.c +++ b/hw/intc/goldfish_pic.c @@ -185,7 +185,7 @@ static const Property goldfish_pic_properties[] = { DEFINE_PROP_UINT8("index", GoldfishPICState, idx, 0), }; -static void goldfish_pic_class_init(ObjectClass *oc, void *data) +static void goldfish_pic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(oc); diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c index 95cdb411d2..e0f26466ba 100644 --- a/hw/intc/grlib_irqmp.c +++ b/hw/intc/grlib_irqmp.c @@ -380,7 +380,7 @@ static const Property grlib_irqmp_properties[] = { DEFINE_PROP_UINT32("ncpus", IRQMP, ncpus, 1), }; -static void grlib_irqmp_class_init(ObjectClass *klass, void *data) +static void grlib_irqmp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/heathrow_pic.c b/hw/intc/heathrow_pic.c index 729498f1df..447e8c25d8 100644 --- a/hw/intc/heathrow_pic.c +++ b/hw/intc/heathrow_pic.c @@ -184,7 +184,7 @@ static void heathrow_init(Object *obj) sysbus_init_mmio(sbd, &s->mem); } -static void heathrow_class_init(ObjectClass *oc, void *data) +static void heathrow_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index d88b20f40b..2359dd8253 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -436,7 +436,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq_in) return irq_set; } -static void i8259_class_init(ObjectClass *klass, void *data) +static void i8259_class_init(ObjectClass *klass, const void *data) { PICClass *k = PIC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index c77ff683bb..4a92e0da90 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -200,7 +200,7 @@ static const Property pic_properties_common[] = { DEFINE_PROP_BIT("master", PICCommonState, master, 0, false), }; -static void pic_common_class_init(ObjectClass *klass, void *data) +static void pic_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); diff --git a/hw/intc/imx_avic.c b/hw/intc/imx_avic.c index e1c9ce769d..09c3bfac0b 100644 --- a/hw/intc/imx_avic.c +++ b/hw/intc/imx_avic.c @@ -341,7 +341,7 @@ static void imx_avic_init(Object *obj) } -static void imx_avic_class_init(ObjectClass *klass, void *data) +static void imx_avic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/imx_gpcv2.c b/hw/intc/imx_gpcv2.c index 9e5cf28371..58d286c1cf 100644 --- a/hw/intc/imx_gpcv2.c +++ b/hw/intc/imx_gpcv2.c @@ -102,7 +102,7 @@ static const VMStateDescription vmstate_imx_gpcv2 = { }, }; -static void imx_gpcv2_class_init(ObjectClass *klass, void *data) +static void imx_gpcv2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index 8cd1d85e06..133bef852d 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -480,7 +480,7 @@ static const Property ioapic_properties[] = { DEFINE_PROP_UINT8("version", IOAPICCommonState, version, IOAPIC_VER_DEF), }; -static void ioapic_class_init(ObjectClass *klass, void *data) +static void ioapic_class_init(ObjectClass *klass, const void *data) { IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c index 769896353a..b0381c7990 100644 --- a/hw/intc/ioapic_common.c +++ b/hw/intc/ioapic_common.c @@ -197,7 +197,7 @@ static const VMStateDescription vmstate_ioapic_common = { } }; -static void ioapic_common_class_init(ObjectClass *klass, void *data) +static void ioapic_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index a558c50185..f4fe961a98 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -401,7 +401,7 @@ static int vmstate_extioi_post_load(void *opaque, int version_id) return 0; } -static void loongarch_extioi_class_init(ObjectClass *klass, void *data) +static void loongarch_extioi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_CLASS(klass); diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index ff3974f2a1..126f13d12c 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -174,7 +174,8 @@ static const Property extioi_properties[] = { features, EXTIOI_HAS_VIRT_EXTENSION, 0), }; -static void loongarch_extioi_common_class_init(ObjectClass *klass, void *data) +static void loongarch_extioi_common_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass); diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index b10641dd03..4dad240689 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -140,7 +140,7 @@ static void loongarch_ipi_cpu_unplug(HotplugHandler *hotplug_dev, core->cpu = NULL; } -static void loongarch_ipi_class_init(ObjectClass *klass, void *data) +static void loongarch_ipi_class_init(ObjectClass *klass, const void *data) { LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); diff --git a/hw/intc/loongarch_pch_msi.c b/hw/intc/loongarch_pch_msi.c index bc93504ff7..06eb944da0 100644 --- a/hw/intc/loongarch_pch_msi.c +++ b/hw/intc/loongarch_pch_msi.c @@ -79,7 +79,7 @@ static const Property loongarch_msi_properties[] = { DEFINE_PROP_UINT32("msi_irq_num", LoongArchPCHMSI, irq_num, 0), }; -static void loongarch_pch_msi_class_init(ObjectClass *klass, void *data) +static void loongarch_pch_msi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index acd75ccb0c..6c2b6de3f0 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -404,7 +404,7 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) } -static void loongarch_pic_class_init(ObjectClass *klass, void *data) +static void loongarch_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass); diff --git a/hw/intc/loongarch_pic_common.c b/hw/intc/loongarch_pic_common.c index e7f541db4b..fdb250c418 100644 --- a/hw/intc/loongarch_pic_common.c +++ b/hw/intc/loongarch_pic_common.c @@ -71,7 +71,8 @@ static const VMStateDescription vmstate_loongarch_pic_common = { } }; -static void loongarch_pic_common_class_init(ObjectClass *klass, void *data) +static void loongarch_pic_common_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass); diff --git a/hw/intc/loongson_ipi.c b/hw/intc/loongson_ipi.c index d2268a27f8..fbc73e8b00 100644 --- a/hw/intc/loongson_ipi.c +++ b/hw/intc/loongson_ipi.c @@ -101,7 +101,7 @@ static const Property loongson_ipi_properties[] = { DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1), }; -static void loongson_ipi_class_init(ObjectClass *klass, void *data) +static void loongson_ipi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongsonIPIClass *lic = LOONGSON_IPI_CLASS(klass); diff --git a/hw/intc/loongson_ipi_common.c b/hw/intc/loongson_ipi_common.c index f5ab5024c0..f32661c40f 100644 --- a/hw/intc/loongson_ipi_common.c +++ b/hw/intc/loongson_ipi_common.c @@ -303,7 +303,7 @@ static const VMStateDescription vmstate_loongson_ipi_common = { } }; -static void loongson_ipi_common_class_init(ObjectClass *klass, void *data) +static void loongson_ipi_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c index a82b80f5c6..215e1a6ed5 100644 --- a/hw/intc/m68k_irqc.c +++ b/hw/intc/m68k_irqc.c @@ -90,7 +90,7 @@ static const Property m68k_irqc_properties[] = { TYPE_M68K_CPU, ArchCPU *), }; -static void m68k_irqc_class_init(ObjectClass *oc, void *data) +static void m68k_irqc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); diff --git a/hw/intc/mips_gic.c b/hw/intc/mips_gic.c index 627a76ba7b..0c50ba41f6 100644 --- a/hw/intc/mips_gic.c +++ b/hw/intc/mips_gic.c @@ -442,7 +442,7 @@ static const Property mips_gic_properties[] = { DEFINE_PROP_UINT32("num-irq", MIPSGICState, num_irq, 256), }; -static void mips_gic_class_init(ObjectClass *klass, void *data) +static void mips_gic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c index 095a3d504f..9e8737be33 100644 --- a/hw/intc/omap_intc.c +++ b/hw/intc/omap_intc.c @@ -379,7 +379,7 @@ static const Property omap_intc_properties[] = { DEFINE_PROP_UINT32("size", OMAPIntcState, size, 0x100), }; -static void omap_intc_class_init(ObjectClass *klass, void *data) +static void omap_intc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/ompic.c b/hw/intc/ompic.c index 169baf2ded..047c367478 100644 --- a/hw/intc/ompic.c +++ b/hw/intc/ompic.c @@ -155,7 +155,7 @@ static const VMStateDescription vmstate_or1k_ompic = { } }; -static void or1k_ompic_class_init(ObjectClass *klass, void *data) +static void or1k_ompic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 78a82d0d30..87733eb7c3 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -1611,7 +1611,7 @@ static const Property openpic_properties[] = { DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), }; -static void openpic_class_init(ObjectClass *oc, void *data) +static void openpic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/intc/openpic_kvm.c b/hw/intc/openpic_kvm.c index 9cdaa97004..673ea9ca05 100644 --- a/hw/intc/openpic_kvm.c +++ b/hw/intc/openpic_kvm.c @@ -267,7 +267,7 @@ static const Property kvm_openpic_properties[] = { OPENPIC_MODEL_FSL_MPIC_20), }; -static void kvm_openpic_class_init(ObjectClass *oc, void *data) +static void kvm_openpic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/intc/pl190.c b/hw/intc/pl190.c index a5e2d76315..838c21c4a0 100644 --- a/hw/intc/pl190.c +++ b/hw/intc/pl190.c @@ -273,7 +273,7 @@ static const VMStateDescription vmstate_pl190 = { } }; -static void pl190_class_init(ObjectClass *klass, void *data) +static void pl190_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index ccbe95a58e..cd73881b5b 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -2068,7 +2068,7 @@ static const Property pnv_xive_properties[] = { DEFINE_PROP_LINK("chip", PnvXive, chip, TYPE_PNV_CHIP, PnvChip *), }; -static void pnv_xive_class_init(ObjectClass *klass, void *data) +static void pnv_xive_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 0b81dad6ba..02437dddac 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -2505,7 +2505,7 @@ static int pnv_xive2_dt_xscom(PnvXScomInterface *dev, void *fdt, return 0; } -static void pnv_xive2_class_init(ObjectClass *klass, void *data) +static void pnv_xive2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/intc/ppc-uic.c b/hw/intc/ppc-uic.c index 7de4bf9885..bc4dc90ade 100644 --- a/hw/intc/ppc-uic.c +++ b/hw/intc/ppc-uic.c @@ -281,7 +281,7 @@ static const VMStateDescription ppc_uic_vmstate = { }, }; -static void ppc_uic_class_init(ObjectClass *klass, void *data) +static void ppc_uic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/realview_gic.c b/hw/intc/realview_gic.c index 9b12116b2a..63e25c2a78 100644 --- a/hw/intc/realview_gic.c +++ b/hw/intc/realview_gic.c @@ -63,7 +63,7 @@ static void realview_gic_init(Object *obj) qdev_prop_set_uint32(DEVICE(&s->gic), "num-cpu", 1); } -static void realview_gic_class_init(ObjectClass *oc, void *data) +static void realview_gic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/intc/riscv_aclint.c b/hw/intc/riscv_aclint.c index db374a7c2d..b0139f03f5 100644 --- a/hw/intc/riscv_aclint.c +++ b/hw/intc/riscv_aclint.c @@ -328,7 +328,7 @@ static const VMStateDescription vmstate_riscv_mtimer = { } }; -static void riscv_aclint_mtimer_class_init(ObjectClass *klass, void *data) +static void riscv_aclint_mtimer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = riscv_aclint_mtimer_realize; @@ -509,7 +509,7 @@ static void riscv_aclint_swi_reset_enter(Object *obj, ResetType type) } } -static void riscv_aclint_swi_class_init(ObjectClass *klass, void *data) +static void riscv_aclint_swi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = riscv_aclint_swi_realize; diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index 789c4a4d6e..8bcd9f4697 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -997,7 +997,7 @@ static const VMStateDescription vmstate_riscv_aplic = { } }; -static void riscv_aplic_class_init(ObjectClass *klass, void *data) +static void riscv_aplic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/riscv_imsic.c b/hw/intc/riscv_imsic.c index 852f413e5a..2169988167 100644 --- a/hw/intc/riscv_imsic.c +++ b/hw/intc/riscv_imsic.c @@ -416,7 +416,7 @@ static const VMStateDescription vmstate_riscv_imsic = { } }; -static void riscv_imsic_class_init(ObjectClass *klass, void *data) +static void riscv_imsic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/rx_icu.c b/hw/intc/rx_icu.c index ca13c5fb37..f8615527b7 100644 --- a/hw/intc/rx_icu.c +++ b/hw/intc/rx_icu.c @@ -368,7 +368,7 @@ static const Property rxicu_properties[] = { qdev_prop_uint8, uint8_t), }; -static void rxicu_class_init(ObjectClass *klass, void *data) +static void rxicu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c index 4fae023197..8f4c9fd52e 100644 --- a/hw/intc/s390_flic.c +++ b/hw/intc/s390_flic.c @@ -450,7 +450,7 @@ static const Property qemu_s390_flic_properties[] = { migrate_all_state, true), }; -static void qemu_s390_flic_class_init(ObjectClass *oc, void *data) +static void qemu_s390_flic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); @@ -477,7 +477,7 @@ static void s390_flic_common_realize(DeviceState *dev, Error **errp) fs->ais_supported = s390_has_feat(S390_FEAT_ADAPTER_INT_SUPPRESSION); } -static void s390_flic_class_init(ObjectClass *oc, void *data) +static void s390_flic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index 10aaafbb31..f833a3996a 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -670,7 +670,7 @@ static void kvm_s390_flic_reset(DeviceState *dev) flic_enable_pfault(flic); } -static void kvm_s390_flic_class_init(ObjectClass *oc, void *data) +static void kvm_s390_flic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc); diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c index a5b0f6ef1b..3160b216fd 100644 --- a/hw/intc/sifive_plic.c +++ b/hw/intc/sifive_plic.c @@ -446,7 +446,7 @@ static const Property sifive_plic_properties[] = { DEFINE_PROP_UINT32("aperture-size", SiFivePLICState, aperture_size, 0), }; -static void sifive_plic_class_init(ObjectClass *klass, void *data) +static void sifive_plic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index f83709a857..5776055a8b 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -441,7 +441,7 @@ static void slavio_intctl_init(Object *obj) } } -static void slavio_intctl_class_init(ObjectClass *klass, void *data) +static void slavio_intctl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); InterruptStatsProviderClass *ic = INTERRUPT_STATS_PROVIDER_CLASS(klass); diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index ce734b03ab..7fde6059bf 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -809,7 +809,7 @@ static bool spapr_xive_in_kernel_xptr(const XivePresenter *xptr) return spapr_xive_in_kernel(SPAPR_XIVE(xptr)); } -static void spapr_xive_class_init(ObjectClass *klass, void *data) +static void spapr_xive_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveRouterClass *xrc = XIVE_ROUTER_CLASS(klass); diff --git a/hw/intc/xics.c b/hw/intc/xics.c index 9c1b7bbe9e..d9a199e883 100644 --- a/hw/intc/xics.c +++ b/hw/intc/xics.c @@ -350,7 +350,7 @@ static const Property icp_properties[] = { DEFINE_PROP_LINK(ICP_PROP_CPU, ICPState, cs, TYPE_CPU, CPUState *), }; -static void icp_class_init(ObjectClass *klass, void *data) +static void icp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -681,7 +681,7 @@ static const Property ics_properties[] = { XICSFabric *), }; -static void ics_class_init(ObjectClass *klass, void *data) +static void ics_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/intc/xics_pnv.c b/hw/intc/xics_pnv.c index 753c067f17..ff602d9a34 100644 --- a/hw/intc/xics_pnv.c +++ b/hw/intc/xics_pnv.c @@ -176,7 +176,7 @@ static void pnv_icp_realize(DeviceState *dev, Error **errp) icp, "icp-thread", 0x1000); } -static void pnv_icp_class_init(ObjectClass *klass, void *data) +static void pnv_icp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICPStateClass *icpc = ICP_CLASS(klass); diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index a0d97bdefe..9e465fb8f3 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -436,7 +436,7 @@ static void xics_spapr_deactivate(SpaprInterruptController *intc) } } -static void ics_spapr_class_init(ObjectClass *klass, void *data) +static void ics_spapr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *isc = ICS_CLASS(klass); diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c index ab1c4a3222..5257ad54b1 100644 --- a/hw/intc/xilinx_intc.c +++ b/hw/intc/xilinx_intc.c @@ -214,7 +214,7 @@ static const Property xilinx_intc_properties[] = { DEFINE_PROP_UINT32("kind-of-intr", XpsIntc, c_kind_of_intr, 0), }; -static void xilinx_intc_class_init(ObjectClass *klass, void *data) +static void xilinx_intc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 3eb28c2265..069c1e9a5e 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -930,7 +930,7 @@ static const Property xive_tctx_properties[] = { XivePresenter *), }; -static void xive_tctx_class_init(ObjectClass *klass, void *data) +static void xive_tctx_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1412,7 +1412,7 @@ static const Property xive_source_properties[] = { XiveNotifier *), }; -static void xive_source_class_init(ObjectClass *klass, void *data) +static void xive_source_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2085,7 +2085,7 @@ static const Property xive_router_properties[] = { TYPE_XIVE_FABRIC, XiveFabric *), }; -static void xive_router_class_init(ObjectClass *klass, void *data) +static void xive_router_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass); @@ -2254,7 +2254,7 @@ static const Property xive_end_source_properties[] = { XiveRouter *), }; -static void xive_end_source_class_init(ObjectClass *klass, void *data) +static void xive_end_source_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 7d584dfafa..3337a943fb 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -1590,7 +1590,7 @@ static const Property xive2_router_properties[] = { TYPE_XIVE_FABRIC, XiveFabric *), }; -static void xive2_router_class_init(ObjectClass *klass, void *data) +static void xive2_router_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveNotifierClass *xnc = XIVE_NOTIFIER_CLASS(klass); @@ -1805,7 +1805,7 @@ static const Property xive2_end_source_properties[] = { Xive2Router *), }; -static void xive2_end_source_class_init(ObjectClass *klass, void *data) +static void xive2_end_source_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/xlnx-pmu-iomod-intc.c b/hw/intc/xlnx-pmu-iomod-intc.c index ccdab244b3..9200585e32 100644 --- a/hw/intc/xlnx-pmu-iomod-intc.c +++ b/hw/intc/xlnx-pmu-iomod-intc.c @@ -531,7 +531,7 @@ static const VMStateDescription vmstate_xlnx_pmu_io_intc = { } }; -static void xlnx_pmu_io_intc_class_init(ObjectClass *klass, void *data) +static void xlnx_pmu_io_intc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/intc/xlnx-zynqmp-ipi.c b/hw/intc/xlnx-zynqmp-ipi.c index 7241377298..610cd0e316 100644 --- a/hw/intc/xlnx-zynqmp-ipi.c +++ b/hw/intc/xlnx-zynqmp-ipi.c @@ -355,7 +355,7 @@ static const VMStateDescription vmstate_zynqmp_pmu_ipi = { } }; -static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, void *data) +static void xlnx_zynqmp_ipi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ipack/ipack.c b/hw/ipack/ipack.c index b6defae602..ab602bff73 100644 --- a/hw/ipack/ipack.c +++ b/hw/ipack/ipack.c @@ -74,7 +74,7 @@ static const Property ipack_device_props[] = { DEFINE_PROP_INT32("slot", IPackDevice, slot, -1), }; -static void ipack_device_class_init(ObjectClass *klass, void *data) +static void ipack_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index 470a4203ae..f6993330d2 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -629,7 +629,7 @@ static const VMStateDescription vmstate_tpci200 = { } }; -static void tpci200_class_init(ObjectClass *klass, void *data) +static void tpci200_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/ipmi/ipmi.c b/hw/ipmi/ipmi.c index fdeaa5269f..b91e487e1b 100644 --- a/hw/ipmi/ipmi.c +++ b/hw/ipmi/ipmi.c @@ -78,7 +78,7 @@ static int ipmi_do_hw_op(IPMIInterface *s, enum ipmi_op op, int checkonly) } } -static void ipmi_interface_class_init(ObjectClass *class, void *data) +static void ipmi_interface_class_init(ObjectClass *class, const void *data) { IPMIInterfaceClass *ik = IPMI_INTERFACE_CLASS(class); @@ -112,7 +112,7 @@ static const Property ipmi_bmc_properties[] = { DEFINE_PROP_UINT8("slave_addr", IPMIBmc, slave_addr, 0x20), }; -static void bmc_class_init(ObjectClass *oc, void *data) +static void bmc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ipmi/ipmi_bmc_extern.c b/hw/ipmi/ipmi_bmc_extern.c index e563214390..9f1ba7b2f8 100644 --- a/hw/ipmi/ipmi_bmc_extern.c +++ b/hw/ipmi/ipmi_bmc_extern.c @@ -513,7 +513,7 @@ static const Property ipmi_bmc_extern_properties[] = { DEFINE_PROP_CHR("chardev", IPMIBmcExtern, chr), }; -static void ipmi_bmc_extern_class_init(ObjectClass *oc, void *data) +static void ipmi_bmc_extern_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); diff --git a/hw/ipmi/ipmi_bmc_sim.c b/hw/ipmi/ipmi_bmc_sim.c index 41fe6835a7..04e1dcd0e7 100644 --- a/hw/ipmi/ipmi_bmc_sim.c +++ b/hw/ipmi/ipmi_bmc_sim.c @@ -2278,7 +2278,7 @@ static const Property ipmi_sim_properties[] = { DEFINE_PROP_UUID_NODEFAULT("guid", IPMIBmcSim, uuid), }; -static void ipmi_sim_class_init(ObjectClass *oc, void *data) +static void ipmi_sim_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIBmcClass *bk = IPMI_BMC_CLASS(oc); diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index 76585e786e..db539e68ae 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -139,7 +139,7 @@ static const Property ipmi_isa_properties[] = { DEFINE_PROP_INT32("irq", ISAIPMIBTDevice, isairq, 5), }; -static void isa_ipmi_bt_class_init(ObjectClass *oc, void *data) +static void isa_ipmi_bt_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index ba3ae208b2..4cbc6c577c 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -145,7 +145,7 @@ static const Property ipmi_isa_properties[] = { DEFINE_PROP_INT32("irq", ISAIPMIKCSDevice, isairq, 5), }; -static void isa_ipmi_kcs_class_init(ObjectClass *oc, void *data) +static void isa_ipmi_kcs_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c index 7ba8b3ab96..23f65c6886 100644 --- a/hw/ipmi/pci_ipmi_bt.c +++ b/hw/ipmi/pci_ipmi_bt.c @@ -119,7 +119,7 @@ static void *pci_ipmi_bt_get_backend_data(IPMIInterface *ii) return &pib->bt; } -static void pci_ipmi_bt_class_init(ObjectClass *oc, void *data) +static void pci_ipmi_bt_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c index 0aa35143e9..4077b6a7b0 100644 --- a/hw/ipmi/pci_ipmi_kcs.c +++ b/hw/ipmi/pci_ipmi_kcs.c @@ -118,7 +118,7 @@ static void *pci_ipmi_kcs_get_backend_data(IPMIInterface *ii) return &pik->kcs; } -static void pci_ipmi_kcs_class_init(ObjectClass *oc, void *data) +static void pci_ipmi_kcs_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c index 56865df7db..7345844a3a 100644 --- a/hw/ipmi/smbus_ipmi.c +++ b/hw/ipmi/smbus_ipmi.c @@ -351,7 +351,7 @@ static void smbus_ipmi_get_fwinfo(struct IPMIInterface *ii, IPMIFwInfo *info) info->uuid = sid->uuid; } -static void smbus_ipmi_class_init(ObjectClass *oc, void *data) +static void smbus_ipmi_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); IPMIInterfaceClass *iic = IPMI_INTERFACE_CLASS(oc); diff --git a/hw/isa/fdc37m81x-superio.c b/hw/isa/fdc37m81x-superio.c index 55e91fbca1..c2a38f04b1 100644 --- a/hw/isa/fdc37m81x-superio.c +++ b/hw/isa/fdc37m81x-superio.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "hw/isa/superio.h" -static void fdc37m81x_class_init(ObjectClass *klass, void *data) +static void fdc37m81x_class_init(ObjectClass *klass, const void *data) { ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index cbaa152a89..26c8ec4f77 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -122,7 +122,7 @@ static void i82378_init(Object *obj) qdev_init_gpio_in(dev, i82378_request_pic_irq, 16); } -static void i82378_class_init(ObjectClass *klass, void *data) +static void i82378_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c index 2599c1219a..6c9802eb7a 100644 --- a/hw/isa/isa-bus.c +++ b/hw/isa/isa-bus.c @@ -29,7 +29,7 @@ static ISABus *isabus; static char *isabus_get_fw_dev_path(DeviceState *dev); -static void isa_bus_class_init(ObjectClass *klass, void *data) +static void isa_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -205,7 +205,7 @@ ISADevice *isa_vga_init(ISABus *bus) } } -static void isabus_bridge_class_init(ObjectClass *klass, void *data) +static void isabus_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -220,7 +220,7 @@ static const TypeInfo isabus_bridge_info = { .class_init = isabus_bridge_class_init, }; -static void isa_device_class_init(ObjectClass *klass, void *data) +static void isa_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->bus_type = TYPE_ISA_BUS; diff --git a/hw/isa/isa-superio.c b/hw/isa/isa-superio.c index 4260da547c..2853485977 100644 --- a/hw/isa/isa-superio.c +++ b/hw/isa/isa-superio.c @@ -172,7 +172,7 @@ static void isa_superio_realize(DeviceState *dev, Error **errp) } } -static void isa_superio_class_init(ObjectClass *oc, void *data) +static void isa_superio_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index dcb0ac2848..d3e623b1e8 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -875,7 +875,7 @@ static void build_ich9_isa_aml(AcpiDevAmlIf *adev, Aml *scope) qbus_build_aml(bus, scope); } -static void ich9_lpc_class_init(ObjectClass *klass, void *data) +static void ich9_lpc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/isa/pc87312.c b/hw/isa/pc87312.c index 5f5868442a..388da8f590 100644 --- a/hw/isa/pc87312.c +++ b/hw/isa/pc87312.c @@ -332,7 +332,7 @@ static const Property pc87312_properties[] = { DEFINE_PROP_UINT8("config", PC87312State, config, 1), }; -static void pc87312_class_init(ObjectClass *klass, void *data) +static void pc87312_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 7fc9e3ec9d..2c6e76f97c 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -417,7 +417,7 @@ static const Property pci_piix_props[] = { DEFINE_PROP_BOOL("smm-enabled", PIIXState, smm_enabled, false), }; -static void pci_piix_class_init(ObjectClass *klass, void *data) +static void pci_piix_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -464,7 +464,7 @@ static void piix3_init(Object *obj) object_initialize_child(obj, "ide", &d->ide, TYPE_PIIX3_IDE); } -static void piix3_class_init(ObjectClass *klass, void *data) +static void piix3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -494,7 +494,7 @@ static void piix4_init(Object *obj) object_initialize_child(obj, "ide", &s->ide, TYPE_PIIX4_IDE); } -static void piix4_class_init(ObjectClass *klass, void *data) +static void piix4_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/isa/smc37c669-superio.c b/hw/isa/smc37c669-superio.c index d2e58c9a89..0ec63f520c 100644 --- a/hw/isa/smc37c669-superio.c +++ b/hw/isa/smc37c669-superio.c @@ -58,7 +58,7 @@ static unsigned int get_fdc_dma(ISASuperIODevice *sio, uint8_t index) return 2; } -static void smc37c669_class_init(ObjectClass *klass, void *data) +static void smc37c669_class_init(ObjectClass *klass, const void *data) { ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 43bd67eeef..80366aaf64 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -220,7 +220,7 @@ typedef struct via_pm_init_info { uint16_t device_id; } ViaPMInitInfo; -static void via_pm_class_init(ObjectClass *klass, void *data) +static void via_pm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -337,7 +337,7 @@ static void via_superio_devices_enable(ViaSuperIOState *s, uint8_t data) isa_fdc_set_enabled(s->superio.floppy, data & BIT(4)); } -static void via_superio_class_init(ObjectClass *klass, void *data) +static void via_superio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); @@ -456,7 +456,7 @@ static void vt82c686b_superio_init(Object *obj) VIA_SUPERIO(obj)->io_ops = &vt82c686b_superio_cfg_ops; } -static void vt82c686b_superio_class_init(ObjectClass *klass, void *data) +static void vt82c686b_superio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); @@ -565,7 +565,7 @@ static void vt8231_superio_init(Object *obj) VIA_SUPERIO(obj)->io_ops = &vt8231_superio_cfg_ops; } -static void vt8231_superio_class_init(ObjectClass *klass, void *data) +static void vt8231_superio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ISASuperIOClass *sc = ISA_SUPERIO_CLASS(klass); @@ -833,7 +833,7 @@ static void vt82c686b_init(Object *obj) object_initialize_child(obj, "pm", &s->pm, TYPE_VT82C686B_PM); } -static void vt82c686b_class_init(ObjectClass *klass, void *data) +static void vt82c686b_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -898,7 +898,7 @@ static void vt8231_init(Object *obj) object_initialize_child(obj, "pm", &s->pm, TYPE_VT8231_PM); } -static void vt8231_class_init(ObjectClass *klass, void *data) +static void vt8231_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index aaaea64c4c..fde25e9409 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -1133,7 +1133,7 @@ static int64_t virt_get_default_cpu_node_id(const MachineState *ms, int idx) } } -static void virt_class_init(ObjectClass *oc, void *data) +static void virt_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/m68k/mcf5206.c b/hw/m68k/mcf5206.c index c22e615f7a..a25e782403 100644 --- a/hw/m68k/mcf5206.c +++ b/hw/m68k/mcf5206.c @@ -605,7 +605,7 @@ static const Property mcf5206_mbar_properties[] = { TYPE_M68K_CPU, M68kCPU *), }; -static void mcf5206_mbar_class_init(ObjectClass *oc, void *data) +static void mcf5206_mbar_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/m68k/mcf_intc.c b/hw/m68k/mcf_intc.c index 7b9213947d..e3055b841e 100644 --- a/hw/m68k/mcf_intc.c +++ b/hw/m68k/mcf_intc.c @@ -182,7 +182,7 @@ static const Property mcf_intc_properties[] = { TYPE_M68K_CPU, M68kCPU *), }; -static void mcf_intc_class_init(ObjectClass *oc, void *data) +static void mcf_intc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/m68k/next-cube.c b/hw/m68k/next-cube.c index 1d5925c17b..957644b2d1 100644 --- a/hw/m68k/next-cube.c +++ b/hw/m68k/next-cube.c @@ -794,7 +794,7 @@ static const VMStateDescription next_scsi_vmstate = { }, }; -static void next_scsi_class_init(ObjectClass *klass, void *data) +static void next_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1064,7 +1064,7 @@ static const VMStateDescription next_rtc_vmstate = { }, }; -static void next_rtc_class_init(ObjectClass *klass, void *data) +static void next_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1228,7 +1228,7 @@ static const VMStateDescription next_pc_vmstate = { }, }; -static void next_pc_class_init(ObjectClass *klass, void *data) +static void next_pc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1348,7 +1348,7 @@ static void next_cube_init(MachineState *machine) memory_region_add_subregion(sysmem, 0x02000000, &m->dmamem); } -static void next_machine_class_init(ObjectClass *oc, void *data) +static void next_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/m68k/next-kbd.c b/hw/m68k/next-kbd.c index 68b17786b2..2bec945acf 100644 --- a/hw/m68k/next-kbd.c +++ b/hw/m68k/next-kbd.c @@ -312,7 +312,7 @@ static const VMStateDescription nextkbd_vmstate = { .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */ }; -static void nextkbd_class_init(ObjectClass *oc, void *data) +static void nextkbd_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index 168665b382..b428e7c833 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -228,7 +228,7 @@ static void glue_init(Object *obj) s->nmi_release = timer_new_ms(QEMU_CLOCK_VIRTUAL, glue_nmi_release, s); } -static void glue_class_init(ObjectClass *klass, void *data) +static void glue_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 46435238d2..793b23f815 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -727,7 +727,7 @@ static GlobalProperty hw_compat_q800[] = { }; static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); -static void q800_machine_class_init(ObjectClass *oc, void *data) +static void q800_machine_class_init(ObjectClass *oc, const void *data) { static const char * const valid_cpu_types[] = { M68K_CPU_TYPE_NAME("m68040"), diff --git a/hw/m68k/virt.c b/hw/m68k/virt.c index e74d709a18..875fd00ef8 100644 --- a/hw/m68k/virt.c +++ b/hw/m68k/virt.c @@ -310,7 +310,7 @@ static void virt_init(MachineState *machine) } } -static void virt_machine_class_init(ObjectClass *oc, void *data) +static void virt_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->desc = "QEMU M68K Virtual Machine"; @@ -339,7 +339,7 @@ type_init(virt_machine_register_types) #define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \ static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \ ObjectClass *oc, \ - void *data) \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \ diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index 43aa02ab2a..c95722a2ae 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -2141,7 +2141,7 @@ void qmp_cxl_release_dynamic_capacity(const char *path, uint16_t host_id, } } -static void ct3_class_init(ObjectClass *oc, void *data) +static void ct3_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); diff --git a/hw/mem/npcm7xx_mc.c b/hw/mem/npcm7xx_mc.c index abc5af5620..07fc108e0a 100644 --- a/hw/mem/npcm7xx_mc.c +++ b/hw/mem/npcm7xx_mc.c @@ -65,7 +65,7 @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio); } -static void npcm7xx_mc_class_init(ObjectClass *klass, void *data) +static void npcm7xx_mc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/mem/nvdimm.c b/hw/mem/nvdimm.c index c05007ab21..23ab143ef8 100644 --- a/hw/mem/nvdimm.c +++ b/hw/mem/nvdimm.c @@ -250,7 +250,7 @@ static const Property nvdimm_properties[] = { DEFINE_PROP_BOOL(NVDIMM_UNARMED_PROP, NVDIMMDevice, unarmed, false), }; -static void nvdimm_class_init(ObjectClass *oc, void *data) +static void nvdimm_class_init(ObjectClass *oc, const void *data) { PCDIMMDeviceClass *ddc = PC_DIMM_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 799a618c1c..6f68171442 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -276,7 +276,7 @@ static void pc_dimm_md_fill_device_info(const MemoryDeviceState *md, } } -static void pc_dimm_class_init(ObjectClass *oc, void *data) +static void pc_dimm_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); MemoryDeviceClass *mdc = MEMORY_DEVICE_CLASS(oc); diff --git a/hw/mem/sparse-mem.c b/hw/mem/sparse-mem.c index 8bed5dbe16..d7b00e563a 100644 --- a/hw/mem/sparse-mem.c +++ b/hw/mem/sparse-mem.c @@ -136,7 +136,7 @@ static void sparse_mem_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->mmio); } -static void sparse_mem_class_init(ObjectClass *klass, void *data) +static void sparse_mem_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index f976c90bd2..032f6f70ea 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -141,7 +141,8 @@ petalogix_s3adsp1800_init(MachineState *machine) NULL); } -static void petalogix_s3adsp1800_machine_class_init(ObjectClass *oc, void *data) +static void petalogix_s3adsp1800_machine_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index 0922c65295..ea1430f408 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -121,7 +121,7 @@ static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) } } -static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, void *data) +static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/mips/cps.c b/hw/mips/cps.c index 0d8cbdc892..2a3ba3f58d 100644 --- a/hw/mips/cps.c +++ b/hw/mips/cps.c @@ -173,7 +173,7 @@ static const Property mips_cps_properties[] = { DEFINE_PROP_BOOL("cpu-big-endian", MIPSCPSState, cpu_is_bigendian, false), }; -static void mips_cps_class_init(ObjectClass *klass, void *data) +static void mips_cps_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index 1700c3765d..cee92e1825 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -415,7 +415,7 @@ void mips_pica61_init(MachineState *machine) mips_jazz_init(machine, JAZZ_PICA61); } -static void mips_magnum_class_init(ObjectClass *oc, void *data) +static void mips_magnum_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -432,7 +432,7 @@ static const TypeInfo mips_magnum_type = { .class_init = mips_magnum_class_init, }; -static void mips_pica61_class_init(ObjectClass *oc, void *data) +static void mips_pica61_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/mips/loongson3_virt.c b/hw/mips/loongson3_virt.c index 1da20dccec..de6fbcc0cb 100644 --- a/hw/mips/loongson3_virt.c +++ b/hw/mips/loongson3_virt.c @@ -667,7 +667,7 @@ static void mips_loongson3_virt_init(MachineState *machine) loongson3_virt_devices_init(machine, liointc); } -static void loongson3v_machine_class_init(ObjectClass *oc, void *data) +static void loongson3v_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/misc/a9scu.c b/hw/misc/a9scu.c index 088d4adb0d..bb00ae2969 100644 --- a/hw/misc/a9scu.c +++ b/hw/misc/a9scu.c @@ -127,7 +127,7 @@ static const Property a9_scu_properties[] = { DEFINE_PROP_UINT32("num-cpu", A9SCUState, num_cpu, 1), }; -static void a9_scu_class_init(ObjectClass *klass, void *data) +static void a9_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-a10-ccm.c b/hw/misc/allwinner-a10-ccm.c index 6ca1daaff8..6b188c25a5 100644 --- a/hw/misc/allwinner-a10-ccm.c +++ b/hw/misc/allwinner-a10-ccm.c @@ -199,7 +199,7 @@ static const VMStateDescription allwinner_a10_ccm_vmstate = { } }; -static void allwinner_a10_ccm_class_init(ObjectClass *klass, void *data) +static void allwinner_a10_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/allwinner-a10-dramc.c b/hw/misc/allwinner-a10-dramc.c index badc4c56eb..c16814cc5b 100644 --- a/hw/misc/allwinner-a10-dramc.c +++ b/hw/misc/allwinner-a10-dramc.c @@ -154,7 +154,7 @@ static const VMStateDescription allwinner_a10_dramc_vmstate = { } }; -static void allwinner_a10_dramc_class_init(ObjectClass *klass, void *data) +static void allwinner_a10_dramc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/allwinner-cpucfg.c b/hw/misc/allwinner-cpucfg.c index a4f7a01141..90dd872abf 100644 --- a/hw/misc/allwinner-cpucfg.c +++ b/hw/misc/allwinner-cpucfg.c @@ -258,7 +258,7 @@ static const VMStateDescription allwinner_cpucfg_vmstate = { } }; -static void allwinner_cpucfg_class_init(ObjectClass *klass, void *data) +static void allwinner_cpucfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-h3-ccu.c b/hw/misc/allwinner-h3-ccu.c index e765f4c54b..be91c0c1ca 100644 --- a/hw/misc/allwinner-h3-ccu.c +++ b/hw/misc/allwinner-h3-ccu.c @@ -218,7 +218,7 @@ static const VMStateDescription allwinner_h3_ccu_vmstate = { } }; -static void allwinner_h3_ccu_class_init(ObjectClass *klass, void *data) +static void allwinner_h3_ccu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-h3-dramc.c b/hw/misc/allwinner-h3-dramc.c index 74ff71b753..8834524c30 100644 --- a/hw/misc/allwinner-h3-dramc.c +++ b/hw/misc/allwinner-h3-dramc.c @@ -331,7 +331,7 @@ static const VMStateDescription allwinner_h3_dramc_vmstate = { } }; -static void allwinner_h3_dramc_class_init(ObjectClass *klass, void *data) +static void allwinner_h3_dramc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-h3-sysctrl.c b/hw/misc/allwinner-h3-sysctrl.c index 32a0ceb01a..6b86524606 100644 --- a/hw/misc/allwinner-h3-sysctrl.c +++ b/hw/misc/allwinner-h3-sysctrl.c @@ -116,7 +116,8 @@ static const VMStateDescription allwinner_h3_sysctrl_vmstate = { } }; -static void allwinner_h3_sysctrl_class_init(ObjectClass *klass, void *data) +static void allwinner_h3_sysctrl_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c index 8f37a9213c..4e21eeafdd 100644 --- a/hw/misc/allwinner-r40-ccu.c +++ b/hw/misc/allwinner-r40-ccu.c @@ -185,7 +185,7 @@ static const VMStateDescription allwinner_r40_ccu_vmstate = { } }; -static void allwinner_r40_ccu_class_init(ObjectClass *klass, void *data) +static void allwinner_r40_ccu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c index 5908a059e8..1c8e17e3c0 100644 --- a/hw/misc/allwinner-r40-dramc.c +++ b/hw/misc/allwinner-r40-dramc.c @@ -484,7 +484,7 @@ static const VMStateDescription allwinner_r40_dramc_vmstate = { } }; -static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data) +static void allwinner_r40_dramc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-sid.c b/hw/misc/allwinner-sid.c index 2bb81f9c54..1e66c14567 100644 --- a/hw/misc/allwinner-sid.c +++ b/hw/misc/allwinner-sid.c @@ -143,7 +143,7 @@ static const VMStateDescription allwinner_sid_vmstate = { } }; -static void allwinner_sid_class_init(ObjectClass *klass, void *data) +static void allwinner_sid_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/allwinner-sramc.c b/hw/misc/allwinner-sramc.c index 51df5e45aa..ed299ecaae 100644 --- a/hw/misc/allwinner-sramc.c +++ b/hw/misc/allwinner-sramc.c @@ -135,7 +135,7 @@ static void allwinner_sramc_reset(DeviceState *dev) } } -static void allwinner_sramc_class_init(ObjectClass *klass, void *data) +static void allwinner_sramc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -163,7 +163,7 @@ static const TypeInfo allwinner_sramc_info = { .class_init = allwinner_sramc_class_init, }; -static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data) +static void allwinner_r40_sramc_class_init(ObjectClass *klass, const void *data) { AwSRAMCClass *sc = AW_SRAMC_CLASS(klass); diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index 97ea842d60..d83a81b60d 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -375,7 +375,7 @@ static void build_applesmc_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(scope, dev); } -static void qdev_applesmc_class_init(ObjectClass *klass, void *data) +static void qdev_applesmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/misc/arm11scu.c b/hw/misc/arm11scu.c index 02493cec31..2ad4fd1d21 100644 --- a/hw/misc/arm11scu.c +++ b/hw/misc/arm11scu.c @@ -79,7 +79,7 @@ static const Property arm11_scu_properties[] = { DEFINE_PROP_UINT32("num-cpu", ARM11SCUState, num_cpu, 1), }; -static void arm11_scu_class_init(ObjectClass *oc, void *data) +static void arm11_scu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c index 39b4642da7..8b4b61eed0 100644 --- a/hw/misc/arm_l2x0.c +++ b/hw/misc/arm_l2x0.c @@ -177,7 +177,7 @@ static const Property l2x0_properties[] = { DEFINE_PROP_UINT32("cache-type", L2x0State, cache_type, 0x1c100100), }; -static void l2x0_class_init(ObjectClass *klass, void *data) +static void l2x0_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/arm_sysctl.c b/hw/misc/arm_sysctl.c index 01663407ec..0f4e37cd47 100644 --- a/hw/misc/arm_sysctl.c +++ b/hw/misc/arm_sysctl.c @@ -634,7 +634,7 @@ static const Property arm_sysctl_properties[] = { db_clock_reset, qdev_prop_uint32, uint32_t), }; -static void arm_sysctl_class_init(ObjectClass *klass, void *data) +static void arm_sysctl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/armsse-cpu-pwrctrl.c b/hw/misc/armsse-cpu-pwrctrl.c index 2d3a0ac29c..66e9218f27 100644 --- a/hw/misc/armsse-cpu-pwrctrl.c +++ b/hw/misc/armsse-cpu-pwrctrl.c @@ -125,7 +125,7 @@ static void pwrctrl_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static void pwrctrl_class_init(ObjectClass *klass, void *data) +static void pwrctrl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/armsse-cpuid.c b/hw/misc/armsse-cpuid.c index 58cb37333f..a57764d731 100644 --- a/hw/misc/armsse-cpuid.c +++ b/hw/misc/armsse-cpuid.c @@ -106,7 +106,7 @@ static void armsse_cpuid_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static void armsse_cpuid_class_init(ObjectClass *klass, void *data) +static void armsse_cpuid_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/armsse-mhu.c b/hw/misc/armsse-mhu.c index 91c49108b0..d5d307a186 100644 --- a/hw/misc/armsse-mhu.c +++ b/hw/misc/armsse-mhu.c @@ -176,7 +176,7 @@ static void armsse_mhu_init(Object *obj) sysbus_init_irq(sbd, &s->cpu1irq); } -static void armsse_mhu_class_init(ObjectClass *klass, void *data) +static void armsse_mhu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/armv7m_ras.c b/hw/misc/armv7m_ras.c index de24922c94..7bf5acd0a5 100644 --- a/hw/misc/armv7m_ras.c +++ b/hw/misc/armv7m_ras.c @@ -72,7 +72,7 @@ static void armv7m_ras_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static void armv7m_ras_class_init(ObjectClass *klass, void *data) +static void armv7m_ras_class_init(ObjectClass *klass, const void *data) { /* This device has no state: no need for vmstate or reset */ } diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index d75da33353..f4bff32a00 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -479,7 +479,7 @@ static const VMStateDescription vmstate_aspeed_hace = { } }; -static void aspeed_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -497,7 +497,7 @@ static const TypeInfo aspeed_hace_info = { .class_size = sizeof(AspeedHACEClass) }; -static void aspeed_ast2400_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_ast2400_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); @@ -516,7 +516,7 @@ static const TypeInfo aspeed_ast2400_hace_info = { .class_init = aspeed_ast2400_hace_class_init, }; -static void aspeed_ast2500_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_ast2500_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); @@ -535,7 +535,7 @@ static const TypeInfo aspeed_ast2500_hace_info = { .class_init = aspeed_ast2500_hace_class_init, }; -static void aspeed_ast2600_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_ast2600_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); @@ -554,7 +554,7 @@ static const TypeInfo aspeed_ast2600_hace_info = { .class_init = aspeed_ast2600_hace_class_init, }; -static void aspeed_ast1030_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_ast1030_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); @@ -573,7 +573,7 @@ static const TypeInfo aspeed_ast1030_hace_info = { .class_init = aspeed_ast1030_hace_class_init, }; -static void aspeed_ast2700_hace_class_init(ObjectClass *klass, void *data) +static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedHACEClass *ahc = ASPEED_HACE_CLASS(klass); diff --git a/hw/misc/aspeed_i3c.c b/hw/misc/aspeed_i3c.c index ab39c6435b..3bef1c84dd 100644 --- a/hw/misc/aspeed_i3c.c +++ b/hw/misc/aspeed_i3c.c @@ -327,7 +327,7 @@ static const Property aspeed_i3c_device_properties[] = { DEFINE_PROP_UINT8("device-id", AspeedI3CDevice, id, 0), }; -static void aspeed_i3c_device_class_init(ObjectClass *klass, void *data) +static void aspeed_i3c_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -356,7 +356,7 @@ static const VMStateDescription vmstate_aspeed_i3c = { } }; -static void aspeed_i3c_class_init(ObjectClass *klass, void *data) +static void aspeed_i3c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/aspeed_lpc.c b/hw/misc/aspeed_lpc.c index 228d250dc0..78406dae24 100644 --- a/hw/misc/aspeed_lpc.c +++ b/hw/misc/aspeed_lpc.c @@ -458,7 +458,7 @@ static const Property aspeed_lpc_properties[] = { DEFINE_PROP_UINT32("hicr7", AspeedLPCState, hicr7, 0), }; -static void aspeed_lpc_class_init(ObjectClass *klass, void *data) +static void aspeed_lpc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/aspeed_peci.c b/hw/misc/aspeed_peci.c index 9025b35f83..a7a449a923 100644 --- a/hw/misc/aspeed_peci.c +++ b/hw/misc/aspeed_peci.c @@ -130,7 +130,7 @@ static void aspeed_peci_reset(DeviceState *dev) memset(s->regs, 0, sizeof(s->regs)); } -static void aspeed_peci_class_init(ObjectClass *klass, void *data) +static void aspeed_peci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/aspeed_sbc.c b/hw/misc/aspeed_sbc.c index e4a6bd1581..a7d101ba71 100644 --- a/hw/misc/aspeed_sbc.c +++ b/hw/misc/aspeed_sbc.c @@ -141,7 +141,7 @@ static const Property aspeed_sbc_properties[] = { DEFINE_PROP_UINT32("signing-settings", AspeedSBCState, signing_settings, 0), }; -static void aspeed_sbc_class_init(ObjectClass *klass, void *data) +static void aspeed_sbc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -159,7 +159,7 @@ static const TypeInfo aspeed_sbc_info = { .class_size = sizeof(AspeedSBCClass) }; -static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, void *data) +static void aspeed_ast2600_sbc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c index 1af1a35a08..4930e00fed 100644 --- a/hw/misc/aspeed_scu.c +++ b/hw/misc/aspeed_scu.c @@ -618,7 +618,7 @@ static const Property aspeed_scu_properties[] = { DEFINE_PROP_UINT32("hw-prot-key", AspeedSCUState, hw_prot_key, 0), }; -static void aspeed_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = aspeed_scu_realize; @@ -637,7 +637,7 @@ static const TypeInfo aspeed_scu_info = { .abstract = true, }; -static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); @@ -659,7 +659,7 @@ static const TypeInfo aspeed_2400_scu_info = { .class_init = aspeed_2400_scu_class_init, }; -static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); @@ -835,7 +835,7 @@ static void aspeed_ast2600_scu_reset(DeviceState *dev) s->regs[PROT_KEY] = s->hw_prot_key; } -static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); @@ -954,7 +954,7 @@ static void aspeed_ast2700_scu_reset(DeviceState *dev) s->regs[AST2700_HW_STRAP1] = s->hw_strap1; } -static void aspeed_2700_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); @@ -1068,7 +1068,7 @@ static const uint32_t ast2700_a0_resets_io[ASPEED_AST2700_SCU_NR_REGS] = { [AST2700_SCUIO_CLK_DUTY_MEAS_RST] = 0x0c9100d2, }; -static void aspeed_2700_scuio_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_scuio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); @@ -1126,7 +1126,7 @@ static void aspeed_ast1030_scu_reset(DeviceState *dev) s->regs[PROT_KEY] = s->hw_prot_key; } -static void aspeed_1030_scu_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_scu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass); diff --git a/hw/misc/aspeed_sdmc.c b/hw/misc/aspeed_sdmc.c index f359640a9a..f04d9930dd 100644 --- a/hw/misc/aspeed_sdmc.c +++ b/hw/misc/aspeed_sdmc.c @@ -299,7 +299,7 @@ static const Property aspeed_sdmc_properties[] = { DEFINE_PROP_BOOL("unlocked", AspeedSDMCState, unlocked, false), }; -static void aspeed_sdmc_class_init(ObjectClass *klass, void *data) +static void aspeed_sdmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = aspeed_sdmc_realize; @@ -380,7 +380,7 @@ static void aspeed_2400_sdmc_write(AspeedSDMCState *s, uint32_t reg, static const uint64_t aspeed_2400_ram_sizes[] = { 64 * MiB, 128 * MiB, 256 * MiB, 512 * MiB, 0}; -static void aspeed_2400_sdmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_sdmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); @@ -448,7 +448,7 @@ static void aspeed_2500_sdmc_write(AspeedSDMCState *s, uint32_t reg, static const uint64_t aspeed_2500_ram_sizes[] = { 128 * MiB, 256 * MiB, 512 * MiB, 1024 * MiB, 0}; -static void aspeed_2500_sdmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_sdmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); @@ -542,7 +542,7 @@ static void aspeed_2600_sdmc_write(AspeedSDMCState *s, uint32_t reg, static const uint64_t aspeed_2600_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB, 2048 * MiB, 0}; -static void aspeed_2600_sdmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_sdmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); @@ -670,7 +670,7 @@ static const uint64_t aspeed_2700_ram_sizes[] = { 256 * MiB, 512 * MiB, 1024 * MiB, 2048 * MiB, 4096 * MiB, 8192 * MiB, 0}; -static void aspeed_2700_sdmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_sdmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDMCClass *asc = ASPEED_SDMC_CLASS(klass); diff --git a/hw/misc/aspeed_sli.c b/hw/misc/aspeed_sli.c index fe720ead50..c51484035e 100644 --- a/hw/misc/aspeed_sli.c +++ b/hw/misc/aspeed_sli.c @@ -124,7 +124,7 @@ static void aspeed_sliio_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void aspeed_sli_class_init(ObjectClass *klass, void *data) +static void aspeed_sli_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -140,14 +140,14 @@ static const TypeInfo aspeed_sli_info = { .abstract = true, }; -static void aspeed_2700_sli_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_sli_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->desc = "AST2700 SLI Controller"; } -static void aspeed_2700_sliio_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_sliio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/aspeed_xdma.c b/hw/misc/aspeed_xdma.c index 1dd32f72f4..cc03c422b0 100644 --- a/hw/misc/aspeed_xdma.c +++ b/hw/misc/aspeed_xdma.c @@ -150,7 +150,7 @@ static const VMStateDescription aspeed_xdma_vmstate = { }, }; -static void aspeed_2600_xdma_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_xdma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); @@ -173,7 +173,7 @@ static const TypeInfo aspeed_2600_xdma_info = { .class_init = aspeed_2600_xdma_class_init, }; -static void aspeed_2500_xdma_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_xdma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); @@ -195,7 +195,7 @@ static const TypeInfo aspeed_2500_xdma_info = { .class_init = aspeed_2500_xdma_class_init, }; -static void aspeed_2400_xdma_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_xdma_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedXDMAClass *axc = ASPEED_XDMA_CLASS(klass); @@ -217,7 +217,7 @@ static const TypeInfo aspeed_2400_xdma_info = { .class_init = aspeed_2400_xdma_class_init, }; -static void aspeed_xdma_class_init(ObjectClass *classp, void *data) +static void aspeed_xdma_class_init(ObjectClass *classp, const void *data) { DeviceClass *dc = DEVICE_CLASS(classp); diff --git a/hw/misc/auxbus.c b/hw/misc/auxbus.c index 28d50d9d09..877f345606 100644 --- a/hw/misc/auxbus.c +++ b/hw/misc/auxbus.c @@ -50,7 +50,7 @@ static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent); static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge); /* aux-bus implementation (internal not public) */ -static void aux_bus_class_init(ObjectClass *klass, void *data) +static void aux_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -256,7 +256,7 @@ struct AUXTOI2CState { I2CBus *i2c_bus; }; -static void aux_bridge_class_init(ObjectClass *oc, void *data) +static void aux_bridge_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -311,7 +311,7 @@ void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio) aux_slave->mmio = mmio; } -static void aux_slave_class_init(ObjectClass *klass, void *data) +static void aux_slave_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/misc/avr_power.c b/hw/misc/avr_power.c index ac7b96f53e..411f016c99 100644 --- a/hw/misc/avr_power.c +++ b/hw/misc/avr_power.c @@ -90,7 +90,7 @@ static void avr_mask_init(Object *dev) s->val = 0x00; } -static void avr_mask_class_init(ObjectClass *klass, void *data) +static void avr_mask_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/axp2xx.c b/hw/misc/axp2xx.c index af646878cd..46d17712dd 100644 --- a/hw/misc/axp2xx.c +++ b/hw/misc/axp2xx.c @@ -225,7 +225,7 @@ static const VMStateDescription vmstate_axp2xx = { } }; -static void axp2xx_class_init(ObjectClass *oc, void *data) +static void axp2xx_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); @@ -247,7 +247,7 @@ static const TypeInfo axp2xx_info = { .abstract = true, }; -static void axp209_class_init(ObjectClass *oc, void *data) +static void axp209_class_init(ObjectClass *oc, const void *data) { AXP2xxClass *sc = AXP2XX_CLASS(oc); @@ -260,7 +260,7 @@ static const TypeInfo axp209_info = { .class_init = axp209_class_init }; -static void axp221_class_init(ObjectClass *oc, void *data) +static void axp221_class_init(ObjectClass *oc, const void *data) { AXP2xxClass *sc = AXP2XX_CLASS(oc); diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c index 0c4d4b7de5..efe6f900db 100644 --- a/hw/misc/bcm2835_cprman.c +++ b/hw/misc/bcm2835_cprman.c @@ -131,7 +131,7 @@ static const VMStateDescription pll_vmstate = { } }; -static void pll_class_init(ObjectClass *klass, void *data) +static void pll_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -237,7 +237,7 @@ static const VMStateDescription pll_channel_vmstate = { } }; -static void pll_channel_class_init(ObjectClass *klass, void *data) +static void pll_channel_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -360,7 +360,7 @@ static const VMStateDescription clock_mux_vmstate = { } }; -static void clock_mux_class_init(ObjectClass *klass, void *data) +static void clock_mux_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -417,7 +417,7 @@ static const VMStateDescription dsi0hsck_mux_vmstate = { } }; -static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data) +static void dsi0hsck_mux_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -790,7 +790,7 @@ static const Property cprman_properties[] = { DEFINE_PROP_UINT32("xosc-freq-hz", BCM2835CprmanState, xosc_freq, 19200000), }; -static void cprman_class_init(ObjectClass *klass, void *data) +static void cprman_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_mbox.c b/hw/misc/bcm2835_mbox.c index ed6dbea191..603eaaa710 100644 --- a/hw/misc/bcm2835_mbox.c +++ b/hw/misc/bcm2835_mbox.c @@ -314,7 +314,7 @@ static void bcm2835_mbox_realize(DeviceState *dev, Error **errp) bcm2835_mbox_reset(dev); } -static void bcm2835_mbox_class_init(ObjectClass *klass, void *data) +static void bcm2835_mbox_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_mphi.c b/hw/misc/bcm2835_mphi.c index 7309cf22fc..55d79e7e87 100644 --- a/hw/misc/bcm2835_mphi.c +++ b/hw/misc/bcm2835_mphi.c @@ -166,7 +166,7 @@ const VMStateDescription vmstate_mphi_state = { } }; -static void mphi_class_init(ObjectClass *klass, void *data) +static void mphi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_powermgt.c b/hw/misc/bcm2835_powermgt.c index e4e9bae374..3ec7abad0e 100644 --- a/hw/misc/bcm2835_powermgt.c +++ b/hw/misc/bcm2835_powermgt.c @@ -136,7 +136,7 @@ static void bcm2835_powermgt_reset(DeviceState *dev) s->wdog = 0x00000000; } -static void bcm2835_powermgt_class_init(ObjectClass *klass, void *data) +static void bcm2835_powermgt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 2bae64b64c..a21c6a541c 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -556,7 +556,7 @@ static const Property bcm2835_property_props[] = { DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), }; -static void bcm2835_property_class_init(ObjectClass *klass, void *data) +static void bcm2835_property_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_rng.c b/hw/misc/bcm2835_rng.c index 06f40817df..e4d2c224c8 100644 --- a/hw/misc/bcm2835_rng.c +++ b/hw/misc/bcm2835_rng.c @@ -123,7 +123,7 @@ static void bcm2835_rng_reset(DeviceState *dev) s->rng_status = 0; } -static void bcm2835_rng_class_init(ObjectClass *klass, void *data) +static void bcm2835_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/bcm2835_thermal.c b/hw/misc/bcm2835_thermal.c index 1c1b0671cc..33bfc91c7a 100644 --- a/hw/misc/bcm2835_thermal.c +++ b/hw/misc/bcm2835_thermal.c @@ -113,7 +113,7 @@ static const VMStateDescription bcm2835_thermal_vmstate = { } }; -static void bcm2835_thermal_class_init(ObjectClass *klass, void *data) +static void bcm2835_thermal_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/debugexit.c b/hw/misc/debugexit.c index 577b884494..04a9fc3122 100644 --- a/hw/misc/debugexit.c +++ b/hw/misc/debugexit.c @@ -61,7 +61,7 @@ static const Property debug_exit_properties[] = { DEFINE_PROP_UINT32("iosize", ISADebugExitState, iosize, 0x02), }; -static void debug_exit_class_initfn(ObjectClass *klass, void *data) +static void debug_exit_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/djmemc.c b/hw/misc/djmemc.c index 96d5efb5e3..c5b09f551b 100644 --- a/hw/misc/djmemc.c +++ b/hw/misc/djmemc.c @@ -113,7 +113,7 @@ static const VMStateDescription vmstate_djmemc = { } }; -static void djmemc_class_init(ObjectClass *oc, void *data) +static void djmemc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/misc/eccmemctl.c b/hw/misc/eccmemctl.c index d7452c4cc8..81fc536131 100644 --- a/hw/misc/eccmemctl.c +++ b/hw/misc/eccmemctl.c @@ -329,7 +329,7 @@ static const Property ecc_properties[] = { DEFINE_PROP_UINT32("version", ECCState, version, -1), }; -static void ecc_class_init(ObjectClass *klass, void *data) +static void ecc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 5723ef0ed1..8224603593 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -415,7 +415,7 @@ static void edu_instance_init(Object *obj) &edu->dma_mask, OBJ_PROP_FLAG_READWRITE); } -static void edu_class_init(ObjectClass *class, void *data) +static void edu_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *k = PCI_DEVICE_CLASS(class); diff --git a/hw/misc/empty_slot.c b/hw/misc/empty_slot.c index 221ea7cb54..239d760320 100644 --- a/hw/misc/empty_slot.c +++ b/hw/misc/empty_slot.c @@ -84,7 +84,7 @@ static const Property empty_slot_properties[] = { DEFINE_PROP_STRING("name", EmptySlot, name), }; -static void empty_slot_class_init(ObjectClass *klass, void *data) +static void empty_slot_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/exynos4210_clk.c b/hw/misc/exynos4210_clk.c index 886d10bbab..fdf5bdd603 100644 --- a/hw/misc/exynos4210_clk.c +++ b/hw/misc/exynos4210_clk.c @@ -141,7 +141,7 @@ static const VMStateDescription exynos4210_clk_vmstate = { } }; -static void exynos4210_clk_class_init(ObjectClass *klass, void *data) +static void exynos4210_clk_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c index d44aac3af5..a86ec9aba8 100644 --- a/hw/misc/exynos4210_pmu.c +++ b/hw/misc/exynos4210_pmu.c @@ -498,7 +498,7 @@ static const VMStateDescription exynos4210_pmu_vmstate = { } }; -static void exynos4210_pmu_class_init(ObjectClass *klass, void *data) +static void exynos4210_pmu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/exynos4210_rng.c b/hw/misc/exynos4210_rng.c index a741cf176b..2d0ebc457b 100644 --- a/hw/misc/exynos4210_rng.c +++ b/hw/misc/exynos4210_rng.c @@ -255,7 +255,7 @@ static const VMStateDescription exynos4210_rng_vmstate = { } }; -static void exynos4210_rng_class_init(ObjectClass *klass, void *data) +static void exynos4210_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/grlib_ahb_apb_pnp.c b/hw/misc/grlib_ahb_apb_pnp.c index 5b05f15859..cdca00ad54 100644 --- a/hw/misc/grlib_ahb_apb_pnp.c +++ b/hw/misc/grlib_ahb_apb_pnp.c @@ -168,7 +168,7 @@ static void grlib_ahb_pnp_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &ahb_pnp->iomem); } -static void grlib_ahb_pnp_class_init(ObjectClass *klass, void *data) +static void grlib_ahb_pnp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -280,7 +280,7 @@ static void grlib_apb_pnp_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &apb_pnp->iomem); } -static void grlib_apb_pnp_class_init(ObjectClass *klass, void *data) +static void grlib_apb_pnp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/i2c-echo.c b/hw/misc/i2c-echo.c index fcd407dfc6..2bb99ec0db 100644 --- a/hw/misc/i2c-echo.c +++ b/hw/misc/i2c-echo.c @@ -145,7 +145,7 @@ static void i2c_echo_realize(DeviceState *dev, Error **errp) state->bh = qemu_bh_new(i2c_echo_bh, state); } -static void i2c_echo_class_init(ObjectClass *oc, void *data) +static void i2c_echo_class_init(ObjectClass *oc, const void *data) { I2CSlaveClass *sc = I2C_SLAVE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c index 9654d23f19..a6665d5535 100644 --- a/hw/misc/imx25_ccm.c +++ b/hw/misc/imx25_ccm.c @@ -292,7 +292,7 @@ static void imx25_ccm_init(Object *obj) sysbus_init_mmio(sd, &s->iomem); } -static void imx25_ccm_class_init(ObjectClass *klass, void *data) +static void imx25_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c index 93130b24e5..339458e859 100644 --- a/hw/misc/imx31_ccm.c +++ b/hw/misc/imx31_ccm.c @@ -319,7 +319,7 @@ static void imx31_ccm_init(Object *obj) sysbus_init_mmio(sd, &s->iomem); } -static void imx31_ccm_class_init(ObjectClass *klass, void *data) +static void imx31_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c index 7d522ed7c5..a10b67d396 100644 --- a/hw/misc/imx6_ccm.c +++ b/hw/misc/imx6_ccm.c @@ -741,7 +741,7 @@ static void imx6_ccm_init(Object *obj) sysbus_init_mmio(sd, &s->container); } -static void imx6_ccm_class_init(ObjectClass *klass, void *data) +static void imx6_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); diff --git a/hw/misc/imx6_src.c b/hw/misc/imx6_src.c index 06cc46292e..8d2c4175e4 100644 --- a/hw/misc/imx6_src.c +++ b/hw/misc/imx6_src.c @@ -273,7 +273,7 @@ static void imx6_src_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } -static void imx6_src_class_init(ObjectClass *klass, void *data) +static void imx6_src_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx6ul_ccm.c b/hw/misc/imx6ul_ccm.c index c836dfe494..7f3ae61710 100644 --- a/hw/misc/imx6ul_ccm.c +++ b/hw/misc/imx6ul_ccm.c @@ -904,7 +904,7 @@ static void imx6ul_ccm_init(Object *obj) sysbus_init_mmio(sd, &s->container); } -static void imx6ul_ccm_class_init(ObjectClass *klass, void *data) +static void imx6ul_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); diff --git a/hw/misc/imx7_ccm.c b/hw/misc/imx7_ccm.c index c3ecfd78c1..c061a584e4 100644 --- a/hw/misc/imx7_ccm.c +++ b/hw/misc/imx7_ccm.c @@ -262,7 +262,7 @@ static uint32_t imx7_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) return freq; } -static void imx7_ccm_class_init(ObjectClass *klass, void *data) +static void imx7_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); @@ -293,7 +293,7 @@ static const VMStateDescription vmstate_imx7_analog = { }, }; -static void imx7_analog_class_init(ObjectClass *klass, void *data) +static void imx7_analog_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx7_gpr.c b/hw/misc/imx7_gpr.c index b03341a2eb..e12b496273 100644 --- a/hw/misc/imx7_gpr.c +++ b/hw/misc/imx7_gpr.c @@ -102,7 +102,7 @@ static void imx7_gpr_init(Object *obj) sysbus_init_mmio(sd, &s->mmio); } -static void imx7_gpr_class_init(ObjectClass *klass, void *data) +static void imx7_gpr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx7_snvs.c b/hw/misc/imx7_snvs.c index c8a096bc13..6a8733d23d 100644 --- a/hw/misc/imx7_snvs.c +++ b/hw/misc/imx7_snvs.c @@ -143,7 +143,7 @@ static void imx7_snvs_init(Object *obj) qemu_clock_get_ns(rtc_clock) / NANOSECONDS_PER_SECOND; } -static void imx7_snvs_class_init(ObjectClass *klass, void *data) +static void imx7_snvs_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx7_src.c b/hw/misc/imx7_src.c index 35341c6819..df0b0a6905 100644 --- a/hw/misc/imx7_src.c +++ b/hw/misc/imx7_src.c @@ -251,7 +251,7 @@ static void imx7_src_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem); } -static void imx7_src_class_init(ObjectClass *klass, void *data) +static void imx7_src_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx8mp_analog.c b/hw/misc/imx8mp_analog.c index f7e7c83cc4..23ffae84f8 100644 --- a/hw/misc/imx8mp_analog.c +++ b/hw/misc/imx8mp_analog.c @@ -138,7 +138,7 @@ static const VMStateDescription imx8mp_analog_vmstate = { }, }; -static void imx8mp_analog_class_init(ObjectClass *klass, void *data) +static void imx8mp_analog_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/imx8mp_ccm.c b/hw/misc/imx8mp_ccm.c index 1a1c932427..911911ed86 100644 --- a/hw/misc/imx8mp_ccm.c +++ b/hw/misc/imx8mp_ccm.c @@ -150,7 +150,7 @@ static uint32_t imx8mp_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock) return freq; } -static void imx8mp_ccm_class_init(ObjectClass *klass, void *data) +static void imx8mp_ccm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); IMXCCMClass *ccm = IMX_CCM_CLASS(klass); diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c index 0cbf28db5d..630f6cb54b 100644 --- a/hw/misc/imx_rngc.c +++ b/hw/misc/imx_rngc.c @@ -254,7 +254,7 @@ static const VMStateDescription vmstate_imx_rngc = { } }; -static void imx_rngc_class_init(ObjectClass *klass, void *data) +static void imx_rngc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/iosb.c b/hw/misc/iosb.c index 31927eaedb..96221e1ee5 100644 --- a/hw/misc/iosb.c +++ b/hw/misc/iosb.c @@ -111,7 +111,7 @@ static const VMStateDescription vmstate_iosb = { } }; -static void iosb_class_init(ObjectClass *oc, void *data) +static void iosb_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/misc/iotkit-secctl.c b/hw/misc/iotkit-secctl.c index 04ced3559c..afd9ab48df 100644 --- a/hw/misc/iotkit-secctl.c +++ b/hw/misc/iotkit-secctl.c @@ -818,7 +818,7 @@ static const Property iotkit_secctl_props[] = { DEFINE_PROP_UINT32("sse-version", IoTKitSecCtl, sse_version, 0), }; -static void iotkit_secctl_class_init(ObjectClass *klass, void *data) +static void iotkit_secctl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/iotkit-sysctl.c b/hw/misc/iotkit-sysctl.c index c654af2e88..d70e51ab2e 100644 --- a/hw/misc/iotkit-sysctl.c +++ b/hw/misc/iotkit-sysctl.c @@ -844,7 +844,7 @@ static const Property iotkit_sysctl_props[] = { 0x10000000), }; -static void iotkit_sysctl_class_init(ObjectClass *klass, void *data) +static void iotkit_sysctl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/iotkit-sysinfo.c b/hw/misc/iotkit-sysinfo.c index 75260f7fab..57405cb7e1 100644 --- a/hw/misc/iotkit-sysinfo.c +++ b/hw/misc/iotkit-sysinfo.c @@ -158,7 +158,7 @@ static void iotkit_sysinfo_realize(DeviceState *dev, Error **errp) } } -static void iotkit_sysinfo_class_init(ObjectClass *klass, void *data) +static void iotkit_sysinfo_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/ivshmem-flat.c b/hw/misc/ivshmem-flat.c index c4e82a0827..be28c24d73 100644 --- a/hw/misc/ivshmem-flat.c +++ b/hw/misc/ivshmem-flat.c @@ -431,7 +431,7 @@ static const Property ivshmem_flat_props[] = { DEFINE_PROP_UINT32("shmem-size", IvshmemFTState, shmem_size, 4 * MiB), }; -static void ivshmem_flat_class_init(ObjectClass *klass, void *data) +static void ivshmem_flat_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/ivshmem-pci.c b/hw/misc/ivshmem-pci.c index 900d523334..2844b6f909 100644 --- a/hw/misc/ivshmem-pci.c +++ b/hw/misc/ivshmem-pci.c @@ -979,7 +979,7 @@ static int ivshmem_post_load(void *opaque, int version_id) return 0; } -static void ivshmem_common_class_init(ObjectClass *klass, void *data) +static void ivshmem_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1044,7 +1044,7 @@ static void ivshmem_plain_realize(PCIDevice *dev, Error **errp) ivshmem_common_realize(dev, errp); } -static void ivshmem_plain_class_init(ObjectClass *klass, void *data) +static void ivshmem_plain_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1103,7 +1103,7 @@ static void ivshmem_doorbell_realize(PCIDevice *dev, Error **errp) ivshmem_common_realize(dev, errp); } -static void ivshmem_doorbell_class_init(ObjectClass *klass, void *data) +static void ivshmem_doorbell_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c index 24d20ffcb8..9f758c6a86 100644 --- a/hw/misc/lasi.c +++ b/hw/misc/lasi.c @@ -263,7 +263,7 @@ static void lasi_init(Object *obj) qdev_init_gpio_in(DEVICE(obj), lasi_set_irq, LASI_IRQS); } -static void lasi_class_init(ObjectClass *klass, void *data) +static void lasi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/led.c b/hw/misc/led.c index 9364d9945e..f7f709072a 100644 --- a/hw/misc/led.c +++ b/hw/misc/led.c @@ -107,7 +107,7 @@ static const Property led_properties[] = { DEFINE_PROP_BOOL("gpio-active-high", LEDState, gpio_active_high, true), }; -static void led_class_init(ObjectClass *klass, void *data) +static void led_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mac_via.c b/hw/misc/mac_via.c index 3c0819c58a..bc37e2a2cb 100644 --- a/hw/misc/mac_via.c +++ b/hw/misc/mac_via.c @@ -1326,7 +1326,7 @@ static const Property mos6522_q800_via1_properties[] = { DEFINE_PROP_DRIVE("drive", MOS6522Q800VIA1State, blk), }; -static void mos6522_q800_via1_class_init(ObjectClass *oc, void *data) +static void mos6522_q800_via1_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); @@ -1415,7 +1415,7 @@ static const VMStateDescription vmstate_q800_via2 = { } }; -static void mos6522_q800_via2_class_init(ObjectClass *oc, void *data) +static void mos6522_q800_via2_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/misc/macio/cuda.c b/hw/misc/macio/cuda.c index 34731ae560..bcd00c9bb1 100644 --- a/hw/misc/macio/cuda.c +++ b/hw/misc/macio/cuda.c @@ -558,7 +558,7 @@ static const Property cuda_properties[] = { DEFINE_PROP_UINT64("timebase-frequency", CUDAState, tb_frequency, 0), }; -static void cuda_class_init(ObjectClass *oc, void *data) +static void cuda_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -598,7 +598,7 @@ static void mos6522_cuda_reset_hold(Object *obj, ResetType type) ms->timers[1].frequency = (SCALE_US * 6000) / 4700; } -static void mos6522_cuda_class_init(ObjectClass *oc, void *data) +static void mos6522_cuda_class_init(ObjectClass *oc, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index e87bfca1f5..e5d1e1168e 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -194,7 +194,7 @@ static void macio_gpio_nmi(NMIState *n, int cpu_index, Error **errp) macio_set_gpio(MACIO_GPIO(n), 9, false); } -static void macio_gpio_class_init(ObjectClass *oc, void *data) +static void macio_gpio_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index de0f934f7d..b2b42dd562 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -917,7 +917,7 @@ static void mac_dbdma_realize(DeviceState *dev, Error **errp) s->bh = qemu_bh_new_guarded(DBDMA_run_bh, s, &dev->mem_reentrancy_guard); } -static void mac_dbdma_class_init(ObjectClass *oc, void *data) +static void mac_dbdma_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 194b152eff..b0418db49e 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -385,7 +385,7 @@ static const VMStateDescription vmstate_macio_oldworld = { } }; -static void macio_oldworld_class_init(ObjectClass *oc, void *data) +static void macio_oldworld_class_init(ObjectClass *oc, const void *data) { PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -410,7 +410,7 @@ static const Property macio_newworld_properties[] = { DEFINE_PROP_BOOL("has-adb", NewWorldMacIOState, has_adb, false), }; -static void macio_newworld_class_init(ObjectClass *oc, void *data) +static void macio_newworld_class_init(ObjectClass *oc, const void *data) { PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -425,7 +425,7 @@ static const Property macio_properties[] = { DEFINE_PROP_UINT64("frequency", MacIOState, frequency, 0), }; -static void macio_class_init(ObjectClass *klass, void *data) +static void macio_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/macio/pmu.c b/hw/misc/macio/pmu.c index 73190559a8..3734913994 100644 --- a/hw/misc/macio/pmu.c +++ b/hw/misc/macio/pmu.c @@ -764,7 +764,7 @@ static const Property pmu_properties[] = { DEFINE_PROP_BOOL("has-adb", PMUState, has_adb, true), }; -static void pmu_class_init(ObjectClass *oc, void *data) +static void pmu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -808,7 +808,7 @@ static void mos6522_pmu_reset_hold(Object *obj, ResetType type) s->last_b = ms->b = TACK | TREQ; } -static void mos6522_pmu_class_init(ObjectClass *oc, void *data) +static void mos6522_pmu_class_init(ObjectClass *oc, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(oc); MOS6522DeviceClass *mdc = MOS6522_CLASS(oc); diff --git a/hw/misc/mchp_pfsoc_dmc.c b/hw/misc/mchp_pfsoc_dmc.c index 43d8e970ab..599f845f45 100644 --- a/hw/misc/mchp_pfsoc_dmc.c +++ b/hw/misc/mchp_pfsoc_dmc.c @@ -110,7 +110,8 @@ static void mchp_pfsoc_ddr_sgmii_phy_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->sgmii_phy); } -static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, void *data) +static void mchp_pfsoc_ddr_sgmii_phy_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -192,7 +193,7 @@ static void mchp_pfsoc_ddr_cfg_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->cfg); } -static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, void *data) +static void mchp_pfsoc_ddr_cfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mchp_pfsoc_ioscb.c b/hw/misc/mchp_pfsoc_ioscb.c index a71d134295..10fc7ea2a9 100644 --- a/hw/misc/mchp_pfsoc_ioscb.c +++ b/hw/misc/mchp_pfsoc_ioscb.c @@ -292,7 +292,7 @@ static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); } -static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data) +static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c index 7876fe0c5b..bfa78d3d2f 100644 --- a/hw/misc/mchp_pfsoc_sysreg.c +++ b/hw/misc/mchp_pfsoc_sysreg.c @@ -85,7 +85,7 @@ static void mchp_pfsoc_sysreg_realize(DeviceState *dev, Error **errp) sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); } -static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, void *data) +static void mchp_pfsoc_sysreg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mips_cmgcr.c b/hw/misc/mips_cmgcr.c index 95f19912b4..5484b73967 100644 --- a/hw/misc/mips_cmgcr.c +++ b/hw/misc/mips_cmgcr.c @@ -229,7 +229,7 @@ static void mips_gcr_realize(DeviceState *dev, Error **errp) s->vps = g_new(MIPSGCRVPState, s->num_vps); } -static void mips_gcr_class_init(ObjectClass *klass, void *data) +static void mips_gcr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, mips_gcr_properties); diff --git a/hw/misc/mips_cpc.c b/hw/misc/mips_cpc.c index b7a13d1afb..9bfb7c9721 100644 --- a/hw/misc/mips_cpc.c +++ b/hw/misc/mips_cpc.c @@ -166,7 +166,7 @@ static const Property mips_cpc_properties[] = { DEFINE_PROP_UINT64("vp-start-running", MIPSCPCState, vp_start_running, 0x1), }; -static void mips_cpc_class_init(ObjectClass *klass, void *data) +static void mips_cpc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mips_itu.c b/hw/misc/mips_itu.c index 2d126ebaf8..fc17385cde 100644 --- a/hw/misc/mips_itu.c +++ b/hw/misc/mips_itu.c @@ -540,7 +540,7 @@ static const Property mips_itu_properties[] = { ITC_SEMAPH_NUM_MAX), }; -static void mips_itu_class_init(ObjectClass *klass, void *data) +static void mips_itu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mos6522.c b/hw/misc/mos6522.c index 0b8f6a4cb4..8dd6b82ac5 100644 --- a/hw/misc/mos6522.c +++ b/hw/misc/mos6522.c @@ -700,7 +700,7 @@ static const Property mos6522_properties[] = { DEFINE_PROP_UINT64("frequency", MOS6522State, frequency, 0), }; -static void mos6522_class_init(ObjectClass *oc, void *data) +static void mos6522_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/misc/mps2-fpgaio.c b/hw/misc/mps2-fpgaio.c index 04a3da5db0..bee1309f5a 100644 --- a/hw/misc/mps2-fpgaio.c +++ b/hw/misc/mps2-fpgaio.c @@ -328,7 +328,7 @@ static const Property mps2_fpgaio_properties[] = { DEFINE_PROP_BOOL("has-dbgctrl", MPS2FPGAIO, has_dbgctrl, false), }; -static void mps2_fpgaio_class_init(ObjectClass *klass, void *data) +static void mps2_fpgaio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/mps2-scc.c b/hw/misc/mps2-scc.c index 5f8d6bca43..a9a5d4a535 100644 --- a/hw/misc/mps2-scc.c +++ b/hw/misc/mps2-scc.c @@ -474,7 +474,7 @@ static const Property mps2_scc_properties[] = { qdev_prop_uint32, uint32_t), }; -static void mps2_scc_class_init(ObjectClass *klass, void *data) +static void mps2_scc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/msf2-sysreg.c b/hw/misc/msf2-sysreg.c index 20009adbd9..ce0ad50c1b 100644 --- a/hw/misc/msf2-sysreg.c +++ b/hw/misc/msf2-sysreg.c @@ -136,7 +136,7 @@ static void msf2_sysreg_realize(DeviceState *dev, Error **errp) } } -static void msf2_sysreg_class_init(ObjectClass *klass, void *data) +static void msf2_sysreg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/npcm7xx_mft.c b/hw/misc/npcm7xx_mft.c index e565cac05d..b35e971fe5 100644 --- a/hw/misc/npcm7xx_mft.c +++ b/hw/misc/npcm7xx_mft.c @@ -515,7 +515,7 @@ static const VMStateDescription vmstate_npcm7xx_mft = { }, }; -static void npcm7xx_mft_class_init(ObjectClass *klass, void *data) +static void npcm7xx_mft_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/npcm7xx_pwm.c b/hw/misc/npcm7xx_pwm.c index f7f77e30a2..2de18d09b8 100644 --- a/hw/misc/npcm7xx_pwm.c +++ b/hw/misc/npcm7xx_pwm.c @@ -543,7 +543,7 @@ static const VMStateDescription vmstate_npcm7xx_pwm_module = { }, }; -static void npcm7xx_pwm_class_init(ObjectClass *klass, void *data) +static void npcm7xx_pwm_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/npcm7xx_rng.c b/hw/misc/npcm7xx_rng.c index 7f7e5eca62..7d47a1caa0 100644 --- a/hw/misc/npcm7xx_rng.c +++ b/hw/misc/npcm7xx_rng.c @@ -158,7 +158,7 @@ static const VMStateDescription vmstate_npcm7xx_rng = { }, }; -static void npcm7xx_rng_class_init(ObjectClass *klass, void *data) +static void npcm7xx_rng_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/npcm_clk.c b/hw/misc/npcm_clk.c index b6a893ffb2..c48d40b446 100644 --- a/hw/misc/npcm_clk.c +++ b/hw/misc/npcm_clk.c @@ -1102,7 +1102,7 @@ static const VMStateDescription vmstate_npcm_clk = { }, }; -static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data) +static void npcm7xx_clk_pll_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1112,7 +1112,7 @@ static void npcm7xx_clk_pll_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data) +static void npcm7xx_clk_sel_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1122,7 +1122,7 @@ static void npcm7xx_clk_sel_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data) +static void npcm7xx_clk_divider_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1132,7 +1132,7 @@ static void npcm7xx_clk_divider_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void npcm_clk_class_init(ObjectClass *klass, void *data) +static void npcm_clk_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -1142,7 +1142,7 @@ static void npcm_clk_class_init(ObjectClass *klass, void *data) rc->phases.enter = npcm_clk_enter_reset; } -static void npcm7xx_clk_class_init(ObjectClass *klass, void *data) +static void npcm7xx_clk_class_init(ObjectClass *klass, const void *data) { NPCMCLKClass *c = NPCM_CLK_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -1152,7 +1152,7 @@ static void npcm7xx_clk_class_init(ObjectClass *klass, void *data) c->cold_reset_values = npcm7xx_cold_reset_values; } -static void npcm8xx_clk_class_init(ObjectClass *klass, void *data) +static void npcm8xx_clk_class_init(ObjectClass *klass, const void *data) { NPCMCLKClass *c = NPCM_CLK_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/npcm_gcr.c b/hw/misc/npcm_gcr.c index 4e8ce2cb89..2acaa16771 100644 --- a/hw/misc/npcm_gcr.c +++ b/hw/misc/npcm_gcr.c @@ -422,7 +422,7 @@ static const Property npcm_gcr_properties[] = { DEFINE_PROP_UINT32("power-on-straps", NPCMGCRState, reset_pwron, 0), }; -static void npcm_gcr_class_init(ObjectClass *klass, void *data) +static void npcm_gcr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -432,7 +432,7 @@ static void npcm_gcr_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, npcm_gcr_properties); } -static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data) +static void npcm7xx_gcr_class_init(ObjectClass *klass, const void *data) { NPCMGCRClass *c = NPCM_GCR_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -446,7 +446,7 @@ static void npcm7xx_gcr_class_init(ObjectClass *klass, void *data) rc->phases.enter = npcm7xx_gcr_enter_reset; } -static void npcm8xx_gcr_class_init(ObjectClass *klass, void *data) +static void npcm8xx_gcr_class_init(ObjectClass *klass, const void *data) { NPCMGCRClass *c = NPCM_GCR_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/nrf51_rng.c b/hw/misc/nrf51_rng.c index 1e67acdf23..8cd7ffe3f5 100644 --- a/hw/misc/nrf51_rng.c +++ b/hw/misc/nrf51_rng.c @@ -240,7 +240,7 @@ static const VMStateDescription vmstate_rng = { } }; -static void nrf51_rng_class_init(ObjectClass *klass, void *data) +static void nrf51_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/pc-testdev.c b/hw/misc/pc-testdev.c index e389651869..67c486f347 100644 --- a/hw/misc/pc-testdev.c +++ b/hw/misc/pc-testdev.c @@ -193,7 +193,7 @@ static void testdev_realizefn(DeviceState *d, Error **errp) memory_region_add_subregion(mem, 0xff000000, &dev->iomem); } -static void testdev_class_init(ObjectClass *klass, void *data) +static void testdev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index f6718a7c37..0ea26451f1 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -323,7 +323,7 @@ static const Property pci_testdev_properties[] = { DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0), }; -static void pci_testdev_class_init(ObjectClass *klass, void *data) +static void pci_testdev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index c3713dc5c4..55522ee56c 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -104,7 +104,7 @@ static const Property pvpanic_isa_properties[] = { PVPANIC_EVENTS), }; -static void pvpanic_isa_class_init(ObjectClass *klass, void *data) +static void pvpanic_isa_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); diff --git a/hw/misc/pvpanic-mmio.c b/hw/misc/pvpanic-mmio.c index 70097cecc7..2a363106b2 100644 --- a/hw/misc/pvpanic-mmio.c +++ b/hw/misc/pvpanic-mmio.c @@ -36,7 +36,7 @@ static const Property pvpanic_mmio_properties[] = { PVPANIC_PANICKED | PVPANIC_CRASH_LOADED), }; -static void pvpanic_mmio_class_init(ObjectClass *klass, void *data) +static void pvpanic_mmio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index e5f0788ec0..51ebf66107 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -58,7 +58,7 @@ static const Property pvpanic_pci_properties[] = { PVPANIC_EVENTS), }; -static void pvpanic_pci_class_init(ObjectClass *klass, void *data) +static void pvpanic_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pc = PCI_DEVICE_CLASS(klass); diff --git a/hw/misc/sbsa_ec.c b/hw/misc/sbsa_ec.c index a1e813691e..dfee1af5ad 100644 --- a/hw/misc/sbsa_ec.c +++ b/hw/misc/sbsa_ec.c @@ -73,7 +73,7 @@ static void sbsa_ec_init(Object *obj) sysbus_init_mmio(dev, &s->iomem); } -static void sbsa_ec_class_init(ObjectClass *klass, void *data) +static void sbsa_ec_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/sifive_e_aon.c b/hw/misc/sifive_e_aon.c index 17a522ccf9..6eef38d622 100644 --- a/hw/misc/sifive_e_aon.c +++ b/hw/misc/sifive_e_aon.c @@ -294,7 +294,7 @@ static const Property sifive_e_aon_properties[] = { SIFIVE_E_LFCLK_DEFAULT_FREQ), }; -static void sifive_e_aon_class_init(ObjectClass *oc, void *data) +static void sifive_e_aon_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index d6df867fbd..1ebed2fd8b 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -270,7 +270,7 @@ static void sifive_u_otp_realize(DeviceState *dev, Error **errp) memset(s->fuse_wo, 0x00, sizeof(s->fuse_wo)); } -static void sifive_u_otp_class_init(ObjectClass *klass, void *data) +static void sifive_u_otp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/sifive_u_prci.c b/hw/misc/sifive_u_prci.c index cafe6a66f4..6e75cb6d0d 100644 --- a/hw/misc/sifive_u_prci.c +++ b/hw/misc/sifive_u_prci.c @@ -146,7 +146,7 @@ static void sifive_u_prci_reset(DeviceState *dev) s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK; } -static void sifive_u_prci_class_init(ObjectClass *klass, void *data) +static void sifive_u_prci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/slavio_misc.c b/hw/misc/slavio_misc.c index dace6d28cc..a034df3592 100644 --- a/hw/misc/slavio_misc.c +++ b/hw/misc/slavio_misc.c @@ -483,7 +483,7 @@ static void slavio_misc_init(Object *obj) qdev_init_gpio_in(dev, slavio_set_power_fail, 1); } -static void slavio_misc_class_init(ObjectClass *klass, void *data) +static void slavio_misc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/stm32_rcc.c b/hw/misc/stm32_rcc.c index 26672b5b24..94e8dae441 100644 --- a/hw/misc/stm32_rcc.c +++ b/hw/misc/stm32_rcc.c @@ -138,7 +138,7 @@ static const VMStateDescription vmstate_stm32_rcc = { } }; -static void stm32_rcc_class_init(ObjectClass *klass, void *data) +static void stm32_rcc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c index 6c7b722274..d285896ea7 100644 --- a/hw/misc/stm32f2xx_syscfg.c +++ b/hw/misc/stm32f2xx_syscfg.c @@ -138,7 +138,7 @@ static void stm32f2xx_syscfg_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } -static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data) +static void stm32f2xx_syscfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/stm32f4xx_exti.c b/hw/misc/stm32f4xx_exti.c index efd996df94..0688e6e73e 100644 --- a/hw/misc/stm32f4xx_exti.c +++ b/hw/misc/stm32f4xx_exti.c @@ -164,7 +164,7 @@ static const VMStateDescription vmstate_stm32f4xx_exti = { } }; -static void stm32f4xx_exti_class_init(ObjectClass *klass, void *data) +static void stm32f4xx_exti_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/stm32f4xx_syscfg.c b/hw/misc/stm32f4xx_syscfg.c index 7d0f3eb5f5..addfb031e8 100644 --- a/hw/misc/stm32f4xx_syscfg.c +++ b/hw/misc/stm32f4xx_syscfg.c @@ -147,7 +147,7 @@ static const VMStateDescription vmstate_stm32f4xx_syscfg = { } }; -static void stm32f4xx_syscfg_class_init(ObjectClass *klass, void *data) +static void stm32f4xx_syscfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/stm32l4x5_exti.c b/hw/misc/stm32l4x5_exti.c index e281841dcf..9c002164c8 100644 --- a/hw/misc/stm32l4x5_exti.c +++ b/hw/misc/stm32l4x5_exti.c @@ -271,7 +271,7 @@ static const VMStateDescription vmstate_stm32l4x5_exti = { } }; -static void stm32l4x5_exti_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_exti_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/stm32l4x5_rcc.c b/hw/misc/stm32l4x5_rcc.c index 158b743cae..0e1f27fbdd 100644 --- a/hw/misc/stm32l4x5_rcc.c +++ b/hw/misc/stm32l4x5_rcc.c @@ -141,7 +141,7 @@ static const VMStateDescription clock_mux_vmstate = { } }; -static void clock_mux_class_init(ObjectClass *klass, void *data) +static void clock_mux_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -295,7 +295,7 @@ static const VMStateDescription pll_vmstate = { } }; -static void pll_class_init(ObjectClass *klass, void *data) +static void pll_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -1439,7 +1439,7 @@ static const Property stm32l4x5_rcc_properties[] = { sai2_extclk_frequency, 0), }; -static void stm32l4x5_rcc_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_rcc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/stm32l4x5_syscfg.c b/hw/misc/stm32l4x5_syscfg.c index a947a9e036..4e21756e0b 100644 --- a/hw/misc/stm32l4x5_syscfg.c +++ b/hw/misc/stm32l4x5_syscfg.c @@ -259,7 +259,7 @@ static const VMStateDescription vmstate_stm32l4x5_syscfg = { } }; -static void stm32l4x5_syscfg_class_init(ObjectClass *klass, void *data) +static void stm32l4x5_syscfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/tz-mpc.c b/hw/misc/tz-mpc.c index 6d827d21dc..a158d4a294 100644 --- a/hw/misc/tz-mpc.c +++ b/hw/misc/tz-mpc.c @@ -592,7 +592,7 @@ static const Property tz_mpc_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void tz_mpc_class_init(ObjectClass *klass, void *data) +static void tz_mpc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -611,7 +611,7 @@ static const TypeInfo tz_mpc_info = { }; static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/misc/tz-msc.c b/hw/misc/tz-msc.c index 505df4e190..af0cc5d471 100644 --- a/hw/misc/tz-msc.c +++ b/hw/misc/tz-msc.c @@ -285,7 +285,7 @@ static const Property tz_msc_properties[] = { TYPE_IDAU_INTERFACE, IDAUInterface *), }; -static void tz_msc_class_init(ObjectClass *klass, void *data) +static void tz_msc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/tz-ppc.c b/hw/misc/tz-ppc.c index 1daa54c5e6..e4235a846d 100644 --- a/hw/misc/tz-ppc.c +++ b/hw/misc/tz-ppc.c @@ -325,7 +325,7 @@ static const Property tz_ppc_properties[] = { DEFINE_PORT(15), }; -static void tz_ppc_class_init(ObjectClass *klass, void *data) +static void tz_ppc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/unimp.c b/hw/misc/unimp.c index 257282a3a9..4370c14ef1 100644 --- a/hw/misc/unimp.c +++ b/hw/misc/unimp.c @@ -75,7 +75,7 @@ static const Property unimp_properties[] = { DEFINE_PROP_STRING("name", UnimplementedDeviceState, name), }; -static void unimp_class_init(ObjectClass *klass, void *data) +static void unimp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/virt_ctrl.c b/hw/misc/virt_ctrl.c index a210a5924c..9f16093ca2 100644 --- a/hw/misc/virt_ctrl.c +++ b/hw/misc/virt_ctrl.c @@ -125,7 +125,7 @@ static void virt_ctrl_instance_init(Object *obj) sysbus_init_irq(dev, &s->irq); } -static void virt_ctrl_class_init(ObjectClass *oc, void *data) +static void virt_ctrl_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/misc/vmcoreinfo.c b/hw/misc/vmcoreinfo.c index b0145fa504..9c2e9005ad 100644 --- a/hw/misc/vmcoreinfo.c +++ b/hw/misc/vmcoreinfo.c @@ -83,7 +83,7 @@ static const VMStateDescription vmstate_vmcoreinfo = { }, }; -static void vmcoreinfo_device_class_init(ObjectClass *klass, void *data) +static void vmcoreinfo_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-cframe-reg.c b/hw/misc/xlnx-versal-cframe-reg.c index 8db0f7e658..e28d569ebe 100644 --- a/hw/misc/xlnx-versal-cframe-reg.c +++ b/hw/misc/xlnx-versal-cframe-reg.c @@ -803,7 +803,7 @@ static const Property cframe_bcast_regs_props[] = { TYPE_XLNX_CFI_IF, XlnxCfiIf *), }; -static void cframe_reg_class_init(ObjectClass *klass, void *data) +static void cframe_reg_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -817,7 +817,7 @@ static void cframe_reg_class_init(ObjectClass *klass, void *data) xcic->cfi_transfer_packet = cframe_reg_cfi_transfer_packet; } -static void cframe_bcast_reg_class_init(ObjectClass *klass, void *data) +static void cframe_bcast_reg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-cfu.c b/hw/misc/xlnx-versal-cfu.c index 26d06e2557..02e4fed05b 100644 --- a/hw/misc/xlnx-versal-cfu.c +++ b/hw/misc/xlnx-versal-cfu.c @@ -496,7 +496,7 @@ static const VMStateDescription vmstate_cfu_sfr = { } }; -static void cfu_apb_class_init(ObjectClass *klass, void *data) +static void cfu_apb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -505,7 +505,7 @@ static void cfu_apb_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, cfu_props); } -static void cfu_fdro_class_init(ObjectClass *klass, void *data) +static void cfu_fdro_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -516,7 +516,7 @@ static void cfu_fdro_class_init(ObjectClass *klass, void *data) rc->phases.enter = cfu_fdro_reset_enter; } -static void cfu_sfr_class_init(ObjectClass *klass, void *data) +static void cfu_sfr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-crl.c b/hw/misc/xlnx-versal-crl.c index f143900d5b..08ff2fcc24 100644 --- a/hw/misc/xlnx-versal-crl.c +++ b/hw/misc/xlnx-versal-crl.c @@ -394,7 +394,7 @@ static const VMStateDescription vmstate_crl = { } }; -static void crl_class_init(ObjectClass *klass, void *data) +static void crl_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-pmc-iou-slcr.c b/hw/misc/xlnx-versal-pmc-iou-slcr.c index e469c04d76..d76df468d4 100644 --- a/hw/misc/xlnx-versal-pmc-iou-slcr.c +++ b/hw/misc/xlnx-versal-pmc-iou-slcr.c @@ -1419,7 +1419,8 @@ static const VMStateDescription vmstate_pmc_iou_slcr = { } }; -static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass, void *data) +static void xlnx_versal_pmc_iou_slcr_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-trng.c b/hw/misc/xlnx-versal-trng.c index ba93f93cab..f34dd3ef35 100644 --- a/hw/misc/xlnx-versal-trng.c +++ b/hw/misc/xlnx-versal-trng.c @@ -682,7 +682,7 @@ static const VMStateDescription vmstate_trng = { } }; -static void trng_class_init(ObjectClass *klass, void *data) +static void trng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/misc/xlnx-versal-xramc.c b/hw/misc/xlnx-versal-xramc.c index d1e76be027..07370b80c0 100644 --- a/hw/misc/xlnx-versal-xramc.c +++ b/hw/misc/xlnx-versal-xramc.c @@ -222,7 +222,7 @@ static const Property xram_ctrl_properties[] = { DEFINE_PROP_UINT64("size", XlnxXramCtrl, cfg.size, 1 * MiB), }; -static void xram_ctrl_class_init(ObjectClass *klass, void *data) +static void xram_ctrl_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/xlnx-zynqmp-apu-ctrl.c b/hw/misc/xlnx-zynqmp-apu-ctrl.c index 87e4a14067..e85da32d99 100644 --- a/hw/misc/xlnx-zynqmp-apu-ctrl.c +++ b/hw/misc/xlnx-zynqmp-apu-ctrl.c @@ -224,7 +224,7 @@ static const VMStateDescription vmstate_zynqmp_apu = { } }; -static void zynqmp_apu_class_init(ObjectClass *klass, void *data) +static void zynqmp_apu_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/xlnx-zynqmp-crf.c b/hw/misc/xlnx-zynqmp-crf.c index e5aba56f69..cccca0e814 100644 --- a/hw/misc/xlnx-zynqmp-crf.c +++ b/hw/misc/xlnx-zynqmp-crf.c @@ -239,7 +239,7 @@ static const VMStateDescription vmstate_crf = { } }; -static void crf_class_init(ObjectClass *klass, void *data) +static void crf_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/misc/zynq_slcr.c b/hw/misc/zynq_slcr.c index a766bab182..010387beec 100644 --- a/hw/misc/zynq_slcr.c +++ b/hw/misc/zynq_slcr.c @@ -627,7 +627,7 @@ static const Property zynq_slcr_props[] = { DEFINE_PROP_UINT8("boot-mode", ZynqSLCRState, boot_mode, 1), }; -static void zynq_slcr_class_init(ObjectClass *klass, void *data) +static void zynq_slcr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index 5adb41dc46..30a81576b4 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -875,7 +875,8 @@ static const VMStateDescription vmstate_aw_emac = { } }; -static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data) +static void allwinner_sun8i_emac_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index 47f1e7f086..77d089d988 100644 --- a/hw/net/allwinner_emac.c +++ b/hw/net/allwinner_emac.c @@ -514,7 +514,7 @@ static const VMStateDescription vmstate_aw_emac = { } }; -static void aw_emac_class_init(ObjectClass *klass, void *data) +static void aw_emac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 80fbbacc1e..50025d5a6f 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -1817,7 +1817,7 @@ static const Property gem_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void gem_class_init(ObjectClass *klass, void *data) +static void gem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c index 9e363d532f..c0bb598bae 100644 --- a/hw/net/can/can_kvaser_pci.c +++ b/hw/net/can/can_kvaser_pci.c @@ -282,7 +282,7 @@ static void kvaser_pci_instance_init(Object *obj) 0); } -static void kvaser_pci_class_init(ObjectClass *klass, void *data) +static void kvaser_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c index 580f099e00..9aac70dccd 100644 --- a/hw/net/can/can_mioe3680_pci.c +++ b/hw/net/can/can_mioe3680_pci.c @@ -223,7 +223,7 @@ static void mioe3680_pci_instance_init(Object *obj) 0); } -static void mioe3680_pci_class_init(ObjectClass *klass, void *data) +static void mioe3680_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c index 3195b79954..b305f7e9b7 100644 --- a/hw/net/can/can_pcm3680_pci.c +++ b/hw/net/can/can_pcm3680_pci.c @@ -224,7 +224,7 @@ static void pcm3680i_pci_instance_init(Object *obj) 0); } -static void pcm3680i_pci_class_init(ObjectClass *klass, void *data) +static void pcm3680i_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c index a8c77b9194..0dee9b59d1 100644 --- a/hw/net/can/ctucan_pci.c +++ b/hw/net/can/ctucan_pci.c @@ -237,7 +237,7 @@ static void ctucan_pci_instance_init(Object *obj) #endif } -static void ctucan_pci_class_init(ObjectClass *klass, void *data) +static void ctucan_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c index b5a4a4af7e..79ccc10098 100644 --- a/hw/net/can/xlnx-versal-canfd.c +++ b/hw/net/can/xlnx-versal-canfd.c @@ -2052,7 +2052,7 @@ static const Property canfd_core_properties[] = { CanBusState *), }; -static void canfd_class_init(ObjectClass *klass, void *data) +static void canfd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/can/xlnx-zynqmp-can.c b/hw/net/can/xlnx-zynqmp-can.c index 9fbdeea368..ca9edd4a5b 100644 --- a/hw/net/can/xlnx-zynqmp-can.c +++ b/hw/net/can/xlnx-zynqmp-can.c @@ -1176,7 +1176,7 @@ static const Property xlnx_zynqmp_can_properties[] = { CanBusState *), }; -static void xlnx_zynqmp_can_class_init(ObjectClass *klass, void *data) +static void xlnx_zynqmp_can_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index c80ddb12e3..d49032059b 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -939,7 +939,7 @@ static const Property dp8393x_properties[] = { DEFINE_PROP_BOOL("big_endian", dp8393xState, big_endian, false), }; -static void dp8393x_class_init(ObjectClass *klass, void *data) +static void dp8393x_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 3d0b227703..d49730f4ad 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1694,7 +1694,7 @@ typedef struct E1000Info { uint16_t phy_id2; } E1000Info; -static void e1000_class_init(ObjectClass *klass, void *data) +static void e1000_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index b72cbab7e8..f38249a6a9 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -673,7 +673,7 @@ static const Property e1000e_properties[] = { DEFINE_PROP_BOOL("migrate-timadj", E1000EState, timadj, true), }; -static void e1000e_class_init(ObjectClass *class, void *data) +static void e1000e_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index 29a39865a6..ef0f9337a0 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -2060,7 +2060,7 @@ static const Property e100_properties[] = { DEFINE_NIC_PROPERTIES(EEPRO100State, conf), }; -static void eepro100_class_init(ObjectClass *klass, void *data) +static void eepro100_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/fsl_etsec/etsec.c b/hw/net/fsl_etsec/etsec.c index adde644892..d14cb2a101 100644 --- a/hw/net/fsl_etsec/etsec.c +++ b/hw/net/fsl_etsec/etsec.c @@ -418,7 +418,7 @@ static const Property etsec_properties[] = { DEFINE_NIC_PROPERTIES(eTSEC, conf), }; -static void etsec_class_init(ObjectClass *klass, void *data) +static void etsec_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 1f524d7a01..c41ce889cf 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -1260,7 +1260,7 @@ static const Property ftgmac100_properties[] = { DEFINE_PROP_BOOL("dma64", FTGMAC100State, dma64, false), }; -static void ftgmac100_class_init(ObjectClass *klass, void *data) +static void ftgmac100_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1419,7 +1419,7 @@ static const Property aspeed_mii_properties[] = { FTGMAC100State *), }; -static void aspeed_mii_class_init(ObjectClass *klass, void *data) +static void aspeed_mii_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/igb.c b/hw/net/igb.c index e318df40e0..ba30433a50 100644 --- a/hw/net/igb.c +++ b/hw/net/igb.c @@ -599,7 +599,7 @@ static const Property igb_properties[] = { DEFINE_PROP_BOOL("x-pcie-flr-init", IGBState, has_flr, true), }; -static void igb_class_init(ObjectClass *class, void *data) +static void igb_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); ResettableClass *rc = RESETTABLE_CLASS(class); diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c index 21a97d4d61..91e7ccf931 100644 --- a/hw/net/igbvf.c +++ b/hw/net/igbvf.c @@ -299,7 +299,7 @@ static void igbvf_pci_uninit(PCIDevice *dev) msix_uninit(dev, &s->msix, &s->msix); } -static void igbvf_class_init(ObjectClass *class, void *data) +static void igbvf_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *c = PCI_DEVICE_CLASS(class); diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index b7c9ee0b9a..e5e34dd1a4 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1230,7 +1230,7 @@ static const Property imx_eth_properties[] = { IMXFECState *), }; -static void imx_eth_class_init(ObjectClass *klass, void *data) +static void imx_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/lan9118.c b/hw/net/lan9118.c index afee68c7db..6dda1e5c94 100644 --- a/hw/net/lan9118.c +++ b/hw/net/lan9118.c @@ -1309,7 +1309,7 @@ static const Property lan9118_properties[] = { DEFINE_PROP_UINT32("mode_16bit", lan9118_state, mode_16bit, 0), }; -static void lan9118_class_init(ObjectClass *klass, void *data) +static void lan9118_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/lan9118_phy.c b/hw/net/lan9118_phy.c index 5c53a4a1e3..4c4e03df11 100644 --- a/hw/net/lan9118_phy.c +++ b/hw/net/lan9118_phy.c @@ -200,7 +200,7 @@ static const VMStateDescription vmstate_lan9118_phy = { } }; -static void lan9118_phy_class_init(ObjectClass *klass, void *data) +static void lan9118_phy_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/lance.c b/hw/net/lance.c index 15492382f9..dfb855c23a 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -143,7 +143,7 @@ static const Property lance_properties[] = { DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf), }; -static void lance_class_init(ObjectClass *klass, void *data) +static void lance_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/lasi_i82596.c b/hw/net/lasi_i82596.c index cad01f5351..9e1dd21546 100644 --- a/hw/net/lasi_i82596.c +++ b/hw/net/lasi_i82596.c @@ -162,7 +162,7 @@ static const Property lasi_82596_properties[] = { DEFINE_NIC_PROPERTIES(SysBusI82596State, state.conf), }; -static void lasi_82596_class_init(ObjectClass *klass, void *data) +static void lasi_82596_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c index d5572a81d3..ae128fa311 100644 --- a/hw/net/mcf_fec.c +++ b/hw/net/mcf_fec.c @@ -664,7 +664,7 @@ static const Property mcf_fec_properties[] = { DEFINE_NIC_PROPERTIES(mcf_fec_state, conf), }; -static void mcf_fec_class_init(ObjectClass *oc, void *data) +static void mcf_fec_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/net/mipsnet.c b/hw/net/mipsnet.c index 8852b6f3a1..583aa1c7de 100644 --- a/hw/net/mipsnet.c +++ b/hw/net/mipsnet.c @@ -270,7 +270,7 @@ static const Property mipsnet_properties[] = { DEFINE_NIC_PROPERTIES(MIPSnetState, conf), }; -static void mipsnet_class_init(ObjectClass *klass, void *data) +static void mipsnet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/msf2-emac.c b/hw/net/msf2-emac.c index 80f75f19dd..59045973ab 100644 --- a/hw/net/msf2-emac.c +++ b/hw/net/msf2-emac.c @@ -565,7 +565,7 @@ static const VMStateDescription vmstate_msf2_emac = { } }; -static void msf2_emac_class_init(ObjectClass *klass, void *data) +static void msf2_emac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/mv88w8618_eth.c b/hw/net/mv88w8618_eth.c index 5a9d14bef6..6f08846c81 100644 --- a/hw/net/mv88w8618_eth.c +++ b/hw/net/mv88w8618_eth.c @@ -377,7 +377,7 @@ static const Property mv88w8618_eth_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void mv88w8618_eth_class_init(ObjectClass *klass, void *data) +static void mv88w8618_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/ne2000-isa.c b/hw/net/ne2000-isa.c index 20973651f3..673c785abc 100644 --- a/hw/net/ne2000-isa.c +++ b/hw/net/ne2000-isa.c @@ -85,7 +85,7 @@ static const Property ne2000_isa_properties[] = { DEFINE_NIC_PROPERTIES(ISANE2000State, ne2000.c), }; -static void isa_ne2000_class_initfn(ObjectClass *klass, void *data) +static void isa_ne2000_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c index 6840d0e720..2153973af4 100644 --- a/hw/net/ne2000-pci.c +++ b/hw/net/ne2000-pci.c @@ -100,7 +100,7 @@ static const Property ne2000_properties[] = { DEFINE_NIC_PROPERTIES(PCINE2000State, ne2000.c), }; -static void ne2000_class_init(ObjectClass *klass, void *data) +static void ne2000_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/npcm7xx_emc.c b/hw/net/npcm7xx_emc.c index e06f652629..9ba35e2c81 100644 --- a/hw/net/npcm7xx_emc.c +++ b/hw/net/npcm7xx_emc.c @@ -849,7 +849,7 @@ static const Property npcm7xx_emc_properties[] = { DEFINE_NIC_PROPERTIES(NPCM7xxEMCState, conf), }; -static void npcm7xx_emc_class_init(ObjectClass *klass, void *data) +static void npcm7xx_emc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/npcm_gmac.c b/hw/net/npcm_gmac.c index e1fb383772..a434112580 100644 --- a/hw/net/npcm_gmac.c +++ b/hw/net/npcm_gmac.c @@ -916,7 +916,7 @@ static const Property npcm_gmac_properties[] = { DEFINE_NIC_PROPERTIES(NPCMGMACState, conf), }; -static void npcm_gmac_class_init(ObjectClass *klass, void *data) +static void npcm_gmac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/npcm_pcs.c b/hw/net/npcm_pcs.c index ce5034e234..6aec105271 100644 --- a/hw/net/npcm_pcs.c +++ b/hw/net/npcm_pcs.c @@ -387,7 +387,7 @@ static const VMStateDescription vmstate_npcm_pcs = { }, }; -static void npcm_pcs_class_init(ObjectClass *klass, void *data) +static void npcm_pcs_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 54daab7b04..7e955c0132 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -747,7 +747,7 @@ static const Property open_eth_properties[] = { DEFINE_NIC_PROPERTIES(OpenEthState, conf), }; -static void open_eth_class_init(ObjectClass *klass, void *data) +static void open_eth_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index b314ea7d6d..429c217180 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -256,7 +256,7 @@ static const Property pcnet_properties[] = { DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), }; -static void pcnet_class_init(ObjectClass *klass, void *data) +static void pcnet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index aa5d87fbc5..3d307f4ab1 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -1475,7 +1475,7 @@ static const VMStateDescription rocker_vmsd = { .unmigratable = 1, }; -static void rocker_class_init(ObjectClass *klass, void *data) +static void rocker_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index 135ab57160..ad812954cf 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3414,7 +3414,7 @@ static const Property rtl8139_properties[] = { DEFINE_NIC_PROPERTIES(RTL8139State, conf), }; -static void rtl8139_class_init(ObjectClass *klass, void *data) +static void rtl8139_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index 9ce42b5615..5cd78e334b 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -913,7 +913,7 @@ static const Property smc91c111_properties[] = { DEFINE_NIC_PROPERTIES(smc91c111_state, conf), }; -static void smc91c111_class_init(ObjectClass *klass, void *data) +static void smc91c111_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 13fc6565f0..f6f217d632 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -848,7 +848,7 @@ static const VMStateDescription vmstate_spapr_llan = { } }; -static void spapr_vlan_class_init(ObjectClass *klass, void *data) +static void spapr_vlan_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c index a420732d48..2fc51e1e16 100644 --- a/hw/net/stellaris_enet.c +++ b/hw/net/stellaris_enet.c @@ -501,7 +501,7 @@ static const Property stellaris_enet_properties[] = { DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf), }; -static void stellaris_enet_class_init(ObjectClass *klass, void *data) +static void stellaris_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 12a9a9df46..123d08ee8e 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -1454,7 +1454,7 @@ static const VMStateDescription vmstate_sungem = { } }; -static void sungem_class_init(ObjectClass *klass, void *data) +static void sungem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index fa234d0da1..46c9f5020b 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -937,7 +937,7 @@ static const VMStateDescription vmstate_hme = { } }; -static void sunhme_class_init(ObjectClass *klass, void *data) +static void sunhme_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/tulip.c b/hw/net/tulip.c index a0646bb84c..fb3366d8ee 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -1011,7 +1011,7 @@ static const Property tulip_properties[] = { DEFINE_NIC_PROPERTIES(TULIPState, c), }; -static void tulip_class_init(ObjectClass *klass, void *data) +static void tulip_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index bd37651dab..2de037c273 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -4134,7 +4134,7 @@ static const Property virtio_net_properties[] = { VIRTIO_NET_F_HOST_USO, true), }; -static void virtio_net_class_init(ObjectClass *klass, void *data) +static void virtio_net_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index f370d4a2ec..4bcf1f902f 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2491,7 +2491,7 @@ static void vmxnet3_realize(DeviceState *qdev, Error **errp) vc->parent_dc_realize(qdev, errp); } -static void vmxnet3_class_init(ObjectClass *class, void *data) +static void vmxnet3_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *c = PCI_DEVICE_CLASS(class); diff --git a/hw/net/xen_nic.c b/hw/net/xen_nic.c index c48691207d..34c6a1d0b0 100644 --- a/hw/net/xen_nic.c +++ b/hw/net/xen_nic.c @@ -559,7 +559,7 @@ static const Property xen_netdev_properties[] = { DEFINE_PROP_INT32("idx", XenNetDev, dev, -1), }; -static void xen_netdev_class_init(ObjectClass *class, void *data) +static void xen_netdev_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); XenDeviceClass *xendev_class = XEN_DEVICE_CLASS(class); diff --git a/hw/net/xgmac.c b/hw/net/xgmac.c index e3cc4c60eb..9c87c4e70f 100644 --- a/hw/net/xgmac.c +++ b/hw/net/xgmac.c @@ -418,7 +418,7 @@ static const Property xgmac_properties[] = { DEFINE_NIC_PROPERTIES(XgmacState, conf), }; -static void xgmac_enet_class_init(ObjectClass *klass, void *data) +static void xgmac_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index 457952af19..e45bc048e0 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -1007,7 +1007,7 @@ static const Property xilinx_enet_properties[] = { tx_control_dev, TYPE_STREAM_SINK, StreamSink *), }; -static void xilinx_enet_class_init(ObjectClass *klass, void *data) +static void xilinx_enet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1017,14 +1017,15 @@ static void xilinx_enet_class_init(ObjectClass *klass, void *data) } static void xilinx_enet_control_stream_class_init(ObjectClass *klass, - void *data) + const void *data) { StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); ssc->push = xilinx_axienet_control_stream_push; } -static void xilinx_enet_data_stream_class_init(ObjectClass *klass, void *data) +static void xilinx_enet_data_stream_class_init(ObjectClass *klass, + const void *data) { StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index 15d9b95aa8..42b19d07c7 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -385,7 +385,7 @@ static const Property xilinx_ethlite_properties[] = { DEFINE_NIC_PROPERTIES(XlnxXpsEthLite, conf), }; -static void xilinx_ethlite_class_init(ObjectClass *klass, void *data) +static void xilinx_ethlite_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nubus/mac-nubus-bridge.c b/hw/nubus/mac-nubus-bridge.c index a0da5a8b2f..0dac8d19b3 100644 --- a/hw/nubus/mac-nubus-bridge.c +++ b/hw/nubus/mac-nubus-bridge.c @@ -40,7 +40,7 @@ static void mac_nubus_bridge_init(Object *obj) sysbus_init_mmio(sbd, &s->slot_alias); } -static void mac_nubus_bridge_class_init(ObjectClass *klass, void *data) +static void mac_nubus_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nubus/nubus-bridge.c b/hw/nubus/nubus-bridge.c index 8fe4362723..fb14402c4f 100644 --- a/hw/nubus/nubus-bridge.c +++ b/hw/nubus/nubus-bridge.c @@ -28,7 +28,7 @@ static const Property nubus_bridge_properties[] = { bus.slot_available_mask, 0xffff), }; -static void nubus_bridge_class_init(ObjectClass *klass, void *data) +static void nubus_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nubus/nubus-bus.c b/hw/nubus/nubus-bus.c index 07c279bde5..44820f13a8 100644 --- a/hw/nubus/nubus-bus.c +++ b/hw/nubus/nubus-bus.c @@ -162,7 +162,7 @@ static bool nubus_check_address(BusState *bus, DeviceState *dev, Error **errp) return true; } -static void nubus_class_init(ObjectClass *oc, void *data) +static void nubus_class_init(ObjectClass *oc, const void *data) { BusClass *bc = BUS_CLASS(oc); diff --git a/hw/nubus/nubus-device.c b/hw/nubus/nubus-device.c index 6755c3dc43..7797e61c7f 100644 --- a/hw/nubus/nubus-device.c +++ b/hw/nubus/nubus-device.c @@ -112,7 +112,7 @@ static const Property nubus_device_properties[] = { DEFINE_PROP_STRING("romfile", NubusDevice, romfile), }; -static void nubus_device_class_init(ObjectClass *oc, void *data) +static void nubus_device_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/nubus/nubus-virtio-mmio.c b/hw/nubus/nubus-virtio-mmio.c index 7a98731c45..63aeca5b12 100644 --- a/hw/nubus/nubus-virtio-mmio.c +++ b/hw/nubus/nubus-virtio-mmio.c @@ -81,7 +81,7 @@ static void nubus_virtio_mmio_init(Object *obj) "pic-input-irq", 1); } -static void nubus_virtio_mmio_class_init(ObjectClass *oc, void *data) +static void nubus_virtio_mmio_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); NubusVirtioMMIODeviceClass *nvmdc = NUBUS_VIRTIO_MMIO_CLASS(oc); diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index d6b77d4fbc..e87295f5f8 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -9183,7 +9183,7 @@ static const VMStateDescription nvme_vmstate = { .unmigratable = 1, }; -static void nvme_class_init(ObjectClass *oc, void *data) +static void nvme_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); diff --git a/hw/nvme/ns.c b/hw/nvme/ns.c index 4ab8ba74f5..6df2e8e7c5 100644 --- a/hw/nvme/ns.c +++ b/hw/nvme/ns.c @@ -806,7 +806,7 @@ static const Property nvme_ns_props[] = { DEFINE_PROP_STRING("fdp.ruhs", NvmeNamespace, params.fdp.ruhs), }; -static void nvme_ns_class_init(ObjectClass *oc, void *data) +static void nvme_ns_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index b617ac3892..38271d78c8 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -218,7 +218,7 @@ static const Property nvme_subsystem_props[] = { DEFINE_PROP_UINT16("fdp.nruh", NvmeSubsystem, params.fdp.nruh, 0), }; -static void nvme_subsys_class_init(ObjectClass *oc, void *data) +static void nvme_subsys_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/nvram/bcm2835_otp.c b/hw/nvram/bcm2835_otp.c index c4aed28472..6816b53417 100644 --- a/hw/nvram/bcm2835_otp.c +++ b/hw/nvram/bcm2835_otp.c @@ -164,7 +164,7 @@ static const VMStateDescription vmstate_bcm2835_otp = { } }; -static void bcm2835_otp_class_init(ObjectClass *klass, void *data) +static void bcm2835_otp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/ds1225y.c b/hw/nvram/ds1225y.c index 6b2aa8c7d2..dbfd0d2e53 100644 --- a/hw/nvram/ds1225y.c +++ b/hw/nvram/ds1225y.c @@ -147,7 +147,7 @@ static const Property nvram_sysbus_properties[] = { DEFINE_PROP_STRING("filename", SysBusNvRamState, nvram.filename), }; -static void nvram_sysbus_class_init(ObjectClass *klass, void *data) +static void nvram_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/eeprom_at24c.c b/hw/nvram/eeprom_at24c.c index ff7a21eee7..82ea97e552 100644 --- a/hw/nvram/eeprom_at24c.c +++ b/hw/nvram/eeprom_at24c.c @@ -235,7 +235,7 @@ static const Property at24c_eeprom_props[] = { }; static -void at24c_eeprom_class_init(ObjectClass *klass, void *data) +void at24c_eeprom_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index cbfb2b5303..237b9f7d1f 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -1228,7 +1228,7 @@ void load_image_to_fw_cfg(FWCfgState *fw_cfg, uint16_t size_key, fw_cfg_add_bytes(fw_cfg, data_key, data, size); } -static void fw_cfg_class_init(ObjectClass *klass, void *data) +static void fw_cfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1303,7 +1303,7 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp) fw_cfg_common_realize(dev, errp); } -static void fw_cfg_io_class_init(ObjectClass *klass, void *data) +static void fw_cfg_io_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1364,7 +1364,7 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp) fw_cfg_common_realize(dev, errp); } -static void fw_cfg_mem_class_init(ObjectClass *klass, void *data) +static void fw_cfg_mem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/mac_nvram.c b/hw/nvram/mac_nvram.c index 0d82e5a128..66526a2291 100644 --- a/hw/nvram/mac_nvram.c +++ b/hw/nvram/mac_nvram.c @@ -140,7 +140,7 @@ static const Property macio_nvram_properties[] = { DEFINE_PROP_DRIVE("drive", MacIONVRAMState, blk), }; -static void macio_nvram_class_init(ObjectClass *oc, void *data) +static void macio_nvram_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/nvram/npcm7xx_otp.c b/hw/nvram/npcm7xx_otp.c index f00ebfa931..1fb752b20f 100644 --- a/hw/nvram/npcm7xx_otp.c +++ b/hw/nvram/npcm7xx_otp.c @@ -391,7 +391,7 @@ static const VMStateDescription vmstate_npcm7xx_otp = { }, }; -static void npcm7xx_otp_class_init(ObjectClass *klass, void *data) +static void npcm7xx_otp_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -403,14 +403,14 @@ static void npcm7xx_otp_class_init(ObjectClass *klass, void *data) rc->phases.enter = npcm7xx_otp_enter_reset; } -static void npcm7xx_key_storage_class_init(ObjectClass *klass, void *data) +static void npcm7xx_key_storage_class_init(ObjectClass *klass, const void *data) { NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass); oc->mmio_ops = &npcm7xx_key_storage_ops; } -static void npcm7xx_fuse_array_class_init(ObjectClass *klass, void *data) +static void npcm7xx_fuse_array_class_init(ObjectClass *klass, const void *data) { NPCM7xxOTPClass *oc = NPCM7XX_OTP_CLASS(klass); diff --git a/hw/nvram/nrf51_nvm.c b/hw/nvram/nrf51_nvm.c index 2ed4078858..23cc9fe9b3 100644 --- a/hw/nvram/nrf51_nvm.c +++ b/hw/nvram/nrf51_nvm.c @@ -370,7 +370,7 @@ static const VMStateDescription vmstate_nvm = { } }; -static void nrf51_nvm_class_init(ObjectClass *klass, void *data) +static void nrf51_nvm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/spapr_nvram.c b/hw/nvram/spapr_nvram.c index a45827f6aa..d0ac4e5735 100644 --- a/hw/nvram/spapr_nvram.c +++ b/hw/nvram/spapr_nvram.c @@ -257,7 +257,7 @@ static const Property spapr_nvram_properties[] = { DEFINE_PROP_DRIVE("drive", SpaprNvram, blk), }; -static void spapr_nvram_class_init(ObjectClass *klass, void *data) +static void spapr_nvram_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/nvram/xlnx-bbram.c b/hw/nvram/xlnx-bbram.c index 14cc9073c7..5702bb3f31 100644 --- a/hw/nvram/xlnx-bbram.c +++ b/hw/nvram/xlnx-bbram.c @@ -525,7 +525,7 @@ static const Property bbram_ctrl_props[] = { DEFINE_PROP_UINT32("crc-zpads", XlnxBBRam, crc_zpads, 1), }; -static void bbram_ctrl_class_init(ObjectClass *klass, void *data) +static void bbram_ctrl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/nvram/xlnx-efuse.c b/hw/nvram/xlnx-efuse.c index 176e88fcd1..4c23f8b931 100644 --- a/hw/nvram/xlnx-efuse.c +++ b/hw/nvram/xlnx-efuse.c @@ -274,7 +274,7 @@ static const Property efuse_properties[] = { qdev_prop_uint32, uint32_t), }; -static void efuse_class_init(ObjectClass *klass, void *data) +static void efuse_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/xlnx-versal-efuse-cache.c b/hw/nvram/xlnx-versal-efuse-cache.c index 2fb599422c..d4ec96a626 100644 --- a/hw/nvram/xlnx-versal-efuse-cache.c +++ b/hw/nvram/xlnx-versal-efuse-cache.c @@ -89,7 +89,7 @@ static const Property efuse_cache_props[] = { TYPE_XLNX_EFUSE, XlnxEFuse *), }; -static void efuse_cache_class_init(ObjectClass *klass, void *data) +static void efuse_cache_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/nvram/xlnx-versal-efuse-ctrl.c b/hw/nvram/xlnx-versal-efuse-ctrl.c index ff4d544ad6..9096219800 100644 --- a/hw/nvram/xlnx-versal-efuse-ctrl.c +++ b/hw/nvram/xlnx-versal-efuse-ctrl.c @@ -751,7 +751,7 @@ static const Property efuse_ctrl_props[] = { extra_pg0_lock_spec, qdev_prop_uint16, uint16_t), }; -static void efuse_ctrl_class_init(ObjectClass *klass, void *data) +static void efuse_ctrl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/nvram/xlnx-zynqmp-efuse.c b/hw/nvram/xlnx-zynqmp-efuse.c index 15024daf4f..5a218c32e8 100644 --- a/hw/nvram/xlnx-zynqmp-efuse.c +++ b/hw/nvram/xlnx-zynqmp-efuse.c @@ -839,7 +839,7 @@ static const Property zynqmp_efuse_props[] = { TYPE_XLNX_EFUSE, XlnxEFuse *), }; -static void zynqmp_efuse_class_init(ObjectClass *klass, void *data) +static void zynqmp_efuse_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/openrisc/openrisc_sim.c b/hw/openrisc/openrisc_sim.c index c2284a7d41..880c8ebbb8 100644 --- a/hw/openrisc/openrisc_sim.c +++ b/hw/openrisc/openrisc_sim.c @@ -357,7 +357,7 @@ static void openrisc_sim_init(MachineState *machine) } } -static void openrisc_sim_machine_init(ObjectClass *oc, void *data) +static void openrisc_sim_machine_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/openrisc/virt.c b/hw/openrisc/virt.c index 0d1c1f103c..a98071c936 100644 --- a/hw/openrisc/virt.c +++ b/hw/openrisc/virt.c @@ -543,7 +543,7 @@ static void openrisc_virt_init(MachineState *machine) } } -static void openrisc_virt_machine_init(ObjectClass *oc, void *data) +static void openrisc_virt_machine_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c index e337f1ac50..ab3b550a88 100644 --- a/hw/pci-bridge/cxl_downstream.c +++ b/hw/pci-bridge/cxl_downstream.c @@ -219,7 +219,7 @@ static const Property cxl_dsp_props[] = { width, PCIE_LINK_WIDTH_16), }; -static void cxl_dsp_class_init(ObjectClass *oc, void *data) +static void cxl_dsp_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c index c0037f2cfb..8b1e149e9b 100644 --- a/hw/pci-bridge/cxl_root_port.c +++ b/hw/pci-bridge/cxl_root_port.c @@ -262,7 +262,7 @@ static void cxl_rp_write_config(PCIDevice *d, uint32_t address, uint32_t val, cxl_rp_dvsec_write_config(d, address, val, len); } -static void cxl_root_port_class_init(ObjectClass *oc, void *data) +static void cxl_root_port_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c index 28b109c49a..822a828555 100644 --- a/hw/pci-bridge/cxl_upstream.c +++ b/hw/pci-bridge/cxl_upstream.c @@ -371,7 +371,7 @@ static const Property cxl_upstream_props[] = { width, PCIE_LINK_WIDTH_16), }; -static void cxl_upstream_class_init(ObjectClass *oc, void *data) +static void cxl_upstream_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *k = PCI_DEVICE_CLASS(oc); diff --git a/hw/pci-bridge/gen_pcie_root_port.c b/hw/pci-bridge/gen_pcie_root_port.c index 3c0b41ef1a..d9078e783b 100644 --- a/hw/pci-bridge/gen_pcie_root_port.c +++ b/hw/pci-bridge/gen_pcie_root_port.c @@ -147,7 +147,7 @@ static const Property gen_rp_props[] = { width, PCIE_LINK_WIDTH_32), }; -static void gen_rp_dev_class_init(ObjectClass *klass, void *data) +static void gen_rp_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index 00d2fbd7cf..f2b294aee2 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -87,7 +87,7 @@ static const VMStateDescription i82801b11_bridge_dev_vmstate = { } }; -static void i82801b11_bridge_class_init(ObjectClass *klass, void *data) +static void i82801b11_bridge_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/ioh3420.c b/hw/pci-bridge/ioh3420.c index be752a4bda..bba640f495 100644 --- a/hw/pci-bridge/ioh3420.c +++ b/hw/pci-bridge/ioh3420.c @@ -96,7 +96,7 @@ static const VMStateDescription vmstate_ioh3420 = { } }; -static void ioh3420_class_init(ObjectClass *klass, void *data) +static void ioh3420_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 4931ea24f6..3b57583199 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -240,7 +240,7 @@ void pci_bridge_dev_unplug_request_cb(HotplugHandler *hotplug_dev, shpc_device_unplug_request_cb(hotplug_dev, dev, errp); } -static void pci_bridge_dev_class_init(ObjectClass *klass, void *data) +static void pci_bridge_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -280,7 +280,7 @@ static const TypeInfo pci_bridge_dev_info = { * different pci id, so we can match it easily in the guest for * automagic multiseat configuration. See docs/multiseat.txt for more. */ -static void pci_bridge_dev_seat_class_init(ObjectClass *klass, void *data) +static void pci_bridge_dev_seat_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 3396ab4bdd..1e2e394ee8 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -92,7 +92,7 @@ static void prop_pxb_uid_get(Object *obj, Visitor *v, const char *name, visit_type_uint32(v, name, &uid, errp); } -static void pxb_bus_class_init(ObjectClass *class, void *data) +static void pxb_bus_class_init(ObjectClass *class, const void *data) { PCIBusClass *pbc = PCI_BUS_CLASS(class); @@ -169,7 +169,7 @@ static char *pxb_host_ofw_unit_address(const SysBusDevice *dev) return NULL; } -static void pxb_host_class_init(ObjectClass *class, void *data) +static void pxb_host_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(class); @@ -224,7 +224,7 @@ void pxb_cxl_hook_up_registers(CXLState *cxl_state, PCIBus *bus, Error **errp) cxl_state->next_mr_idx++; } -static void pxb_cxl_host_class_init(ObjectClass *class, void *data) +static void pxb_cxl_host_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(class); @@ -427,7 +427,7 @@ static const Property pxb_dev_properties[] = { DEFINE_PROP_BOOL("bypass_iommu", PXBDev, bypass_iommu, false), }; -static void pxb_dev_class_init(ObjectClass *klass, void *data) +static void pxb_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -465,7 +465,7 @@ static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp) pxb_dev_realize_common(dev, PCIE, errp); } -static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data) +static void pxb_pcie_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -510,7 +510,7 @@ static const Property pxb_cxl_dev_properties[] = { DEFINE_PROP_BOOL("hdm_for_passthrough", PXBCXLDev, hdm_for_passthrough, false), }; -static void pxb_cxl_dev_class_init(ObjectClass *klass, void *data) +static void pxb_cxl_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c index 2429503cfb..833fe35cd5 100644 --- a/hw/pci-bridge/pcie_pci_bridge.c +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -137,7 +137,7 @@ static const VMStateDescription pcie_pci_bridge_dev_vmstate = { } }; -static void pcie_pci_bridge_class_init(ObjectClass *klass, void *data) +static void pcie_pci_bridge_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index dd40b366bf..512c2ab305 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -167,7 +167,7 @@ static void rp_instance_post_init(Object *obj) } } -static void rp_class_init(ObjectClass *klass, void *data) +static void rp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c index 5fe090df6c..c7565d9e94 100644 --- a/hw/pci-bridge/simba.c +++ b/hw/pci-bridge/simba.c @@ -66,7 +66,7 @@ static void simba_pci_bridge_realize(PCIDevice *dev, Error **errp) pci_bridge_update_mappings(PCI_BRIDGE(br)); } -static void simba_pci_bridge_class_init(ObjectClass *klass, void *data) +static void simba_pci_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index d4e94f2657..d85c23fe4a 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -153,7 +153,7 @@ static const VMStateDescription vmstate_xio3130_downstream = { } }; -static void xio3130_downstream_class_init(ObjectClass *klass, void *data) +static void xio3130_downstream_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index fb1547b74a..d7a2715812 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -123,7 +123,7 @@ static const VMStateDescription vmstate_xio3130_upstream = { } }; -static void xio3130_upstream_class_init(ObjectClass *klass, void *data) +static void xio3130_upstream_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c index f3fcc49f81..043fb85e84 100644 --- a/hw/pci-host/articia.c +++ b/hw/pci-host/articia.c @@ -195,7 +195,7 @@ static void articia_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq)); } -static void articia_class_init(ObjectClass *klass, void *data) +static void articia_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -228,7 +228,7 @@ static void articia_pci_host_cfg_write(PCIDevice *d, uint32_t addr, } } -static void articia_pci_host_class_init(ObjectClass *klass, void *data) +static void articia_pci_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -246,7 +246,7 @@ static void articia_pci_host_class_init(ObjectClass *klass, void *data) /* TYPE_ARTICIA_PCI_BRIDGE */ -static void articia_pci_bridge_class_init(ObjectClass *klass, void *data) +static void articia_pci_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-host/astro.c b/hw/pci-host/astro.c index c6f2d4f494..859e308c57 100644 --- a/hw/pci-host/astro.c +++ b/hw/pci-host/astro.c @@ -482,7 +482,7 @@ static const VMStateDescription vmstate_elroy = { } }; -static void elroy_pcihost_class_init(ObjectClass *klass, void *data) +static void elroy_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -909,7 +909,7 @@ static void astro_realize(DeviceState *obj, Error **errp) } } -static void astro_class_init(ObjectClass *klass, void *data) +static void astro_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -932,7 +932,7 @@ static const TypeInfo astro_chip_info = { }; static void astro_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 4966914892..4508cdd21a 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -757,7 +757,7 @@ PCIBus *bonito_init(qemu_irq *pic) return phb->bus; } -static void bonito_pci_class_init(ObjectClass *klass, void *data) +static void bonito_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -789,7 +789,7 @@ static const TypeInfo bonito_pci_info = { }, }; -static void bonito_host_class_init(ObjectClass *klass, void *data) +static void bonito_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index 9c3a5f8d91..d03c998e3a 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -56,7 +56,8 @@ #define DESIGNWARE_PCIE_ATU_DEVFN(x) (((x) >> 16) & 0xff) #define DESIGNWARE_PCIE_ATU_UPPER_TARGET 0x91C -static void designware_pcie_root_bus_class_init(ObjectClass *klass, void *data) +static void designware_pcie_root_bus_class_init(ObjectClass *klass, + const void *data) { BusClass *k = BUS_CLASS(klass); @@ -587,7 +588,8 @@ static const VMStateDescription vmstate_designware_pcie_root = { } }; -static void designware_pcie_root_class_init(ObjectClass *klass, void *data) +static void designware_pcie_root_class_init(ObjectClass *klass, + const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -727,7 +729,8 @@ static const VMStateDescription vmstate_designware_pcie_host = { } }; -static void designware_pcie_host_class_init(ObjectClass *klass, void *data) +static void designware_pcie_host_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); diff --git a/hw/pci-host/dino.c b/hw/pci-host/dino.c index 58fdbf7bc9..11b353be2e 100644 --- a/hw/pci-host/dino.c +++ b/hw/pci-host/dino.c @@ -497,7 +497,7 @@ static const Property dino_pcihost_properties[] = { MemoryRegion *), }; -static void dino_pcihost_class_init(ObjectClass *klass, void *data) +static void dino_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/fsl_imx8m_phy.c b/hw/pci-host/fsl_imx8m_phy.c index aa304b102b..04da3f99a0 100644 --- a/hw/pci-host/fsl_imx8m_phy.c +++ b/hw/pci-host/fsl_imx8m_phy.c @@ -76,7 +76,7 @@ static const VMStateDescription fsl_imx8m_pcie_phy_vmstate = { } }; -static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, void *data) +static void fsl_imx8m_pcie_phy_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index 9fcedd7fc5..7dcac4ee3c 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -192,7 +192,7 @@ static const Property gpex_host_properties[] = { DEFINE_PROP_UINT8("num-irqs", GPEXHost, num_irqs, PCI_NUM_PINS), }; -static void gpex_host_class_init(ObjectClass *klass, void *data) +static void gpex_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); @@ -237,7 +237,7 @@ static const VMStateDescription vmstate_gpex_root = { } }; -static void gpex_root_class_init(ObjectClass *klass, void *data) +static void gpex_root_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index 84e5ee8c6e..b48d44623d 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -94,7 +94,7 @@ static void grackle_pci_realize(PCIDevice *d, Error **errp) d->config[PCI_CLASS_PROG] = 0x01; } -static void grackle_pci_class_init(ObjectClass *klass, void *data) +static void grackle_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -133,7 +133,7 @@ static const Property grackle_properties[] = { DEFINE_PROP_UINT32("ofw-addr", GrackleState, ofw_addr, -1), }; -static void grackle_class_init(ObjectClass *klass, void *data) +static void grackle_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c index d5c13a89b6..bd74b6e871 100644 --- a/hw/pci-host/gt64120.c +++ b/hw/pci-host/gt64120.c @@ -1244,7 +1244,7 @@ static void gt64120_pci_reset_hold(Object *obj, ResetType type) pci_set_byte(d->config + 0x3d, 0x01); } -static void gt64120_pci_class_init(ObjectClass *klass, void *data) +static void gt64120_pci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -1279,7 +1279,7 @@ static const Property gt64120_properties[] = { cpu_little_endian, false), }; -static void gt64120_class_init(ObjectClass *klass, void *data) +static void gt64120_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index 1e69691c6d..fcc9f3818a 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -315,7 +315,7 @@ static void i440fx_pcihost_realize(DeviceState *dev, Error **errp) i440fx_update_memory_mappings(f); } -static void i440fx_class_init(ObjectClass *klass, void *data) +static void i440fx_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -364,7 +364,7 @@ static const Property i440fx_props[] = { DEFINE_PROP_STRING(I440FX_HOST_PROP_PCI_TYPE, I440FXState, pci_type), }; -static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) +static void i440fx_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index a297318c6e..f51f385b22 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -26,7 +26,7 @@ #define TYPE_MV64361_PCI_BRIDGE "mv64361-pcibridge" -static void mv64361_pcibridge_class_init(ObjectClass *klass, void *data) +static void mv64361_pcibridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -102,7 +102,7 @@ static const Property mv64361_pcihost_props[] = { DEFINE_PROP_UINT8("index", MV64361PCIState, index, 0), }; -static void mv64361_pcihost_class_init(ObjectClass *klass, void *data) +static void mv64361_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -923,7 +923,7 @@ static void mv64361_reset(DeviceState *dev) set_mem_windows(s, 0xfbfff); } -static void mv64361_class_init(ObjectClass *klass, void *data) +static void mv64361_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c index 6c1e76fbbb..4b0ced79b0 100644 --- a/hw/pci-host/pnv_phb.c +++ b/hw/pci-host/pnv_phb.c @@ -194,7 +194,7 @@ static const Property pnv_phb_properties[] = { PnvPhb4PecState *), }; -static void pnv_phb_class_init(ObjectClass *klass, void *data) +static void pnv_phb_class_init(ObjectClass *klass, const void *data) { PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -304,7 +304,7 @@ static const Property pnv_phb_root_port_properties[] = { DEFINE_PROP_UINT32("version", PnvPHBRootPort, version, 0), }; -static void pnv_phb_root_port_class_init(ObjectClass *klass, void *data) +static void pnv_phb_root_port_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/pci-host/pnv_phb3.c b/hw/pci-host/pnv_phb3.c index 82884e1e92..a4335f44f2 100644 --- a/hw/pci-host/pnv_phb3.c +++ b/hw/pci-host/pnv_phb3.c @@ -888,7 +888,7 @@ DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, PNV_PHB3_IOMMU_MEMORY_REGION, TYPE_PNV_PHB3_IOMMU_MEMORY_REGION) static void pnv_phb3_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); @@ -1097,7 +1097,7 @@ static const Property pnv_phb3_properties[] = { DEFINE_PROP_LINK("phb-base", PnvPHB3, phb_base, TYPE_PNV_PHB, PnvPHB *), }; -static void pnv_phb3_class_init(ObjectClass *klass, void *data) +static void pnv_phb3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1149,7 +1149,7 @@ static void pnv_phb3_root_bus_set_prop(Object *obj, Visitor *v, } } -static void pnv_phb3_root_bus_class_init(ObjectClass *klass, void *data) +static void pnv_phb3_root_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); diff --git a/hw/pci-host/pnv_phb3_msi.c b/hw/pci-host/pnv_phb3_msi.c index 81986644b1..3a83311faf 100644 --- a/hw/pci-host/pnv_phb3_msi.c +++ b/hw/pci-host/pnv_phb3_msi.c @@ -284,7 +284,7 @@ static void phb3_msi_instance_init(Object *obj) ics->offset = 0; } -static void phb3_msi_class_init(ObjectClass *klass, void *data) +static void phb3_msi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ICSStateClass *isc = ICS_CLASS(klass); diff --git a/hw/pci-host/pnv_phb3_pbcq.c b/hw/pci-host/pnv_phb3_pbcq.c index 82f70efa43..4e24b1449d 100644 --- a/hw/pci-host/pnv_phb3_pbcq.c +++ b/hw/pci-host/pnv_phb3_pbcq.c @@ -337,7 +337,7 @@ static void phb3_pbcq_instance_init(Object *obj) OBJ_PROP_LINK_STRONG); } -static void pnv_pbcq_class_init(ObjectClass *klass, void *data) +static void pnv_pbcq_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index 178c73f519..feb812dc1a 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1362,7 +1362,7 @@ DECLARE_INSTANCE_CHECKER(IOMMUMemoryRegion, PNV_PHB4_IOMMU_MEMORY_REGION, TYPE_PNV_PHB4_IOMMU_MEMORY_REGION) static void pnv_phb4_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); @@ -1696,7 +1696,7 @@ static const Property pnv_phb4_properties[] = { DEFINE_PROP_LINK("phb-base", PnvPHB4, phb_base, TYPE_PNV_PHB, PnvPHB *), }; -static void pnv_phb4_class_init(ObjectClass *klass, void *data) +static void pnv_phb4_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XiveNotifierClass *xfc = XIVE_NOTIFIER_CLASS(klass); @@ -1761,7 +1761,7 @@ static void pnv_phb4_root_bus_set_prop(Object *obj, Visitor *v, } } -static void pnv_phb4_root_bus_class_init(ObjectClass *klass, void *data) +static void pnv_phb4_root_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index cb8a7e3afa..cc46641cdf 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -354,7 +354,7 @@ static uint32_t pnv_pec_xscom_nest_base(PnvPhb4PecState *pec) */ static const uint32_t pnv_pec_num_phbs[] = { 1, 2, 3 }; -static void pnv_pec_class_init(ObjectClass *klass, void *data) +static void pnv_pec_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); @@ -419,7 +419,7 @@ static uint32_t pnv_phb5_pec_xscom_nest_base(PnvPhb4PecState *pec) */ static const uint32_t pnv_phb5_pec_num_stacks[] = { 3, 3 }; -static void pnv_phb5_pec_class_init(ObjectClass *klass, void *data) +static void pnv_phb5_pec_class_init(ObjectClass *klass, const void *data) { PnvPhb4PecClass *pecc = PNV_PHB4_PEC_CLASS(klass); static const char compat[] = "ibm,power10-pbcq"; diff --git a/hw/pci-host/ppc440_pcix.c b/hw/pci-host/ppc440_pcix.c index 07924bce28..744b85e49c 100644 --- a/hw/pci-host/ppc440_pcix.c +++ b/hw/pci-host/ppc440_pcix.c @@ -519,7 +519,7 @@ static void ppc440_pcix_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void ppc440_pcix_class_init(ObjectClass *klass, void *data) +static void ppc440_pcix_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/ppc4xx_pci.c b/hw/pci-host/ppc4xx_pci.c index 292cb308ba..dcc4b78660 100644 --- a/hw/pci-host/ppc4xx_pci.c +++ b/hw/pci-host/ppc4xx_pci.c @@ -349,7 +349,7 @@ static void ppc4xx_pcihost_realize(DeviceState *dev, Error **errp) qemu_register_reset(ppc4xx_pci_reset, s); } -static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data) +static void ppc4xx_host_bridge_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -376,7 +376,7 @@ static const TypeInfo ppc4xx_host_bridge_info = { }, }; -static void ppc4xx_pcihost_class_init(ObjectClass *klass, void *data) +static void ppc4xx_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 9b905d1971..2f6354c931 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -490,7 +490,7 @@ static void e500_pcihost_realize(DeviceState *dev, Error **errp) pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq); } -static void e500_host_bridge_class_init(ObjectClass *klass, void *data) +static void e500_host_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -512,7 +512,7 @@ static const Property pcihost_properties[] = { DEFINE_PROP_UINT32("first_pin_irq", PPCE500PCIState, first_pin_irq, 0x1), }; -static void e500_pcihost_class_init(ObjectClass *klass, void *data) +static void e500_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index 06be3d77cb..c2a71108f2 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -184,7 +184,7 @@ static const Property q35_host_props[] = { DEFINE_PROP_BOOL("x-pci-hole64-fix", Q35PCIHost, pci_hole64_fix, true), }; -static void q35_host_class_init(ObjectClass *klass, void *data) +static void q35_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); @@ -667,7 +667,7 @@ static const Property mch_props[] = { DEFINE_PROP_BOOL("smbase-smram", MCHPCIState, has_smram_at_smbase, true), }; -static void mch_class_init(ObjectClass *klass, void *data) +static void mch_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index e3d8d206b7..3f158838a0 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -392,7 +392,7 @@ static const VMStateDescription vmstate_raven = { }, }; -static void raven_class_init(ObjectClass *klass, void *data) +static void raven_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -431,7 +431,7 @@ static const Property raven_pcihost_properties[] = { false), }; -static void raven_pcihost_class_init(ObjectClass *klass, void *data) +static void raven_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/remote.c b/hw/pci-host/remote.c index be077d075e..e6d2af4502 100644 --- a/hw/pci-host/remote.c +++ b/hw/pci-host/remote.c @@ -46,7 +46,7 @@ static void remote_pcihost_realize(DeviceState *dev, Error **errp) 0, TYPE_PCIE_BUS); } -static void remote_pcihost_class_init(ObjectClass *klass, void *data) +static void remote_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index be6641de15..f7086086f9 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -456,7 +456,7 @@ static void sabre_pci_realize(PCIDevice *d, Error **errp) PCI_STATUS_DEVSEL_MEDIUM); } -static void sabre_pci_class_init(ObjectClass *klass, void *data) +static void sabre_pci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -497,7 +497,7 @@ static const Property sabre_properties[] = { DEFINE_PROP_UINT64("mem-base", SabreState, mem_base, 0), }; -static void sabre_class_init(ObjectClass *klass, void *data) +static void sabre_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 4edebced5e..52bff66d6a 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -153,7 +153,7 @@ static void sh_pcic_pci_realize(PCIDevice *d, Error **errp) PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); } -static void sh_pcic_pci_class_init(ObjectClass *klass, void *data) +static void sh_pcic_pci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -168,7 +168,7 @@ static void sh_pcic_pci_class_init(ObjectClass *klass, void *data) dc->user_creatable = false; } -static void sh_pcic_host_class_init(ObjectClass *klass, void *data) +static void sh_pcic_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 37e2461bbb..7cb37e01d8 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -311,7 +311,7 @@ static void unin_internal_pci_host_realize(PCIDevice *d, Error **errp) d->config[PCI_CAPABILITY_LIST] = 0x00; } -static void unin_main_pci_host_class_init(ObjectClass *klass, void *data) +static void unin_main_pci_host_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -339,7 +339,7 @@ static const TypeInfo unin_main_pci_host_info = { }, }; -static void u3_agp_pci_host_class_init(ObjectClass *klass, void *data) +static void u3_agp_pci_host_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -367,7 +367,7 @@ static const TypeInfo u3_agp_pci_host_info = { }, }; -static void unin_agp_pci_host_class_init(ObjectClass *klass, void *data) +static void unin_agp_pci_host_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -395,7 +395,8 @@ static const TypeInfo unin_agp_pci_host_info = { }, }; -static void unin_internal_pci_host_class_init(ObjectClass *klass, void *data) +static void unin_internal_pci_host_class_init(ObjectClass *klass, + const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -427,7 +428,7 @@ static const Property pci_unin_main_pci_host_props[] = { DEFINE_PROP_UINT32("ofw-addr", UNINHostState, ofw_addr, -1), }; -static void pci_unin_main_class_init(ObjectClass *klass, void *data) +static void pci_unin_main_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); @@ -447,7 +448,7 @@ static const TypeInfo pci_unin_main_info = { .class_init = pci_unin_main_class_init, }; -static void pci_u3_agp_class_init(ObjectClass *klass, void *data) +static void pci_u3_agp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -463,7 +464,7 @@ static const TypeInfo pci_u3_agp_info = { .class_init = pci_u3_agp_class_init, }; -static void pci_unin_agp_class_init(ObjectClass *klass, void *data) +static void pci_unin_agp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -479,7 +480,7 @@ static const TypeInfo pci_unin_agp_info = { .class_init = pci_unin_agp_class_init, }; -static void pci_unin_internal_class_init(ObjectClass *klass, void *data) +static void pci_unin_internal_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -535,7 +536,7 @@ static void unin_init(Object *obj) sysbus_init_mmio(sbd, &s->mem); } -static void unin_class_init(ObjectClass *klass, void *data) +static void unin_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index 33a8ceb3b5..b333158e10 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -471,7 +471,7 @@ static void versatile_pci_host_realize(PCIDevice *d, Error **errp) pci_set_byte(d->config + PCI_LATENCY_TIMER, 0x10); } -static void versatile_pci_host_class_init(ObjectClass *klass, void *data) +static void versatile_pci_host_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -503,7 +503,7 @@ static const Property pci_vpb_properties[] = { PCI_VPB_IRQMAP_ASSUME_OK), }; -static void pci_vpb_class_init(ObjectClass *klass, void *data) +static void pci_vpb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci-host/xen_igd_pt.c b/hw/pci-host/xen_igd_pt.c index d094b675d6..5dd17ef236 100644 --- a/hw/pci-host/xen_igd_pt.c +++ b/hw/pci-host/xen_igd_pt.c @@ -95,7 +95,8 @@ static void igd_pt_i440fx_realize(PCIDevice *pci_dev, Error **errp) } } -static void igd_passthrough_i440fx_class_init(ObjectClass *klass, void *data) +static void igd_passthrough_i440fx_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index 18688485f4..70e9b2b981 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -165,7 +165,7 @@ static const Property xilinx_pcie_host_props[] = { DEFINE_PROP_BOOL("link_up", XilinxPCIEHost, link_up, true), }; -static void xilinx_pcie_host_class_init(ObjectClass *klass, void *data) +static void xilinx_pcie_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); @@ -286,7 +286,7 @@ static void xilinx_pcie_root_realize(PCIDevice *pci_dev, Error **errp) } } -static void xilinx_pcie_root_class_init(ObjectClass *klass, void *data) +static void xilinx_pcie_root_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 475b97c649..c60991def8 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -261,7 +261,7 @@ static GByteArray *pci_bus_fw_cfg_gen_data(Object *obj, Error **errp) return byte_array; } -static void pci_bus_class_init(ObjectClass *klass, void *data) +static void pci_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); PCIBusClass *pbc = PCI_BUS_CLASS(klass); @@ -309,7 +309,7 @@ static const TypeInfo conventional_pci_interface_info = { .parent = TYPE_INTERFACE, }; -static void pcie_bus_class_init(ObjectClass *klass, void *data) +static void pcie_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -2795,7 +2795,7 @@ MemoryRegion *pci_address_space_io(PCIDevice *dev) return pci_get_bus(dev)->address_space_io; } -static void pci_device_class_init(ObjectClass *klass, void *data) +static void pci_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index aee4dd7d1f..0fe66e8b12 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -482,7 +482,7 @@ static const Property pci_bridge_properties[] = { pcie_writeable_slt_bug, false), }; -static void pci_bridge_class_init(ObjectClass *klass, void *data) +static void pci_bridge_class_init(ObjectClass *klass, const void *data) { AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass); DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index 80f91f409f..abe83bbab8 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -246,7 +246,7 @@ static const Property pci_host_properties_common[] = { DEFINE_PROP_BOOL(PCI_HOST_BYPASS_IOMMU, PCIHostState, bypass_iommu, false), }; -static void pci_host_class_init(ObjectClass *klass, void *data) +static void pci_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_props(dc, pci_host_properties_common); diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index c73db30e98..8629b3aafd 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -118,7 +118,7 @@ static const Property pcie_port_props[] = { PCIE_AER_LOG_MAX_DEFAULT), }; -static void pcie_port_class_init(ObjectClass *oc, void *data) +static void pcie_port_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -211,7 +211,7 @@ static const Property pcie_slot_props[] = { hide_native_hotplug_cap, false), }; -static void pcie_slot_class_init(ObjectClass *oc, void *data) +static void pcie_slot_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c index e9407a51b5..12279f42bc 100644 --- a/hw/ppc/amigaone.c +++ b/hw/ppc/amigaone.c @@ -173,7 +173,7 @@ static const Property nvram_properties[] = { DEFINE_PROP_DRIVE("drive", A1NVRAMState, blk), }; -static void nvram_class_init(ObjectClass *oc, void *data) +static void nvram_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 70a8033373..cd594eeb3e 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -68,7 +68,7 @@ HotplugHandler *e500plat_machine_get_hotpug_handler(MachineState *machine, #define TYPE_E500PLAT_MACHINE MACHINE_TYPE_NAME("ppce500") -static void e500plat_machine_class_init(ObjectClass *oc, void *data) +static void e500plat_machine_class_init(ObjectClass *oc, const void *data) { PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 5a827846ed..92fe60b2a2 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -563,7 +563,7 @@ static int core99_kvm_type(MachineState *machine, const char *arg) return 2; } -static void core99_machine_class_init(ObjectClass *oc, void *data) +static void core99_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 0d34e6bfda..5c5bf99b4d 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -402,7 +402,7 @@ static int heathrow_kvm_type(MachineState *machine, const char *arg) return 2; } -static void heathrow_class_init(ObjectClass *oc, void *data) +static void heathrow_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index d74af766ee..97fb0f35ba 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -37,7 +37,7 @@ static void mpc8544ds_init(MachineState *machine) ppce500_init(machine); } -static void mpc8544ds_machine_class_init(ObjectClass *oc, void *data) +static void mpc8544ds_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); PPCE500MachineClass *pmc = PPCE500_MACHINE_CLASS(oc); diff --git a/hw/ppc/pef.c b/hw/ppc/pef.c index 8b2d726e00..254f570787 100644 --- a/hw/ppc/pef.c +++ b/hw/ppc/pef.c @@ -128,7 +128,7 @@ OBJECT_DEFINE_TYPE_WITH_INTERFACES(PefGuest, { TYPE_USER_CREATABLE }, { NULL }) -static void pef_guest_class_init(ObjectClass *oc, void *data) +static void pef_guest_class_init(ObjectClass *oc, const void *data) { ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc); diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index 7b2dc6985c..bb6f94f502 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -588,7 +588,7 @@ static bool pegasos2_setprop(MachineState *ms, const char *path, return true; } -static void pegasos2_machine_class_init(ObjectClass *oc, void *data) +static void pegasos2_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); PPCVirtualHypervisorClass *vhc = PPC_VIRTUAL_HYPERVISOR_CLASS(oc); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 63f2232f32..4590231f88 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -1618,7 +1618,7 @@ static uint32_t pnv_chip_power8_xscom_pcba(PnvChip *chip, uint64_t addr) return ((addr >> 4) & ~0xfull) | ((addr >> 3) & 0xf); } -static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) +static void pnv_chip_power8e_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvChipClass *k = PNV_CHIP_CLASS(klass); @@ -1642,7 +1642,7 @@ static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) &k->parent_realize); } -static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) +static void pnv_chip_power8_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvChipClass *k = PNV_CHIP_CLASS(klass); @@ -1666,7 +1666,7 @@ static void pnv_chip_power8_class_init(ObjectClass *klass, void *data) &k->parent_realize); } -static void pnv_chip_power8nvl_class_init(ObjectClass *klass, void *data) +static void pnv_chip_power8nvl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvChipClass *k = PNV_CHIP_CLASS(klass); @@ -1954,7 +1954,7 @@ static uint32_t pnv_chip_power9_xscom_pcba(PnvChip *chip, uint64_t addr) return addr >> 3; } -static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) +static void pnv_chip_power9_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvChipClass *k = PNV_CHIP_CLASS(klass); @@ -2302,7 +2302,7 @@ static uint32_t pnv_chip_power10_xscom_pcba(PnvChip *chip, uint64_t addr) return addr >> 3; } -static void pnv_chip_power10_class_init(ObjectClass *klass, void *data) +static void pnv_chip_power10_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvChipClass *k = PNV_CHIP_CLASS(klass); @@ -2461,7 +2461,7 @@ static const Property pnv_chip_properties[] = { DEFINE_PROP_BOOL("lpar-per-core", PnvChip, lpar_per_core, false), }; -static void pnv_chip_class_init(ObjectClass *klass, void *data) +static void pnv_chip_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2724,7 +2724,7 @@ static void pnv_machine_set_hb(Object *obj, bool value, Error **errp) } } -static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) +static void pnv_machine_power8_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); XICSFabricClass *xic = XICS_FABRIC_CLASS(oc); @@ -2753,7 +2753,7 @@ static void pnv_machine_power8_class_init(ObjectClass *oc, void *data) machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB); } -static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) +static void pnv_machine_power9_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); XiveFabricClass *xfc = XIVE_FABRIC_CLASS(oc); @@ -2792,7 +2792,7 @@ static void pnv_machine_power9_class_init(ObjectClass *oc, void *data) "Use 1 LPAR per core mode"); } -static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data) +static void pnv_machine_p10_common_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc); @@ -2822,7 +2822,7 @@ static void pnv_machine_p10_common_class_init(ObjectClass *oc, void *data) machine_class_allow_dynamic_sysbus_dev(mc, TYPE_PNV_PHB); } -static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) +static void pnv_machine_power10_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -2847,7 +2847,8 @@ static void pnv_machine_power10_class_init(ObjectClass *oc, void *data) "Use 1 LPAR per core mode"); } -static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, void *data) +static void pnv_machine_p10_rainier_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); PnvMachineClass *pmc = PNV_MACHINE_CLASS(oc); @@ -2912,7 +2913,7 @@ static void pnv_nmi(NMIState *n, int cpu_index, Error **errp) } } -static void pnv_machine_class_init(ObjectClass *oc, void *data) +static void pnv_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); InterruptStatsProviderClass *ispc = INTERRUPT_STATS_PROVIDER_CLASS(oc); diff --git a/hw/ppc/pnv_adu.c b/hw/ppc/pnv_adu.c index d09a167466..f9620806ec 100644 --- a/hw/ppc/pnv_adu.c +++ b/hw/ppc/pnv_adu.c @@ -189,7 +189,7 @@ static const Property pnv_adu_properties[] = { DEFINE_PROP_LINK("lpc", PnvADU, lpc, TYPE_PNV_LPC, PnvLpcController *), }; -static void pnv_adu_class_init(ObjectClass *klass, void *data) +static void pnv_adu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c index c8987ae67a..4ca511a4de 100644 --- a/hw/ppc/pnv_chiptod.c +++ b/hw/ppc/pnv_chiptod.c @@ -456,7 +456,7 @@ static const Property pnv_chiptod_properties[] = { DEFINE_PROP_LINK("chip", PnvChipTOD , chip, TYPE_PNV_CHIP, PnvChip *), }; -static void pnv_chiptod_power9_class_init(ObjectClass *klass, void *data) +static void pnv_chiptod_power9_class_init(ObjectClass *klass, const void *data) { PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -492,7 +492,7 @@ static int pnv_chiptod_power10_dt_xscom(PnvXScomInterface *dev, void *fdt, return pnv_chiptod_dt_xscom(dev, fdt, xscom_offset, compat, sizeof(compat)); } -static void pnv_chiptod_power10_class_init(ObjectClass *klass, void *data) +static void pnv_chiptod_power10_class_init(ObjectClass *klass, const void *data) { PnvChipTODClass *pctc = PNV_CHIPTOD_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -555,7 +555,7 @@ static void pnv_chiptod_unrealize(DeviceState *dev) qemu_unregister_reset(pnv_chiptod_reset, chiptod); } -static void pnv_chiptod_class_init(ObjectClass *klass, void *data) +static void pnv_chiptod_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c index a33977da18..08c20224b9 100644 --- a/hw/ppc/pnv_core.c +++ b/hw/ppc/pnv_core.c @@ -449,7 +449,7 @@ static const Property pnv_core_properties[] = { DEFINE_PROP_LINK("chip", PnvCore, chip, TYPE_PNV_CHIP, PnvChip *), }; -static void pnv_core_power8_class_init(ObjectClass *oc, void *data) +static void pnv_core_power8_class_init(ObjectClass *oc, const void *data) { PnvCoreClass *pcc = PNV_CORE_CLASS(oc); @@ -457,7 +457,7 @@ static void pnv_core_power8_class_init(ObjectClass *oc, void *data) pcc->xscom_size = PNV_XSCOM_EX_SIZE; } -static void pnv_core_power9_class_init(ObjectClass *oc, void *data) +static void pnv_core_power9_class_init(ObjectClass *oc, const void *data) { PnvCoreClass *pcc = PNV_CORE_CLASS(oc); @@ -465,7 +465,7 @@ static void pnv_core_power9_class_init(ObjectClass *oc, void *data) pcc->xscom_size = PNV_XSCOM_EX_SIZE; } -static void pnv_core_power10_class_init(ObjectClass *oc, void *data) +static void pnv_core_power10_class_init(ObjectClass *oc, const void *data) { PnvCoreClass *pcc = PNV_CORE_CLASS(oc); @@ -473,7 +473,7 @@ static void pnv_core_power10_class_init(ObjectClass *oc, void *data) pcc->xscom_size = PNV10_XSCOM_EC_SIZE; } -static void pnv_core_class_init(ObjectClass *oc, void *data) +static void pnv_core_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -700,7 +700,7 @@ static const Property pnv_quad_properties[] = { DEFINE_PROP_UINT32("quad-id", PnvQuad, quad_id, 0), }; -static void pnv_quad_power9_class_init(ObjectClass *oc, void *data) +static void pnv_quad_power9_class_init(ObjectClass *oc, const void *data) { PnvQuadClass *pqc = PNV_QUAD_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -711,7 +711,7 @@ static void pnv_quad_power9_class_init(ObjectClass *oc, void *data) pqc->xscom_size = PNV9_XSCOM_EQ_SIZE; } -static void pnv_quad_power10_class_init(ObjectClass *oc, void *data) +static void pnv_quad_power10_class_init(ObjectClass *oc, const void *data) { PnvQuadClass *pqc = PNV_QUAD_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -725,7 +725,7 @@ static void pnv_quad_power10_class_init(ObjectClass *oc, void *data) pqc->xscom_qme_size = PNV10_XSCOM_QME_SIZE; } -static void pnv_quad_class_init(ObjectClass *oc, void *data) +static void pnv_quad_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/pnv_homer.c b/hw/ppc/pnv_homer.c index 0521f9a428..2208ffe632 100644 --- a/hw/ppc/pnv_homer.c +++ b/hw/ppc/pnv_homer.c @@ -89,7 +89,7 @@ static hwaddr pnv_homer_power8_get_base(PnvChip *chip) return PNV_HOMER_BASE(chip); } -static void pnv_homer_power8_class_init(ObjectClass *klass, void *data) +static void pnv_homer_power8_class_init(ObjectClass *klass, const void *data) { PnvHomerClass *homer = PNV_HOMER_CLASS(klass); @@ -156,7 +156,7 @@ static hwaddr pnv_homer_power9_get_base(PnvChip *chip) return PNV9_HOMER_BASE(chip); } -static void pnv_homer_power9_class_init(ObjectClass *klass, void *data) +static void pnv_homer_power9_class_init(ObjectClass *klass, const void *data) { PnvHomerClass *homer = PNV_HOMER_CLASS(klass); @@ -223,7 +223,7 @@ static hwaddr pnv_homer_power10_get_base(PnvChip *chip) return PNV10_HOMER_BASE(chip); } -static void pnv_homer_power10_class_init(ObjectClass *klass, void *data) +static void pnv_homer_power10_class_init(ObjectClass *klass, const void *data) { PnvHomerClass *homer = PNV_HOMER_CLASS(klass); @@ -266,7 +266,7 @@ static const Property pnv_homer_properties[] = { DEFINE_PROP_LINK("chip", PnvHomer, chip, TYPE_PNV_CHIP, PnvChip *), }; -static void pnv_homer_class_init(ObjectClass *klass, void *data) +static void pnv_homer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c index 8d35f452a2..b2f372c874 100644 --- a/hw/ppc/pnv_i2c.c +++ b/hw/ppc/pnv_i2c.c @@ -549,7 +549,7 @@ static const Property pnv_i2c_properties[] = { DEFINE_PROP_UINT32("num-busses", PnvI2C, num_busses, 1), }; -static void pnv_i2c_class_init(ObjectClass *klass, void *data) +static void pnv_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index d812dc8268..d92347bcd2 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -714,7 +714,7 @@ static void pnv_lpc_power8_realize(DeviceState *dev, Error **errp) PNV_XSCOM_LPC_SIZE); } -static void pnv_lpc_power8_class_init(ObjectClass *klass, void *data) +static void pnv_lpc_power8_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); @@ -760,7 +760,7 @@ static void pnv_lpc_power9_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out_named(dev, lpc->psi_irq_serirq, "SERIRQ", 4); } -static void pnv_lpc_power9_class_init(ObjectClass *klass, void *data) +static void pnv_lpc_power9_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvLpcClass *plc = PNV_LPC_CLASS(klass); @@ -777,7 +777,7 @@ static const TypeInfo pnv_lpc_power9_info = { .class_init = pnv_lpc_power9_class_init, }; -static void pnv_lpc_power10_class_init(ObjectClass *klass, void *data) +static void pnv_lpc_power10_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -843,7 +843,7 @@ static const Property pnv_lpc_properties[] = { DEFINE_PROP_BOOL("psi-serirq", PnvLpcController, psi_has_serirq, false), }; -static void pnv_lpc_class_init(ObjectClass *klass, void *data) +static void pnv_lpc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_n1_chiplet.c b/hw/ppc/pnv_n1_chiplet.c index 03ff9fbad0..05e3fd6f73 100644 --- a/hw/ppc/pnv_n1_chiplet.c +++ b/hw/ppc/pnv_n1_chiplet.c @@ -136,7 +136,7 @@ static void pnv_n1_chiplet_realize(DeviceState *dev, Error **errp) PNV10_XSCOM_N1_PB_SCOM_ES_SIZE); } -static void pnv_n1_chiplet_class_init(ObjectClass *klass, void *data) +static void pnv_n1_chiplet_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_nest_pervasive.c b/hw/ppc/pnv_nest_pervasive.c index 780fa69dde..b5182d54fa 100644 --- a/hw/ppc/pnv_nest_pervasive.c +++ b/hw/ppc/pnv_nest_pervasive.c @@ -181,7 +181,7 @@ static void pnv_nest_pervasive_realize(DeviceState *dev, Error **errp) PNV10_XSCOM_CHIPLET_CTRL_REGS_SIZE); } -static void pnv_nest_pervasive_class_init(ObjectClass *klass, void *data) +static void pnv_nest_pervasive_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_occ.c b/hw/ppc/pnv_occ.c index 0c9d3daec2..fa6f31cb8d 100644 --- a/hw/ppc/pnv_occ.c +++ b/hw/ppc/pnv_occ.c @@ -172,7 +172,7 @@ const MemoryRegionOps pnv_occ_sram_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) +static void pnv_occ_power8_class_init(ObjectClass *klass, const void *data) { PnvOCCClass *poc = PNV_OCC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -246,7 +246,7 @@ static const MemoryRegionOps pnv_occ_power9_xscom_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_occ_power9_class_init(ObjectClass *klass, void *data) +static void pnv_occ_power9_class_init(ObjectClass *klass, const void *data) { PnvOCCClass *poc = PNV_OCC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -266,7 +266,7 @@ static const TypeInfo pnv_occ_power9_type_info = { .class_init = pnv_occ_power9_class_init, }; -static void pnv_occ_power10_class_init(ObjectClass *klass, void *data) +static void pnv_occ_power10_class_init(ObjectClass *klass, const void *data) { PnvOCCClass *poc = PNV_OCC_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -335,7 +335,7 @@ static const Property pnv_occ_properties[] = { DEFINE_PROP_LINK("homer", PnvOCC, homer, TYPE_PNV_HOMER, PnvHomer *), }; -static void pnv_occ_class_init(ObjectClass *klass, void *data) +static void pnv_occ_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_pnor.c b/hw/ppc/pnv_pnor.c index 9db44ca21d..af7cfd028b 100644 --- a/hw/ppc/pnv_pnor.c +++ b/hw/ppc/pnv_pnor.c @@ -119,7 +119,7 @@ static const Property pnv_pnor_properties[] = { DEFINE_PROP_DRIVE("drive", PnvPnor, blk), }; -static void pnv_pnor_class_init(ObjectClass *klass, void *data) +static void pnv_pnor_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index f832ee61e8..0fd247e6ad 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -557,7 +557,7 @@ static const Property pnv_psi_properties[] = { DEFINE_PROP_UINT64("fsp-bar", PnvPsi, fsp_bar, 0), }; -static void pnv_psi_power8_class_init(ObjectClass *klass, void *data) +static void pnv_psi_power8_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvPsiClass *ppc = PNV_PSI_CLASS(klass); @@ -887,7 +887,7 @@ static void pnv_psi_power9_realize(DeviceState *dev, Error **errp) pnv_psi_realize(dev, errp); } -static void pnv_psi_power9_class_init(ObjectClass *klass, void *data) +static void pnv_psi_power9_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvPsiClass *ppc = PNV_PSI_CLASS(klass); @@ -919,7 +919,7 @@ static const TypeInfo pnv_psi_power9_info = { }, }; -static void pnv_psi_power10_class_init(ObjectClass *klass, void *data) +static void pnv_psi_power10_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvPsiClass *ppc = PNV_PSI_CLASS(klass); @@ -939,7 +939,7 @@ static const TypeInfo pnv_psi_power10_info = { .class_init = pnv_psi_power10_class_init, }; -static void pnv_psi_class_init(ObjectClass *klass, void *data) +static void pnv_psi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xdc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/ppc/pnv_sbe.c b/hw/ppc/pnv_sbe.c index 74cee4eea7..34dc013d47 100644 --- a/hw/ppc/pnv_sbe.c +++ b/hw/ppc/pnv_sbe.c @@ -331,7 +331,7 @@ static const MemoryRegionOps pnv_sbe_power9_xscom_mbox_ops = { .endianness = DEVICE_BIG_ENDIAN, }; -static void pnv_sbe_power9_class_init(ObjectClass *klass, void *data) +static void pnv_sbe_power9_class_init(ObjectClass *klass, const void *data) { PnvSBEClass *psc = PNV_SBE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -350,7 +350,7 @@ static const TypeInfo pnv_sbe_power9_type_info = { .class_init = pnv_sbe_power9_class_init, }; -static void pnv_sbe_power10_class_init(ObjectClass *klass, void *data) +static void pnv_sbe_power10_class_init(ObjectClass *klass, const void *data) { PnvSBEClass *psc = PNV_SBE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -386,7 +386,7 @@ static void pnv_sbe_realize(DeviceState *dev, Error **errp) sbe->timer = timer_new_us(QEMU_CLOCK_VIRTUAL, sbe_timer, sbe); } -static void pnv_sbe_class_init(ObjectClass *klass, void *data) +static void pnv_sbe_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index 9da30a1724..89e3fae08d 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -1027,7 +1027,7 @@ static const Property ppc460ex_pcie_props[] = { PowerPCCPU *), }; -static void ppc460ex_pcie_class_init(ObjectClass *klass, void *data) +static void ppc460ex_pcie_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c index 9ce9777510..f36c519c8b 100644 --- a/hw/ppc/ppc4xx_devs.c +++ b/hw/ppc/ppc4xx_devs.c @@ -236,7 +236,7 @@ static const Property ppc4xx_mal_properties[] = { DEFINE_PROP_UINT8("rxc-num", Ppc4xxMalState, rxcnum, 0), }; -static void ppc4xx_mal_class_init(ObjectClass *oc, void *data) +static void ppc4xx_mal_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -326,7 +326,7 @@ static void ppc405_plb_realize(DeviceState *dev, Error **errp) ppc4xx_dcr_register(dcr, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb); } -static void ppc405_plb_class_init(ObjectClass *oc, void *data) +static void ppc405_plb_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -512,7 +512,7 @@ static void ppc405_ebc_realize(DeviceState *dev, Error **errp) ppc4xx_dcr_register(dcr, EBC0_CFGDATA, ebc, &dcr_read_ebc, &dcr_write_ebc); } -static void ppc405_ebc_class_init(ObjectClass *oc, void *data) +static void ppc405_ebc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -543,7 +543,7 @@ static const Property ppc4xx_dcr_properties[] = { PowerPCCPU *), }; -static void ppc4xx_dcr_class_init(ObjectClass *oc, void *data) +static void ppc4xx_dcr_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/ppc4xx_sdram.c b/hw/ppc/ppc4xx_sdram.c index bf0faad9e7..592769826b 100644 --- a/hw/ppc/ppc4xx_sdram.c +++ b/hw/ppc/ppc4xx_sdram.c @@ -431,7 +431,7 @@ static const Property ppc4xx_sdram_ddr_props[] = { DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdrState, nbanks, 4), }; -static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, void *data) +static void ppc4xx_sdram_ddr_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -715,7 +715,7 @@ static const Property ppc4xx_sdram_ddr2_props[] = { DEFINE_PROP_UINT32("nbanks", Ppc4xxSdramDdr2State, nbanks, 4), }; -static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, void *data) +static void ppc4xx_sdram_ddr2_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c index baab74c4ed..2310f62a91 100644 --- a/hw/ppc/ppce500_spin.c +++ b/hw/ppc/ppce500_spin.c @@ -175,7 +175,7 @@ static void ppce500_spin_initfn(Object *obj) sysbus_init_mmio(dev, &s->iomem); } -static void ppce500_spin_class_init(ObjectClass *klass, void *data) +static void ppce500_spin_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/prep_systemio.c b/hw/ppc/prep_systemio.c index 08f29e72e4..41cd923b94 100644 --- a/hw/ppc/prep_systemio.c +++ b/hw/ppc/prep_systemio.c @@ -290,7 +290,7 @@ static const Property prep_systemio_properties[] = { DEFINE_PROP_UINT8("equipment", PrepSystemIoState, equipment, 0), }; -static void prep_systemio_class_initfn(ObjectClass *klass, void *data) +static void prep_systemio_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/rs6000_mc.c b/hw/ppc/rs6000_mc.c index 27f1c90f06..a0964051d1 100644 --- a/hw/ppc/rs6000_mc.c +++ b/hw/ppc/rs6000_mc.c @@ -212,7 +212,7 @@ static const Property rs6000mc_properties[] = { DEFINE_PROP_BOOL("auto-configure", RS6000MCState, autoconfigure, true), }; -static void rs6000mc_class_initfn(ObjectClass *klass, void *data) +static void rs6000mc_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index c1a7ac3536..02663851ae 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4595,7 +4595,7 @@ static void spapr_cpu_exec_exit(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu) } } -static void spapr_machine_class_init(ObjectClass *oc, void *data) +static void spapr_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); SpaprMachineClass *smc = SPAPR_MACHINE_CLASS(oc); @@ -4739,7 +4739,7 @@ static void spapr_machine_latest_class_options(MachineClass *mc) #define DEFINE_SPAPR_MACHINE_IMPL(latest, ...) \ static void MACHINE_VER_SYM(class_init, spapr, __VA_ARGS__)( \ ObjectClass *oc, \ - void *data) \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ MACHINE_VER_SYM(class_options, spapr, __VA_ARGS__)(mc); \ diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index faf9170ba6..b4b926d759 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -373,7 +373,7 @@ static const Property spapr_cpu_core_properties[] = { DEFINE_PROP_INT32("node-id", SpaprCpuCore, node_id, CPU_UNSET_NUMA_NODE_ID), }; -static void spapr_cpu_core_class_init(ObjectClass *oc, void *data) +static void spapr_cpu_core_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc); diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c index 549b652c20..d2044b4fb5 100644 --- a/hw/ppc/spapr_drc.c +++ b/hw/ppc/spapr_drc.c @@ -589,7 +589,7 @@ static void spapr_dr_connector_instance_init(Object *obj) drc->state = drck->empty_state; } -static void spapr_dr_connector_class_init(ObjectClass *k, void *data) +static void spapr_dr_connector_class_init(ObjectClass *k, const void *data) { DeviceClass *dk = DEVICE_CLASS(k); @@ -665,7 +665,7 @@ static void unrealize_physical(DeviceState *d) qemu_unregister_reset(drc_physical_reset, drcp); } -static void spapr_drc_physical_class_init(ObjectClass *k, void *data) +static void spapr_drc_physical_class_init(ObjectClass *k, const void *data) { DeviceClass *dk = DEVICE_CLASS(k); SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -679,7 +679,7 @@ static void spapr_drc_physical_class_init(ObjectClass *k, void *data) drck->empty_state = SPAPR_DRC_STATE_PHYSICAL_POWERON; } -static void spapr_drc_logical_class_init(ObjectClass *k, void *data) +static void spapr_drc_logical_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -690,7 +690,7 @@ static void spapr_drc_logical_class_init(ObjectClass *k, void *data) drck->empty_state = SPAPR_DRC_STATE_LOGICAL_UNUSABLE; } -static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) +static void spapr_drc_cpu_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -701,7 +701,7 @@ static void spapr_drc_cpu_class_init(ObjectClass *k, void *data) drck->dt_populate = spapr_core_dt_populate; } -static void spapr_drc_pci_class_init(ObjectClass *k, void *data) +static void spapr_drc_pci_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -712,7 +712,7 @@ static void spapr_drc_pci_class_init(ObjectClass *k, void *data) drck->dt_populate = spapr_pci_dt_populate; } -static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) +static void spapr_drc_lmb_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -723,7 +723,7 @@ static void spapr_drc_lmb_class_init(ObjectClass *k, void *data) drck->dt_populate = spapr_lmb_dt_populate; } -static void spapr_drc_phb_class_init(ObjectClass *k, void *data) +static void spapr_drc_phb_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); @@ -734,7 +734,7 @@ static void spapr_drc_phb_class_init(ObjectClass *k, void *data) drck->dt_populate = spapr_phb_dt_populate; } -static void spapr_drc_pmem_class_init(ObjectClass *k, void *data) +static void spapr_drc_pmem_class_init(ObjectClass *k, const void *data) { SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_CLASS(k); diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c index db3a14c1df..c2432a0c00 100644 --- a/hw/ppc/spapr_iommu.c +++ b/hw/ppc/spapr_iommu.c @@ -668,7 +668,7 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, tcet->liobn, 0, tcet->nb_table << tcet->page_shift); } -static void spapr_tce_table_class_init(ObjectClass *klass, void *data) +static void spapr_tce_table_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = spapr_tce_table_realize; @@ -693,7 +693,8 @@ static const TypeInfo spapr_tce_table_info = { .class_init = spapr_tce_table_class_init, }; -static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void spapr_iommu_memory_region_class_init(ObjectClass *klass, + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/ppc/spapr_nvdimm.c b/hw/ppc/spapr_nvdimm.c index 6e93ff9b33..72b4a6329f 100644 --- a/hw/ppc/spapr_nvdimm.c +++ b/hw/ppc/spapr_nvdimm.c @@ -888,7 +888,7 @@ static const Property spapr_nvdimm_properties[] = { }; #endif -static void spapr_nvdimm_class_init(ObjectClass *oc, void *data) +static void spapr_nvdimm_class_init(ObjectClass *oc, const void *data) { NVDIMMClass *nvc = NVDIMM_CLASS(oc); diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 384269b831..d0468e3fe6 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2173,7 +2173,7 @@ static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge, return sphb->dtbusname; } -static void spapr_phb_class_init(ObjectClass *klass, void *data) +static void spapr_phb_class_init(ObjectClass *klass, const void *data) { PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ppc/spapr_rng.c b/hw/ppc/spapr_rng.c index 95def5b1e5..6fec607037 100644 --- a/hw/ppc/spapr_rng.c +++ b/hw/ppc/spapr_rng.c @@ -136,7 +136,7 @@ static const Property spapr_rng_properties[] = { RngBackend *), }; -static void spapr_rng_class_init(ObjectClass *oc, void *data) +static void spapr_rng_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/spapr_rtc.c b/hw/ppc/spapr_rtc.c index 46fbc78900..1f7d2d8f89 100644 --- a/hw/ppc/spapr_rtc.c +++ b/hw/ppc/spapr_rtc.c @@ -163,7 +163,7 @@ static const VMStateDescription vmstate_spapr_rtc = { }, }; -static void spapr_rtc_class_init(ObjectClass *oc, void *data) +static void spapr_rtc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ppc/spapr_tpm_proxy.c b/hw/ppc/spapr_tpm_proxy.c index ceaa0acaa1..862eeaa50a 100644 --- a/hw/ppc/spapr_tpm_proxy.c +++ b/hw/ppc/spapr_tpm_proxy.c @@ -149,7 +149,7 @@ static const Property spapr_tpm_proxy_properties[] = { DEFINE_PROP_STRING("host-path", SpaprTpmProxy, host_path), }; -static void spapr_tpm_proxy_class_init(ObjectClass *k, void *data) +static void spapr_tpm_proxy_class_init(ObjectClass *k, const void *data) { DeviceClass *dk = DEVICE_CLASS(k); diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index 09243c183b..7759436a4f 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -50,7 +50,7 @@ static char *spapr_vio_get_dev_name(DeviceState *qdev) return g_strdup_printf("%s@%x", pc->dt_name, dev->reg); } -static void spapr_vio_bus_class_init(ObjectClass *klass, void *data) +static void spapr_vio_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -599,7 +599,7 @@ SpaprVioBus *spapr_vio_bus_init(void) return bus; } -static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data) +static void spapr_vio_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -631,7 +631,7 @@ const VMStateDescription vmstate_spapr_vio = { }, }; -static void vio_spapr_device_class_init(ObjectClass *klass, void *data) +static void vio_spapr_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->realize = spapr_vio_busdev_realize; diff --git a/hw/remote/machine.c b/hw/remote/machine.c index d4616025e8..9fb92ec6f1 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -121,7 +121,7 @@ static void remote_machine_dev_unplug_cb(HotplugHandler *hotplug_dev, } } -static void remote_machine_class_init(ObjectClass *oc, void *data) +static void remote_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index 96d831a579..d2de48c9e3 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -195,7 +195,7 @@ static const Property proxy_properties[] = { DEFINE_PROP_STRING("fd", PCIProxyDev, fd), }; -static void pci_proxy_dev_class_init(ObjectClass *klass, void *data) +static void pci_proxy_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c index 2f25f92dcd..75f8d6df8a 100644 --- a/hw/remote/remote-obj.c +++ b/hw/remote/remote-obj.c @@ -163,7 +163,7 @@ static void remote_object_finalize(Object *obj) g_free(o->devid); } -static void remote_object_class_init(ObjectClass *klass, void *data) +static void remote_object_class_init(ObjectClass *klass, const void *data) { RemoteObjectClass *k = REMOTE_OBJECT_CLASS(klass); diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index 9bdd0a465b..b0ae403f06 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -917,7 +917,7 @@ static void vfu_object_finalize(Object *obj) } } -static void vfu_object_class_init(ObjectClass *klass, void *data) +static void vfu_object_class_init(ObjectClass *klass, const void *data) { VfuObjectClass *k = VFU_OBJECT_CLASS(klass); diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 9c846f9b5b..e39ee657cd 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -479,7 +479,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) qspi_xip_mem); } -static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data) +static void microchip_pfsoc_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -639,7 +639,8 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } } -static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data) +static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 019d6b3986..d369a8a7dc 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -112,7 +112,7 @@ static void opentitan_machine_init(MachineState *machine) } } -static void opentitan_machine_class_init(ObjectClass *oc, void *data) +static void opentitan_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -313,7 +313,7 @@ static const Property lowrisc_ibex_soc_props[] = { DEFINE_PROP_UINT32("resetvec", LowRISCIbexSoCState, resetvec, 0x20000400), }; -static void lowrisc_ibex_soc_class_init(ObjectClass *oc, void *data) +static void lowrisc_ibex_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/riscv/riscv-iommu-pci.c b/hw/riscv/riscv-iommu-pci.c index a795464803..d93cf7521b 100644 --- a/hw/riscv/riscv-iommu-pci.c +++ b/hw/riscv/riscv-iommu-pci.c @@ -184,7 +184,7 @@ static void riscv_iommu_pci_reset_hold(Object *obj, ResetType type) trace_riscv_iommu_pci_reset_hold(type); } -static void riscv_iommu_pci_class_init(ObjectClass *klass, void *data) +static void riscv_iommu_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c index 65b24fb07d..be2e3944dc 100644 --- a/hw/riscv/riscv-iommu-sys.c +++ b/hw/riscv/riscv-iommu-sys.c @@ -227,7 +227,7 @@ static void riscv_iommu_sys_reset_hold(Object *obj, ResetType type) trace_riscv_iommu_sys_reset_hold(type); } -static void riscv_iommu_sys_class_init(ObjectClass *klass, void *data) +static void riscv_iommu_sys_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index 65411b3e4c..a877e5da84 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -2513,7 +2513,7 @@ static const Property riscv_iommu_properties[] = { RISCV_IOMMU_IOCOUNT_NUM), }; -static void riscv_iommu_class_init(ObjectClass *klass, void* data) +static void riscv_iommu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2654,7 +2654,7 @@ static int riscv_iommu_memory_region_index_len(IOMMUMemoryRegion *iommu_mr) return 1 << as->iommu->pid_bits; } -static void riscv_iommu_memory_region_init(ObjectClass *klass, void *data) +static void riscv_iommu_memory_region_init(ObjectClass *klass, const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index a55d156668..ac6539bd3e 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -160,7 +160,7 @@ static void riscv_harts_realize(DeviceState *dev, Error **errp) } } -static void riscv_harts_class_init(ObjectClass *klass, void *data) +static void riscv_harts_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/riscv/shakti_c.c b/hw/riscv/shakti_c.c index 17c5c72102..3e7f441172 100644 --- a/hw/riscv/shakti_c.c +++ b/hw/riscv/shakti_c.c @@ -71,7 +71,7 @@ static void shakti_c_machine_instance_init(Object *obj) { } -static void shakti_c_machine_class_init(ObjectClass *klass, void *data) +static void shakti_c_machine_class_init(ObjectClass *klass, const void *data) { MachineClass *mc = MACHINE_CLASS(klass); static const char * const valid_cpu_types[] = { @@ -142,7 +142,7 @@ static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp) shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom); } -static void shakti_c_soc_class_init(ObjectClass *klass, void *data) +static void shakti_c_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = shakti_c_soc_state_realize; diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 73d3b74281..7baed1958e 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -143,7 +143,7 @@ static void sifive_e_machine_instance_init(Object *obj) s->revb = false; } -static void sifive_e_machine_class_init(ObjectClass *oc, void *data) +static void sifive_e_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -284,7 +284,7 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp) &s->xip_mem); } -static void sifive_e_soc_class_init(ObjectClass *oc, void *data) +static void sifive_e_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 679f2024bc..d69f942cfb 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -713,7 +713,7 @@ static void sifive_u_machine_instance_init(Object *obj) object_property_set_description(obj, "serial", "Board serial number"); } -static void sifive_u_machine_class_init(ObjectClass *oc, void *data) +static void sifive_u_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -946,7 +946,7 @@ static const Property sifive_u_soc_props[] = { DEFINE_PROP_STRING("cpu-type", SiFiveUSoCState, cpu_type), }; -static void sifive_u_soc_class_init(ObjectClass *oc, void *data) +static void sifive_u_soc_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 74a20016f1..641aae8c01 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -342,7 +342,7 @@ static void spike_machine_instance_init(Object *obj) { } -static void spike_machine_class_init(ObjectClass *oc, void *data) +static void spike_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 85849e604c..557efd15a1 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1906,7 +1906,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, } } -static void virt_machine_class_init(ObjectClass *oc, void *data) +static void virt_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c index fd8355a867..a747bff534 100644 --- a/hw/rtc/allwinner-rtc.c +++ b/hw/rtc/allwinner-rtc.c @@ -315,7 +315,7 @@ static const Property allwinner_rtc_properties[] = { DEFINE_PROP_INT32("base-year", AwRtcState, base_year, 0), }; -static void allwinner_rtc_class_init(ObjectClass *klass, void *data) +static void allwinner_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -330,7 +330,7 @@ static void allwinner_rtc_sun4i_init(Object *obj) s->base_year = 2010; } -static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, void *data) +static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, const void *data) { AwRtcClass *arc = AW_RTC_CLASS(klass); @@ -346,7 +346,7 @@ static void allwinner_rtc_sun6i_init(Object *obj) s->base_year = 1970; } -static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, void *data) +static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, const void *data) { AwRtcClass *arc = AW_RTC_CLASS(klass); @@ -362,7 +362,7 @@ static void allwinner_rtc_sun7i_init(Object *obj) s->base_year = 1970; } -static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, void *data) +static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, const void *data) { AwRtcClass *arc = AW_RTC_CLASS(klass); allwinner_rtc_sun4i_class_init(klass, arc); diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c index fbdeb0781f..c4feea23a0 100644 --- a/hw/rtc/aspeed_rtc.c +++ b/hw/rtc/aspeed_rtc.c @@ -156,7 +156,7 @@ static void aspeed_rtc_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void aspeed_rtc_class_init(ObjectClass *klass, void *data) +static void aspeed_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c index 8dd17fdc07..5f1ee2e410 100644 --- a/hw/rtc/ds1338.c +++ b/hw/rtc/ds1338.c @@ -220,7 +220,7 @@ static void ds1338_reset(DeviceState *dev) s->addr_byte = false; } -static void ds1338_class_init(ObjectClass *klass, void *data) +static void ds1338_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c index aa1b3cd115..624b4f61a8 100644 --- a/hw/rtc/exynos4210_rtc.c +++ b/hw/rtc/exynos4210_rtc.c @@ -592,7 +592,7 @@ static void exynos4210_rtc_finalize(Object *obj) ptimer_free(s->ptimer_1Hz); } -static void exynos4210_rtc_class_init(ObjectClass *klass, void *data) +static void exynos4210_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index d83cc26481..78df031cf2 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -273,7 +273,7 @@ static const Property goldfish_rtc_properties[] = { false), }; -static void goldfish_rtc_class_init(ObjectClass *klass, void *data) +static void goldfish_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c index fce23a3dbe..10097b2db7 100644 --- a/hw/rtc/ls7a_rtc.c +++ b/hw/rtc/ls7a_rtc.c @@ -464,7 +464,7 @@ static const VMStateDescription vmstate_ls7a_rtc = { } }; -static void ls7a_rtc_class_init(ObjectClass *klass, void *data) +static void ls7a_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->vmsd = &vmstate_ls7a_rtc; diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c index 9600695679..c631ec3ea1 100644 --- a/hw/rtc/m41t80.c +++ b/hw/rtc/m41t80.c @@ -94,7 +94,7 @@ static int m41t80_event(I2CSlave *i2c, enum i2c_event event) return 0; } -static void m41t80_class_init(ObjectClass *klass, void *data) +static void m41t80_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c index 9c3855a3ef..4a7c0af9f0 100644 --- a/hw/rtc/m48t59-isa.c +++ b/hw/rtc/m48t59-isa.c @@ -113,7 +113,7 @@ static void m48t59_isa_realize(DeviceState *dev, Error **errp) } } -static void m48txx_isa_class_init(ObjectClass *klass, void *data) +static void m48txx_isa_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); NvramClass *nc = NVRAM_CLASS(klass); @@ -126,7 +126,7 @@ static void m48txx_isa_class_init(ObjectClass *klass, void *data) nc->toggle_lock = m48txx_isa_toggle_lock; } -static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data) +static void m48txx_isa_concrete_class_init(ObjectClass *klass, const void *data) { M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass); const M48txxInfo *info = data; diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index 3fb2f27d9d..821472a680 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -622,7 +622,7 @@ static const Property m48t59_sysbus_properties[] = { DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0), }; -static void m48txx_sysbus_class_init(ObjectClass *klass, void *data) +static void m48txx_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); NvramClass *nc = NVRAM_CLASS(klass); @@ -636,7 +636,8 @@ static void m48txx_sysbus_class_init(ObjectClass *klass, void *data) nc->toggle_lock = m48txx_sysbus_toggle_lock; } -static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data) +static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, + const void *data) { M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass); const M48txxInfo *info = data; diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index e322fc2ffb..93b632bdf4 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -1018,7 +1018,7 @@ static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(scope, dev); } -static void rtc_class_initfn(ObjectClass *klass, void *data) +static void rtc_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c index ed439bd3ad..e545b9dfd6 100644 --- a/hw/rtc/pl031.c +++ b/hw/rtc/pl031.c @@ -332,7 +332,7 @@ static const Property pl031_properties[] = { PL031State, migrate_tick_offset, true), }; -static void pl031_class_init(ObjectClass *klass, void *data) +static void pl031_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c index 5542f74085..bb924534a7 100644 --- a/hw/rtc/rs5c372.c +++ b/hw/rtc/rs5c372.c @@ -210,7 +210,7 @@ static void rs5c372_init(Object *obj) qdev_prop_set_uint8(DEVICE(obj), "address", 0x32); } -static void rs5c372_class_init(ObjectClass *klass, void *data) +static void rs5c372_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c index ffcc0aa25d..29e24ef6be 100644 --- a/hw/rtc/sun4v-rtc.c +++ b/hw/rtc/sun4v-rtc.c @@ -75,7 +75,7 @@ static void sun4v_rtc_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); } -static void sun4v_rtc_class_init(ObjectClass *klass, void *data) +static void sun4v_rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c index b596b608c5..500982a801 100644 --- a/hw/rtc/xlnx-zynqmp-rtc.c +++ b/hw/rtc/xlnx-zynqmp-rtc.c @@ -251,7 +251,7 @@ static const VMStateDescription vmstate_rtc = { } }; -static void rtc_class_init(ObjectClass *klass, void *data) +static void rtc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/rx/rx-gdbsim.c b/hw/rx/rx-gdbsim.c index 4afd77efd5..5b9004e9e1 100644 --- a/hw/rx/rx-gdbsim.c +++ b/hw/rx/rx-gdbsim.c @@ -155,7 +155,7 @@ static void rx_gdbsim_init(MachineState *machine) } } -static void rx_gdbsim_class_init(ObjectClass *oc, void *data) +static void rx_gdbsim_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -165,7 +165,7 @@ static void rx_gdbsim_class_init(ObjectClass *oc, void *data) mc->default_ram_id = "ext-sdram"; } -static void rx62n7_class_init(ObjectClass *oc, void *data) +static void rx62n7_class_init(ObjectClass *oc, const void *data) { RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); @@ -175,7 +175,7 @@ static void rx62n7_class_init(ObjectClass *oc, void *data) mc->desc = "gdb simulator (R5F562N7 MCU and external RAM)"; }; -static void rx62n8_class_init(ObjectClass *oc, void *data) +static void rx62n8_class_init(ObjectClass *oc, const void *data) { RxGdbSimMachineClass *rxc = RX_GDBSIM_MACHINE_CLASS(oc); MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/rx/rx62n.c b/hw/rx/rx62n.c index e6bac4f053..a2a243afa4 100644 --- a/hw/rx/rx62n.c +++ b/hw/rx/rx62n.c @@ -264,7 +264,7 @@ static const Property rx62n_properties[] = { DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0), }; -static void rx62n_class_init(ObjectClass *klass, void *data) +static void rx62n_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -272,7 +272,7 @@ static void rx62n_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, rx62n_properties); } -static void r5f562n7_class_init(ObjectClass *oc, void *data) +static void r5f562n7_class_init(ObjectClass *oc, const void *data) { RX62NClass *rxc = RX62N_MCU_CLASS(oc); @@ -281,7 +281,7 @@ static void r5f562n7_class_init(ObjectClass *oc, void *data) rxc->data_flash_size = 32 * KiB; }; -static void r5f562n8_class_init(ObjectClass *oc, void *data) +static void r5f562n8_class_init(ObjectClass *oc, const void *data) { RX62NClass *rxc = RX62N_MCU_CLASS(oc); diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index 3a8930dfd1..3f0d384fd8 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -150,7 +150,7 @@ out_err: g_free(sch); } -static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data) +static void emulated_ccw_3270_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index ef8fa2b15b..4aa7d5a90d 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -22,7 +22,7 @@ static char *ap_bus_get_dev_path(DeviceState *dev) return g_strdup_printf("/1"); } -static void ap_bus_class_init(ObjectClass *oc, void *data) +static void ap_bus_class_init(ObjectClass *oc, const void *data) { BusClass *k = BUS_CLASS(oc); @@ -61,7 +61,7 @@ void s390_init_ap(void) qbus_set_hotplug_handler(bus, OBJECT(dev)); } -static void ap_bridge_class_init(ObjectClass *oc, void *data) +static void ap_bridge_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); diff --git a/hw/s390x/ap-device.c b/hw/s390x/ap-device.c index 237d1f19c5..733104403e 100644 --- a/hw/s390x/ap-device.c +++ b/hw/s390x/ap-device.c @@ -12,7 +12,7 @@ #include "qapi/error.h" #include "hw/s390x/ap-device.h" -static void ap_class_init(ObjectClass *klass, void *data) +static void ap_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/s390x/ccw-device.c b/hw/s390x/ccw-device.c index 1ea9934f6c..19c2238f76 100644 --- a/hw/s390x/ccw-device.c +++ b/hw/s390x/ccw-device.c @@ -94,7 +94,7 @@ static void ccw_device_reset_hold(Object *obj, ResetType type) css_reset_sch(ccw_dev->sch); } -static void ccw_device_class_init(ObjectClass *klass, void *data) +static void ccw_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CCWDeviceClass *k = CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index c48d5571b5..9d91e5a5fe 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -70,7 +70,7 @@ static char *virtual_css_bus_get_dev_path(DeviceState *dev) return g_strdup_printf("/%02x.%1x.%04x", sch->cssid, sch->ssid, sch->devno); } -static void virtual_css_bus_class_init(ObjectClass *klass, void *data) +static void virtual_css_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -117,7 +117,7 @@ static bool prop_get_true(Object *obj, Error **errp) return true; } -static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) +static void virtual_css_bridge_class_init(ObjectClass *klass, const void *data) { HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 2b0332c20e..1afe364573 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -460,7 +460,7 @@ static void reset_event_facility(DeviceState *dev) sdev->receive_mask = 0; } -static void init_event_facility_class(ObjectClass *klass, void *data) +static void init_event_facility_class(ObjectClass *klass, const void *data) { SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(sbdc); @@ -497,7 +497,7 @@ static void event_realize(DeviceState *qdev, Error **errp) } } -static void event_class_init(ObjectClass *klass, void *data) +static void event_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index ce6f6078d7..716a6b7869 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -736,7 +736,7 @@ static void s390_ipl_reset(DeviceState *dev) } } -static void s390_ipl_class_init(ObjectClass *klass, void *data) +static void s390_ipl_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 909475f048..10c81a4c89 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -175,7 +175,7 @@ static void s390_ccw_instance_init(Object *obj) "/disk@0,0", DEVICE(obj)); } -static void s390_ccw_class_init(ObjectClass *klass, void *data) +static void s390_ccw_class_init(ObjectClass *klass, const void *data) { S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 501330bfa7..838b7e6484 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1373,7 +1373,7 @@ static void s390_pcihost_reset(DeviceState *dev) pci_for_each_device_under_bus(bus, s390_pci_enumerate_bridge, s); } -static void s390_pcihost_class_init(ObjectClass *klass, void *data) +static void s390_pcihost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); @@ -1557,7 +1557,7 @@ static const VMStateDescription s390_pci_device_vmstate = { .unmigratable = 1, }; -static void s390_pci_device_class_init(ObjectClass *klass, void *data) +static void s390_pci_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1583,7 +1583,8 @@ static const TypeInfo s390_pci_iommu_info = { .instance_size = sizeof(S390PCIIOMMU), }; -static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void s390_iommu_memory_region_class_init(ObjectClass *klass, + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c index 0215e94388..f3056d6d25 100644 --- a/hw/s390x/s390-skeys-kvm.c +++ b/hw/s390x/s390-skeys-kvm.c @@ -52,7 +52,7 @@ static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, return kvm_vm_ioctl(kvm_state, KVM_S390_SET_SKEYS, &args); } -static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data) +static void kvm_s390_skeys_class_init(ObjectClass *oc, const void *data) { S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index d437fe070d..aedb62b2d3 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -304,7 +304,7 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, return 0; } -static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) +static void qemu_s390_skeys_class_init(ObjectClass *oc, const void *data) { S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -466,7 +466,7 @@ static void s390_skeys_realize(DeviceState *dev, Error **errp) register_savevm_live(TYPE_S390_SKEYS, 0, 1, &savevm_s390_storage_keys, ss); } -static void s390_skeys_class_init(ObjectClass *oc, void *data) +static void s390_skeys_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c index ebcd56368f..e1fee361dc 100644 --- a/hw/s390x/s390-stattrib-kvm.c +++ b/hw/s390x/s390-stattrib-kvm.c @@ -188,7 +188,7 @@ static int kvm_s390_stattrib_get_active(S390StAttribState *sa) return kvm_s390_cmma_active(); } -static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) +static void kvm_s390_stattrib_class_init(ObjectClass *oc, const void *data) { S390StAttribClass *sac = S390_STATTRIB_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index a86002be6a..f74cf32636 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -307,7 +307,7 @@ static int qemu_s390_get_active(S390StAttribState *sa) return true; } -static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) +static void qemu_s390_stattrib_class_init(ObjectClass *oc, const void *data) { S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -360,7 +360,7 @@ static void s390_stattrib_realize(DeviceState *dev, Error **errp) &savevm_s390_stattrib_handlers, dev); } -static void s390_stattrib_class_init(ObjectClass *oc, void *data) +static void s390_stattrib_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index cf5b9974c5..00e9e46aef 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -804,7 +804,7 @@ static void machine_set_loadparm(Object *obj, Visitor *v, s390_ipl_fmt_loadparm(ms->loadparm, val, errp); } -static void ccw_machine_class_init(ObjectClass *oc, void *data) +static void ccw_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); NMIClass *nc = NMI_CLASS(oc); @@ -892,7 +892,7 @@ static const TypeInfo ccw_machine_info = { } \ static void MACHINE_VER_SYM(class_init, ccw, __VA_ARGS__)( \ ObjectClass *oc, \ - void *data) \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ MACHINE_VER_SYM(class_options, ccw, __VA_ARGS__)(mc); \ diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 5945c9b1d8..9718564fa4 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -424,7 +424,7 @@ static void sclp_init(Object *obj) sclp_memory_init(sclp); } -static void sclp_class_init(ObjectClass *oc, void *data) +static void sclp_class_init(ObjectClass *oc, const void *data) { SCLPDeviceClass *sc = SCLP_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index a178a9dd4c..4b6ebfed46 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -73,7 +73,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, return 1; } -static void sclp_cpu_class_init(ObjectClass *oc, void *data) +static void sclp_cpu_class_init(ObjectClass *oc, const void *data) { SCLPEventClass *k = SCLP_EVENT_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 7bb5aad520..da4c8f3e36 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -112,7 +112,7 @@ static void quiesce_reset(DeviceState *dev) event->event_pending = false; } -static void quiesce_class_init(ObjectClass *klass, void *data) +static void quiesce_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCLPEventClass *k = SCLP_EVENT_CLASS(klass); diff --git a/hw/s390x/tod-kvm.c b/hw/s390x/tod-kvm.c index 5da9037e0c..c9b8896b63 100644 --- a/hw/s390x/tod-kvm.c +++ b/hw/s390x/tod-kvm.c @@ -133,7 +133,7 @@ static void kvm_s390_tod_realize(DeviceState *dev, Error **errp) qemu_add_vm_change_state_handler(kvm_s390_tod_vm_state_change, td); } -static void kvm_s390_tod_class_init(ObjectClass *oc, void *data) +static void kvm_s390_tod_class_init(ObjectClass *oc, const void *data) { S390TODClass *tdc = S390_TOD_CLASS(oc); diff --git a/hw/s390x/tod-tcg.c b/hw/s390x/tod-tcg.c index 3b3ef8843e..0cc96624e1 100644 --- a/hw/s390x/tod-tcg.c +++ b/hw/s390x/tod-tcg.c @@ -52,7 +52,7 @@ static void qemu_s390_tod_set(S390TODState *td, const S390TOD *tod, } } -static void qemu_s390_tod_class_init(ObjectClass *oc, void *data) +static void qemu_s390_tod_class_init(ObjectClass *oc, const void *data) { S390TODClass *tdc = S390_TOD_CLASS(oc); diff --git a/hw/s390x/tod.c b/hw/s390x/tod.c index 6afbb23fc7..3f913cc88a 100644 --- a/hw/s390x/tod.c +++ b/hw/s390x/tod.c @@ -111,7 +111,7 @@ static void s390_tod_realize(DeviceState *dev, Error **errp) register_savevm_live("todclock", 0, 1, &savevm_tod, td); } -static void s390_tod_class_init(ObjectClass *oc, void *data) +static void s390_tod_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/s390x/vhost-scsi-ccw.c b/hw/s390x/vhost-scsi-ccw.c index e6bf0c55bc..8341b23a95 100644 --- a/hw/s390x/vhost-scsi-ccw.c +++ b/hw/s390x/vhost-scsi-ccw.c @@ -46,7 +46,7 @@ static const Property vhost_ccw_scsi_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) +static void vhost_ccw_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/vhost-user-fs-ccw.c b/hw/s390x/vhost-user-fs-ccw.c index 6a9654d77b..cc1b8227fc 100644 --- a/hw/s390x/vhost-user-fs-ccw.c +++ b/hw/s390x/vhost-user-fs-ccw.c @@ -48,7 +48,7 @@ static void vhost_user_fs_ccw_instance_init(Object *obj) TYPE_VHOST_USER_FS); } -static void vhost_user_fs_ccw_class_init(ObjectClass *klass, void *data) +static void vhost_user_fs_ccw_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/vhost-vsock-ccw.c b/hw/s390x/vhost-vsock-ccw.c index 875ccf3485..552e9e86a4 100644 --- a/hw/s390x/vhost-vsock-ccw.c +++ b/hw/s390x/vhost-vsock-ccw.c @@ -35,7 +35,7 @@ static void vhost_vsock_ccw_realize(VirtioCcwDevice *ccw_dev, Error **errp) qdev_realize(vdev, BUS(&ccw_dev->bus), errp); } -static void vhost_vsock_ccw_class_init(ObjectClass *klass, void *data) +static void vhost_vsock_ccw_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-9p.c b/hw/s390x/virtio-ccw-9p.c index 287ae2ba76..72bf6ec80c 100644 --- a/hw/s390x/virtio-ccw-9p.c +++ b/hw/s390x/virtio-ccw-9p.c @@ -48,7 +48,7 @@ static const Property virtio_ccw_9p_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_9p_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-balloon.c b/hw/s390x/virtio-ccw-balloon.c index 1180efaf6d..399b40f366 100644 --- a/hw/s390x/virtio-ccw-balloon.c +++ b/hw/s390x/virtio-ccw-balloon.c @@ -53,7 +53,7 @@ static const Property virtio_ccw_balloon_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_balloon_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-blk.c b/hw/s390x/virtio-ccw-blk.c index db9d442ffb..7d8c4a75ce 100644 --- a/hw/s390x/virtio-ccw-blk.c +++ b/hw/s390x/virtio-ccw-blk.c @@ -51,7 +51,7 @@ static const Property virtio_ccw_blk_properties[] = { DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm), }; -static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_blk_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-crypto.c b/hw/s390x/virtio-ccw-crypto.c index b693f87c70..75e714603b 100644 --- a/hw/s390x/virtio-ccw-crypto.c +++ b/hw/s390x/virtio-ccw-crypto.c @@ -51,7 +51,7 @@ static const Property virtio_ccw_crypto_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_crypto_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_crypto_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-gpu.c b/hw/s390x/virtio-ccw-gpu.c index a6b14c25d9..edb6a47d37 100644 --- a/hw/s390x/virtio-ccw-gpu.c +++ b/hw/s390x/virtio-ccw-gpu.c @@ -49,7 +49,7 @@ static const Property virtio_ccw_gpu_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_gpu_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_gpu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-input.c b/hw/s390x/virtio-ccw-input.c index 6ca10d58ee..2250d8cf98 100644 --- a/hw/s390x/virtio-ccw-input.c +++ b/hw/s390x/virtio-ccw-input.c @@ -50,7 +50,7 @@ static const Property virtio_ccw_input_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_input_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_input_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-mem.c b/hw/s390x/virtio-ccw-mem.c index 90fd89f015..daa485d189 100644 --- a/hw/s390x/virtio-ccw-mem.c +++ b/hw/s390x/virtio-ccw-mem.c @@ -160,7 +160,7 @@ static const Property virtio_ccw_mem_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_mem_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_mem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-net.c b/hw/s390x/virtio-ccw-net.c index 80a5581baf..a7d4afbeb9 100644 --- a/hw/s390x/virtio-ccw-net.c +++ b/hw/s390x/virtio-ccw-net.c @@ -54,7 +54,7 @@ static const Property virtio_ccw_net_properties[] = { DEFINE_PROP_CCW_LOADPARM("loadparm", CcwDevice, loadparm), }; -static void virtio_ccw_net_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_net_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-rng.c b/hw/s390x/virtio-ccw-rng.c index ccd124ee91..3263287d45 100644 --- a/hw/s390x/virtio-ccw-rng.c +++ b/hw/s390x/virtio-ccw-rng.c @@ -50,7 +50,7 @@ static const Property virtio_ccw_rng_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-scsi.c b/hw/s390x/virtio-ccw-scsi.c index bfcea3cfe7..06b4c6c4a5 100644 --- a/hw/s390x/virtio-ccw-scsi.c +++ b/hw/s390x/virtio-ccw-scsi.c @@ -60,7 +60,7 @@ static const Property virtio_ccw_scsi_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw-serial.c b/hw/s390x/virtio-ccw-serial.c index 59743d1e25..0dac590c08 100644 --- a/hw/s390x/virtio-ccw-serial.c +++ b/hw/s390x/virtio-ccw-serial.c @@ -60,7 +60,7 @@ static const Property virtio_ccw_serial_properties[] = { VIRTIO_CCW_MAX_REV), }; -static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_serial_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e8ecb90826..d2f85b39f3 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -1228,7 +1228,7 @@ static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, virtio_ccw_stop_ioeventfd(_dev); } -static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CCWDeviceClass *k = CCW_DEVICE_CLASS(dc); @@ -1262,7 +1262,7 @@ static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, qbus_init(bus, bus_size, TYPE_VIRTIO_CCW_BUS, qdev, virtio_bus_name); } -static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) +static void virtio_ccw_bus_class_init(ObjectClass *klass, const void *data) { VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); BusClass *bus_class = BUS_CLASS(klass); diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index fe4e045a6f..74e9af0b5d 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -427,7 +427,7 @@ static void esp_pci_init(Object *obj) object_initialize_child(obj, "esp", &pci->esp, TYPE_ESP); } -static void esp_pci_class_init(ObjectClass *klass, void *data) +static void esp_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -557,7 +557,7 @@ static void dc390_scsi_realize(PCIDevice *dev, Error **errp) contents[EE_CHKSUM2] = chksum >> 8; } -static void dc390_class_init(ObjectClass *klass, void *data) +static void dc390_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 01bdfe2701..f24991fd16 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -1568,7 +1568,7 @@ static const VMStateDescription vmstate_sysbus_esp_scsi = { } }; -static void sysbus_esp_class_init(ObjectClass *klass, void *data) +static void sysbus_esp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1594,7 +1594,7 @@ static void esp_init(Object *obj) fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ); } -static void esp_class_init(ObjectClass *klass, void *data) +static void esp_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 6689ebba25..0ad61565bf 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2375,7 +2375,7 @@ static void lsi_scsi_exit(PCIDevice *dev) timer_free(s->scripts_timer); } -static void lsi_class_init(ObjectClass *klass, void *data) +static void lsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -2402,7 +2402,7 @@ static const TypeInfo lsi_info = { }, }; -static void lsi53c810_class_init(ObjectClass *klass, void *data) +static void lsi53c810_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index d56bfc711d..ffcabd5a8e 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2527,7 +2527,7 @@ static struct MegasasInfo megasas_devices[] = { } }; -static void megasas_class_init(ObjectClass *oc, void *data) +static void megasas_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index ba7a7d0770..17f73ce381 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -1416,7 +1416,7 @@ static const Property mptsas_properties[] = { DEFINE_PROP_ON_OFF_AUTO("msi", MPTSASState, msi, ON_OFF_AUTO_AUTO), }; -static void mptsas1068_class_init(ObjectClass *oc, void *data) +static void mptsas1068_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ece1107ee8..0456b4de0a 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -2001,7 +2001,7 @@ static const Property scsi_props[] = { DEFINE_PROP_UINT32("lun", SCSIDevice, lun, -1), }; -static void scsi_device_class_init(ObjectClass *klass, void *data) +static void scsi_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); set_bit(DEVICE_CATEGORY_STORAGE, k->categories); @@ -2030,7 +2030,7 @@ static const TypeInfo scsi_device_type_info = { .instance_init = scsi_dev_instance_init, }; -static void scsi_bus_class_init(ObjectClass *klass, void *data) +static void scsi_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index e59632e9b1..cb4af1b715 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3177,7 +3177,7 @@ static void scsi_property_add_specifics(DeviceClass *dc) } } -static void scsi_disk_base_class_initfn(ObjectClass *klass, void *data) +static void scsi_disk_base_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDiskClass *sdc = SCSI_DISK_BASE_CLASS(klass); @@ -3247,7 +3247,7 @@ static const VMStateDescription vmstate_scsi_disk_state = { } }; -static void scsi_hd_class_initfn(ObjectClass *klass, void *data) +static void scsi_hd_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); @@ -3289,7 +3289,7 @@ static const Property scsi_cd_properties[] = { SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0), }; -static void scsi_cd_class_initfn(ObjectClass *klass, void *data) +static void scsi_cd_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); @@ -3326,7 +3326,7 @@ static const Property scsi_block_properties[] = { DEFAULT_IO_TIMEOUT), }; -static void scsi_block_class_initfn(ObjectClass *klass, void *data) +static void scsi_block_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); diff --git a/hw/scsi/scsi-generic.c b/hw/scsi/scsi-generic.c index 6566720064..9e380a2109 100644 --- a/hw/scsi/scsi-generic.c +++ b/hw/scsi/scsi-generic.c @@ -786,7 +786,7 @@ static int scsi_generic_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, return scsi_bus_parse_cdb(dev, cmd, buf, buf_len, hba_private); } -static void scsi_generic_class_initfn(ObjectClass *klass, void *data) +static void scsi_generic_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SCSIDeviceClass *sc = SCSI_DEVICE_CLASS(klass); diff --git a/hw/scsi/spapr_vscsi.c b/hw/scsi/spapr_vscsi.c index 6962194eaa..20f70fb272 100644 --- a/hw/scsi/spapr_vscsi.c +++ b/hw/scsi/spapr_vscsi.c @@ -1267,7 +1267,7 @@ static const VMStateDescription vmstate_spapr_vscsi = { }, }; -static void spapr_vscsi_class_init(ObjectClass *klass, void *data) +static void spapr_vscsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 66e0c21c22..be5a416c1d 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -363,7 +363,7 @@ static const Property vhost_scsi_properties[] = { conf.worker_per_virtqueue, false), }; -static void vhost_scsi_class_init(ObjectClass *klass, void *data) +static void vhost_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index adb41b9816..807a58ecf4 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -386,7 +386,7 @@ static const VMStateDescription vmstate_vhost_scsi = { }, }; -static void vhost_user_scsi_class_init(ObjectClass *klass, void *data) +static void vhost_user_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index f5a3aa2366..ae67a7682a 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -1395,7 +1395,7 @@ static const VMStateDescription vmstate_virtio_scsi = { }, }; -static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) +static void virtio_scsi_common_class_init(ObjectClass *klass, const void *data) { VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -1404,7 +1404,7 @@ static void virtio_scsi_common_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } -static void virtio_scsi_class_init(ObjectClass *klass, void *data) +static void virtio_scsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index f07e377cb8..a8ea57ffad 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1317,7 +1317,7 @@ static void pvscsi_realize(DeviceState *qdev, Error **errp) pvs_c->parent_dc_realize(qdev, errp); } -static void pvscsi_class_init(ObjectClass *klass, void *data) +static void pvscsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/sd/allwinner-sdhost.c b/hw/sd/allwinner-sdhost.c index 03980d2716..b31da5c399 100644 --- a/hw/sd/allwinner-sdhost.c +++ b/hw/sd/allwinner-sdhost.c @@ -888,14 +888,15 @@ static void allwinner_sdhost_reset(DeviceState *dev) } } -static void allwinner_sdhost_bus_class_init(ObjectClass *klass, void *data) +static void allwinner_sdhost_bus_class_init(ObjectClass *klass, + const void *data) { SDBusClass *sbc = SD_BUS_CLASS(klass); sbc->set_inserted = allwinner_sdhost_set_inserted; } -static void allwinner_sdhost_class_init(ObjectClass *klass, void *data) +static void allwinner_sdhost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -905,7 +906,8 @@ static void allwinner_sdhost_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, allwinner_sdhost_properties); } -static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) +static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, + const void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 8 * KiB; @@ -913,7 +915,8 @@ static void allwinner_sdhost_sun4i_class_init(ObjectClass *klass, void *data) sc->can_calibrate = false; } -static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) +static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, + const void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 64 * KiB; @@ -922,7 +925,7 @@ static void allwinner_sdhost_sun5i_class_init(ObjectClass *klass, void *data) } static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass, - void *data) + const void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 64 * KiB; @@ -931,7 +934,7 @@ static void allwinner_sdhost_sun50i_a64_class_init(ObjectClass *klass, } static void allwinner_sdhost_sun50i_a64_emmc_class_init(ObjectClass *klass, - void *data) + const void *data) { AwSdHostClass *sc = AW_SDHOST_CLASS(klass); sc->max_desc_size = 8 * KiB; diff --git a/hw/sd/aspeed_sdhci.c b/hw/sd/aspeed_sdhci.c index 12cbbae5e7..fc38ad39ce 100644 --- a/hw/sd/aspeed_sdhci.c +++ b/hw/sd/aspeed_sdhci.c @@ -208,7 +208,7 @@ static const Property aspeed_sdhci_properties[] = { DEFINE_PROP_UINT8("num-slots", AspeedSDHCIState, num_slots, 0), }; -static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) +static void aspeed_sdhci_class_init(ObjectClass *classp, const void *data) { DeviceClass *dc = DEVICE_CLASS(classp); @@ -218,7 +218,7 @@ static void aspeed_sdhci_class_init(ObjectClass *classp, void *data) device_class_set_props(dc, aspeed_sdhci_properties); } -static void aspeed_2400_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -227,7 +227,7 @@ static void aspeed_2400_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000001e80080; } -static void aspeed_2500_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -236,7 +236,7 @@ static void aspeed_2500_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000001e80080; } -static void aspeed_2600_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); @@ -245,7 +245,7 @@ static void aspeed_2600_sdhci_class_init(ObjectClass *klass, void *data) asc->capareg = 0x0000000701f80080; } -static void aspeed_2700_sdhci_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_sdhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSDHCIClass *asc = ASPEED_SDHCI_CLASS(klass); diff --git a/hw/sd/bcm2835_sdhost.c b/hw/sd/bcm2835_sdhost.c index 0724949d0c..29debdf59e 100644 --- a/hw/sd/bcm2835_sdhost.c +++ b/hw/sd/bcm2835_sdhost.c @@ -428,7 +428,7 @@ static void bcm2835_sdhost_reset(DeviceState *dev) s->fifo_len = 0; } -static void bcm2835_sdhost_class_init(ObjectClass *klass, void *data) +static void bcm2835_sdhost_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sd/cadence_sdhci.c b/hw/sd/cadence_sdhci.c index ad9daa20ed..d576855a1a 100644 --- a/hw/sd/cadence_sdhci.c +++ b/hw/sd/cadence_sdhci.c @@ -165,7 +165,7 @@ static const VMStateDescription vmstate_cadence_sdhci = { }, }; -static void cadence_sdhci_class_init(ObjectClass *classp, void *data) +static void cadence_sdhci_class_init(ObjectClass *classp, const void *data) { DeviceClass *dc = DEVICE_CLASS(classp); diff --git a/hw/sd/npcm7xx_sdhci.c b/hw/sd/npcm7xx_sdhci.c index 99028c1a2c..0233d7bd4d 100644 --- a/hw/sd/npcm7xx_sdhci.c +++ b/hw/sd/npcm7xx_sdhci.c @@ -149,7 +149,7 @@ static const VMStateDescription vmstate_npcm7xx_sdhci = { }, }; -static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data) +static void npcm7xx_sdhci_class_init(ObjectClass *classp, const void *data) { DeviceClass *dc = DEVICE_CLASS(classp); diff --git a/hw/sd/omap_mmc.c b/hw/sd/omap_mmc.c index bbe7b971bb..b7648d41cc 100644 --- a/hw/sd/omap_mmc.c +++ b/hw/sd/omap_mmc.c @@ -612,7 +612,7 @@ static void omap_mmc_initfn(Object *obj) qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_SD_BUS, DEVICE(obj), "sd-bus"); } -static void omap_mmc_class_init(ObjectClass *oc, void *data) +static void omap_mmc_class_init(ObjectClass *oc, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(oc); diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c index 03d2ae7d21..b8fc9f86f1 100644 --- a/hw/sd/pl181.c +++ b/hw/sd/pl181.c @@ -509,7 +509,7 @@ static void pl181_init(Object *obj) qbus_init(&s->sdbus, sizeof(s->sdbus), TYPE_PL181_BUS, dev, "sd-bus"); } -static void pl181_class_init(ObjectClass *klass, void *data) +static void pl181_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); @@ -519,7 +519,7 @@ static void pl181_class_init(ObjectClass *klass, void *data) k->user_creatable = false; } -static void pl181_bus_class_init(ObjectClass *klass, void *data) +static void pl181_bus_class_init(ObjectClass *klass, const void *data) { SDBusClass *sbc = SD_BUS_CLASS(klass); diff --git a/hw/sd/sd.c b/hw/sd/sd.c index e541c57f8c..c275fdda2d 100644 --- a/hw/sd/sd.c +++ b/hw/sd/sd.c @@ -2751,7 +2751,7 @@ static const Property emmc_properties[] = { DEFINE_PROP_UINT8("boot-config", SDState, boot_config, 0x0), }; -static void sdmmc_common_class_init(ObjectClass *klass, void *data) +static void sdmmc_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SDCardClass *sc = SDMMC_COMMON_CLASS(klass); @@ -2774,7 +2774,7 @@ static void sdmmc_common_class_init(ObjectClass *klass, void *data) sc->get_readonly = sd_get_readonly; } -static void sd_class_init(ObjectClass *klass, void *data) +static void sd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SDCardClass *sc = SDMMC_COMMON_CLASS(klass); @@ -2793,7 +2793,7 @@ static void sd_class_init(ObjectClass *klass, void *data) * board to ensure that ssi transfers only occur when the chip select * is asserted. */ -static void sd_spi_class_init(ObjectClass *klass, void *data) +static void sd_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SDCardClass *sc = SDMMC_COMMON_CLASS(klass); @@ -2802,7 +2802,7 @@ static void sd_spi_class_init(ObjectClass *klass, void *data) sc->proto = &sd_proto_spi; } -static void emmc_class_init(ObjectClass *klass, void *data) +static void emmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SDCardClass *sc = SDMMC_COMMON_CLASS(klass); diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c index bca149e811..2a56fbf2cd 100644 --- a/hw/sd/sdhci-pci.c +++ b/hw/sd/sdhci-pci.c @@ -54,7 +54,7 @@ static void sdhci_pci_exit(PCIDevice *dev) sdhci_uninitfn(s); } -static void sdhci_pci_class_init(ObjectClass *klass, void *data) +static void sdhci_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c index 69baf73ae9..226ff133ff 100644 --- a/hw/sd/sdhci.c +++ b/hw/sd/sdhci.c @@ -1620,7 +1620,7 @@ static void sdhci_sysbus_unrealize(DeviceState *dev) } } -static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) +static void sdhci_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1633,7 +1633,7 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data) /* --- qdev bus master --- */ -static void sdhci_bus_class_init(ObjectClass *klass, void *data) +static void sdhci_bus_class_init(ObjectClass *klass, const void *data) { SDBusClass *sbc = SD_BUS_CLASS(klass); diff --git a/hw/sd/ssi-sd.c b/hw/sd/ssi-sd.c index c4a58da0ab..6c90a86ab4 100644 --- a/hw/sd/ssi-sd.c +++ b/hw/sd/ssi-sd.c @@ -389,7 +389,7 @@ static void ssi_sd_reset(DeviceState *dev) s->stopping = 0; } -static void ssi_sd_class_init(ObjectClass *klass, void *data) +static void ssi_sd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); diff --git a/hw/sensor/adm1266.c b/hw/sensor/adm1266.c index 25b87a7296..9017ce6116 100644 --- a/hw/sensor/adm1266.c +++ b/hw/sensor/adm1266.c @@ -223,7 +223,7 @@ static void adm1266_init(Object *obj) } } -static void adm1266_class_init(ObjectClass *klass, void *data) +static void adm1266_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sensor/adm1272.c b/hw/sensor/adm1272.c index 3fc1e5d0ad..0c739aa0d8 100644 --- a/hw/sensor/adm1272.c +++ b/hw/sensor/adm1272.c @@ -511,7 +511,7 @@ static void adm1272_init(Object *obj) } -static void adm1272_class_init(ObjectClass *klass, void *data) +static void adm1272_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sensor/dps310.c b/hw/sensor/dps310.c index 6966a53248..bcf615423a 100644 --- a/hw/sensor/dps310.c +++ b/hw/sensor/dps310.c @@ -197,7 +197,7 @@ static const VMStateDescription vmstate_dps310 = { } }; -static void dps310_class_init(ObjectClass *klass, void *data) +static void dps310_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/sensor/emc141x.c b/hw/sensor/emc141x.c index 33c1bd330f..7b2ce383a1 100644 --- a/hw/sensor/emc141x.c +++ b/hw/sensor/emc141x.c @@ -277,7 +277,7 @@ static void emc141x_class_init(ObjectClass *klass, const void *data) dc->vmsd = &vmstate_emc141x; } -static void emc1413_class_init(ObjectClass *klass, void *data) +static void emc1413_class_init(ObjectClass *klass, const void *data) { EMC141XClass *ec = EMC141X_CLASS(klass); @@ -286,7 +286,7 @@ static void emc1413_class_init(ObjectClass *klass, void *data) ec->sensors_count = 3; } -static void emc1414_class_init(ObjectClass *klass, void *data) +static void emc1414_class_init(ObjectClass *klass, const void *data) { EMC141XClass *ec = EMC141X_CLASS(klass); diff --git a/hw/sensor/isl_pmbus_vr.c b/hw/sensor/isl_pmbus_vr.c index c60282cfe7..e8d29b08ff 100644 --- a/hw/sensor/isl_pmbus_vr.c +++ b/hw/sensor/isl_pmbus_vr.c @@ -242,7 +242,7 @@ static void isl_pmbus_vr_class_init(ObjectClass *klass, const void *data, k->device_num_pages = pages; } -static void isl69260_class_init(ObjectClass *klass, void *data) +static void isl69260_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -251,7 +251,7 @@ static void isl69260_class_init(ObjectClass *klass, void *data) isl_pmbus_vr_class_init(klass, data, 2); } -static void raa228000_class_init(ObjectClass *klass, void *data) +static void raa228000_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -260,7 +260,7 @@ static void raa228000_class_init(ObjectClass *klass, void *data) isl_pmbus_vr_class_init(klass, data, 1); } -static void raa229004_class_init(ObjectClass *klass, void *data) +static void raa229004_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -269,7 +269,7 @@ static void raa229004_class_init(ObjectClass *klass, void *data) isl_pmbus_vr_class_init(klass, data, 2); } -static void isl69259_class_init(ObjectClass *klass, void *data) +static void isl69259_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sensor/lsm303dlhc_mag.c b/hw/sensor/lsm303dlhc_mag.c index 04471539b5..f9e501da84 100644 --- a/hw/sensor/lsm303dlhc_mag.c +++ b/hw/sensor/lsm303dlhc_mag.c @@ -530,7 +530,7 @@ static void lsm303dlhc_mag_initfn(Object *obj) /* * Set the virtual method pointers (bus state change, tx/rx, etc.). */ -static void lsm303dlhc_mag_class_init(ObjectClass *klass, void *data) +static void lsm303dlhc_mag_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/sensor/max31785.c b/hw/sensor/max31785.c index 3577a7c218..c75581455a 100644 --- a/hw/sensor/max31785.c +++ b/hw/sensor/max31785.c @@ -544,7 +544,7 @@ static void max31785_init(Object *obj) } } -static void max31785_class_init(ObjectClass *klass, void *data) +static void max31785_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sensor/max34451.c b/hw/sensor/max34451.c index 93b53f3db2..a369d2b531 100644 --- a/hw/sensor/max34451.c +++ b/hw/sensor/max34451.c @@ -746,7 +746,7 @@ static void max34451_init(Object *obj) } -static void max34451_class_init(ObjectClass *klass, void *data) +static void max34451_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/sensor/tmp105.c b/hw/sensor/tmp105.c index ef2824f3e1..f5b61109e3 100644 --- a/hw/sensor/tmp105.c +++ b/hw/sensor/tmp105.c @@ -313,7 +313,7 @@ static void tmp105_initfn(Object *obj) tmp105_set_temperature, NULL, NULL); } -static void tmp105_class_init(ObjectClass *klass, void *data) +static void tmp105_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/sensor/tmp421.c b/hw/sensor/tmp421.c index 007f7cd018..263bfa1bbd 100644 --- a/hw/sensor/tmp421.c +++ b/hw/sensor/tmp421.c @@ -337,7 +337,7 @@ static void tmp421_realize(DeviceState *dev, Error **errp) tmp421_reset(&s->i2c); } -static void tmp421_class_init(ObjectClass *klass, void *data) +static void tmp421_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index edbf19d958..8ac7e625ef 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -595,7 +595,7 @@ static void idreg_realize(DeviceState *ds, Error **errp) sysbus_init_mmio(dev, &s->mem); } -static void idreg_class_init(ObjectClass *oc, void *data) +static void idreg_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -645,7 +645,7 @@ static void afx_realize(DeviceState *ds, Error **errp) sysbus_init_mmio(dev, &s->mem); } -static void afx_class_init(ObjectClass *oc, void *data) +static void afx_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -727,7 +727,7 @@ static void prom_realize(DeviceState *ds, Error **errp) sysbus_init_mmio(dev, &s->prom); } -static void prom_class_init(ObjectClass *klass, void *data) +static void prom_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -771,7 +771,7 @@ static void ram_initfn(Object *obj) "Valid value is ID of a hostmem backend"); } -static void ram_class_init(ObjectClass *klass, void *data) +static void ram_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1098,7 +1098,7 @@ enum { ss600mp_id, }; -static void sun4m_machine_class_init(ObjectClass *oc, void *data) +static void sun4m_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1109,7 +1109,7 @@ static void sun4m_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_id = "sun4m.ram"; } -static void ss5_class_init(ObjectClass *oc, void *data) +static void ss5_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1146,7 +1146,7 @@ static void ss5_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss5_hwdef; } -static void ss10_class_init(ObjectClass *oc, void *data) +static void ss10_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1181,7 +1181,7 @@ static void ss10_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss10_hwdef; } -static void ss600mp_class_init(ObjectClass *oc, void *data) +static void ss600mp_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1214,7 +1214,7 @@ static void ss600mp_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss600mp_hwdef; } -static void ss20_class_init(ObjectClass *oc, void *data) +static void ss20_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1265,7 +1265,7 @@ static void ss20_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss20_hwdef; } -static void voyager_class_init(ObjectClass *oc, void *data) +static void voyager_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1297,7 +1297,7 @@ static void voyager_class_init(ObjectClass *oc, void *data) smc->hwdef = &voyager_hwdef; } -static void ss_lx_class_init(ObjectClass *oc, void *data) +static void ss_lx_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1330,7 +1330,7 @@ static void ss_lx_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss_lx_hwdef; } -static void ss4_class_init(ObjectClass *oc, void *data) +static void ss4_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1363,7 +1363,7 @@ static void ss4_class_init(ObjectClass *oc, void *data) smc->hwdef = &ss4_hwdef; } -static void scls_class_init(ObjectClass *oc, void *data) +static void scls_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); @@ -1395,7 +1395,7 @@ static void scls_class_init(ObjectClass *oc, void *data) smc->hwdef = &scls_hwdef; } -static void sbook_class_init(ObjectClass *oc, void *data) +static void sbook_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); Sun4mMachineClass *smc = SUN4M_MACHINE_CLASS(mc); diff --git a/hw/sparc/sun4m_iommu.c b/hw/sparc/sun4m_iommu.c index 4a542b18d2..a7ff36ee78 100644 --- a/hw/sparc/sun4m_iommu.c +++ b/hw/sparc/sun4m_iommu.c @@ -372,7 +372,7 @@ static const Property iommu_properties[] = { DEFINE_PROP_UINT32("version", IOMMUState, version, 0), }; -static void iommu_class_init(ObjectClass *klass, void *data) +static void iommu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -389,7 +389,8 @@ static const TypeInfo iommu_info = { .class_init = iommu_class_init, }; -static void sun4m_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void sun4m_iommu_memory_region_class_init(ObjectClass *klass, + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/sparc64/niagara.c b/hw/sparc64/niagara.c index 805ba6b1e3..1ffe92060a 100644 --- a/hw/sparc64/niagara.c +++ b/hw/sparc64/niagara.c @@ -157,7 +157,7 @@ static void niagara_init(MachineState *machine) sun4v_rtc_init(NIAGARA_RTC_BASE); } -static void niagara_class_init(ObjectClass *oc, void *data) +static void niagara_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index becdf3ea98..0e5fb4e1b5 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -266,7 +266,7 @@ static void power_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &d->power_mmio); } -static void power_class_init(ObjectClass *klass, void *data) +static void power_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -373,7 +373,7 @@ static const Property ebus_properties[] = { console_serial_base, 0), }; -static void ebus_class_init(ObjectClass *klass, void *data) +static void ebus_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -464,7 +464,7 @@ static void prom_realize(DeviceState *ds, Error **errp) sysbus_init_mmio(dev, &s->prom); } -static void prom_class_init(ObjectClass *klass, void *data) +static void prom_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -524,7 +524,7 @@ static const Property ram_properties[] = { DEFINE_PROP_UINT64("size", RamDevice, size, 0), }; -static void ram_class_init(ObjectClass *klass, void *data) +static void ram_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -787,7 +787,7 @@ static GlobalProperty hw_compat_sparc64[] = { }; static const size_t hw_compat_sparc64_len = G_N_ELEMENTS(hw_compat_sparc64); -static void sun4u_class_init(ObjectClass *oc, void *data) +static void sun4u_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc); @@ -817,7 +817,7 @@ static const TypeInfo sun4u_type = { }, }; -static void sun4v_class_init(ObjectClass *oc, void *data) +static void sun4v_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/sparc64/sun4u_iommu.c b/hw/sparc64/sun4u_iommu.c index 533fcae1fb..14645f475a 100644 --- a/hw/sparc64/sun4u_iommu.c +++ b/hw/sparc64/sun4u_iommu.c @@ -305,7 +305,7 @@ static void iommu_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); } -static void iommu_class_init(ObjectClass *klass, void *data) +static void iommu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -320,7 +320,8 @@ static const TypeInfo iommu_info = { .class_init = iommu_class_init, }; -static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, void *data) +static void sun4u_iommu_memory_region_class_init(ObjectClass *klass, + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/ssi/allwinner-a10-spi.c b/hw/ssi/allwinner-a10-spi.c index d2f6bb9cdc..6b7cca8d32 100644 --- a/hw/ssi/allwinner-a10-spi.c +++ b/hw/ssi/allwinner-a10-spi.c @@ -535,7 +535,7 @@ static void allwinner_a10_spi_realize(DeviceState *dev, Error **errp) fifo8_create(&s->rx_fifo, AW_A10_SPI_FIFO_SIZE); } -static void allwinner_a10_spi_class_init(ObjectClass *klass, void *data) +static void allwinner_a10_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index faef1a8e5b..0d38f95c7a 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -1294,7 +1294,7 @@ static const Property aspeed_smc_properties[] = { TYPE_MEMORY_REGION, MemoryRegion *), }; -static void aspeed_smc_class_init(ObjectClass *klass, void *data) +static void aspeed_smc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1341,7 +1341,7 @@ static const Property aspeed_smc_flash_properties[] = { AspeedSMCState *), }; -static void aspeed_smc_flash_class_init(ObjectClass *klass, void *data) +static void aspeed_smc_flash_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1383,7 +1383,7 @@ static const AspeedSegments aspeed_2400_smc_segments[] = { { 0x10000000, 32 * MiB }, }; -static void aspeed_2400_smc_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_smc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1429,7 +1429,7 @@ static const AspeedSegments aspeed_2400_fmc_segments[] = { { 0x2A000000, 32 * MiB } }; -static void aspeed_2400_fmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1473,7 +1473,7 @@ static int aspeed_2400_spi1_addr_width(const AspeedSMCState *s) return s->regs[R_SPI_CTRL0] & CTRL_AST2400_SPI_4BYTE ? 4 : 3; } -static void aspeed_2400_spi1_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_spi1_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1515,7 +1515,7 @@ static const AspeedSegments aspeed_2500_fmc_segments[] = { { 0x2A000000, 32 * MiB }, }; -static void aspeed_2500_fmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1555,7 +1555,7 @@ static const AspeedSegments aspeed_2500_spi1_segments[] = { { 0x32000000, 96 * MiB }, /* end address is readonly */ }; -static void aspeed_2500_spi1_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_spi1_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1591,7 +1591,7 @@ static const AspeedSegments aspeed_2500_spi2_segments[] = { { 0x3A000000, 96 * MiB }, /* end address is readonly */ }; -static void aspeed_2500_spi2_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_spi2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1674,7 +1674,7 @@ static const AspeedSegments aspeed_2600_fmc_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2600_fmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1715,7 +1715,7 @@ static const AspeedSegments aspeed_2600_spi1_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2600_spi1_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_spi1_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1756,7 +1756,7 @@ static const AspeedSegments aspeed_2600_spi2_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2600_spi2_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_spi2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1839,7 +1839,7 @@ static const AspeedSegments aspeed_1030_fmc_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_1030_fmc_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1879,7 +1879,7 @@ static const AspeedSegments aspeed_1030_spi1_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_1030_spi1_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_spi1_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -1917,7 +1917,7 @@ static const AspeedSegments aspeed_1030_spi2_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_1030_spi2_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_spi2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -2022,7 +2022,7 @@ static const AspeedSegments aspeed_2700_fmc_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2700_fmc_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_fmc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -2064,7 +2064,7 @@ static const AspeedSegments aspeed_2700_spi0_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2700_spi0_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_spi0_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -2104,7 +2104,7 @@ static const AspeedSegments aspeed_2700_spi1_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2700_spi1_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_spi1_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); @@ -2144,7 +2144,7 @@ static const AspeedSegments aspeed_2700_spi2_segments[] = { { 0x0, 0 }, /* disabled */ }; -static void aspeed_2700_spi2_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_spi2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedSMCClass *asc = ASPEED_SMC_CLASS(klass); diff --git a/hw/ssi/bcm2835_spi.c b/hw/ssi/bcm2835_spi.c index ebd8809f7c..bf8ba35e04 100644 --- a/hw/ssi/bcm2835_spi.c +++ b/hw/ssi/bcm2835_spi.c @@ -264,7 +264,7 @@ static const VMStateDescription vmstate_bcm2835_spi = { } }; -static void bcm2835_spi_class_init(ObjectClass *klass, void *data) +static void bcm2835_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/ibex_spi_host.c b/hw/ssi/ibex_spi_host.c index 6b28cda200..f05be68748 100644 --- a/hw/ssi/ibex_spi_host.c +++ b/hw/ssi/ibex_spi_host.c @@ -622,7 +622,7 @@ static void ibex_spi_host_init(Object *obj) sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); } -static void ibex_spi_host_class_init(ObjectClass *klass, void *data) +static void ibex_spi_host_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = ibex_spi_host_realize; diff --git a/hw/ssi/imx_spi.c b/hw/ssi/imx_spi.c index 2e317879b4..1312f588d2 100644 --- a/hw/ssi/imx_spi.c +++ b/hw/ssi/imx_spi.c @@ -475,7 +475,7 @@ static void imx_spi_realize(DeviceState *dev, Error **errp) fifo32_create(&s->rx_fifo, ECSPI_FIFO_SIZE); } -static void imx_spi_class_init(ObjectClass *klass, void *data) +static void imx_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/mss-spi.c b/hw/ssi/mss-spi.c index 340adcdd3f..fd7ba7eeb0 100644 --- a/hw/ssi/mss-spi.c +++ b/hw/ssi/mss-spi.c @@ -398,7 +398,7 @@ static const VMStateDescription vmstate_mss_spi = { } }; -static void mss_spi_class_init(ObjectClass *klass, void *data) +static void mss_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/npcm7xx_fiu.c b/hw/ssi/npcm7xx_fiu.c index 8df4bec3f1..056ce13394 100644 --- a/hw/ssi/npcm7xx_fiu.c +++ b/hw/ssi/npcm7xx_fiu.c @@ -557,7 +557,7 @@ static const Property npcm7xx_fiu_properties[] = { DEFINE_PROP_SIZE("flash-size", NPCM7xxFIUState, flash_size, 0), }; -static void npcm7xx_fiu_class_init(ObjectClass *klass, void *data) +static void npcm7xx_fiu_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/npcm_pspi.c b/hw/ssi/npcm_pspi.c index 41a5323530..a31dcc050e 100644 --- a/hw/ssi/npcm_pspi.c +++ b/hw/ssi/npcm_pspi.c @@ -199,7 +199,7 @@ static const VMStateDescription vmstate_npcm_pspi = { }; -static void npcm_pspi_class_init(ObjectClass *klass, void *data) +static void npcm_pspi_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/pl022.c b/hw/ssi/pl022.c index 53c9c225ad..1dc0bcbcc0 100644 --- a/hw/ssi/pl022.c +++ b/hw/ssi/pl022.c @@ -292,7 +292,7 @@ static void pl022_realize(DeviceState *dev, Error **errp) s->ssi = ssi_create_bus(dev, "ssi"); } -static void pl022_class_init(ObjectClass *klass, void *data) +static void pl022_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/pnv_spi.c b/hw/ssi/pnv_spi.c index 367a2ff3bb..0bb6b0d935 100644 --- a/hw/ssi/pnv_spi.c +++ b/hw/ssi/pnv_spi.c @@ -1199,7 +1199,7 @@ static int pnv_spi_dt_xscom(PnvXScomInterface *dev, void *fdt, return 0; } -static void pnv_spi_class_init(ObjectClass *klass, void *data) +static void pnv_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PnvXScomInterfaceClass *xscomc = PNV_XSCOM_INTERFACE_CLASS(klass); diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c index 76f8654f41..3e01fef61c 100644 --- a/hw/ssi/sifive_spi.c +++ b/hw/ssi/sifive_spi.c @@ -332,7 +332,7 @@ static const Property sifive_spi_properties[] = { DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1), }; -static void sifive_spi_class_init(ObjectClass *klass, void *data) +static void sifive_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/ssi.c b/hw/ssi/ssi.c index 872c4e8036..d0de640fe6 100644 --- a/hw/ssi/ssi.c +++ b/hw/ssi/ssi.c @@ -55,7 +55,7 @@ static bool ssi_bus_check_address(BusState *b, DeviceState *dev, Error **errp) return true; } -static void ssi_bus_class_init(ObjectClass *klass, void *data) +static void ssi_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); @@ -112,7 +112,7 @@ static const Property ssi_peripheral_properties[] = { DEFINE_PROP_UINT8("cs", SSIPeripheral, cs_index, 0), }; -static void ssi_peripheral_class_init(ObjectClass *klass, void *data) +static void ssi_peripheral_class_init(ObjectClass *klass, const void *data) { SSIPeripheralClass *ssc = SSI_PERIPHERAL_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/stm32f2xx_spi.c b/hw/ssi/stm32f2xx_spi.c index ea9b74a409..871d57324d 100644 --- a/hw/ssi/stm32f2xx_spi.c +++ b/hw/ssi/stm32f2xx_spi.c @@ -202,7 +202,7 @@ static void stm32f2xx_spi_init(Object *obj) s->ssi = ssi_create_bus(dev, "ssi"); } -static void stm32f2xx_spi_class_init(ObjectClass *klass, void *data) +static void stm32f2xx_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c index be5baa6b35..4144c8a627 100644 --- a/hw/ssi/xilinx_spi.c +++ b/hw/ssi/xilinx_spi.c @@ -379,7 +379,7 @@ static const Property xilinx_spi_properties[] = { DEFINE_PROP_UINT8("num-ss-bits", XilinxSPI, num_cs, 1), }; -static void xilinx_spi_class_init(ObjectClass *klass, void *data) +static void xilinx_spi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ssi/xilinx_spips.c b/hw/ssi/xilinx_spips.c index 60d092039f..a79f3b8e49 100644 --- a/hw/ssi/xilinx_spips.c +++ b/hw/ssi/xilinx_spips.c @@ -1430,7 +1430,7 @@ static const Property xilinx_spips_properties[] = { DEFINE_PROP_UINT8("num-txrx-bytes", XilinxSPIPS, num_txrx_bytes, 1), }; -static void xilinx_qspips_class_init(ObjectClass *klass, void * data) +static void xilinx_qspips_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); @@ -1442,7 +1442,7 @@ static void xilinx_qspips_class_init(ObjectClass *klass, void * data) xsc->tx_fifo_size = TXFF_A_Q; } -static void xilinx_spips_class_init(ObjectClass *klass, void *data) +static void xilinx_spips_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); @@ -1458,7 +1458,7 @@ static void xilinx_spips_class_init(ObjectClass *klass, void *data) xsc->tx_fifo_size = TXFF_A; } -static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, void * data) +static void xlnx_zynqmp_qspips_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); XilinxSPIPSClass *xsc = XILINX_SPIPS_CLASS(klass); diff --git a/hw/ssi/xlnx-versal-ospi.c b/hw/ssi/xlnx-versal-ospi.c index 9e96c9b69a..56d51ce0e3 100644 --- a/hw/ssi/xlnx-versal-ospi.c +++ b/hw/ssi/xlnx-versal-ospi.c @@ -1831,7 +1831,7 @@ static const Property xlnx_versal_ospi_properties[] = { ind_write_disabled, false), }; -static void xlnx_versal_ospi_class_init(ObjectClass *klass, void *data) +static void xlnx_versal_ospi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/a9gtimer.c b/hw/timer/a9gtimer.c index 9835c35483..690140f5a6 100644 --- a/hw/timer/a9gtimer.c +++ b/hw/timer/a9gtimer.c @@ -377,7 +377,7 @@ static const Property a9_gtimer_properties[] = { DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0), }; -static void a9_gtimer_class_init(ObjectClass *klass, void *data) +static void a9_gtimer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index da3d7173ef..e4c353273a 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -288,7 +288,7 @@ static void a10_pit_finalize(Object *obj) } } -static void a10_pit_class_init(ObjectClass *klass, void *data) +static void a10_pit_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 803dad1e8a..7cc5915e9e 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -304,7 +304,7 @@ static const Property arm_mptimer_properties[] = { DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0), }; -static void arm_mptimer_class_init(ObjectClass *klass, void *data) +static void arm_mptimer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index 1213b77aa0..56638ff5cd 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -392,7 +392,7 @@ static const Property sp804_properties[] = { DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000), }; -static void sp804_class_init(ObjectClass *klass, void *data) +static void sp804_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); diff --git a/hw/timer/armv7m_systick.c b/hw/timer/armv7m_systick.c index a07febd1d1..7e4ddcd405 100644 --- a/hw/timer/armv7m_systick.c +++ b/hw/timer/armv7m_systick.c @@ -285,7 +285,7 @@ static const VMStateDescription vmstate_systick = { } }; -static void systick_class_init(ObjectClass *klass, void *data) +static void systick_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index ecda49574e..57db03512f 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -895,7 +895,7 @@ static const Property aspeed_timer_properties[] = { AspeedSCUState *), }; -static void timer_class_init(ObjectClass *klass, void *data) +static void timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -915,7 +915,7 @@ static const TypeInfo aspeed_timer_info = { .abstract = true, }; -static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); @@ -931,7 +931,7 @@ static const TypeInfo aspeed_2400_timer_info = { .class_init = aspeed_2400_timer_class_init, }; -static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); @@ -947,7 +947,7 @@ static const TypeInfo aspeed_2500_timer_info = { .class_init = aspeed_2500_timer_class_init, }; -static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); @@ -963,7 +963,7 @@ static const TypeInfo aspeed_2600_timer_info = { .class_init = aspeed_2600_timer_class_init, }; -static void aspeed_1030_timer_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); @@ -979,7 +979,7 @@ static const TypeInfo aspeed_1030_timer_info = { .class_init = aspeed_1030_timer_class_init, }; -static void aspeed_2700_timer_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); diff --git a/hw/timer/avr_timer16.c b/hw/timer/avr_timer16.c index 96baf9cf60..012d829001 100644 --- a/hw/timer/avr_timer16.c +++ b/hw/timer/avr_timer16.c @@ -595,7 +595,7 @@ static void avr_timer16_realize(DeviceState *dev, Error **errp) s->enabled = true; } -static void avr_timer16_class_init(ObjectClass *klass, void *data) +static void avr_timer16_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/bcm2835_systmr.c b/hw/timer/bcm2835_systmr.c index 2f0fee3342..7929aaa882 100644 --- a/hw/timer/bcm2835_systmr.c +++ b/hw/timer/bcm2835_systmr.c @@ -154,7 +154,7 @@ static const VMStateDescription bcm2835_systmr_vmstate = { } }; -static void bcm2835_systmr_class_init(ObjectClass *klass, void *data) +static void bcm2835_systmr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/cadence_ttc.c b/hw/timer/cadence_ttc.c index 54dbd4c564..9c7ba16876 100644 --- a/hw/timer/cadence_ttc.c +++ b/hw/timer/cadence_ttc.c @@ -451,7 +451,7 @@ static const VMStateDescription vmstate_cadence_ttc = { } }; -static void cadence_ttc_class_init(ObjectClass *klass, void *data) +static void cadence_ttc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c index 2ecd8dfe3c..34c550a3f9 100644 --- a/hw/timer/cmsdk-apb-dualtimer.c +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -534,7 +534,7 @@ static const VMStateDescription cmsdk_apb_dualtimer_vmstate = { } }; -static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data) +static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c index 16d0b2170e..4095267b4a 100644 --- a/hw/timer/cmsdk-apb-timer.c +++ b/hw/timer/cmsdk-apb-timer.c @@ -261,7 +261,7 @@ static const VMStateDescription cmsdk_apb_timer_vmstate = { } }; -static void cmsdk_apb_timer_class_init(ObjectClass *klass, void *data) +static void cmsdk_apb_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 00c32978d2..355138d354 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -161,7 +161,7 @@ static void digic_timer_finalize(Object *obj) ptimer_free(s->ptimer); } -static void digic_timer_class_init(ObjectClass *klass, void *class_data) +static void digic_timer_class_init(ObjectClass *klass, const void *class_data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 5c6e139b20..bb0f9c8b9a 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1546,7 +1546,7 @@ static void exynos4210_mct_finalize(Object *obj) } } -static void exynos4210_mct_class_init(ObjectClass *klass, void *data) +static void exynos4210_mct_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index 703d1d2b4a..69f737a8e6 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -420,7 +420,7 @@ static void exynos4210_pwm_finalize(Object *obj) } } -static void exynos4210_pwm_class_init(ObjectClass *klass, void *data) +static void exynos4210_pwm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index f0802b6eb6..0e06fa09e9 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -409,7 +409,7 @@ static const Property grlib_gptimer_properties[] = { DEFINE_PROP_UINT32("nr-timers", GPTimerUnit, nr_timers, 2), }; -static void grlib_gptimer_class_init(ObjectClass *klass, void *data) +static void grlib_gptimer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index ea82472105..d1b7bc52b7 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -736,7 +736,7 @@ static const Property hpet_device_properties[] = { DEFINE_PROP_BOOL("hpet-offset-saved", HPETState, hpet_offset_saved, true), }; -static void hpet_device_class_init(ObjectClass *klass, void *data) +static void hpet_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/i8254.c b/hw/timer/i8254.c index 058fc61ce9..4b25c487f7 100644 --- a/hw/timer/i8254.c +++ b/hw/timer/i8254.c @@ -350,7 +350,7 @@ static void pit_realizefn(DeviceState *dev, Error **errp) pc->parent_realize(dev, errp); } -static void pit_class_initfn(ObjectClass *klass, void *data) +static void pit_class_initfn(ObjectClass *klass, const void *data) { PITClass *pc = PIT_CLASS(klass); PITCommonClass *k = PIT_COMMON_CLASS(klass); diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c index 29105afcc3..ad091594cd 100644 --- a/hw/timer/i8254_common.c +++ b/hw/timer/i8254_common.c @@ -242,7 +242,7 @@ static const Property pit_common_properties[] = { DEFINE_PROP_UINT32("iobase", PITCommonState, iobase, -1), }; -static void pit_common_class_init(ObjectClass *klass, void *data) +static void pit_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/ibex_timer.c b/hw/timer/ibex_timer.c index 3ebc870097..c7320ef30f 100644 --- a/hw/timer/ibex_timer.c +++ b/hw/timer/ibex_timer.c @@ -286,7 +286,7 @@ static void ibex_timer_realize(DeviceState *dev, Error **errp) } -static void ibex_timer_class_init(ObjectClass *klass, void *data) +static void ibex_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index f40ab16697..6123321c35 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -427,7 +427,7 @@ static void imx_epit_dev_reset(DeviceState *dev) imx_epit_reset(s, true); } -static void imx_epit_class_init(ObjectClass *klass, void *data) +static void imx_epit_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 200a89225b..8c7cbfdeac 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -518,7 +518,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_LEGACY); } -static void imx_gpt_class_init(ObjectClass *klass, void *data) +static void imx_gpt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c index 594da64eae..2ce821178b 100644 --- a/hw/timer/mss-timer.c +++ b/hw/timer/mss-timer.c @@ -285,7 +285,7 @@ static const Property mss_timer_properties[] = { 100 * 1000000), }; -static void mss_timer_class_init(ObjectClass *klass, void *data) +static void mss_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/npcm7xx_timer.c b/hw/timer/npcm7xx_timer.c index c55ba02235..6a116ad54b 100644 --- a/hw/timer/npcm7xx_timer.c +++ b/hw/timer/npcm7xx_timer.c @@ -689,7 +689,7 @@ static const VMStateDescription vmstate_npcm7xx_timer_ctrl = { }, }; -static void npcm7xx_timer_class_init(ObjectClass *klass, void *data) +static void npcm7xx_timer_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/nrf51_timer.c b/hw/timer/nrf51_timer.c index 11ad8b575e..e228fdebc3 100644 --- a/hw/timer/nrf51_timer.c +++ b/hw/timer/nrf51_timer.c @@ -383,7 +383,7 @@ static const Property nrf51_timer_properties[] = { DEFINE_PROP_UINT8("id", NRF51TimerState, id, 0), }; -static void nrf51_timer_class_init(ObjectClass *klass, void *data) +static void nrf51_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 9e4dd0fd9f..7a94366b0f 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -555,7 +555,7 @@ static const Property pxa25x_timer_dev_properties[] = { PXA2XX_TIMER_HAVE_TM4, false), }; -static void pxa25x_timer_dev_class_init(ObjectClass *klass, void *data) +static void pxa25x_timer_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -570,7 +570,7 @@ static const TypeInfo pxa25x_timer_dev_info = { .class_init = pxa25x_timer_dev_class_init, }; -static void pxa2xx_timer_class_init(ObjectClass *oc, void *data) +static void pxa2xx_timer_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/timer/renesas_cmt.c b/hw/timer/renesas_cmt.c index 93e7f58cc2..cdff7f47f1 100644 --- a/hw/timer/renesas_cmt.c +++ b/hw/timer/renesas_cmt.c @@ -257,7 +257,7 @@ static const Property rcmt_properties[] = { DEFINE_PROP_UINT64("input-freq", RCMTState, input_freq, 0), }; -static void rcmt_class_init(ObjectClass *klass, void *data) +static void rcmt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/renesas_tmr.c b/hw/timer/renesas_tmr.c index 884349c2cc..95707f2b8c 100644 --- a/hw/timer/renesas_tmr.c +++ b/hw/timer/renesas_tmr.c @@ -467,7 +467,7 @@ static const Property rtmr_properties[] = { DEFINE_PROP_UINT64("input-freq", RTMRState, input_freq, 0), }; -static void rtmr_class_init(ObjectClass *klass, void *data) +static void rtmr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/sifive_pwm.c b/hw/timer/sifive_pwm.c index fc796e9bc3..e85e389f7a 100644 --- a/hw/timer/sifive_pwm.c +++ b/hw/timer/sifive_pwm.c @@ -441,7 +441,7 @@ static void sifive_pwm_realize(DeviceState *dev, Error **errp) sifive_pwm_interrupt_3, s); } -static void sifive_pwm_class_init(ObjectClass *klass, void *data) +static void sifive_pwm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index 65b24e4f06..3e071fbdb4 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -424,7 +424,7 @@ static const Property slavio_timer_properties[] = { DEFINE_PROP_UINT32("num_cpus", SLAVIO_TIMERState, num_cpus, 0), }; -static void slavio_timer_class_init(ObjectClass *klass, void *data) +static void slavio_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/sse-counter.c b/hw/timer/sse-counter.c index f17064abe3..31f77acf61 100644 --- a/hw/timer/sse-counter.c +++ b/hw/timer/sse-counter.c @@ -448,7 +448,7 @@ static const VMStateDescription sse_counter_vmstate = { } }; -static void sse_counter_class_init(ObjectClass *klass, void *data) +static void sse_counter_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/sse-timer.c b/hw/timer/sse-timer.c index e106739ea9..866d5eef8a 100644 --- a/hw/timer/sse-timer.c +++ b/hw/timer/sse-timer.c @@ -444,7 +444,7 @@ static const Property sse_timer_properties[] = { DEFINE_PROP_LINK("counter", SSETimer, counter, TYPE_SSE_COUNTER, SSECounter *), }; -static void sse_timer_class_init(ObjectClass *klass, void *data) +static void sse_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/stellaris-gptm.c b/hw/timer/stellaris-gptm.c index f28958cefc..d97b2f8309 100644 --- a/hw/timer/stellaris-gptm.c +++ b/hw/timer/stellaris-gptm.c @@ -308,7 +308,7 @@ static void stellaris_gptm_realize(DeviceState *dev, Error **errp) s->timer[1] = timer_new_ns(QEMU_CLOCK_VIRTUAL, gptm_tick, &s->opaque[1]); } -static void stellaris_gptm_class_init(ObjectClass *klass, void *data) +static void stellaris_gptm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c index 4707190d6a..be844e7f5a 100644 --- a/hw/timer/stm32f2xx_timer.c +++ b/hw/timer/stm32f2xx_timer.c @@ -320,7 +320,7 @@ static void stm32f2xx_timer_realize(DeviceState *dev, Error **errp) s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s); } -static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data) +static void stm32f2xx_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 4620528f98..ff4a224d08 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -268,7 +268,7 @@ static const Property xilinx_timer_properties[] = { DEFINE_PROP_UINT8("one-timer-only", XpsTimerState, one_timer_only, 0), }; -static void xilinx_timer_class_init(ObjectClass *klass, void *data) +static void xilinx_timer_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index b668aee97a..9aff4d1a6f 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -315,7 +315,7 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp) } } -static void tpm_crb_class_init(ObjectClass *klass, void *data) +static void tpm_crb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); TPMIfClass *tc = TPM_IF_CLASS(klass); diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index 9a031e1e75..1cad9a88ea 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -387,7 +387,7 @@ static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp) s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX); } -static void tpm_spapr_class_init(ObjectClass *klass, void *data) +static void tpm_spapr_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c index 92d3de1ea3..b97d768a5b 100644 --- a/hw/tpm/tpm_tis_i2c.c +++ b/hw/tpm/tpm_tis_i2c.c @@ -526,7 +526,7 @@ static void tpm_tis_i2c_reset(DeviceState *dev) return tpm_tis_reset(s); } -static void tpm_tis_i2c_class_init(ObjectClass *klass, void *data) +static void tpm_tis_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index 876cb02cb5..c0098a26e8 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -166,7 +166,7 @@ static void build_tpm_tis_isa_aml(AcpiDevAmlIf *adev, Aml *scope) aml_append(scope, dev); } -static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) +static void tpm_tis_isa_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); TPMIfClass *tc = TPM_IF_CLASS(klass); diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index 4f187690a2..19abf0b948 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -124,7 +124,7 @@ static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) } } -static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) +static void tpm_tis_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); TPMIfClass *tc = TPM_IF_CLASS(klass); diff --git a/hw/tricore/tc27x_soc.c b/hw/tricore/tc27x_soc.c index 81bb16d89b..f3b84980e5 100644 --- a/hw/tricore/tc27x_soc.c +++ b/hw/tricore/tc27x_soc.c @@ -201,14 +201,14 @@ static void tc27x_soc_init(Object *obj) object_initialize_child(obj, "tc27x", &s->cpu, sc->cpu_type); } -static void tc27x_soc_class_init(ObjectClass *klass, void *data) +static void tc27x_soc_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = tc27x_soc_realize; } -static void tc277d_soc_class_init(ObjectClass *oc, void *data) +static void tc277d_soc_class_init(ObjectClass *oc, const void *data) { TC27XSoCClass *sc = TC27X_SOC_CLASS(oc); diff --git a/hw/tricore/triboard.c b/hw/tricore/triboard.c index f5baa8ccbb..cb45b01d2d 100644 --- a/hw/tricore/triboard.c +++ b/hw/tricore/triboard.c @@ -65,7 +65,7 @@ static void triboard_machine_init(MachineState *machine) } static void triboard_machine_tc277d_class_init(ObjectClass *oc, - void *data) + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); TriBoardMachineClass *amc = TRIBOARD_MACHINE_CLASS(oc); diff --git a/hw/tricore/tricore_testdevice.c b/hw/tricore/tricore_testdevice.c index d2da74e384..e8daf95298 100644 --- a/hw/tricore/tricore_testdevice.c +++ b/hw/tricore/tricore_testdevice.c @@ -58,7 +58,7 @@ static void tricore_testdevice_init(Object *obj) "tricore_testdevice", 0x4); } -static void tricore_testdevice_class_init(ObjectClass *klass, void *data) +static void tricore_testdevice_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/uefi/var-service-sysbus.c b/hw/uefi/var-service-sysbus.c index 97da8672ee..a5aa218e26 100644 --- a/hw/uefi/var-service-sysbus.c +++ b/hw/uefi/var-service-sysbus.c @@ -64,7 +64,7 @@ static void uefi_vars_sysbus_realize(DeviceState *dev, Error **errp) uefi_vars_realize(&uv->state, errp); } -static void uefi_vars_sysbus_class_init(ObjectClass *klass, void *data) +static void uefi_vars_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -100,7 +100,7 @@ static void uefi_vars_x64_realize(DeviceState *dev, Error **errp) sysbus_mmio_map(sysbus, 0, hwinfo.mmio_address); } -static void uefi_vars_x64_class_init(ObjectClass *klass, void *data) +static void uefi_vars_x64_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/ufs/lu.c b/hw/ufs/lu.c index 1c3794b2d4..57b307ea56 100644 --- a/hw/ufs/lu.c +++ b/hw/ufs/lu.c @@ -419,7 +419,7 @@ static void ufs_lu_unrealize(DeviceState *dev) } } -static void ufs_lu_class_init(ObjectClass *oc, void *data) +static void ufs_lu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 542f13b10e..749519760f 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1844,7 +1844,7 @@ static const VMStateDescription ufs_vmstate = { .unmigratable = 1, }; -static void ufs_class_init(ObjectClass *oc, void *data) +static void ufs_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PCIDeviceClass *pc = PCI_DEVICE_CLASS(oc); @@ -1880,7 +1880,7 @@ static char *ufs_bus_get_dev_path(DeviceState *dev) return qdev_get_dev_path(bus->parent); } -static void ufs_bus_class_init(ObjectClass *class, void *data) +static void ufs_bus_class_init(ObjectClass *class, const void *data) { BusClass *bc = BUS_CLASS(class); bc->get_dev_path = ufs_bus_get_dev_path; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index f45b82c776..d8446cf50e 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -26,7 +26,7 @@ static const Property usb_props[] = { DEFINE_PROP_STRING("pcap", USBDevice, pcap_filename), }; -static void usb_bus_class_init(ObjectClass *klass, void *data) +static void usb_bus_class_init(ObjectClass *klass, const void *data) { BusClass *k = BUS_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); @@ -713,7 +713,7 @@ static void usb_device_instance_init(Object *obj) } } -static void usb_device_class_init(ObjectClass *klass, void *data) +static void usb_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->bus_type = TYPE_USB_BUS; diff --git a/hw/usb/canokey.c b/hw/usb/canokey.c index e2d66179e0..cbefbb5daf 100644 --- a/hw/usb/canokey.c +++ b/hw/usb/canokey.c @@ -300,7 +300,7 @@ static const Property canokey_properties[] = { DEFINE_PROP_STRING("file", CanoKeyState, file), }; -static void canokey_class_init(ObjectClass *klass, void *data) +static void canokey_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/ccid-card-emulated.c b/hw/usb/ccid-card-emulated.c index b1e330f21d..c21cefd82d 100644 --- a/hw/usb/ccid-card-emulated.c +++ b/hw/usb/ccid-card-emulated.c @@ -591,7 +591,7 @@ static const Property emulated_card_properties[] = { DEFINE_PROP_UINT8("debug", EmulatedState, debug, 0), }; -static void emulated_class_initfn(ObjectClass *klass, void *data) +static void emulated_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CCIDCardClass *cc = CCID_CARD_CLASS(klass); diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c index bf81485f87..1eea21a733 100644 --- a/hw/usb/ccid-card-passthru.c +++ b/hw/usb/ccid-card-passthru.c @@ -393,7 +393,7 @@ static const Property passthru_card_properties[] = { DEFINE_PROP_UINT8("debug", PassthruState, debug, 0), }; -static void passthru_class_initfn(ObjectClass *klass, void *data) +static void passthru_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CCIDCardClass *cc = CCID_CARD_CLASS(klass); diff --git a/hw/usb/chipidea.c b/hw/usb/chipidea.c index b1c85404d6..250c2b3bca 100644 --- a/hw/usb/chipidea.c +++ b/hw/usb/chipidea.c @@ -144,7 +144,7 @@ static void chipidea_init(Object *obj) } } -static void chipidea_class_init(ObjectClass *klass, void *data) +static void chipidea_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c index 40f031252a..26af709f31 100644 --- a/hw/usb/dev-audio.c +++ b/hw/usb/dev-audio.c @@ -997,7 +997,7 @@ static const Property usb_audio_properties[] = { DEFINE_PROP_BOOL("multi", USBAudioState, multi, false), }; -static void usb_audio_class_init(ObjectClass *klass, void *data) +static void usb_audio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *k = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index accdd460e3..54d064e54e 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -774,7 +774,7 @@ static const VMStateDescription vmstate_usb_kbd = { } }; -static void usb_hid_class_initfn(ObjectClass *klass, void *data) +static void usb_hid_class_initfn(ObjectClass *klass, const void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -799,7 +799,7 @@ static const Property usb_tablet_properties[] = { DEFINE_PROP_UINT32("head", USBHIDState, head, 0), }; -static void usb_tablet_class_initfn(ObjectClass *klass, void *data) +static void usb_tablet_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -821,7 +821,7 @@ static const Property usb_mouse_properties[] = { DEFINE_PROP_UINT32("usb_version", USBHIDState, usb_version, 2), }; -static void usb_mouse_class_initfn(ObjectClass *klass, void *data) +static void usb_mouse_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -844,7 +844,7 @@ static const Property usb_keyboard_properties[] = { DEFINE_PROP_STRING("display", USBHIDState, display), }; -static void usb_keyboard_class_initfn(ObjectClass *klass, void *data) +static void usb_keyboard_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 3880e2aca8..a19350d9c4 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -670,7 +670,7 @@ static const Property usb_hub_properties[] = { DEFINE_PROP_BOOL("port-power", USBHubState, port_power, false), }; -static void usb_hub_class_initfn(ObjectClass *klass, void *data) +static void usb_hub_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c index 4cd14c3df4..ce45c9cd06 100644 --- a/hw/usb/dev-mtp.c +++ b/hw/usb/dev-mtp.c @@ -2082,7 +2082,7 @@ static const Property mtp_properties[] = { DEFINE_PROP_BOOL("readonly", MTPState, readonly, true), }; -static void usb_mtp_class_initfn(ObjectClass *klass, void *data) +static void usb_mtp_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c index a87a0ffb95..81cc09dcac 100644 --- a/hw/usb/dev-network.c +++ b/hw/usb/dev-network.c @@ -1411,7 +1411,7 @@ static const Property net_properties[] = { DEFINE_NIC_PROPERTIES(USBNetState, conf), }; -static void usb_net_class_initfn(ObjectClass *klass, void *data) +static void usb_net_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c index 31f6cf5b31..1c116d8b0f 100644 --- a/hw/usb/dev-serial.c +++ b/hw/usb/dev-serial.c @@ -637,7 +637,7 @@ static const Property serial_properties[] = { DEFINE_PROP_BOOL("always-plugged", USBSerialState, always_plugged, false), }; -static void usb_serial_dev_class_init(ObjectClass *klass, void *data) +static void usb_serial_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -658,7 +658,7 @@ static const TypeInfo usb_serial_dev_type_info = { .class_init = usb_serial_dev_class_init, }; -static void usb_serial_class_initfn(ObjectClass *klass, void *data) +static void usb_serial_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -678,7 +678,7 @@ static const Property braille_properties[] = { DEFINE_PROP_CHR("chardev", USBSerialState, cs), }; -static void usb_braille_class_initfn(ObjectClass *klass, void *data) +static void usb_braille_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 84ca8c48e2..87018a3f01 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1433,7 +1433,7 @@ static const Property ccid_properties[] = { DEFINE_PROP_UINT8("debug", USBCCIDState, debug, 0), }; -static void ccid_class_initfn(ObjectClass *klass, void *data) +static void ccid_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); @@ -1464,7 +1464,7 @@ static const TypeInfo ccid_info = { } }; -static void ccid_card_class_init(ObjectClass *klass, void *data) +static void ccid_card_class_init(ObjectClass *klass, const void *data) { DeviceClass *k = DEVICE_CLASS(klass); k->bus_type = TYPE_CCID_BUS; diff --git a/hw/usb/dev-storage-bot.c b/hw/usb/dev-storage-bot.c index 1e5c5c711f..df6ab7f656 100644 --- a/hw/usb/dev-storage-bot.c +++ b/hw/usb/dev-storage-bot.c @@ -40,7 +40,7 @@ static void usb_msd_bot_realize(USBDevice *dev, Error **errp) usb_msd_handle_reset(dev); } -static void usb_msd_class_bot_initfn(ObjectClass *klass, void *data) +static void usb_msd_class_bot_initfn(ObjectClass *klass, const void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-storage-classic.c b/hw/usb/dev-storage-classic.c index 56ef39da2e..dabe156359 100644 --- a/hw/usb/dev-storage-classic.c +++ b/hw/usb/dev-storage-classic.c @@ -74,7 +74,7 @@ static const Property msd_properties[] = { DEFINE_PROP_BOOL("commandlog", MSDState, commandlog, false), }; -static void usb_msd_class_storage_initfn(ObjectClass *klass, void *data) +static void usb_msd_class_storage_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index 4f1e8b7f6c..b13fe345c4 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -585,7 +585,7 @@ static const VMStateDescription vmstate_usb_msd = { } }; -static void usb_msd_class_initfn_common(ObjectClass *klass, void *data) +static void usb_msd_class_initfn_common(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index b1d6b6ecc3..21cc2835c6 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -956,7 +956,7 @@ static const Property uas_properties[] = { DEFINE_PROP_UINT32("log-scsi-req", UASDevice, requestlog, 0), }; -static void usb_uas_class_initfn(ObjectClass *klass, void *data) +static void usb_uas_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/dev-wacom.c b/hw/usb/dev-wacom.c index 7177c17f03..f4b71a2147 100644 --- a/hw/usb/dev-wacom.c +++ b/hw/usb/dev-wacom.c @@ -420,7 +420,7 @@ static const VMStateDescription vmstate_usb_wacom = { .unmigratable = 1, }; -static void usb_wacom_class_init(ObjectClass *klass, void *data) +static void usb_wacom_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c index e8152719f8..83864505bb 100644 --- a/hw/usb/hcd-dwc2.c +++ b/hw/usb/hcd-dwc2.c @@ -1452,7 +1452,7 @@ static const Property dwc2_usb_properties[] = { DEFINE_PROP_UINT32("usb_version", DWC2State, usb_version, 2), }; -static void dwc2_class_init(ObjectClass *klass, void *data) +static void dwc2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); DWC2Class *c = DWC2_USB_CLASS(klass); diff --git a/hw/usb/hcd-dwc3.c b/hw/usb/hcd-dwc3.c index 0bceee2712..98a342b8b8 100644 --- a/hw/usb/hcd-dwc3.c +++ b/hw/usb/hcd-dwc3.c @@ -666,7 +666,7 @@ static const Property usb_dwc3_properties[] = { 0x12345678), }; -static void usb_dwc3_class_init(ObjectClass *klass, void *data) +static void usb_dwc3_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index e00316721a..73122aa797 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -150,7 +150,7 @@ static const VMStateDescription vmstate_ehci_pci = { } }; -static void ehci_class_init(ObjectClass *klass, void *data) +static void ehci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -178,7 +178,7 @@ static const TypeInfo ehci_pci_type_info = { }, }; -static void ehci_data_class_init(ObjectClass *klass, void *data) +static void ehci_data_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 768c3dd797..0449f5fa6d 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -80,7 +80,7 @@ static void ehci_sysbus_finalize(Object *obj) usb_ehci_finalize(s); } -static void ehci_sysbus_class_init(ObjectClass *klass, void *data) +static void ehci_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(klass); @@ -95,7 +95,7 @@ static void ehci_sysbus_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_USB, dc->categories); } -static void ehci_platform_class_init(ObjectClass *oc, void *data) +static void ehci_platform_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -105,7 +105,7 @@ static void ehci_platform_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_USB, dc->categories); } -static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) +static void ehci_exynos4210_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -115,7 +115,7 @@ static void ehci_exynos4210_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_USB, dc->categories); } -static void ehci_aw_h3_class_init(ObjectClass *oc, void *data) +static void ehci_aw_h3_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -125,7 +125,7 @@ static void ehci_aw_h3_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_USB, dc->categories); } -static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data) +static void ehci_npcm7xx_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -137,7 +137,7 @@ static void ehci_npcm7xx_class_init(ObjectClass *oc, void *data) set_bit(DEVICE_CATEGORY_USB, dc->categories); } -static void ehci_tegra2_class_init(ObjectClass *oc, void *data) +static void ehci_tegra2_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -154,7 +154,7 @@ static void ehci_ppc4xx_init(Object *o) s->ehci.companion_enable = true; } -static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data) +static void ehci_ppc4xx_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); @@ -220,7 +220,7 @@ static void fusbh200_ehci_init(Object *obj) &f->mem_vendor); } -static void fusbh200_ehci_class_init(ObjectClass *oc, void *data) +static void fusbh200_ehci_class_init(ObjectClass *oc, const void *data) { SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c index b3684a2ef6..3c82525a1e 100644 --- a/hw/usb/hcd-ohci-pci.c +++ b/hw/usb/hcd-ohci-pci.c @@ -126,7 +126,7 @@ static const VMStateDescription vmstate_ohci = { } }; -static void ohci_pci_class_init(ObjectClass *klass, void *data) +static void ohci_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-ohci-sysbus.c b/hw/usb/hcd-ohci-sysbus.c index 15311949b3..3fc6cce44b 100644 --- a/hw/usb/hcd-ohci-sysbus.c +++ b/hw/usb/hcd-ohci-sysbus.c @@ -64,7 +64,7 @@ static const Property ohci_sysbus_properties[] = { DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), }; -static void ohci_sysbus_class_init(ObjectClass *klass, void *data) +static void ohci_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 0561a6d801..2b1aee1f21 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1260,7 +1260,7 @@ static const Property uhci_properties_standalone[] = { DEFINE_PROP_UINT32("maxframes", UHCIState, maxframes, 128), }; -static void uhci_class_init(ObjectClass *klass, void *data) +static void uhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -1284,7 +1284,7 @@ static const TypeInfo uhci_pci_type_info = { }, }; -void uhci_data_class_init(ObjectClass *klass, void *data) +void uhci_data_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-uhci.h b/hw/usb/hcd-uhci.h index d4664297cf..e0a6525505 100644 --- a/hw/usb/hcd-uhci.h +++ b/hw/usb/hcd-uhci.h @@ -88,7 +88,7 @@ typedef struct UHCIInfo { bool notuser; /* disallow user_creatable */ } UHCIInfo; -void uhci_data_class_init(ObjectClass *klass, void *data); +void uhci_data_class_init(ObjectClass *klass, const void *data); void usb_uhci_common_realize(PCIDevice *dev, Error **errp); #define TYPE_PIIX3_USB_UHCI "piix3-usb-uhci" diff --git a/hw/usb/hcd-xhci-nec.c b/hw/usb/hcd-xhci-nec.c index 1df518baf5..9e0fea26f4 100644 --- a/hw/usb/hcd-xhci-nec.c +++ b/hw/usb/hcd-xhci-nec.c @@ -50,7 +50,7 @@ static void nec_xhci_instance_init(Object *obj) pci->xhci.numslots = nec->slots; } -static void nec_xhci_class_init(ObjectClass *klass, void *data) +static void nec_xhci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index d908eb787d..6167bb9100 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -223,7 +223,7 @@ static const Property xhci_pci_properties[] = { conditional_intr_mapping, false), }; -static void xhci_class_init(ObjectClass *klass, void *data) +static void xhci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); @@ -255,7 +255,7 @@ static const TypeInfo xhci_pci_info = { }, }; -static void qemu_xhci_class_init(ObjectClass *klass, void *data) +static void qemu_xhci_class_init(ObjectClass *klass, const void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-xhci-sysbus.c b/hw/usb/hcd-xhci-sysbus.c index ce43322396..244698e5f2 100644 --- a/hw/usb/hcd-xhci-sysbus.c +++ b/hw/usb/hcd-xhci-sysbus.c @@ -96,7 +96,7 @@ static const VMStateDescription vmstate_xhci_sysbus = { } }; -static void xhci_sysbus_class_init(ObjectClass *klass, void *data) +static void xhci_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 64c3a23b9b..b3785b8ba6 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -3638,7 +3638,7 @@ static const Property xhci_properties[] = { DeviceState *), }; -static void xhci_class_init(ObjectClass *klass, void *data) +static void xhci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c index c3d642c9d3..b74670ae25 100644 --- a/hw/usb/host-libusb.c +++ b/hw/usb/host-libusb.c @@ -1781,7 +1781,7 @@ static const Property usb_host_dev_properties[] = { suppress_remote_wake, true), }; -static void usb_host_class_initfn(ObjectClass *klass, void *data) +static void usb_host_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/imx-usb-phy.c b/hw/usb/imx-usb-phy.c index f519250567..c25566d0fa 100644 --- a/hw/usb/imx-usb-phy.c +++ b/hw/usb/imx-usb-phy.c @@ -214,7 +214,7 @@ static void imx_usbphy_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); } -static void imx_usbphy_class_init(ObjectClass *klass, void *data) +static void imx_usbphy_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index f3a83b3f4c..f516ff42a1 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -2582,7 +2582,7 @@ static const Property usbredir_properties[] = { suppress_remote_wake, true), }; -static void usbredir_class_initfn(ObjectClass *klass, void *data) +static void usbredir_class_initfn(ObjectClass *klass, const void *data) { USBDeviceClass *uc = USB_DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/u2f-emulated.c b/hw/usb/u2f-emulated.c index e1dd19ee92..ace5eceadd 100644 --- a/hw/usb/u2f-emulated.c +++ b/hw/usb/u2f-emulated.c @@ -377,7 +377,7 @@ static const Property u2f_emulated_properties[] = { DEFINE_PROP_STRING("counter", U2FEmulatedState, counter), }; -static void u2f_emulated_class_init(ObjectClass *klass, void *data) +static void u2f_emulated_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); U2FKeyClass *kc = U2F_KEY_CLASS(klass); diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index 8df5215a1f..fa8d9cdda8 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -520,7 +520,7 @@ static const Property u2f_passthru_properties[] = { DEFINE_PROP_STRING("hidraw", U2FPassthruState, hidraw), }; -static void u2f_passthru_class_init(ObjectClass *klass, void *data) +static void u2f_passthru_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); U2FKeyClass *kc = U2F_KEY_CLASS(klass); diff --git a/hw/usb/u2f.c b/hw/usb/u2f.c index 1fb59cf404..b051a999d3 100644 --- a/hw/usb/u2f.c +++ b/hw/usb/u2f.c @@ -317,7 +317,7 @@ const VMStateDescription vmstate_u2f_key = { } }; -static void u2f_key_class_init(ObjectClass *klass, void *data) +static void u2f_key_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); diff --git a/hw/usb/xlnx-usb-subsystem.c b/hw/usb/xlnx-usb-subsystem.c index d8deeb6ced..98967ef49f 100644 --- a/hw/usb/xlnx-usb-subsystem.c +++ b/hw/usb/xlnx-usb-subsystem.c @@ -69,7 +69,7 @@ static void versal_usb2_init(Object *obj) object_property_add_alias(obj, "dma", OBJECT(&s->dwc3.sysbus_xhci), "dma"); } -static void versal_usb2_class_init(ObjectClass *klass, void *data) +static void versal_usb2_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/usb/xlnx-versal-usb2-ctrl-regs.c b/hw/usb/xlnx-versal-usb2-ctrl-regs.c index 66c793a602..4114672d4f 100644 --- a/hw/usb/xlnx-versal-usb2-ctrl-regs.c +++ b/hw/usb/xlnx-versal-usb2-ctrl-regs.c @@ -202,7 +202,7 @@ static const VMStateDescription vmstate_usb2_ctrl_regs = { } }; -static void usb2_ctrl_regs_class_init(ObjectClass *klass, void *data) +static void usb2_ctrl_regs_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/vfio/amd-xgbe.c b/hw/vfio/amd-xgbe.c index 5927503b5c..58f590e385 100644 --- a/hw/vfio/amd-xgbe.c +++ b/hw/vfio/amd-xgbe.c @@ -34,7 +34,7 @@ static const VMStateDescription vfio_platform_amd_xgbe_vmstate = { .unmigratable = 1, }; -static void vfio_amd_xgbe_class_init(ObjectClass *klass, void *data) +static void vfio_amd_xgbe_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VFIOAmdXgbeDeviceClass *vcxc = diff --git a/hw/vfio/ap.c b/hw/vfio/ap.c index d6575d7c44..a8f0e6ae14 100644 --- a/hw/vfio/ap.c +++ b/hw/vfio/ap.c @@ -241,7 +241,7 @@ static void vfio_ap_set_fd(Object *obj, const char *str, Error **errp) } #endif -static void vfio_ap_class_init(ObjectClass *klass, void *data) +static void vfio_ap_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/vfio/calxeda-xgmac.c b/hw/vfio/calxeda-xgmac.c index a5ef262def..03f2ff5763 100644 --- a/hw/vfio/calxeda-xgmac.c +++ b/hw/vfio/calxeda-xgmac.c @@ -34,7 +34,7 @@ static const VMStateDescription vfio_platform_calxeda_xgmac_vmstate = { .unmigratable = 1, }; -static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, void *data) +static void vfio_calxeda_xgmac_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VFIOCalxedaXgmacDeviceClass *vcxc = diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 29e804e122..a381ab09ff 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -689,7 +689,7 @@ static void vfio_ccw_set_fd(Object *obj, const char *str, Error **errp) } #endif -static void vfio_ccw_class_init(ObjectClass *klass, void *data) +static void vfio_ccw_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); diff --git a/hw/vfio/container.c b/hw/vfio/container.c index 812d5edbcf..63fbe2b054 100644 --- a/hw/vfio/container.c +++ b/hw/vfio/container.c @@ -1121,7 +1121,7 @@ out_single: return ret; } -static void vfio_iommu_legacy_class_init(ObjectClass *klass, void *data) +static void vfio_iommu_legacy_class_init(ObjectClass *klass, const void *data) { VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); @@ -1185,7 +1185,7 @@ static void vfio_iommu_legacy_instance_init(Object *obj) QLIST_INIT(&container->group_list); } -static void hiod_legacy_vfio_class_init(ObjectClass *oc, void *data) +static void hiod_legacy_vfio_class_init(ObjectClass *oc, const void *data) { HostIOMMUDeviceClass *hioc = HOST_IOMMU_DEVICE_CLASS(oc); diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index 265fffc2aa..fd55b8d884 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -301,7 +301,8 @@ static void vfio_pci_igd_lpc_bridge_realize(PCIDevice *pdev, Error **errp) } } -static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, void *data) +static void vfio_pci_igd_lpc_bridge_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c index 42c8412bbf..911da7d86d 100644 --- a/hw/vfio/iommufd.c +++ b/hw/vfio/iommufd.c @@ -786,7 +786,7 @@ out_single: return ret; } -static void vfio_iommu_iommufd_class_init(ObjectClass *klass, void *data) +static void vfio_iommu_iommufd_class_init(ObjectClass *klass, const void *data) { VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); @@ -846,7 +846,7 @@ hiod_iommufd_vfio_get_page_size_mask(HostIOMMUDevice *hiod) } -static void hiod_iommufd_vfio_class_init(ObjectClass *oc, void *data) +static void hiod_iommufd_vfio_class_init(ObjectClass *oc, const void *data) { HostIOMMUDeviceClass *hiodc = HOST_IOMMU_DEVICE_CLASS(oc); diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index f87f3ccbe1..0db9f03846 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3409,7 +3409,7 @@ static void vfio_pci_set_fd(Object *obj, const char *str, Error **errp) } #endif -static void vfio_pci_dev_class_init(ObjectClass *klass, void *data) +static void vfio_pci_dev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pdc = PCI_DEVICE_CLASS(klass); @@ -3567,7 +3567,8 @@ static const Property vfio_pci_dev_nohotplug_properties[] = { ON_OFF_AUTO_AUTO), }; -static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, void *data) +static void vfio_pci_nohotplug_dev_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/vfio/platform.c b/hw/vfio/platform.c index f273ae9a51..3f8d092f7f 100644 --- a/hw/vfio/platform.c +++ b/hw/vfio/platform.c @@ -658,7 +658,7 @@ static void vfio_platform_set_fd(Object *obj, const char *str, Error **errp) } #endif -static void vfio_platform_class_init(ObjectClass *klass, void *data) +static void vfio_platform_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass); diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 66a2d2bb0d..bc795bdaf1 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -534,7 +534,7 @@ listener_unregister_exit: return false; } -static void vfio_iommu_spapr_class_init(ObjectClass *klass, void *data) +static void vfio_iommu_spapr_class_init(ObjectClass *klass, const void *data) { VFIOIOMMUClass *vioc = VFIO_IOMMU_CLASS(klass); diff --git a/hw/virtio/vdpa-dev-pci.c b/hw/virtio/vdpa-dev-pci.c index 787926801a..3068112146 100644 --- a/hw/virtio/vdpa-dev-pci.c +++ b/hw/virtio/vdpa-dev-pci.c @@ -70,7 +70,8 @@ vhost_vdpa_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(DEVICE(&dev->vdev), BUS(&vpci_dev->bus), errp); } -static void vhost_vdpa_device_pci_class_init(ObjectClass *klass, void *data) +static void vhost_vdpa_device_pci_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index a7e73b1c99..dd8837ce4e 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -353,7 +353,7 @@ static const VMStateDescription vmstate_vhost_vdpa_device = { }, }; -static void vhost_vdpa_device_class_init(ObjectClass *klass, void *data) +static void vhost_vdpa_device_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c index 3778f6131e..7399acef8e 100644 --- a/hw/virtio/vhost-scsi-pci.c +++ b/hw/virtio/vhost-scsi-pci.c @@ -61,7 +61,7 @@ static void vhost_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_scsi_pci_class_init(ObjectClass *klass, void *data) +static void vhost_scsi_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-base.c b/hw/virtio/vhost-user-base.c index 2bc3423326..77143320a2 100644 --- a/hw/virtio/vhost-user-base.c +++ b/hw/virtio/vhost-user-base.c @@ -348,7 +348,7 @@ static void vub_device_unrealize(DeviceState *dev) do_vhost_user_cleanup(vdev, vub); } -static void vub_class_init(ObjectClass *klass, void *data) +static void vub_class_init(ObjectClass *klass, const void *data) { VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c index 1767ef2c9c..904369f5a3 100644 --- a/hw/virtio/vhost-user-blk-pci.c +++ b/hw/virtio/vhost-user-blk-pci.c @@ -65,7 +65,7 @@ static void vhost_user_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_blk_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_blk_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-device-pci.c b/hw/virtio/vhost-user-device-pci.c index efaf55d3dd..f10bac874e 100644 --- a/hw/virtio/vhost-user-device-pci.c +++ b/hw/virtio/vhost-user-device-pci.c @@ -31,7 +31,8 @@ static void vhost_user_device_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_device_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_device_pci_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-device.c b/hw/virtio/vhost-user-device.c index 86eba138b4..3939bdf755 100644 --- a/hw/virtio/vhost-user-device.c +++ b/hw/virtio/vhost-user-device.c @@ -37,7 +37,7 @@ static const Property vud_properties[] = { DEFINE_PROP_UINT32("config_size", VHostUserBase, config_size, 0), }; -static void vud_class_init(ObjectClass *klass, void *data) +static void vud_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c index 116eaab907..1490c118bc 100644 --- a/hw/virtio/vhost-user-fs-pci.c +++ b/hw/virtio/vhost-user-fs-pci.c @@ -47,7 +47,7 @@ static void vhost_user_fs_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_fs_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_fs_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index 0e8d4b3823..f6d1fc8804 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -418,7 +418,7 @@ static void vuf_instance_init(Object *obj) "/filesystem@0", DEVICE(obj)); } -static void vuf_class_init(ObjectClass *klass, void *data) +static void vuf_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-user-gpio-pci.c b/hw/virtio/vhost-user-gpio-pci.c index b3028a24a1..9b165b54f8 100644 --- a/hw/virtio/vhost-user-gpio-pci.c +++ b/hw/virtio/vhost-user-gpio-pci.c @@ -32,7 +32,7 @@ static void vhost_user_gpio_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_gpio_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_gpio_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-gpio.c b/hw/virtio/vhost-user-gpio.c index 4a08814904..a7fd49b10a 100644 --- a/hw/virtio/vhost-user-gpio.c +++ b/hw/virtio/vhost-user-gpio.c @@ -36,7 +36,7 @@ static const VMStateDescription vu_gpio_vmstate = { .unmigratable = 1, }; -static void vu_gpio_class_init(ObjectClass *klass, void *data) +static void vu_gpio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass); diff --git a/hw/virtio/vhost-user-i2c-pci.c b/hw/virtio/vhost-user-i2c-pci.c index 00ac10941f..692cd66fde 100644 --- a/hw/virtio/vhost-user-i2c-pci.c +++ b/hw/virtio/vhost-user-i2c-pci.c @@ -32,7 +32,7 @@ static void vhost_user_i2c_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_i2c_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_i2c_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-i2c.c b/hw/virtio/vhost-user-i2c.c index 1c7cde503c..ae007fe97d 100644 --- a/hw/virtio/vhost-user-i2c.c +++ b/hw/virtio/vhost-user-i2c.c @@ -36,7 +36,7 @@ static const VMStateDescription vu_i2c_vmstate = { .unmigratable = 1, }; -static void vu_i2c_class_init(ObjectClass *klass, void *data) +static void vu_i2c_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass); diff --git a/hw/virtio/vhost-user-input.c b/hw/virtio/vhost-user-input.c index 917405329f..5cfc5bbb56 100644 --- a/hw/virtio/vhost-user-input.c +++ b/hw/virtio/vhost-user-input.c @@ -30,7 +30,7 @@ static const VMStateDescription vmstate_vhost_input = { .unmigratable = 1, }; -static void vhost_input_class_init(ObjectClass *klass, void *data) +static void vhost_input_class_init(ObjectClass *klass, const void *data) { VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-user-rng-pci.c b/hw/virtio/vhost-user-rng-pci.c index a4e690148d..9f45fc6f35 100644 --- a/hw/virtio/vhost-user-rng-pci.c +++ b/hw/virtio/vhost-user-rng-pci.c @@ -40,7 +40,7 @@ static void vhost_user_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_rng_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_rng_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-rng.c b/hw/virtio/vhost-user-rng.c index 5aa432e5e1..61dadcda05 100644 --- a/hw/virtio/vhost-user-rng.c +++ b/hw/virtio/vhost-user-rng.c @@ -37,7 +37,7 @@ static void vu_rng_base_realize(DeviceState *dev, Error **errp) vubs->parent_realize(dev, errp); } -static void vu_rng_class_init(ObjectClass *klass, void *data) +static void vu_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass); diff --git a/hw/virtio/vhost-user-scmi-pci.c b/hw/virtio/vhost-user-scmi-pci.c index 7f53af7fce..0ab56a50bb 100644 --- a/hw/virtio/vhost-user-scmi-pci.c +++ b/hw/virtio/vhost-user-scmi-pci.c @@ -31,7 +31,7 @@ static void vhost_user_scmi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_scmi_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_scmi_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c index 04cd36dd2e..7a0f622181 100644 --- a/hw/virtio/vhost-user-scmi.c +++ b/hw/virtio/vhost-user-scmi.c @@ -279,7 +279,7 @@ static const Property vu_scmi_properties[] = { DEFINE_PROP_CHR("chardev", VHostUserSCMI, chardev), }; -static void vu_scmi_class_init(ObjectClass *klass, void *data) +static void vu_scmi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c index 4a4128d961..994e51a37b 100644 --- a/hw/virtio/vhost-user-scsi-pci.c +++ b/hw/virtio/vhost-user-scsi-pci.c @@ -67,7 +67,7 @@ static void vhost_user_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_scsi_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_scsi_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-snd-pci.c b/hw/virtio/vhost-user-snd-pci.c index 0cb86b7d85..f5015fb6c4 100644 --- a/hw/virtio/vhost-user-snd-pci.c +++ b/hw/virtio/vhost-user-snd-pci.c @@ -33,7 +33,7 @@ static void vhost_user_snd_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_snd_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_snd_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-snd.c b/hw/virtio/vhost-user-snd.c index b414c75c06..732411c655 100644 --- a/hw/virtio/vhost-user-snd.c +++ b/hw/virtio/vhost-user-snd.c @@ -54,7 +54,7 @@ static void vu_snd_base_realize(DeviceState *dev, Error **errp) vubs->parent_realize(dev, errp); } -static void vu_snd_class_init(ObjectClass *klass, void *data) +static void vu_snd_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VHostUserBaseClass *vubc = VHOST_USER_BASE_CLASS(klass); diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c index f730a05e78..adb877b6e0 100644 --- a/hw/virtio/vhost-user-vsock-pci.c +++ b/hw/virtio/vhost-user-vsock-pci.c @@ -46,7 +46,8 @@ static void vhost_user_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_user_vsock_pci_class_init(ObjectClass *klass, void *data) +static void vhost_user_vsock_pci_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index d21cd4b516..2776792f59 100644 --- a/hw/virtio/vhost-user-vsock.c +++ b/hw/virtio/vhost-user-vsock.c @@ -151,7 +151,7 @@ static const Property vuv_properties[] = { DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev), }; -static void vuv_class_init(ObjectClass *klass, void *data) +static void vuv_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index 9ac587d20c..4b4fbb45cc 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -290,7 +290,7 @@ static const Property vhost_vsock_common_properties[] = { ON_OFF_AUTO_AUTO), }; -static void vhost_vsock_common_class_init(ObjectClass *klass, void *data) +static void vhost_vsock_common_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c index 6c618ee908..0022a713d4 100644 --- a/hw/virtio/vhost-vsock-pci.c +++ b/hw/virtio/vhost-vsock-pci.c @@ -56,7 +56,7 @@ static void vhost_vsock_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void vhost_vsock_pci_class_init(ObjectClass *klass, void *data) +static void vhost_vsock_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index 940b30fa27..b73dc723c2 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -210,7 +210,7 @@ static const Property vhost_vsock_properties[] = { DEFINE_PROP_STRING("vhostfd", VHostVSock, conf.vhostfd), }; -static void vhost_vsock_class_init(ObjectClass *klass, void *data) +static void vhost_vsock_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c index aa1dce8f28..594742ff65 100644 --- a/hw/virtio/virtio-9p-pci.c +++ b/hw/virtio/virtio-9p-pci.c @@ -49,7 +49,7 @@ static const Property virtio_9p_pci_properties[] = { DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), }; -static void virtio_9p_pci_class_init(ObjectClass *klass, void *data) +static void virtio_9p_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c index db7e1cb475..96e88b6b86 100644 --- a/hw/virtio/virtio-balloon-pci.c +++ b/hw/virtio/virtio-balloon-pci.c @@ -55,7 +55,7 @@ static void virtio_balloon_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_balloon_pci_class_init(ObjectClass *klass, void *data) +static void virtio_balloon_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 0d0603c674..91510ec2e2 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -1058,7 +1058,7 @@ static const Property virtio_balloon_properties[] = { IOThread *), }; -static void virtio_balloon_class_init(ObjectClass *klass, void *data) +static void virtio_balloon_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c index fc06cec656..fd33bbd7e8 100644 --- a/hw/virtio/virtio-blk-pci.c +++ b/hw/virtio/virtio-blk-pci.c @@ -63,7 +63,7 @@ static void virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_blk_pci_class_init(ObjectClass *klass, void *data) +static void virtio_blk_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index d1c79c567b..11adfbf3ab 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -348,7 +348,7 @@ bool virtio_bus_device_iommu_enabled(VirtIODevice *vdev) return klass->iommu_enabled(qbus->parent); } -static void virtio_bus_class_init(ObjectClass *klass, void *data) +static void virtio_bus_class_init(ObjectClass *klass, const void *data) { BusClass *bus_class = BUS_CLASS(klass); bus_class->get_dev_path = virtio_bus_get_dev_path; diff --git a/hw/virtio/virtio-crypto-pci.c b/hw/virtio/virtio-crypto-pci.c index 8699481375..868abc03a9 100644 --- a/hw/virtio/virtio-crypto-pci.c +++ b/hw/virtio/virtio-crypto-pci.c @@ -59,7 +59,7 @@ static void virtio_crypto_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_crypto_pci_class_init(ObjectClass *klass, void *data) +static void virtio_crypto_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index a1b3c90618..e24d6914b6 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -1264,7 +1264,7 @@ static struct vhost_dev *virtio_crypto_get_vhost(VirtIODevice *vdev) return &vhost_crypto->dev; } -static void virtio_crypto_class_init(ObjectClass *klass, void *data) +static void virtio_crypto_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c index 9e3c106777..3be5358b4c 100644 --- a/hw/virtio/virtio-input-pci.c +++ b/hw/virtio/virtio-input-pci.c @@ -50,7 +50,7 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_input_pci_class_init(ObjectClass *klass, void *data) +static void virtio_input_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); @@ -63,7 +63,8 @@ static void virtio_input_pci_class_init(ObjectClass *klass, void *data) pcidev_k->class_id = PCI_CLASS_INPUT_OTHER; } -static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) +static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, + const void *data) { PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); @@ -71,7 +72,7 @@ static void virtio_input_hid_kbd_pci_class_init(ObjectClass *klass, void *data) } static void virtio_input_hid_mouse_pci_class_init(ObjectClass *klass, - void *data) + const void *data) { PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c index 97e03ce803..8123c6f83a 100644 --- a/hw/virtio/virtio-iommu-pci.c +++ b/hw/virtio/virtio-iommu-pci.c @@ -73,7 +73,7 @@ static void virtio_iommu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_iommu_pci_class_init(ObjectClass *klass, void *data) +static void virtio_iommu_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index b6e7e01ef7..54060988ef 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1664,7 +1664,7 @@ static const Property virtio_iommu_properties[] = { DEFINE_PROP_UINT8("aw-bits", VirtIOIOMMU, aw_bits, 64), }; -static void virtio_iommu_class_init(ObjectClass *klass, void *data) +static void virtio_iommu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); @@ -1690,7 +1690,7 @@ static void virtio_iommu_class_init(ObjectClass *klass, void *data) } static void virtio_iommu_memory_region_class_init(ObjectClass *klass, - void *data) + const void *data) { IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); diff --git a/hw/virtio/virtio-mem-pci.c b/hw/virtio/virtio-mem-pci.c index 6cc5f0fd3b..f592eb1a78 100644 --- a/hw/virtio/virtio-mem-pci.c +++ b/hw/virtio/virtio-mem-pci.c @@ -163,7 +163,7 @@ static const Property virtio_mem_pci_class_properties[] = { DEV_NVECTORS_UNSPECIFIED), }; -static void virtio_mem_pci_class_init(ObjectClass *klass, void *data) +static void virtio_mem_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index c7968ee0c6..0e14dd37d6 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -1865,7 +1865,7 @@ static void virtio_mem_unplug_request_check(VirtIOMEM *vmem, Error **errp) } } -static void virtio_mem_class_init(ObjectClass *klass, void *data) +static void virtio_mem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); @@ -1957,7 +1957,8 @@ static void virtio_mem_system_reset_hold(Object *obj, ResetType type) virtio_mem_unplug_all(vmem); } -static void virtio_mem_system_reset_class_init(ObjectClass *klass, void *data) +static void virtio_mem_system_reset_class_init(ObjectClass *klass, + const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 029817139b..532c67107b 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -784,7 +784,7 @@ static void virtio_mmio_realizefn(DeviceState *d, Error **errp) sysbus_init_mmio(sbd, &proxy->iomem); } -static void virtio_mmio_class_init(ObjectClass *klass, void *data) +static void virtio_mmio_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -855,7 +855,7 @@ static void virtio_mmio_vmstate_change(DeviceState *d, bool running) } } -static void virtio_mmio_bus_class_init(ObjectClass *klass, void *data) +static void virtio_mmio_bus_class_init(ObjectClass *klass, const void *data) { BusClass *bus_class = BUS_CLASS(klass); VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index e18953ad67..8cf9788bc3 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -63,7 +63,7 @@ static void virtio_net_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_net_pci_class_init(ObjectClass *klass, void *data) +static void virtio_net_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-nsm-pci.c b/hw/virtio/virtio-nsm-pci.c index dca797315a..ec243963e1 100644 --- a/hw/virtio/virtio-nsm-pci.c +++ b/hw/virtio/virtio-nsm-pci.c @@ -40,7 +40,7 @@ static void virtio_nsm_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_nsm_pci_class_init(ObjectClass *klass, void *data) +static void virtio_nsm_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-nsm.c b/hw/virtio/virtio-nsm.c index accf7334e3..3bf5e7009a 100644 --- a/hw/virtio/virtio-nsm.c +++ b/hw/virtio/virtio-nsm.c @@ -1708,7 +1708,7 @@ static const Property virtio_nsm_properties[] = { DEFINE_PROP_STRING("module-id", VirtIONSM, module_id), }; -static void virtio_nsm_class_init(ObjectClass *klass, void *data) +static void virtio_nsm_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3ca3f849d3..c0fd3db063 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2399,7 +2399,7 @@ static int virtio_pci_sync_config(DeviceState *dev, Error **errp) return qdev_sync_config(DEVICE(vdev), errp); } -static void virtio_pci_class_init(ObjectClass *klass, void *data) +static void virtio_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); @@ -2433,7 +2433,7 @@ static const Property virtio_pci_generic_properties[] = { DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false), }; -static void virtio_pci_base_class_init(ObjectClass *klass, void *data) +static void virtio_pci_base_class_init(ObjectClass *klass, const void *data) { const VirtioPCIDeviceTypeInfo *t = data; if (t->class_init) { @@ -2441,7 +2441,7 @@ static void virtio_pci_base_class_init(ObjectClass *klass, void *data) } } -static void virtio_pci_generic_class_init(ObjectClass *klass, void *data) +static void virtio_pci_generic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -2586,7 +2586,7 @@ static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size, qbus_init(bus, bus_size, TYPE_VIRTIO_PCI_BUS, qdev, virtio_bus_name); } -static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) +static void virtio_pci_bus_class_init(ObjectClass *klass, const void *data) { BusClass *bus_class = BUS_CLASS(klass); VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); diff --git a/hw/virtio/virtio-pmem-pci.c b/hw/virtio/virtio-pmem-pci.c index cfe7f3b67c..babd91c21f 100644 --- a/hw/virtio/virtio-pmem-pci.c +++ b/hw/virtio/virtio-pmem-pci.c @@ -80,7 +80,7 @@ static void virtio_pmem_pci_fill_device_info(const MemoryDeviceState *md, info->type = MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM; } -static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data) +static void virtio_pmem_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c index adb3268bd4..3416ea1827 100644 --- a/hw/virtio/virtio-pmem.c +++ b/hw/virtio/virtio-pmem.c @@ -161,7 +161,7 @@ static const Property virtio_pmem_properties[] = { TYPE_MEMORY_BACKEND, HostMemoryBackend *), }; -static void virtio_pmem_class_init(ObjectClass *klass, void *data) +static void virtio_pmem_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c index a94ff767b2..39b600356e 100644 --- a/hw/virtio/virtio-rng-pci.c +++ b/hw/virtio/virtio-rng-pci.c @@ -53,7 +53,7 @@ static void virtio_rng_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) } } -static void virtio_rng_pci_class_init(ObjectClass *klass, void *data) +static void virtio_rng_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index a515fc5cd9..dcb3c71d6a 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -260,7 +260,7 @@ static const Property virtio_rng_properties[] = { DEFINE_PROP_LINK("rng", VirtIORNG, conf.rng, TYPE_RNG_BACKEND, RngBackend *), }; -static void virtio_rng_class_init(ObjectClass *klass, void *data) +static void virtio_rng_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c index d44fd2fffb..af87759207 100644 --- a/hw/virtio/virtio-scsi-pci.c +++ b/hw/virtio/virtio-scsi-pci.c @@ -72,7 +72,7 @@ static void virtio_scsi_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) qdev_realize(vdev, BUS(&vpci_dev->bus), errp); } -static void virtio_scsi_pci_class_init(ObjectClass *klass, void *data) +static void virtio_scsi_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c index b5b77eb266..3f212ffe52 100644 --- a/hw/virtio/virtio-serial-pci.c +++ b/hw/virtio/virtio-serial-pci.c @@ -76,7 +76,7 @@ static const Property virtio_serial_pci_properties[] = { DEFINE_PROP_UINT32("class", VirtIOPCIProxy, class_code, 0), }; -static void virtio_serial_pci_class_init(ObjectClass *klass, void *data) +static void virtio_serial_pci_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index ffc12635ae..f0fa36f8ce 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -4138,7 +4138,7 @@ void virtio_device_release_ioeventfd(VirtIODevice *vdev) virtio_bus_release_ioeventfd(vbus); } -static void virtio_device_class_init(ObjectClass *klass, void *data) +static void virtio_device_class_init(ObjectClass *klass, const void *data) { /* Set the default value here. */ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); diff --git a/hw/vmapple/aes.c b/hw/vmapple/aes.c index 3a7641ab4b..a4853a98f8 100644 --- a/hw/vmapple/aes.c +++ b/hw/vmapple/aes.c @@ -558,7 +558,7 @@ static void aes_init(Object *obj) s->as = &address_space_memory; } -static void aes_class_init(ObjectClass *klass, void *data) +static void aes_class_init(ObjectClass *klass, const void *data) { ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/vmapple/bdif.c b/hw/vmapple/bdif.c index 5827dd2aab..5ccd374581 100644 --- a/hw/vmapple/bdif.c +++ b/hw/vmapple/bdif.c @@ -250,7 +250,7 @@ static const Property bdif_properties[] = { DEFINE_PROP_DRIVE("root", VMAppleBdifState, root), }; -static void bdif_class_init(ObjectClass *klass, void *data) +static void bdif_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/vmapple/cfg.c b/hw/vmapple/cfg.c index 63414d801f..3d58a29f69 100644 --- a/hw/vmapple/cfg.c +++ b/hw/vmapple/cfg.c @@ -168,7 +168,7 @@ static const Property vmapple_cfg_properties[] = { DEFINE_PROP_STRING("soc_name", VMAppleCfgState, soc_name), }; -static void vmapple_cfg_class_init(ObjectClass *klass, void *data) +static void vmapple_cfg_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); diff --git a/hw/vmapple/virtio-blk.c b/hw/vmapple/virtio-blk.c index aa3f18c47d..532b5649ab 100644 --- a/hw/vmapple/virtio-blk.c +++ b/hw/vmapple/virtio-blk.c @@ -82,7 +82,7 @@ static void vmapple_virtio_blk_get_config(VirtIODevice *vdev, uint8_t *config) stl_he_p(&blkcfg->max_secure_erase_sectors, dev->apple_type); } -static void vmapple_virtio_blk_class_init(ObjectClass *klass, void *data) +static void vmapple_virtio_blk_class_init(ObjectClass *klass, const void *data) { VirtIOBlkClass *vbk = VIRTIO_BLK_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); @@ -165,7 +165,8 @@ static void vmapple_virtio_blk_pci_realize(VirtIOPCIProxy *vpci_dev, Error **err PCI_DEVICE_ID_APPLE_VIRTIO_BLK); } -static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass, void *data) +static void vmapple_virtio_blk_pci_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass); diff --git a/hw/vmapple/vmapple.c b/hw/vmapple/vmapple.c index fa117bf151..16e6110b68 100644 --- a/hw/vmapple/vmapple.c +++ b/hw/vmapple/vmapple.c @@ -570,7 +570,7 @@ static GlobalProperty vmapple_compat_defaults[] = { { TYPE_XHCI_PCI, "conditional-intr-mapping", "on" }, }; -static void vmapple_machine_class_init(ObjectClass *oc, void *data) +static void vmapple_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/watchdog/allwinner-wdt.c b/hw/watchdog/allwinner-wdt.c index 78f4f9d6f6..8fcd776675 100644 --- a/hw/watchdog/allwinner-wdt.c +++ b/hw/watchdog/allwinner-wdt.c @@ -348,7 +348,7 @@ static void allwinner_wdt_realize(DeviceState *dev, Error **errp) ptimer_transaction_commit(s->timer); } -static void allwinner_wdt_class_init(ObjectClass *klass, void *data) +static void allwinner_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); ResettableClass *rc = RESETTABLE_CLASS(klass); @@ -358,7 +358,7 @@ static void allwinner_wdt_class_init(ObjectClass *klass, void *data) dc->vmsd = &allwinner_wdt_vmstate; } -static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, void *data) +static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, const void *data) { AwWdtClass *awc = AW_WDT_CLASS(klass); @@ -371,7 +371,7 @@ static void allwinner_wdt_sun4i_class_init(ObjectClass *klass, void *data) awc->get_intv_value = allwinner_wdt_sun4i_get_intv_value; } -static void allwinner_wdt_sun6i_class_init(ObjectClass *klass, void *data) +static void allwinner_wdt_sun6i_class_init(ObjectClass *klass, const void *data) { AwWdtClass *awc = AW_WDT_CLASS(klass); diff --git a/hw/watchdog/cmsdk-apb-watchdog.c b/hw/watchdog/cmsdk-apb-watchdog.c index a52121dc44..6a8d07ca56 100644 --- a/hw/watchdog/cmsdk-apb-watchdog.c +++ b/hw/watchdog/cmsdk-apb-watchdog.c @@ -394,7 +394,7 @@ static const VMStateDescription cmsdk_apb_watchdog_vmstate = { } }; -static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, void *data) +static void cmsdk_apb_watchdog_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c index 1dd21392a9..ce84849df0 100644 --- a/hw/watchdog/sbsa_gwdt.c +++ b/hw/watchdog/sbsa_gwdt.c @@ -271,7 +271,7 @@ static const Property wdt_sbsa_gwdt_props[] = { 62500000), }; -static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, void *data) +static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/watchdog/spapr_watchdog.c b/hw/watchdog/spapr_watchdog.c index 2bb1d3c532..5b3f50de3a 100644 --- a/hw/watchdog/spapr_watchdog.c +++ b/hw/watchdog/spapr_watchdog.c @@ -249,7 +249,7 @@ static void spapr_wdt_realize(DeviceState *dev, Error **errp) &w->leave_others, OBJ_PROP_FLAG_READ); } -static void spapr_wdt_class_init(ObjectClass *oc, void *data) +static void spapr_wdt_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/hw/watchdog/wdt_aspeed.c b/hw/watchdog/wdt_aspeed.c index a503b2aea7..30226435ef 100644 --- a/hw/watchdog/wdt_aspeed.c +++ b/hw/watchdog/wdt_aspeed.c @@ -307,7 +307,7 @@ static const Property aspeed_wdt_properties[] = { AspeedSCUState *), }; -static void aspeed_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -329,7 +329,7 @@ static const TypeInfo aspeed_wdt_info = { .abstract = true, }; -static void aspeed_2400_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_2400_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); @@ -366,7 +366,7 @@ static void aspeed_2500_wdt_reset_pulse(AspeedWDTState *s, uint32_t property) } } -static void aspeed_2500_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_2500_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); @@ -389,7 +389,7 @@ static const TypeInfo aspeed_2500_wdt_info = { .class_init = aspeed_2500_wdt_class_init, }; -static void aspeed_2600_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_2600_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); @@ -412,7 +412,7 @@ static const TypeInfo aspeed_2600_wdt_info = { .class_init = aspeed_2600_wdt_class_init, }; -static void aspeed_1030_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_1030_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); @@ -435,7 +435,7 @@ static const TypeInfo aspeed_1030_wdt_info = { .class_init = aspeed_1030_wdt_class_init, }; -static void aspeed_2700_wdt_class_init(ObjectClass *klass, void *data) +static void aspeed_2700_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedWDTClass *awc = ASPEED_WDT_CLASS(klass); diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index 39f2894f21..1275353e8e 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -108,7 +108,7 @@ static void wdt_diag288_unrealize(DeviceState *dev) timer_free(diag288->timer); } -static void wdt_diag288_class_init(ObjectClass *klass, void *data) +static void wdt_diag288_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); DIAG288Class *diag288 = DIAG288_CLASS(klass); diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index aa1d0866c8..1536e1fe03 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -457,7 +457,7 @@ static void i6300esb_exit(PCIDevice *dev) timer_free(d->timer); } -static void i6300esb_class_init(ObjectClass *klass, void *data) +static void i6300esb_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/watchdog/wdt_ib700.c b/hw/watchdog/wdt_ib700.c index 23519e058e..51a26a4cbb 100644 --- a/hw/watchdog/wdt_ib700.c +++ b/hw/watchdog/wdt_ib700.c @@ -128,7 +128,7 @@ static void wdt_ib700_reset(DeviceState *dev) timer_del(s->timer); } -static void wdt_ib700_class_init(ObjectClass *klass, void *data) +static void wdt_ib700_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/watchdog/wdt_imx2.c b/hw/watchdog/wdt_imx2.c index 18e40bd466..10151a15d0 100644 --- a/hw/watchdog/wdt_imx2.c +++ b/hw/watchdog/wdt_imx2.c @@ -286,7 +286,7 @@ static const Property imx2_wdt_properties[] = { false), }; -static void imx2_wdt_class_init(ObjectClass *klass, void *data) +static void imx2_wdt_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index f808a01813..e6272282cd 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -380,7 +380,7 @@ static void xen_bus_unplug_request(HotplugHandler *hotplug, xen_device_unplug(xendev, errp); } -static void xen_bus_class_init(ObjectClass *class, void *data) +static void xen_bus_class_init(ObjectClass *class, const void *data) { BusClass *bus_class = BUS_CLASS(class); HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); @@ -1107,7 +1107,7 @@ static const Property xen_device_props[] = { DOMID_INVALID), }; -static void xen_device_class_init(ObjectClass *class, void *data) +static void xen_device_class_init(ObjectClass *class, const void *data) { DeviceClass *dev_class = DEVICE_CLASS(class); diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index bf58db0ca6..d6fe7d4f3e 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -635,7 +635,7 @@ int xen_be_bind_evtchn(struct XenLegacyDevice *xendev) } -static void xendev_class_init(ObjectClass *klass, void *data) +static void xendev_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -650,7 +650,7 @@ static const TypeInfo xendev_type_info = { .instance_size = sizeof(XenLegacyDevice), }; -static void xen_sysbus_class_init(ObjectClass *klass, void *data) +static void xen_sysbus_class_init(ObjectClass *klass, const void *data) { HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); diff --git a/hw/xen/xen-pvh-common.c b/hw/xen/xen-pvh-common.c index d675f7a8ae..b93ff80c85 100644 --- a/hw/xen/xen-pvh-common.c +++ b/hw/xen/xen-pvh-common.c @@ -369,7 +369,7 @@ do { \ #endif } -static void xen_pvh_class_init(ObjectClass *oc, void *data) +static void xen_pvh_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 9487f68f2e..7f9c351d96 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -1047,7 +1047,7 @@ static void xen_igd_clear_slot(DeviceState *qdev, Error **errp) xpdc->pci_qdev_realize(qdev, errp); } -static void xen_pci_passthrough_class_init(ObjectClass *klass, void *data) +static void xen_pci_passthrough_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index 6c2e3f4840..264851ece3 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -347,7 +347,7 @@ static const IGDDeviceIDInfo igd_combo_id_infos[] = { {0x162D, 0x9cc3, 0x03}, /* BDWGT3SRVR, BDWM_w7 */ }; -static void isa_bridge_class_init(ObjectClass *klass, void *data) +static void isa_bridge_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c index 3bd0ef8268..6efffae466 100644 --- a/hw/xtensa/xtfpga.c +++ b/hw/xtensa/xtfpga.c @@ -585,7 +585,7 @@ static void xtfpga_kc705_nommu_init(MachineState *machine) xtfpga_init(&kc705_board, machine); } -static void xtfpga_lx60_class_init(ObjectClass *oc, void *data) +static void xtfpga_lx60_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -602,7 +602,7 @@ static const TypeInfo xtfpga_lx60_type = { .class_init = xtfpga_lx60_class_init, }; -static void xtfpga_lx60_nommu_class_init(ObjectClass *oc, void *data) +static void xtfpga_lx60_nommu_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -619,7 +619,7 @@ static const TypeInfo xtfpga_lx60_nommu_type = { .class_init = xtfpga_lx60_nommu_class_init, }; -static void xtfpga_lx200_class_init(ObjectClass *oc, void *data) +static void xtfpga_lx200_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -636,7 +636,7 @@ static const TypeInfo xtfpga_lx200_type = { .class_init = xtfpga_lx200_class_init, }; -static void xtfpga_lx200_nommu_class_init(ObjectClass *oc, void *data) +static void xtfpga_lx200_nommu_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -653,7 +653,7 @@ static const TypeInfo xtfpga_lx200_nommu_type = { .class_init = xtfpga_lx200_nommu_class_init, }; -static void xtfpga_ml605_class_init(ObjectClass *oc, void *data) +static void xtfpga_ml605_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -670,7 +670,7 @@ static const TypeInfo xtfpga_ml605_type = { .class_init = xtfpga_ml605_class_init, }; -static void xtfpga_ml605_nommu_class_init(ObjectClass *oc, void *data) +static void xtfpga_ml605_nommu_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -687,7 +687,7 @@ static const TypeInfo xtfpga_ml605_nommu_type = { .class_init = xtfpga_ml605_nommu_class_init, }; -static void xtfpga_kc705_class_init(ObjectClass *oc, void *data) +static void xtfpga_kc705_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -704,7 +704,7 @@ static const TypeInfo xtfpga_kc705_type = { .class_init = xtfpga_kc705_class_init, }; -static void xtfpga_kc705_nommu_class_init(ObjectClass *oc, void *data) +static void xtfpga_kc705_nommu_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/include/hw/boards.h b/include/hw/boards.h index 8556e01e21..765dc8dd35 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -745,7 +745,7 @@ struct MachineState { } while (0) #define DEFINE_MACHINE(namestr, machine_initfn) \ - static void machine_initfn##_class_init(ObjectClass *oc, void *data) \ + static void machine_initfn##_class_init(ObjectClass *oc, const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ machine_initfn(mc); \ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 8677dc8950..9563674e2d 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -306,7 +306,8 @@ extern GlobalProperty pc_compat_2_4[]; extern const size_t pc_compat_2_4_len; #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ - static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ + static void pc_machine_##suffix##_class_init(ObjectClass *oc, \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ optsfn(mc); \ @@ -331,7 +332,7 @@ extern const size_t pc_compat_2_4_len; } \ static void MACHINE_VER_SYM(class_init, namesym, __VA_ARGS__)( \ ObjectClass *oc, \ - void *data) \ + const void *data) \ { \ MachineClass *mc = MACHINE_CLASS(oc); \ MACHINE_VER_SYM(options, namesym, __VA_ARGS__)(mc); \ diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 971c5fabd4..567a9b0a9d 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -255,7 +255,7 @@ typedef struct VirtioPCIDeviceTypeInfo { size_t class_size; void (*instance_init)(Object *obj); void (*instance_finalize)(Object *obj); - void (*class_init)(ObjectClass *klass, void *data); + void (*class_init)(ObjectClass *klass, const void *data); InterfaceInfo *interfaces; } VirtioPCIDeviceTypeInfo; diff --git a/include/qom/object.h b/include/qom/object.h index 7bb14ca706..2fb86f00a6 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -280,7 +280,7 @@ struct Object static void \ module_obj_name##_finalize(Object *obj); \ static void \ - module_obj_name##_class_init(ObjectClass *oc, void *data); \ + module_obj_name##_class_init(ObjectClass *oc, const void *data); \ static void \ module_obj_name##_init(Object *obj); \ \ @@ -486,7 +486,7 @@ struct TypeInfo bool abstract; size_t class_size; - void (*class_init)(ObjectClass *klass, void *data); + void (*class_init)(ObjectClass *klass, const void *data); void (*class_base_init)(ObjectClass *klass, const void *data); void *class_data; diff --git a/io/channel-buffer.c b/io/channel-buffer.c index 8096180f85..189fa67ac2 100644 --- a/io/channel-buffer.c +++ b/io/channel-buffer.c @@ -225,7 +225,7 @@ static GSource *qio_channel_buffer_create_watch(QIOChannel *ioc, static void qio_channel_buffer_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-command.c b/io/channel-command.c index 6d5f64e146..8966dd3a2b 100644 --- a/io/channel-command.c +++ b/io/channel-command.c @@ -358,7 +358,7 @@ static GSource *qio_channel_command_create_watch(QIOChannel *ioc, static void qio_channel_command_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-file.c b/io/channel-file.c index 2ea8d08360..ca3f180cc2 100644 --- a/io/channel-file.c +++ b/io/channel-file.c @@ -290,7 +290,7 @@ static GSource *qio_channel_file_create_watch(QIOChannel *ioc, } static void qio_channel_file_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-null.c b/io/channel-null.c index ef99586348..49f1c80a54 100644 --- a/io/channel-null.c +++ b/io/channel-null.c @@ -207,7 +207,7 @@ qio_channel_null_create_watch(QIOChannel *ioc, static void qio_channel_null_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-socket.c b/io/channel-socket.c index 608bcf066e..088b49ffdb 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -949,7 +949,7 @@ static GSource *qio_channel_socket_create_watch(QIOChannel *ioc, } static void qio_channel_socket_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-tls.c b/io/channel-tls.c index caf8301a9e..db2ac1deae 100644 --- a/io/channel-tls.c +++ b/io/channel-tls.c @@ -561,7 +561,7 @@ qio_channel_tls_get_session(QIOChannelTLS *ioc) } static void qio_channel_tls_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/io/channel-websock.c b/io/channel-websock.c index 55192b770a..08ddb274f0 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -1308,7 +1308,7 @@ static GSource *qio_channel_websock_create_watch(QIOChannel *ioc, } static void qio_channel_websock_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/iothread.c b/iothread.c index 589bcd3552..8810376dce 100644 --- a/iothread.c +++ b/iothread.c @@ -292,7 +292,7 @@ static void iothread_set_poll_param(Object *obj, Visitor *v, } } -static void iothread_class_init(ObjectClass *klass, void *class_data) +static void iothread_class_init(ObjectClass *klass, const void *class_data) { EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(klass); diff --git a/migration/channel-block.c b/migration/channel-block.c index b0477f5b6d..97de5a691b 100644 --- a/migration/channel-block.c +++ b/migration/channel-block.c @@ -170,7 +170,7 @@ qio_channel_block_set_aio_fd_handler(QIOChannel *ioc, static void qio_channel_block_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/migration/migration.c b/migration/migration.c index d46e776e24..55ec4bfab6 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -4016,7 +4016,7 @@ fail: migration_cleanup(s); } -static void migration_class_init(ObjectClass *klass, void *data) +static void migration_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); diff --git a/migration/rdma.c b/migration/rdma.c index d9603ab603..b31652baac 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3985,7 +3985,7 @@ static void qio_channel_rdma_finalize(Object *obj) } static void qio_channel_rdma_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass); diff --git a/net/can/can_core.c b/net/can/can_core.c index 0115d78794..e16e15c036 100644 --- a/net/can/can_core.c +++ b/net/can/can_core.c @@ -149,7 +149,7 @@ static bool can_bus_can_be_deleted(UserCreatable *uc) } static void can_bus_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); diff --git a/net/can/can_host.c b/net/can/can_host.c index b2fe553f91..ca5fcf1ea1 100644 --- a/net/can/can_host.c +++ b/net/can/can_host.c @@ -72,7 +72,7 @@ static void can_host_complete(UserCreatable *uc, Error **errp) } static void can_host_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c index c1a1ad0563..8a57ae0717 100644 --- a/net/can/can_socketcan.c +++ b/net/can/can_socketcan.c @@ -308,7 +308,7 @@ static void can_host_socketcan_instance_init(Object *obj) } static void can_host_socketcan_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { CanHostClass *chc = CAN_HOST_CLASS(klass); diff --git a/net/colo-compare.c b/net/colo-compare.c index 893beed528..425eb6e971 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1352,7 +1352,7 @@ static void colo_flush_packets(void *opaque, void *user_data) } } -static void colo_compare_class_init(ObjectClass *oc, void *data) +static void colo_compare_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/net/dump.c b/net/dump.c index 140215aa10..581234b775 100644 --- a/net/dump.c +++ b/net/dump.c @@ -234,7 +234,7 @@ static void filter_dump_instance_finalize(Object *obj) g_free(nfds->filename); } -static void filter_dump_class_init(ObjectClass *oc, void *data) +static void filter_dump_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 283dc9cbe6..a36be31dc8 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -172,7 +172,7 @@ static void filter_buffer_set_interval(Object *obj, Visitor *v, s->interval = value; } -static void filter_buffer_class_init(ObjectClass *oc, void *data) +static void filter_buffer_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/net/filter-mirror.c b/net/filter-mirror.c index 34a63b5dbb..27734c91a7 100644 --- a/net/filter-mirror.c +++ b/net/filter-mirror.c @@ -410,7 +410,7 @@ static void filter_redirector_set_vnet_hdr(Object *obj, s->vnet_hdr = value; } -static void filter_mirror_class_init(ObjectClass *oc, void *data) +static void filter_mirror_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); @@ -425,7 +425,7 @@ static void filter_mirror_class_init(ObjectClass *oc, void *data) nfc->receive_iov = filter_mirror_receive_iov; } -static void filter_redirector_class_init(ObjectClass *oc, void *data) +static void filter_redirector_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/net/filter-replay.c b/net/filter-replay.c index 81b71afe35..451663c5a5 100644 --- a/net/filter-replay.c +++ b/net/filter-replay.c @@ -65,7 +65,7 @@ static void filter_replay_instance_finalize(Object *obj) replay_unregister_net(nfrs->rns); } -static void filter_replay_class_init(ObjectClass *oc, void *data) +static void filter_replay_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/net/filter-rewriter.c b/net/filter-rewriter.c index c18c4c2019..cdf85aa5ee 100644 --- a/net/filter-rewriter.c +++ b/net/filter-rewriter.c @@ -411,7 +411,7 @@ static void filter_rewriter_init(Object *obj) s->failover_mode = FAILOVER_MODE_OFF; } -static void colo_rewriter_class_init(ObjectClass *oc, void *data) +static void colo_rewriter_class_init(ObjectClass *oc, const void *data) { NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/net/filter.c b/net/filter.c index 3335908771..03b3c793f7 100644 --- a/net/filter.c +++ b/net/filter.c @@ -333,7 +333,7 @@ static void default_handle_event(NetFilterState *nf, int event, Error **errp) } } -static void netfilter_class_init(ObjectClass *oc, void *data) +static void netfilter_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); NetFilterClass *nfc = NETFILTER_CLASS(oc); diff --git a/qom/object.c b/qom/object.c index dfd59502d1..06d7367032 100644 --- a/qom/object.c +++ b/qom/object.c @@ -54,7 +54,7 @@ struct TypeImpl size_t instance_size; size_t instance_align; - void (*class_init)(ObjectClass *klass, void *data); + void (*class_init)(ObjectClass *klass, const void *data); void (*class_base_init)(ObjectClass *klass, const void *data); void *class_data; @@ -2891,7 +2891,7 @@ void object_class_property_set_description(ObjectClass *klass, op->description = g_strdup(description); } -static void object_class_init(ObjectClass *klass, void *data) +static void object_class_init(ObjectClass *klass, const void *data) { object_class_property_add_str(klass, "type", object_get_type, NULL); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 03fe6247ff..f385cb7275 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -227,7 +227,7 @@ unsafe extern "C" fn rust_instance_post_init(obj: *mut bindings:: unsafe extern "C" fn rust_class_init( klass: *mut ObjectClass, - _data: *mut c_void, + _data: *const c_void, ) { let mut klass = NonNull::new(klass) .unwrap() diff --git a/scripts/codeconverter/codeconverter/qom_type_info.py b/scripts/codeconverter/codeconverter/qom_type_info.py index f92c3a4730..22a2556076 100644 --- a/scripts/codeconverter/codeconverter/qom_type_info.py +++ b/scripts/codeconverter/codeconverter/qom_type_info.py @@ -798,7 +798,8 @@ class RedundantTypeSizes(TypeInfoVar): # # # if 'class_init' not in fields: -# yield self.prepend(('static void %s_class_init(ObjectClass *oc, void *data)\n' +# yield self.prepend(('static void %s_class_init(ObjectClass *oc,\n' +# 'const void *data)\n' # '{\n' # '}\n\n') % (ids.lowercase)) # yield self.append_field('class_init', ids.lowercase+'_class_init') diff --git a/scsi/pr-manager-helper.c b/scsi/pr-manager-helper.c index 3be52a98d5..6b86f01b01 100644 --- a/scsi/pr-manager-helper.c +++ b/scsi/pr-manager-helper.c @@ -300,7 +300,7 @@ static void pr_manager_helper_instance_init(Object *obj) } static void pr_manager_helper_class_init(ObjectClass *klass, - void *class_data G_GNUC_UNUSED) + const void *class_data G_GNUC_UNUSED) { PRManagerClass *prmgr_klass = PR_MANAGER_CLASS(klass); UserCreatableClass *uc_klass = USER_CREATABLE_CLASS(klass); diff --git a/system/qtest.c b/system/qtest.c index 523a047995..b7689088a4 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -994,7 +994,7 @@ static char *qtest_get_chardev(Object *obj, Error **errp) return g_strdup(q->chr_name); } -static void qtest_class_init(ObjectClass *oc, void *data) +static void qtest_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 35fb145d27..27e2008a4e 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -258,7 +258,7 @@ static const TCGCPUOps alpha_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void alpha_cpu_class_init(ObjectClass *oc, void *data) +static void alpha_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 377791c84d..81257f20fd 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2699,7 +2699,7 @@ static const TCGCPUOps arm_tcg_ops = { }; #endif /* CONFIG_TCG */ -static void arm_cpu_class_init(ObjectClass *oc, void *data) +static void arm_cpu_class_init(ObjectClass *oc, const void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(acc); @@ -2740,7 +2740,7 @@ static void arm_cpu_instance_init(Object *obj) arm_cpu_post_init(obj); } -static void cpu_register_class_init(ObjectClass *oc, void *data) +static void cpu_register_class_init(ObjectClass *oc, const void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(acc); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 3705b34285..fdcf8cd1ae 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1123,7 +1123,7 @@ typedef struct ARMCPUInfo { const char *name; const char *deprecation_note; void (*initfn)(Object *obj); - void (*class_init)(ObjectClass *oc, void *data); + void (*class_init)(ObjectClass *oc, const void *data); } ARMCPUInfo; /** diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 8188ede5cc..1184c92b4c 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -818,7 +818,7 @@ static const gchar *aarch64_gdb_arch_name(CPUState *cs) return "aarch64"; } -static void aarch64_cpu_class_init(ObjectClass *oc, void *data) +static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) { CPUClass *cc = CPU_CLASS(oc); @@ -842,7 +842,7 @@ static void aarch64_cpu_instance_init(Object *obj) arm_cpu_post_init(obj); } -static void cpu_register_class_init(ObjectClass *oc, void *data) +static void cpu_register_class_init(ObjectClass *oc, const void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index f71560aa43..7426aac0dc 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -259,7 +259,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void arm_v7m_class_init(ObjectClass *oc, void *data) +static void arm_v7m_class_init(ObjectClass *oc, const void *data) { ARMCPUClass *acc = ARM_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 84f3b839c9..3f261c6fec 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -237,7 +237,7 @@ static const TCGCPUOps avr_tcg_ops = { .do_interrupt = avr_cpu_do_interrupt, }; -static void avr_cpu_class_init(ObjectClass *oc, void *data) +static void avr_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 3c5191282e..a5d31c33bd 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -335,7 +335,7 @@ static const TCGCPUOps hexagon_tcg_ops = { .mmu_index = hexagon_cpu_mmu_index, }; -static void hexagon_cpu_class_init(ObjectClass *c, void *data) +static void hexagon_cpu_class_init(ObjectClass *c, const void *data) { HexagonCPUClass *mcc = HEXAGON_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 10e18c945e..b792cb247a 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -278,7 +278,7 @@ static const TCGCPUOps hppa_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void hppa_cpu_class_init(ObjectClass *oc, void *data) +static void hppa_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/i386/confidential-guest.c b/target/i386/confidential-guest.c index b3727845ad..cfb71bf034 100644 --- a/target/i386/confidential-guest.c +++ b/target/i386/confidential-guest.c @@ -20,7 +20,7 @@ OBJECT_DEFINE_ABSTRACT_TYPE(X86ConfidentialGuest, X86_CONFIDENTIAL_GUEST, CONFIDENTIAL_GUEST_SUPPORT) -static void x86_confidential_guest_class_init(ObjectClass *oc, void *data) +static void x86_confidential_guest_class_init(ObjectClass *oc, const void *data) { } diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 955295fe79..6f21d5ed22 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5703,7 +5703,7 @@ static void max_x86_cpu_realize(DeviceState *dev, Error **errp) x86_cpu_realizefn(dev, errp); } -static void max_x86_cpu_class_init(ObjectClass *oc, void *data) +static void max_x86_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); X86CPUClass *xcc = X86_CPU_CLASS(oc); @@ -6702,7 +6702,7 @@ static const gchar *x86_gdb_arch_name(CPUState *cs) #endif } -static void x86_cpu_cpudef_class_init(ObjectClass *oc, void *data) +static void x86_cpu_cpudef_class_init(ObjectClass *oc, const void *data) { const X86CPUModel *model = data; X86CPUClass *xcc = X86_CPU_CLASS(oc); @@ -8886,7 +8886,7 @@ static const struct SysemuCPUOps i386_sysemu_ops = { }; #endif -static void x86_cpu_common_class_init(ObjectClass *oc, void *data) +static void x86_cpu_common_class_init(ObjectClass *oc, const void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); @@ -8986,7 +8986,7 @@ static const TypeInfo x86_cpu_type_info = { }; /* "base" CPU model, used by query-cpu-model-expansion */ -static void x86_cpu_base_class_init(ObjectClass *oc, void *data) +static void x86_cpu_base_class_init(ObjectClass *oc, const void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index 072731a4dd..a2d3830f5b 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -161,7 +161,7 @@ void host_cpu_max_instance_init(X86CPU *cpu) &error_abort); } -static void host_cpu_class_init(ObjectClass *oc, void *data) +static void host_cpu_class_init(ObjectClass *oc, const void *data) { X86CPUClass *xcc = X86_CPU_CLASS(oc); diff --git a/target/i386/hvf/hvf-cpu.c b/target/i386/hvf/hvf-cpu.c index b5f4c80028..dfdda70126 100644 --- a/target/i386/hvf/hvf-cpu.c +++ b/target/i386/hvf/hvf-cpu.c @@ -74,7 +74,7 @@ static void hvf_cpu_instance_init(CPUState *cs) hvf_cpu_xsave_init(); } -static void hvf_cpu_accel_class_init(ObjectClass *oc, void *data) +static void hvf_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c index 6269fa8045..16bde4de01 100644 --- a/target/i386/kvm/kvm-cpu.c +++ b/target/i386/kvm/kvm-cpu.c @@ -223,7 +223,7 @@ static void kvm_cpu_instance_init(CPUState *cs) kvm_cpu_xsave_init(); } -static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); diff --git a/target/i386/nvmm/nvmm-accel-ops.c b/target/i386/nvmm/nvmm-accel-ops.c index 4e4e63de78..21443078b7 100644 --- a/target/i386/nvmm/nvmm-accel-ops.c +++ b/target/i386/nvmm/nvmm-accel-ops.c @@ -81,7 +81,7 @@ static void nvmm_kick_vcpu_thread(CPUState *cpu) cpus_kick_thread(cpu); } -static void nvmm_accel_ops_class_init(ObjectClass *oc, void *data) +static void nvmm_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/target/i386/nvmm/nvmm-all.c b/target/i386/nvmm/nvmm-all.c index 17394d073d..f1c6120ccf 100644 --- a/target/i386/nvmm/nvmm-all.c +++ b/target/i386/nvmm/nvmm-all.c @@ -1200,7 +1200,7 @@ nvmm_enabled(void) } static void -nvmm_accel_class_init(ObjectClass *oc, void *data) +nvmm_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "NVMM"; diff --git a/target/i386/sev.c b/target/i386/sev.c index 878dd20f2c..7ef4801d5f 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -2046,7 +2046,7 @@ static void sev_common_set_kernel_hashes(Object *obj, bool value, Error **errp) } static void -sev_common_class_init(ObjectClass *oc, void *data) +sev_common_class_init(ObjectClass *oc, const void *data) { ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc); @@ -2141,7 +2141,7 @@ static void sev_guest_set_legacy_vm_type(Object *obj, Visitor *v, } static void -sev_guest_class_init(ObjectClass *oc, void *data) +sev_guest_class_init(ObjectClass *oc, const void *data) { SevCommonStateClass *klass = SEV_COMMON_CLASS(oc); X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc); @@ -2395,7 +2395,7 @@ sev_snp_guest_set_host_data(Object *obj, const char *value, Error **errp) } static void -sev_snp_guest_class_init(ObjectClass *oc, void *data) +sev_snp_guest_class_init(ObjectClass *oc, const void *data) { SevCommonStateClass *klass = SEV_COMMON_CLASS(oc); X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc); diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 621502c984..e53aaa31bf 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -193,7 +193,7 @@ static void x86_tcg_cpu_instance_init(CPUState *cs) x86_tcg_cpu_xsave_init(); } -static void x86_tcg_cpu_accel_class_init(ObjectClass *oc, void *data) +static void x86_tcg_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); diff --git a/target/i386/whpx/whpx-accel-ops.c b/target/i386/whpx/whpx-accel-ops.c index 81fdd06e48..b8bebe403c 100644 --- a/target/i386/whpx/whpx-accel-ops.c +++ b/target/i386/whpx/whpx-accel-ops.c @@ -83,7 +83,7 @@ static bool whpx_vcpu_thread_is_idle(CPUState *cpu) return !whpx_apic_in_platform(); } -static void whpx_accel_ops_class_init(ObjectClass *oc, void *data) +static void whpx_accel_ops_class_init(ObjectClass *oc, const void *data) { AccelOpsClass *ops = ACCEL_OPS_CLASS(oc); diff --git a/target/i386/whpx/whpx-all.c b/target/i386/whpx/whpx-all.c index 2e1c03b20e..cf6d3e4cdd 100644 --- a/target/i386/whpx/whpx-all.c +++ b/target/i386/whpx/whpx-all.c @@ -2698,7 +2698,7 @@ bool whpx_apic_in_platform(void) { return whpx_global.apic_in_platform; } -static void whpx_accel_class_init(ObjectClass *oc, void *data) +static void whpx_accel_class_init(ObjectClass *oc, const void *data) { AccelClass *ac = ACCEL_CLASS(oc); ac->name = "WHPX"; diff --git a/target/i386/whpx/whpx-apic.c b/target/i386/whpx/whpx-apic.c index 630a9616d7..e1ef6d4e6d 100644 --- a/target/i386/whpx/whpx-apic.c +++ b/target/i386/whpx/whpx-apic.c @@ -252,7 +252,7 @@ static void whpx_apic_realize(DeviceState *dev, Error **errp) msi_nonbroken = true; } -static void whpx_apic_class_init(ObjectClass *klass, void *data) +static void whpx_apic_class_init(ObjectClass *klass, const void *data) { APICCommonClass *k = APIC_COMMON_CLASS(klass); diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 0e6c89eb1b..8ad45b453d 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -908,7 +908,7 @@ static const Property loongarch_cpu_properties[] = { DEFINE_PROP_INT32("node-id", LoongArchCPU, node_id, CPU_UNSET_NUMA_NODE_ID), }; -static void loongarch_cpu_class_init(ObjectClass *c, void *data) +static void loongarch_cpu_class_init(ObjectClass *c, const void *data) { LoongArchCPUClass *lacc = LOONGARCH_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); @@ -948,7 +948,7 @@ static const gchar *loongarch32_gdb_arch_name(CPUState *cs) return "loongarch32"; } -static void loongarch32_cpu_class_init(ObjectClass *c, void *data) +static void loongarch32_cpu_class_init(ObjectClass *c, const void *data) { CPUClass *cc = CPU_CLASS(c); @@ -961,7 +961,7 @@ static const gchar *loongarch64_gdb_arch_name(CPUState *cs) return "loongarch64"; } -static void loongarch64_cpu_class_init(ObjectClass *c, void *data) +static void loongarch64_cpu_class_init(ObjectClass *c, const void *data) { CPUClass *cc = CPU_CLASS(c); diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 99adc5eb91..6f33b86c7d 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -607,7 +607,7 @@ static const TCGCPUOps m68k_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void m68k_cpu_class_init(ObjectClass *c, void *data) +static void m68k_cpu_class_init(ObjectClass *c, const void *data) { M68kCPUClass *mcc = M68K_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); @@ -634,7 +634,7 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data) cc->tcg_ops = &m68k_tcg_ops; } -static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data) +static void m68k_cpu_class_init_cf_core(ObjectClass *c, const void *data) { CPUClass *cc = CPU_CLASS(c); @@ -649,7 +649,7 @@ static void m68k_cpu_class_init_cf_core(ObjectClass *c, void *data) .class_init = m68k_cpu_class_init_cf_core \ } -static void m68k_cpu_class_init_m68k_core(ObjectClass *c, void *data) +static void m68k_cpu_class_init_m68k_core(ObjectClass *c, const void *data) { CPUClass *cc = CPU_CLASS(c); diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index edfb05758b..00a2730de4 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -447,7 +447,7 @@ static const TCGCPUOps mb_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void mb_cpu_class_init(ObjectClass *oc, void *data) +static void mb_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 473cecdebc..29611a0a1c 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -572,7 +572,7 @@ static const TCGCPUOps mips_tcg_ops = { }; #endif /* CONFIG_TCG */ -static void mips_cpu_class_init(ObjectClass *c, void *data) +static void mips_cpu_class_init(ObjectClass *c, const void *data) { MIPSCPUClass *mcc = MIPS_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); @@ -613,7 +613,7 @@ static const TypeInfo mips_cpu_type_info = { .class_init = mips_cpu_class_init, }; -static void mips_cpu_cpudef_class_init(ObjectClass *oc, void *data) +static void mips_cpu_cpudef_class_init(ObjectClass *oc, const void *data) { MIPSCPUClass *mcc = MIPS_CPU_CLASS(oc); mcc->cpu_def = data; diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 6601e0c066..2ec267efec 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -260,7 +260,7 @@ static const TCGCPUOps openrisc_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void openrisc_cpu_class_init(ObjectClass *oc, void *data) +static void openrisc_cpu_class_init(ObjectClass *oc, const void *data) { OpenRISCCPUClass *occ = OPENRISC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(occ); diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index ece3481781..ea86ea202a 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -35,7 +35,7 @@ #define POWERPC_DEF_SVR(_name, _desc, _pvr, _svr, _type) \ static void \ glue(POWERPC_DEF_PREFIX(_pvr, _svr, _type), _cpu_class_init) \ - (ObjectClass *oc, void *data) \ + (ObjectClass *oc, const void *data) \ { \ DeviceClass *dc = DEVICE_CLASS(oc); \ PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); \ diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index f4cc823c5c..13115a89ff 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -3047,7 +3047,8 @@ static inline int check_attn_none(CPUPPCState *env) #define POWERPC_FAMILY(_name) \ static void \ - glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, void *); \ + glue(glue(ppc_, _name), _cpu_family_class_init)(ObjectClass *, \ + const void *); \ \ static const TypeInfo \ glue(glue(ppc_, _name), _cpu_family_type_info) = { \ diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 077991ed53..90b21b9c93 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -2167,7 +2167,7 @@ static void init_proc_405(CPUPPCState *env) SET_WDT_PERIOD(16, 20, 24, 28); } -POWERPC_FAMILY(405)(ObjectClass *oc, void *data) +POWERPC_FAMILY(405)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2235,7 +2235,7 @@ static void init_proc_440EP(CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } -POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) +POWERPC_FAMILY(440EP)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2274,7 +2274,7 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data) +POWERPC_FAMILY(460EX)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2329,7 +2329,7 @@ static void init_proc_440GP(CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } -POWERPC_FAMILY(440GP)(ObjectClass *oc, void *data) +POWERPC_FAMILY(440GP)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2399,7 +2399,7 @@ static void init_proc_440x5(CPUPPCState *env) SET_WDT_PERIOD(20, 24, 28, 32); } -POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) +POWERPC_FAMILY(440x5)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2435,7 +2435,7 @@ POWERPC_FAMILY(440x5)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } -POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, void *data) +POWERPC_FAMILY(440x5wDFPU)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2484,7 +2484,7 @@ static void init_proc_MPC5xx(CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } -POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, void *data) +POWERPC_FAMILY(MPC5xx)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2527,7 +2527,7 @@ static void init_proc_MPC8xx(CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } -POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, void *data) +POWERPC_FAMILY(MPC8xx)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2578,7 +2578,7 @@ static void init_proc_G2(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) +POWERPC_FAMILY(G2)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2617,7 +2617,7 @@ POWERPC_FAMILY(G2)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -POWERPC_FAMILY(G2LE)(ObjectClass *oc, void *data) +POWERPC_FAMILY(G2LE)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -2752,7 +2752,7 @@ static void init_proc_e200(CPUPPCState *env) /* XXX: TODO: allocate internal IRQ controller */ } -POWERPC_FAMILY(e200)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e200)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3045,7 +3045,7 @@ static void init_proc_e500v1(CPUPPCState *env) init_proc_e500(env, fsl_e500v1); } -POWERPC_FAMILY(e500v1)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e500v1)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3089,7 +3089,7 @@ static void init_proc_e500v2(CPUPPCState *env) init_proc_e500(env, fsl_e500v2); } -POWERPC_FAMILY(e500v2)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e500v2)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3133,7 +3133,7 @@ static void init_proc_e500mc(CPUPPCState *env) init_proc_e500(env, fsl_e500mc); } -POWERPC_FAMILY(e500mc)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e500mc)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3180,7 +3180,7 @@ static void init_proc_e5500(CPUPPCState *env) init_proc_e500(env, fsl_e5500); } -POWERPC_FAMILY(e5500)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e5500)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3229,7 +3229,7 @@ static void init_proc_e6500(CPUPPCState *env) init_proc_e500(env, fsl_e6500); } -POWERPC_FAMILY(e6500)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e6500)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3292,7 +3292,7 @@ static void init_proc_603(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(603)(ObjectClass *oc, void *data) +POWERPC_FAMILY(603)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3332,7 +3332,7 @@ POWERPC_FAMILY(603)(ObjectClass *oc, void *data) POWERPC_FLAG_BE | POWERPC_FLAG_BUS_CLK; } -POWERPC_FAMILY(603E)(ObjectClass *oc, void *data) +POWERPC_FAMILY(603E)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3378,7 +3378,7 @@ static void init_proc_e300(CPUPPCState *env) register_e300_sprs(env); } -POWERPC_FAMILY(e300)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e300)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3434,7 +3434,7 @@ static void init_proc_604(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(604)(ObjectClass *oc, void *data) +POWERPC_FAMILY(604)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3480,7 +3480,7 @@ static void init_proc_604E(CPUPPCState *env) register_604e_sprs(env); } -POWERPC_FAMILY(604E)(ObjectClass *oc, void *data) +POWERPC_FAMILY(604E)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3537,7 +3537,7 @@ static void init_proc_740(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(740)(ObjectClass *oc, void *data) +POWERPC_FAMILY(740)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3603,7 +3603,7 @@ static void init_proc_750(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(750)(ObjectClass *oc, void *data) +POWERPC_FAMILY(750)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3750,7 +3750,7 @@ static void init_proc_750cl(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(750cl)(ObjectClass *oc, void *data) +POWERPC_FAMILY(750cl)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3858,7 +3858,7 @@ static void init_proc_750cx(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(750cx)(ObjectClass *oc, void *data) +POWERPC_FAMILY(750cx)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -3931,7 +3931,7 @@ static void init_proc_750fx(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(750fx)(ObjectClass *oc, void *data) +POWERPC_FAMILY(750fx)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4004,7 +4004,7 @@ static void init_proc_750gx(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(750gx)(ObjectClass *oc, void *data) +POWERPC_FAMILY(750gx)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4064,7 +4064,7 @@ static void init_proc_745(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(745)(ObjectClass *oc, void *data) +POWERPC_FAMILY(745)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4110,7 +4110,7 @@ static void init_proc_755(CPUPPCState *env) register_755_sprs(env); } -POWERPC_FAMILY(755)(ObjectClass *oc, void *data) +POWERPC_FAMILY(755)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4177,7 +4177,7 @@ static void init_proc_7400(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7400)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7400)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4257,7 +4257,7 @@ static void init_proc_7410(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7410)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7410)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4358,7 +4358,7 @@ static void init_proc_7440(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7440)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7440)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4481,7 +4481,7 @@ static void init_proc_7450(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7450)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7450)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4611,7 +4611,7 @@ static void init_proc_7445(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7445)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7445)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4743,7 +4743,7 @@ static void init_proc_7455(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7455)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7455)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -4895,7 +4895,7 @@ static void init_proc_7457(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) +POWERPC_FAMILY(7457)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -5030,7 +5030,7 @@ static void init_proc_e600(CPUPPCState *env) ppc6xx_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(e600)(ObjectClass *oc, void *data) +POWERPC_FAMILY(e600)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -5995,7 +5995,7 @@ static void init_proc_970(CPUPPCState *env) ppc970_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(970)(ObjectClass *oc, void *data) +POWERPC_FAMILY(970)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6070,7 +6070,7 @@ static void init_proc_power5plus(CPUPPCState *env) ppc970_irq_init(env_archcpu(env)); } -POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER5P)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6176,7 +6176,7 @@ static bool ppc_pvr_match_power7(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER7)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6340,7 +6340,7 @@ static bool ppc_pvr_match_power8(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return true; } -POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER8)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6549,7 +6549,7 @@ static bool ppc_pvr_match_power9(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER9)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6647,7 +6647,7 @@ static bool ppc_pvr_match_power10(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER10)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -6707,7 +6707,7 @@ static bool ppc_pvr_match_power11(PowerPCCPUClass *pcc, uint32_t pvr, bool best) return false; } -POWERPC_FAMILY(POWER11)(ObjectClass *oc, void *data) +POWERPC_FAMILY(POWER11)(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); @@ -7504,7 +7504,7 @@ static const TCGCPUOps ppc_tcg_ops = { }; #endif /* CONFIG_TCG */ -static void ppc_cpu_class_init(ObjectClass *oc, void *data) +static void ppc_cpu_class_init(ObjectClass *oc, const void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 3fe54798c6..8a957c3c7d 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -2383,7 +2383,7 @@ static bool kvmppc_cpu_realize(CPUState *cs, Error **errp) return true; } -static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) +static void kvmppc_host_cpu_class_init(ObjectClass *oc, const void *data) { PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size"); @@ -3004,7 +3004,7 @@ void kvm_arch_accel_class_init(ObjectClass *oc) { } -static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2b830b3317..e0604f4c78 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -3028,7 +3028,7 @@ static const struct SysemuCPUOps riscv_sysemu_ops = { }; #endif -static void riscv_cpu_common_class_init(ObjectClass *c, void *data) +static void riscv_cpu_common_class_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); @@ -3061,7 +3061,7 @@ static void riscv_cpu_common_class_init(ObjectClass *c, void *data) device_class_set_props(dc, riscv_cpu_properties); } -static void riscv_cpu_class_init(ObjectClass *c, void *data) +static void riscv_cpu_class_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 5315134e08..75724b6af4 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1976,7 +1976,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) kvm_riscv_destroy_scratch_vcpu(&kvmcpu); } -static void kvm_cpu_accel_class_init(ObjectClass *oc, void *data) +static void kvm_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); @@ -1997,7 +1997,7 @@ static void kvm_cpu_accel_register_types(void) } type_init(kvm_cpu_accel_register_types); -static void riscv_host_cpu_class_init(ObjectClass *c, void *data) +static void riscv_host_cpu_class_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 426145c3b9..54ac54f2e1 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1528,7 +1528,7 @@ static void riscv_tcg_cpu_instance_init(CPUState *cs) } } -static void riscv_tcg_cpu_accel_class_init(ObjectClass *oc, void *data) +static void riscv_tcg_cpu_accel_class_init(ObjectClass *oc, const void *data) { AccelCPUClass *acc = ACCEL_CPU_CLASS(oc); diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 0a7a2b55b5..a51b543028 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -220,7 +220,7 @@ static const TCGCPUOps rx_tcg_ops = { .do_interrupt = rx_cpu_do_interrupt, }; -static void rx_cpu_class_init(ObjectClass *klass, void *data) +static void rx_cpu_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *cc = CPU_CLASS(klass); diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 43fc3194bc..3d644f5e23 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -371,7 +371,7 @@ static const TCGCPUOps s390_tcg_ops = { }; #endif /* CONFIG_TCG */ -static void s390_cpu_class_init(ObjectClass *oc, void *data) +static void s390_cpu_class_init(ObjectClass *oc, const void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(scc); diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index 8e0b01dc65..b097ed55d9 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -919,7 +919,7 @@ void s390_cpu_model_class_register_props(ObjectClass *oc) } #ifdef CONFIG_KVM -static void s390_host_cpu_model_class_init(ObjectClass *oc, void *data) +static void s390_host_cpu_model_class_init(ObjectClass *oc, const void *data) { S390CPUClass *xcc = S390_CPU_CLASS(oc); @@ -928,7 +928,7 @@ static void s390_host_cpu_model_class_init(ObjectClass *oc, void *data) } #endif -static void s390_base_cpu_model_class_init(ObjectClass *oc, void *data) +static void s390_base_cpu_model_class_init(ObjectClass *oc, const void *data) { S390CPUClass *xcc = S390_CPU_CLASS(oc); @@ -939,7 +939,7 @@ static void s390_base_cpu_model_class_init(ObjectClass *oc, void *data) xcc->desc = xcc->cpu_def->desc; } -static void s390_cpu_model_class_init(ObjectClass *oc, void *data) +static void s390_cpu_model_class_init(ObjectClass *oc, const void *data) { S390CPUClass *xcc = S390_CPU_CLASS(oc); @@ -949,7 +949,7 @@ static void s390_cpu_model_class_init(ObjectClass *oc, void *data) xcc->desc = xcc->cpu_def->desc; } -static void s390_qemu_cpu_model_class_init(ObjectClass *oc, void *data) +static void s390_qemu_cpu_model_class_init(ObjectClass *oc, const void *data) { S390CPUClass *xcc = S390_CPU_CLASS(oc); @@ -958,7 +958,7 @@ static void s390_qemu_cpu_model_class_init(ObjectClass *oc, void *data) qemu_hw_version()); } -static void s390_max_cpu_model_class_init(ObjectClass *oc, void *data) +static void s390_max_cpu_model_class_init(ObjectClass *oc, const void *data) { S390CPUClass *xcc = S390_CPU_CLASS(oc); diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c index b191a4a68a..fe0a72c416 100644 --- a/target/s390x/kvm/pv.c +++ b/target/s390x/kvm/pv.c @@ -367,7 +367,7 @@ OBJECT_DEFINE_TYPE_WITH_INTERFACES(S390PVGuest, { TYPE_USER_CREATABLE }, { NULL }) -static void s390_pv_guest_class_init(ObjectClass *oc, void *data) +static void s390_pv_guest_class_init(ObjectClass *oc, const void *data) { ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc); diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 861fdd47f7..57d7b5fbc8 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -177,7 +177,7 @@ static void sh7750r_cpu_initfn(Object *obj) env->features = SH_FEATURE_BCR3_AND_BCR4; } -static void sh7750r_class_init(ObjectClass *oc, void *data) +static void sh7750r_class_init(ObjectClass *oc, const void *data) { SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); @@ -194,7 +194,7 @@ static void sh7751r_cpu_initfn(Object *obj) env->features = SH_FEATURE_BCR3_AND_BCR4; } -static void sh7751r_class_init(ObjectClass *oc, void *data) +static void sh7751r_class_init(ObjectClass *oc, const void *data) { SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); @@ -211,7 +211,7 @@ static void sh7785_cpu_initfn(Object *obj) env->features = SH_FEATURE_SH4A; } -static void sh7785_class_init(ObjectClass *oc, void *data) +static void sh7785_class_init(ObjectClass *oc, const void *data) { SuperHCPUClass *scc = SUPERH_CPU_CLASS(oc); @@ -282,7 +282,7 @@ static const TCGCPUOps superh_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void superh_cpu_class_init(ObjectClass *oc, void *data) +static void superh_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 174b76f762..981aa86e0e 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1042,7 +1042,7 @@ static const TCGCPUOps sparc_tcg_ops = { }; #endif /* CONFIG_TCG */ -static void sparc_cpu_class_init(ObjectClass *oc, void *data) +static void sparc_cpu_class_init(ObjectClass *oc, const void *data) { SPARCCPUClass *scc = SPARC_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); @@ -1091,7 +1091,7 @@ static const TypeInfo sparc_cpu_type_info = { .class_init = sparc_cpu_class_init, }; -static void sparc_cpu_cpudef_class_init(ObjectClass *oc, void *data) +static void sparc_cpu_cpudef_class_init(ObjectClass *oc, const void *data) { SPARCCPUClass *scc = SPARC_CPU_CLASS(oc); scc->cpu_def = data; diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index a4f93e7d91..098cd06c54 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -185,7 +185,7 @@ static const TCGCPUOps tricore_tcg_ops = { .cpu_exec_halt = tricore_cpu_has_work, }; -static void tricore_cpu_class_init(ObjectClass *c, void *data) +static void tricore_cpu_class_init(ObjectClass *c, const void *data) { TriCoreCPUClass *mcc = TRICORE_CPU_CLASS(c); CPUClass *cc = CPU_CLASS(c); diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 971e67ad97..27d6e40195 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -253,7 +253,7 @@ static const TCGCPUOps xtensa_tcg_ops = { #endif /* !CONFIG_USER_ONLY */ }; -static void xtensa_cpu_class_init(ObjectClass *oc, void *data) +static void xtensa_cpu_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); CPUClass *cc = CPU_CLASS(oc); diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index d02d16f9ec..0459787981 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -170,7 +170,7 @@ static void xtensa_finalize_config(XtensaConfig *config) } } -static void xtensa_core_class_init(ObjectClass *oc, void *data) +static void xtensa_core_class_init(ObjectClass *oc, const void *data) { CPUClass *cc = CPU_CLASS(oc); XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); diff --git a/tests/unit/check-qom-interface.c b/tests/unit/check-qom-interface.c index c99be97ed8..4e1c4d6729 100644 --- a/tests/unit/check-qom-interface.c +++ b/tests/unit/check-qom-interface.c @@ -38,7 +38,7 @@ static const TypeInfo test_if_info = { #define PATTERN 0xFAFBFCFD -static void test_class_init(ObjectClass *oc, void *data) +static void test_class_init(ObjectClass *oc, const void *data) { TestIfClass *tc = TEST_IF_CLASS(oc); diff --git a/tests/unit/check-qom-proplist.c b/tests/unit/check-qom-proplist.c index 13d632cfed..f1de1618f6 100644 --- a/tests/unit/check-qom-proplist.c +++ b/tests/unit/check-qom-proplist.c @@ -135,7 +135,7 @@ static void dummy_init(Object *obj) } -static void dummy_class_init(ObjectClass *cls, void *data) +static void dummy_class_init(ObjectClass *cls, const void *data) { object_class_property_add_str(cls, "sv", dummy_get_sv, @@ -264,7 +264,7 @@ static void dummy_dev_unparent(Object *obj) object_unparent(OBJECT(dev->bus)); } -static void dummy_dev_class_init(ObjectClass *klass, void *opaque) +static void dummy_dev_class_init(ObjectClass *klass, const void *opaque) { klass->unparent = dummy_dev_unparent; } @@ -288,7 +288,7 @@ static void dummy_bus_unparent(Object *obj) object_unparent(OBJECT(bus->backend)); } -static void dummy_bus_class_init(ObjectClass *klass, void *opaque) +static void dummy_bus_class_init(ObjectClass *klass, const void *opaque) { klass->unparent = dummy_bus_unparent; } diff --git a/tests/unit/test-qdev-global-props.c b/tests/unit/test-qdev-global-props.c index 6f6a306788..33062762a6 100644 --- a/tests/unit/test-qdev-global-props.c +++ b/tests/unit/test-qdev-global-props.c @@ -51,7 +51,7 @@ static const Property static_props[] = { DEFINE_PROP_UINT32("prop2", MyType, prop2, PROP_DEFAULT), }; -static void static_prop_class_init(ObjectClass *oc, void *data) +static void static_prop_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -177,7 +177,7 @@ static void dynamic_instance_init(Object *obj) NULL, NULL); } -static void dynamic_class_init(ObjectClass *oc, void *data) +static void dynamic_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -193,7 +193,7 @@ static const TypeInfo dynamic_prop_type = { .class_init = dynamic_class_init, }; -static void hotplug_class_init(ObjectClass *oc, void *data) +static void hotplug_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); @@ -209,7 +209,7 @@ static const TypeInfo hotplug_type = { .class_init = hotplug_class_init, }; -static void nohotplug_class_init(ObjectClass *oc, void *data) +static void nohotplug_class_init(ObjectClass *oc, const void *data) { DeviceClass *dc = DEVICE_CLASS(oc); diff --git a/tests/unit/test-smp-parse.c b/tests/unit/test-smp-parse.c index f9bccb56ab..326045ecbb 100644 --- a/tests/unit/test-smp-parse.c +++ b/tests/unit/test-smp-parse.c @@ -924,7 +924,7 @@ static void unsupported_params_init(const MachineClass *mc, SMPTestData *data) } } -static void machine_base_class_init(ObjectClass *oc, void *data) +static void machine_base_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -934,7 +934,8 @@ static void machine_base_class_init(ObjectClass *oc, void *data) mc->name = g_strdup(SMP_MACHINE_NAME); } -static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) +static void machine_generic_invalid_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -943,21 +944,22 @@ static void machine_generic_invalid_class_init(ObjectClass *oc, void *data) mc->max_cpus = MAX_CPUS - 1; } -static void machine_with_modules_class_init(ObjectClass *oc, void *data) +static void machine_with_modules_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->smp_props.modules_supported = true; } -static void machine_with_dies_class_init(ObjectClass *oc, void *data) +static void machine_with_dies_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->smp_props.dies_supported = true; } -static void machine_with_modules_dies_class_init(ObjectClass *oc, void *data) +static void machine_with_modules_dies_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -965,28 +967,29 @@ static void machine_with_modules_dies_class_init(ObjectClass *oc, void *data) mc->smp_props.dies_supported = true; } -static void machine_with_clusters_class_init(ObjectClass *oc, void *data) +static void machine_with_clusters_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->smp_props.clusters_supported = true; } -static void machine_with_books_class_init(ObjectClass *oc, void *data) +static void machine_with_books_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->smp_props.books_supported = true; } -static void machine_with_drawers_class_init(ObjectClass *oc, void *data) +static void machine_with_drawers_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); mc->smp_props.drawers_supported = true; } -static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data) +static void machine_with_drawers_books_class_init(ObjectClass *oc, + const void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -994,7 +997,7 @@ static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data) mc->smp_props.books_supported = true; } -static void machine_full_topo_class_init(ObjectClass *oc, void *data) +static void machine_full_topo_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); diff --git a/ui/console-vc.c b/ui/console-vc.c index df1341513d..830842064d 100644 --- a/ui/console-vc.c +++ b/ui/console-vc.c @@ -1036,7 +1036,7 @@ qemu_text_console_finalize(Object *obj) } static void -qemu_text_console_class_init(ObjectClass *oc, void *data) +qemu_text_console_class_init(ObjectClass *oc, const void *data) { if (!cursor_timer) { cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME, cursor_timer_cb, NULL); @@ -1065,7 +1065,7 @@ qemu_fixed_text_console_finalize(Object *obj) } static void -qemu_fixed_text_console_class_init(ObjectClass *oc, void *data) +qemu_fixed_text_console_class_init(ObjectClass *oc, const void *data) { } @@ -1181,7 +1181,7 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp) } } -static void char_vc_class_init(ObjectClass *oc, void *data) +static void char_vc_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/ui/console.c b/ui/console.c index 6cd122cf40..2d00828c53 100644 --- a/ui/console.c +++ b/ui/console.c @@ -401,7 +401,7 @@ qemu_console_finalize(Object *obj) } static void -qemu_console_class_init(ObjectClass *oc, void *data) +qemu_console_class_init(ObjectClass *oc, const void *data) { } @@ -437,7 +437,7 @@ qemu_graphic_console_prop_get_head(Object *obj, Visitor *v, const char *name, } static void -qemu_graphic_console_class_init(ObjectClass *oc, void *data) +qemu_graphic_console_class_init(ObjectClass *oc, const void *data) { object_class_property_add_link(oc, "device", TYPE_DEVICE, offsetof(QemuGraphicConsole, device), diff --git a/ui/dbus-chardev.c b/ui/dbus-chardev.c index bf061cbc93..d05dddaf81 100644 --- a/ui/dbus-chardev.c +++ b/ui/dbus-chardev.c @@ -269,7 +269,7 @@ dbus_chr_parse(QemuOpts *opts, ChardevBackend *backend, } static void -char_dbus_class_init(ObjectClass *oc, void *data) +char_dbus_class_init(ObjectClass *oc, const void *data) { DBusChardevClass *klass = DBUS_CHARDEV_CLASS(oc); ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/ui/dbus.c b/ui/dbus.c index 2eb03aa247..0c0f86eaa6 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -404,7 +404,7 @@ set_gl_mode(Object *o, int val, Error **errp) } static void -dbus_display_class_init(ObjectClass *oc, void *data) +dbus_display_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); @@ -453,7 +453,7 @@ dbus_vc_parse(QemuOpts *opts, ChardevBackend *backend, } static void -dbus_vc_class_init(ObjectClass *oc, void *data) +dbus_vc_class_init(ObjectClass *oc, const void *data) { DBusVCClass *klass = DBUS_VC_CLASS(oc); ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/ui/gtk.c b/ui/gtk.c index 59bda83da6..982037b2c0 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -1879,7 +1879,7 @@ static void gd_vc_open(Chardev *chr, *be_opened = false; } -static void char_gd_vc_class_init(ObjectClass *oc, void *data) +static void char_gd_vc_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/ui/input-barrier.c b/ui/input-barrier.c index c86e5d67eb..9dce31ea9a 100644 --- a/ui/input-barrier.c +++ b/ui/input-barrier.c @@ -696,7 +696,7 @@ static void input_barrier_instance_init(Object *obj) ib->height = 1080; } -static void input_barrier_class_init(ObjectClass *oc, void *data) +static void input_barrier_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/ui/input-linux.c b/ui/input-linux.c index 203e264212..2f5adb82d2 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -494,7 +494,7 @@ static void input_linux_instance_init(Object *obj) { } -static void input_linux_class_init(ObjectClass *oc, void *data) +static void input_linux_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); diff --git a/ui/spice-app.c b/ui/spice-app.c index 91e258a621..24f78f305c 100644 --- a/ui/spice-app.c +++ b/ui/spice-app.c @@ -101,7 +101,7 @@ static void vc_chr_parse(QemuOpts *opts, ChardevBackend *backend, Error **errp) /* fqdn is dealt with in vc_chr_open() */ } -static void char_vc_class_init(ObjectClass *oc, void *data) +static void char_vc_class_init(ObjectClass *oc, const void *data) { VCChardevClass *vc = CHARDEV_VC_CLASS(oc); ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/ui/vdagent.c b/ui/vdagent.c index 724eff972f..04513ded29 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -905,7 +905,7 @@ static void vdagent_chr_parse(QemuOpts *opts, ChardevBackend *backend, /* ------------------------------------------------------------------ */ -static void vdagent_chr_class_init(ObjectClass *oc, void *data) +static void vdagent_chr_class_init(ObjectClass *oc, const void *data) { ChardevClass *cc = CHARDEV_CLASS(oc); diff --git a/util/main-loop.c b/util/main-loop.c index 4683db1888..51aeb2432e 100644 --- a/util/main-loop.c +++ b/util/main-loop.c @@ -220,7 +220,7 @@ static bool main_loop_can_be_deleted(EventLoopBase *base) return false; } -static void main_loop_class_init(ObjectClass *oc, void *class_data) +static void main_loop_class_init(ObjectClass *oc, const void *class_data) { EventLoopBaseClass *bc = EVENT_LOOP_BASE_CLASS(oc); diff --git a/util/thread-context.c b/util/thread-context.c index 2bc7883b9e..95228a3d4f 100644 --- a/util/thread-context.c +++ b/util/thread-context.c @@ -273,7 +273,7 @@ static void thread_context_instance_complete(UserCreatable *uc, Error **errp) } } -static void thread_context_class_init(ObjectClass *oc, void *data) +static void thread_context_class_init(ObjectClass *oc, const void *data) { UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); From b282b859cf3442d922644e2cd2bee68272baafd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 10 Feb 2025 09:56:56 +0100 Subject: [PATCH 0309/2760] qom: Constify TypeInfo::class_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All callers now correctly expect a const class data. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250424194905.82506-5-philmd@linaro.org> --- hw/arm/armsse.c | 2 +- hw/block/m25p80.c | 2 +- hw/isa/vt82c686.c | 4 ++-- hw/net/e1000.c | 2 +- hw/ppc/spapr_cpu_core.c | 2 +- hw/scsi/megasas.c | 2 +- hw/sensor/tmp421.c | 2 +- hw/virtio/virtio-pci.c | 4 ++-- include/qom/object.h | 2 +- qom/object.c | 2 +- rust/qemu-api/src/qom.rs | 2 +- scripts/codeconverter/codeconverter/test_regexps.py | 2 +- target/arm/cpu.c | 2 +- target/arm/cpu64.c | 2 +- target/mips/cpu.c | 2 +- target/s390x/cpu_models.c | 4 ++-- target/sparc/cpu.c | 2 +- target/xtensa/helper.c | 2 +- 18 files changed, 21 insertions(+), 21 deletions(-) diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index d65a46b8d8..9403b65ddb 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -1730,7 +1730,7 @@ static void armsse_register_types(void) .name = armsse_variants[i].name, .parent = TYPE_ARM_SSE, .class_init = armsse_class_init, - .class_data = (void *)&armsse_variants[i], + .class_data = &armsse_variants[i], }; type_register_static(&ti); } diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 75b9d71251..a5336d92ff 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -1893,7 +1893,7 @@ static void m25p80_register_types(void) .name = known_devices[i].part_name, .parent = TYPE_M25P80, .class_init = m25p80_class_init, - .class_data = (void *)&known_devices[i], + .class_data = &known_devices[i], }; type_register_static(&ti); } diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index 80366aaf64..c62afc907b 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -259,7 +259,7 @@ static const TypeInfo vt82c686b_pm_info = { .name = TYPE_VT82C686B_PM, .parent = TYPE_VIA_PM, .class_init = via_pm_class_init, - .class_data = (void *)&vt82c686b_pm_init_info, + .class_data = &vt82c686b_pm_init_info, }; static const ViaPMInitInfo vt8231_pm_init_info = { @@ -272,7 +272,7 @@ static const TypeInfo vt8231_pm_info = { .name = TYPE_VT8231_PM, .parent = TYPE_VIA_PM, .class_init = via_pm_class_init, - .class_data = (void *)&vt8231_pm_init_info, + .class_data = &vt8231_pm_init_info, }; diff --git a/hw/net/e1000.c b/hw/net/e1000.c index d49730f4ad..13814e84d1 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1770,7 +1770,7 @@ static void e1000_register_types(void) type_info.name = info->name; type_info.parent = TYPE_E1000_BASE; - type_info.class_data = (void *)info; + type_info.class_data = info; type_info.class_init = e1000_class_init; type_register_static(&type_info); diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index b4b926d759..4952f9bd2c 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -388,7 +388,7 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, const void *data) #define DEFINE_SPAPR_CPU_CORE_TYPE(cpu_model) \ { \ .parent = TYPE_SPAPR_CPU_CORE, \ - .class_data = (void *) POWERPC_CPU_TYPE_NAME(cpu_model), \ + .class_data = POWERPC_CPU_TYPE_NAME(cpu_model), \ .class_init = spapr_cpu_core_class_init, \ .name = SPAPR_CPU_CORE_TYPE_NAME(cpu_model), \ } diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index ffcabd5a8e..b024905a01 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2572,7 +2572,7 @@ static void megasas_register_types(void) type_info.name = info->name; type_info.parent = TYPE_MEGASAS_BASE; - type_info.class_data = (void *)info; + type_info.class_data = info; type_info.class_init = megasas_class_init; type_info.interfaces = info->interfaces; diff --git a/hw/sensor/tmp421.c b/hw/sensor/tmp421.c index 263bfa1bbd..3421c44086 100644 --- a/hw/sensor/tmp421.c +++ b/hw/sensor/tmp421.c @@ -382,7 +382,7 @@ static void tmp421_register_types(void) .name = devices[i].name, .parent = TYPE_TMP421, .class_init = tmp421_class_init, - .class_data = (void *) &devices[i], + .class_data = &devices[i], }; type_register_static(&ti); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index c0fd3db063..95bf7ddd97 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2497,13 +2497,13 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) generic_type_info.parent = base_name; generic_type_info.class_init = virtio_pci_base_class_init; - generic_type_info.class_data = (void *)t; + generic_type_info.class_data = t; assert(!t->non_transitional_name); assert(!t->transitional_name); } else { base_type_info.class_init = virtio_pci_base_class_init; - base_type_info.class_data = (void *)t; + base_type_info.class_data = t; } type_register_static(&base_type_info); diff --git a/include/qom/object.h b/include/qom/object.h index 2fb86f00a6..42b75d10a4 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -488,7 +488,7 @@ struct TypeInfo void (*class_init)(ObjectClass *klass, const void *data); void (*class_base_init)(ObjectClass *klass, const void *data); - void *class_data; + const void *class_data; InterfaceInfo *interfaces; }; diff --git a/qom/object.c b/qom/object.c index 06d7367032..425ee2f0ee 100644 --- a/qom/object.c +++ b/qom/object.c @@ -57,7 +57,7 @@ struct TypeImpl void (*class_init)(ObjectClass *klass, const void *data); void (*class_base_init)(ObjectClass *klass, const void *data); - void *class_data; + const void *class_data; void (*instance_init)(Object *obj); void (*instance_post_init)(Object *obj); diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index f385cb7275..f0a79f96d5 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -513,7 +513,7 @@ pub trait ObjectImpl: ObjectType + IsA { class_size: core::mem::size_of::(), class_init: Some(rust_class_init::), class_base_init: Self::CLASS_BASE_INIT, - class_data: core::ptr::null_mut(), + class_data: core::ptr::null(), interfaces: core::ptr::null_mut(), }; diff --git a/scripts/codeconverter/codeconverter/test_regexps.py b/scripts/codeconverter/codeconverter/test_regexps.py index 7211392796..08857c5008 100644 --- a/scripts/codeconverter/codeconverter/test_regexps.py +++ b/scripts/codeconverter/codeconverter/test_regexps.py @@ -70,7 +70,7 @@ static const TypeInfo char_file_type_info = { .name = armsse_variants[i].name, .parent = TYPE_ARMSSE, .class_init = armsse_class_init, - .class_data = (void *)&armsse_variants[i], + .class_data = &armsse_variants[i], };''', re.MULTILINE) print(RE_ARRAY_ITEM) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 81257f20fd..00577f97eb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2758,7 +2758,7 @@ void arm_cpu_register(const ARMCPUInfo *info) .parent = TYPE_ARM_CPU, .instance_init = arm_cpu_instance_init, .class_init = info->class_init ?: cpu_register_class_init, - .class_data = (void *)info, + .class_data = info, }; type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 1184c92b4c..eaf5705cdc 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -855,7 +855,7 @@ void aarch64_cpu_register(const ARMCPUInfo *info) .parent = TYPE_AARCH64_CPU, .instance_init = aarch64_cpu_instance_init, .class_init = info->class_init ?: cpu_register_class_init, - .class_data = (void *)info, + .class_data = info, }; type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 29611a0a1c..d13361a150 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -626,7 +626,7 @@ static void mips_register_cpudef_type(const struct mips_def_t *def) .name = typename, .parent = TYPE_MIPS_CPU, .class_init = mips_cpu_cpudef_class_init, - .class_data = (void *)def, + .class_data = def, }; type_register_static(&ti); diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index b097ed55d9..8951f1b36f 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -1072,7 +1072,7 @@ static void register_types(void) .instance_init = s390_cpu_model_initfn, .instance_finalize = s390_cpu_model_finalize, .class_init = s390_base_cpu_model_class_init, - .class_data = (void *) &s390_cpu_defs[i], + .class_data = &s390_cpu_defs[i], }; char *name = s390_cpu_type_name(s390_cpu_defs[i].name); TypeInfo ti = { @@ -1081,7 +1081,7 @@ static void register_types(void) .instance_init = s390_cpu_model_initfn, .instance_finalize = s390_cpu_model_finalize, .class_init = s390_cpu_model_class_init, - .class_data = (void *) &s390_cpu_defs[i], + .class_data = &s390_cpu_defs[i], }; type_register_static(&ti_base); diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 981aa86e0e..bc753d5f62 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1104,7 +1104,7 @@ static void sparc_register_cpudef_type(const struct sparc_def_t *def) .name = typename, .parent = TYPE_SPARC_CPU, .class_init = sparc_cpu_cpudef_class_init, - .class_data = (void *)def, + .class_data = def, }; type_register_static(&ti); diff --git a/target/xtensa/helper.c b/target/xtensa/helper.c index 0459787981..2d93b45036 100644 --- a/target/xtensa/helper.c +++ b/target/xtensa/helper.c @@ -192,7 +192,7 @@ void xtensa_register_core(XtensaConfigList *node) TypeInfo type = { .parent = TYPE_XTENSA_CPU, .class_init = xtensa_core_class_init, - .class_data = (void *)node->config, + .class_data = node->config, }; xtensa_finalize_config(node->config); From 231bf6dda1ef7b4894ba374efb248c65b1841e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Apr 2025 18:44:12 +0200 Subject: [PATCH 0310/2760] qom: Constify TypeInfo::interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250424194905.82506-6-philmd@linaro.org> --- hw/scsi/megasas.c | 2 +- include/hw/virtio/virtio-pci.h | 2 +- include/qom/object.h | 2 +- rust/qemu-api/src/qom.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index b024905a01..a39e3e0e4f 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2486,7 +2486,7 @@ typedef struct MegasasInfo { const VMStateDescription *vmsd; const Property *props; size_t props_count; - InterfaceInfo *interfaces; + const InterfaceInfo *interfaces; } MegasasInfo; static struct MegasasInfo megasas_devices[] = { diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 567a9b0a9d..31ec144509 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -256,7 +256,7 @@ typedef struct VirtioPCIDeviceTypeInfo { void (*instance_init)(Object *obj); void (*instance_finalize)(Object *obj); void (*class_init)(ObjectClass *klass, const void *data); - InterfaceInfo *interfaces; + const InterfaceInfo *interfaces; } VirtioPCIDeviceTypeInfo; /* Register virtio-pci type(s). @t must be static. */ diff --git a/include/qom/object.h b/include/qom/object.h index 42b75d10a4..26a45f638c 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -490,7 +490,7 @@ struct TypeInfo void (*class_base_init)(ObjectClass *klass, const void *data); const void *class_data; - InterfaceInfo *interfaces; + const InterfaceInfo *interfaces; }; /** diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index f0a79f96d5..f1b4022157 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -514,7 +514,7 @@ pub trait ObjectImpl: ObjectType + IsA { class_init: Some(rust_class_init::), class_base_init: Self::CLASS_BASE_INIT, class_data: core::ptr::null(), - interfaces: core::ptr::null_mut(), + interfaces: core::ptr::null(), }; // methods on ObjectClass From 2cd09e47aa522dfc7bb206f13d6dccb68dd09887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Apr 2025 18:46:19 +0200 Subject: [PATCH 0311/2760] qom: Make InterfaceInfo[] uses const MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mechanical change using: $ sed -i -E 's/\(InterfaceInfo.?\[/\(const InterfaceInfo\[/g' \ $(git grep -lE '\(InterfaceInfo.?\[\]\)') Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250424194905.82506-7-philmd@linaro.org> --- authz/list.c | 2 +- authz/listfile.c | 2 +- authz/pamacct.c | 2 +- authz/simple.c | 2 +- backends/cryptodev.c | 2 +- backends/dbus-vmstate.c | 2 +- backends/hostmem.c | 2 +- backends/iommufd.c | 2 +- backends/rng.c | 2 +- block/throttle-groups.c | 2 +- crypto/secret_common.c | 2 +- crypto/tls-cipher-suites.c | 2 +- crypto/tlscredsanon.c | 2 +- crypto/tlscredspsk.c | 2 +- crypto/tlscredsx509.c | 2 +- event-loop-base.c | 2 +- hw/acpi/erst.c | 2 +- hw/acpi/generic_event_device.c | 2 +- hw/acpi/piix4.c | 2 +- hw/arm/armsse.c | 2 +- hw/arm/mps2-tz.c | 2 +- hw/arm/virt.c | 2 +- hw/audio/ac97.c | 2 +- hw/audio/es1370.c | 2 +- hw/audio/intel-hda.c | 2 +- hw/audio/via-ac97.c | 4 ++-- hw/block/fdc-isa.c | 2 +- hw/char/diva-gsp.c | 4 ++-- hw/char/parallel.c | 2 +- hw/char/serial-isa.c | 2 +- hw/char/serial-pci-multi.c | 4 ++-- hw/char/serial-pci.c | 2 +- hw/char/virtio-serial-bus.c | 2 +- hw/core/bus.c | 2 +- hw/core/qdev.c | 2 +- hw/cxl/switch-mailbox-cci.c | 2 +- hw/display/apple-gfx-pci.m | 2 +- hw/display/ati.c | 2 +- hw/display/bochs-display.c | 2 +- hw/display/cirrus_vga.c | 2 +- hw/display/qxl.c | 2 +- hw/display/sm501.c | 2 +- hw/display/vga-pci.c | 2 +- hw/display/virtio-gpu-pci-rutabaga.c | 2 +- hw/display/vmware_vga.c | 2 +- hw/dma/i8257.c | 2 +- hw/dma/xilinx_axidma.c | 4 ++-- hw/dma/xlnx_csu_dma.c | 2 +- hw/hppa/machine.c | 4 ++-- hw/i2c/smbus_ich9.c | 2 +- hw/i386/amd_iommu.c | 2 +- hw/i386/microvm.c | 2 +- hw/i386/pc.c | 2 +- hw/i386/sgx-epc.c | 2 +- hw/i386/x86.c | 2 +- hw/i386/xen/xen_platform.c | 2 +- hw/i386/xen/xen_pvdevice.c | 2 +- hw/ide/ich.c | 2 +- hw/ide/pci.c | 2 +- hw/input/pckbd.c | 2 +- hw/intc/arm_gic_common.c | 2 +- hw/intc/arm_gicv3_common.c | 2 +- hw/intc/goldfish_pic.c | 2 +- hw/intc/i8259_common.c | 2 +- hw/intc/ioapic_common.c | 2 +- hw/intc/loongarch_extioi_common.c | 2 +- hw/intc/loongarch_ipi.c | 2 +- hw/intc/m68k_irqc.c | 2 +- hw/intc/pnv_xive.c | 2 +- hw/intc/pnv_xive2.c | 2 +- hw/intc/slavio_intctl.c | 2 +- hw/intc/spapr_xive.c | 2 +- hw/intc/xics_spapr.c | 2 +- hw/intc/xive.c | 2 +- hw/intc/xive2.c | 2 +- hw/ipack/tpci200.c | 2 +- hw/ipmi/isa_ipmi_bt.c | 2 +- hw/ipmi/isa_ipmi_kcs.c | 2 +- hw/ipmi/pci_ipmi_bt.c | 2 +- hw/ipmi/pci_ipmi_kcs.c | 2 +- hw/ipmi/smbus_ipmi.c | 2 +- hw/isa/i82378.c | 2 +- hw/isa/lpc_ich9.c | 2 +- hw/isa/piix.c | 2 +- hw/isa/vt82c686.c | 4 ++-- hw/loongarch/virt.c | 2 +- hw/m68k/q800-glue.c | 2 +- hw/mem/cxl_type3.c | 2 +- hw/mem/pc-dimm.c | 2 +- hw/misc/applesmc.c | 2 +- hw/misc/edu.c | 2 +- hw/misc/ivshmem-pci.c | 2 +- hw/misc/macio/gpio.c | 2 +- hw/misc/macio/macio.c | 2 +- hw/misc/pci-testdev.c | 2 +- hw/misc/pvpanic-isa.c | 2 +- hw/misc/pvpanic-pci.c | 2 +- hw/misc/xlnx-versal-cframe-reg.c | 2 +- hw/misc/xlnx-versal-cfu.c | 4 ++-- hw/net/can/can_kvaser_pci.c | 2 +- hw/net/can/can_mioe3680_pci.c | 2 +- hw/net/can/can_pcm3680_pci.c | 2 +- hw/net/can/ctucan_pci.c | 2 +- hw/net/e1000.c | 2 +- hw/net/e1000e.c | 2 +- hw/net/eepro100.c | 2 +- hw/net/igb.c | 2 +- hw/net/igbvf.c | 2 +- hw/net/ne2000-pci.c | 2 +- hw/net/pcnet-pci.c | 2 +- hw/net/rocker/rocker.c | 2 +- hw/net/rtl8139.c | 2 +- hw/net/sungem.c | 2 +- hw/net/sunhme.c | 2 +- hw/net/tulip.c | 2 +- hw/net/vmxnet3.c | 2 +- hw/net/xilinx_axienet.c | 4 ++-- hw/nvme/ctrl.c | 2 +- hw/pci-bridge/cxl_downstream.c | 2 +- hw/pci-bridge/cxl_root_port.c | 2 +- hw/pci-bridge/cxl_upstream.c | 2 +- hw/pci-bridge/i82801b11.c | 2 +- hw/pci-bridge/pci_bridge_dev.c | 2 +- hw/pci-bridge/pci_expander_bridge.c | 6 +++--- hw/pci-bridge/pcie_pci_bridge.c | 2 +- hw/pci-bridge/pcie_root_port.c | 2 +- hw/pci-bridge/simba.c | 2 +- hw/pci-bridge/xio3130_downstream.c | 2 +- hw/pci-bridge/xio3130_upstream.c | 2 +- hw/pci-host/articia.c | 4 ++-- hw/pci-host/bonito.c | 2 +- hw/pci-host/designware.c | 2 +- hw/pci-host/gpex.c | 2 +- hw/pci-host/grackle.c | 2 +- hw/pci-host/gt64120.c | 2 +- hw/pci-host/i440fx.c | 2 +- hw/pci-host/mv64361.c | 2 +- hw/pci-host/pnv_phb3_pbcq.c | 2 +- hw/pci-host/pnv_phb4.c | 2 +- hw/pci-host/pnv_phb4_pec.c | 4 ++-- hw/pci-host/ppc4xx_pci.c | 2 +- hw/pci-host/ppce500.c | 2 +- hw/pci-host/q35.c | 2 +- hw/pci-host/raven.c | 2 +- hw/pci-host/sabre.c | 2 +- hw/pci-host/sh_pci.c | 2 +- hw/pci-host/uninorth.c | 8 ++++---- hw/pci-host/versatile.c | 2 +- hw/pci-host/xilinx-pcie.c | 2 +- hw/pci/pci.c | 2 +- hw/pci/pci_bridge.c | 2 +- hw/pci/pcie_port.c | 2 +- hw/ppc/e500plat.c | 2 +- hw/ppc/mac_newworld.c | 2 +- hw/ppc/mac_oldworld.c | 2 +- hw/ppc/pegasos2.c | 2 +- hw/ppc/pnv.c | 8 ++++---- hw/ppc/pnv_adu.c | 2 +- hw/ppc/pnv_chiptod.c | 4 ++-- hw/ppc/pnv_i2c.c | 2 +- hw/ppc/pnv_lpc.c | 2 +- hw/ppc/pnv_n1_chiplet.c | 2 +- hw/ppc/pnv_nest_pervasive.c | 2 +- hw/ppc/pnv_psi.c | 4 ++-- hw/ppc/spapr.c | 2 +- hw/ppc/spapr_pci.c | 2 +- hw/remote/machine.c | 2 +- hw/remote/proxy.c | 2 +- hw/remote/remote-obj.c | 2 +- hw/remote/vfio-user-obj.c | 2 +- hw/riscv/riscv-iommu-pci.c | 2 +- hw/riscv/virt.c | 2 +- hw/rtc/m48t59-isa.c | 2 +- hw/rtc/m48t59.c | 2 +- hw/rtc/mc146818rtc.c | 2 +- hw/s390x/ap-bridge.c | 2 +- hw/s390x/css-bridge.c | 2 +- hw/s390x/s390-pci-bus.c | 2 +- hw/s390x/s390-virtio-ccw.c | 2 +- hw/s390x/virtio-ccw-md.c | 2 +- hw/scsi/esp-pci.c | 2 +- hw/scsi/lsi53c895a.c | 2 +- hw/scsi/megasas.c | 4 ++-- hw/scsi/mptsas.c | 2 +- hw/scsi/scsi-bus.c | 2 +- hw/scsi/vhost-scsi.c | 2 +- hw/scsi/vhost-user-scsi.c | 2 +- hw/scsi/virtio-scsi.c | 2 +- hw/scsi/vmw_pvscsi.c | 2 +- hw/sd/sdhci-pci.c | 2 +- hw/sparc64/sun4u.c | 4 ++-- hw/ssi/pnv_spi.c | 2 +- hw/tpm/tpm_crb.c | 2 +- hw/tpm/tpm_spapr.c | 2 +- hw/tpm/tpm_tis_i2c.c | 2 +- hw/tpm/tpm_tis_isa.c | 2 +- hw/tpm/tpm_tis_sysbus.c | 2 +- hw/ufs/ufs.c | 2 +- hw/usb/bus.c | 2 +- hw/usb/dev-smartcard-reader.c | 2 +- hw/usb/hcd-ehci-pci.c | 2 +- hw/usb/hcd-ohci-pci.c | 2 +- hw/usb/hcd-uhci.c | 2 +- hw/usb/hcd-xhci-pci.c | 2 +- hw/vfio/igd.c | 2 +- hw/vfio/pci.c | 2 +- hw/virtio/virtio-md-pci.c | 2 +- hw/virtio/virtio-mem.c | 2 +- hw/virtio/virtio-pci.c | 6 +++--- hw/watchdog/wdt_i6300esb.c | 2 +- hw/xen/xen-bus.c | 2 +- hw/xen/xen-legacy-backend.c | 2 +- hw/xen/xen_pt.c | 2 +- hw/xen/xen_pt_graphics.c | 2 +- include/qom/object.h | 2 +- net/can/can_core.c | 2 +- net/can/can_host.c | 2 +- net/colo-compare.c | 2 +- net/filter.c | 2 +- scripts/codeconverter/codeconverter/test_regexps.py | 10 +++++----- scsi/pr-manager.c | 2 +- system/qtest.c | 2 +- target/i386/sev.c | 2 +- target/ppc/cpu_init.c | 2 +- tests/unit/check-qom-interface.c | 2 +- tests/unit/check-qom-proplist.c | 2 +- ui/dbus.c | 2 +- ui/input-barrier.c | 2 +- ui/input-linux.c | 2 +- util/thread-context.c | 2 +- 230 files changed, 258 insertions(+), 258 deletions(-) diff --git a/authz/list.c b/authz/list.c index bbd99f2b7f..17aa0efd80 100644 --- a/authz/list.c +++ b/authz/list.c @@ -253,7 +253,7 @@ static const TypeInfo qauthz_list_info = { .instance_size = sizeof(QAuthZList), .instance_finalize = qauthz_list_finalize, .class_init = qauthz_list_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/authz/listfile.c b/authz/listfile.c index b58d4ebd1d..13741d5a72 100644 --- a/authz/listfile.c +++ b/authz/listfile.c @@ -272,7 +272,7 @@ static const TypeInfo qauthz_list_file_info = { .instance_size = sizeof(QAuthZListFile), .instance_finalize = qauthz_list_file_finalize, .class_init = qauthz_list_file_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/authz/pamacct.c b/authz/pamacct.c index 07b8aad497..c0ad67479a 100644 --- a/authz/pamacct.c +++ b/authz/pamacct.c @@ -136,7 +136,7 @@ static const TypeInfo qauthz_pam_info = { .instance_size = sizeof(QAuthZPAM), .instance_finalize = qauthz_pam_finalize, .class_init = qauthz_pam_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/authz/simple.c b/authz/simple.c index f6985b840e..f8f2b98518 100644 --- a/authz/simple.c +++ b/authz/simple.c @@ -111,7 +111,7 @@ static const TypeInfo qauthz_simple_info = { .instance_size = sizeof(QAuthZSimple), .instance_finalize = qauthz_simple_finalize, .class_init = qauthz_simple_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/backends/cryptodev.c b/backends/cryptodev.c index 51bbe5ce40..79f8882d3b 100644 --- a/backends/cryptodev.c +++ b/backends/cryptodev.c @@ -641,7 +641,7 @@ static const TypeInfo cryptodev_backend_info = { .instance_finalize = cryptodev_backend_finalize, .class_size = sizeof(CryptoDevBackendClass), .class_init = cryptodev_backend_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/backends/dbus-vmstate.c b/backends/dbus-vmstate.c index 8c2deef43d..7d5b58b4c9 100644 --- a/backends/dbus-vmstate.c +++ b/backends/dbus-vmstate.c @@ -505,7 +505,7 @@ static const TypeInfo dbus_vmstate_info = { .instance_size = sizeof(DBusVMState), .instance_finalize = dbus_vmstate_finalize, .class_init = dbus_vmstate_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { TYPE_VMSTATE_IF }, { } diff --git a/backends/hostmem.c b/backends/hostmem.c index 195f37fa44..35734d6f4d 100644 --- a/backends/hostmem.c +++ b/backends/hostmem.c @@ -586,7 +586,7 @@ static const TypeInfo host_memory_backend_info = { .instance_size = sizeof(HostMemoryBackend), .instance_init = host_memory_backend_init, .instance_post_init = host_memory_backend_post_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/backends/iommufd.c b/backends/iommufd.c index 17f7ae3809..1498102099 100644 --- a/backends/iommufd.c +++ b/backends/iommufd.c @@ -342,7 +342,7 @@ static const TypeInfo types[] = { .instance_finalize = iommufd_backend_finalize, .class_size = sizeof(IOMMUFDBackendClass), .class_init = iommufd_backend_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/backends/rng.c b/backends/rng.c index b3480d27a1..ab94dfea85 100644 --- a/backends/rng.c +++ b/backends/rng.c @@ -119,7 +119,7 @@ static const TypeInfo rng_backend_info = { .class_size = sizeof(RngBackendClass), .class_init = rng_backend_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/block/throttle-groups.c b/block/throttle-groups.c index 9720cafb96..66fdce9a90 100644 --- a/block/throttle-groups.c +++ b/block/throttle-groups.c @@ -967,7 +967,7 @@ static const TypeInfo throttle_group_info = { .instance_size = sizeof(ThrottleGroup), .instance_init = throttle_group_obj_init, .instance_finalize = throttle_group_obj_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } }, diff --git a/crypto/secret_common.c b/crypto/secret_common.c index 2399ce412b..a5ecb876ae 100644 --- a/crypto/secret_common.c +++ b/crypto/secret_common.c @@ -375,7 +375,7 @@ static const TypeInfo qcrypto_secret_info = { .class_size = sizeof(QCryptoSecretCommonClass), .class_init = qcrypto_secret_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/crypto/tls-cipher-suites.c b/crypto/tls-cipher-suites.c index e546cc7c0e..d9b61d0c08 100644 --- a/crypto/tls-cipher-suites.c +++ b/crypto/tls-cipher-suites.c @@ -118,7 +118,7 @@ static const TypeInfo qcrypto_tls_cipher_suites_info = { .instance_size = sizeof(QCryptoTLSCipherSuites), .class_size = sizeof(QCryptoTLSCredsClass), .class_init = qcrypto_tls_cipher_suites_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { TYPE_FW_CFG_DATA_GENERATOR_INTERFACE }, { } diff --git a/crypto/tlscredsanon.c b/crypto/tlscredsanon.c index 0e2d133821..44af9e6c9a 100644 --- a/crypto/tlscredsanon.c +++ b/crypto/tlscredsanon.c @@ -152,7 +152,7 @@ static const TypeInfo qcrypto_tls_creds_anon_info = { .instance_finalize = qcrypto_tls_creds_anon_finalize, .class_size = sizeof(QCryptoTLSCredsAnonClass), .class_init = qcrypto_tls_creds_anon_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/crypto/tlscredspsk.c b/crypto/tlscredspsk.c index 287c2a3c96..5b68a6b7ba 100644 --- a/crypto/tlscredspsk.c +++ b/crypto/tlscredspsk.c @@ -255,7 +255,7 @@ static const TypeInfo qcrypto_tls_creds_psk_info = { .instance_finalize = qcrypto_tls_creds_psk_finalize, .class_size = sizeof(QCryptoTLSCredsPSKClass), .class_init = qcrypto_tls_creds_psk_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/crypto/tlscredsx509.c b/crypto/tlscredsx509.c index 143993f539..63a72fe47c 100644 --- a/crypto/tlscredsx509.c +++ b/crypto/tlscredsx509.c @@ -828,7 +828,7 @@ static const TypeInfo qcrypto_tls_creds_x509_info = { .instance_finalize = qcrypto_tls_creds_x509_finalize, .class_size = sizeof(QCryptoTLSCredsX509Class), .class_init = qcrypto_tls_creds_x509_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/event-loop-base.c b/event-loop-base.c index 733c54486c..8ca143bea4 100644 --- a/event-loop-base.c +++ b/event-loop-base.c @@ -126,7 +126,7 @@ static const TypeInfo event_loop_base_info = { .class_size = sizeof(EventLoopBaseClass), .class_init = event_loop_base_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/hw/acpi/erst.c b/hw/acpi/erst.c index 90148ec9dc..099cabb7ab 100644 --- a/hw/acpi/erst.c +++ b/hw/acpi/erst.c @@ -1044,7 +1044,7 @@ static const TypeInfo erst_type_info = { .parent = TYPE_PCI_DEVICE, .class_init = erst_class_init, .instance_size = sizeof(ERSTDeviceState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/acpi/generic_event_device.c b/hw/acpi/generic_event_device.c index f589e79a2b..d8adfea648 100644 --- a/hw/acpi/generic_event_device.c +++ b/hw/acpi/generic_event_device.c @@ -494,7 +494,7 @@ static const TypeInfo acpi_ged_info = { .instance_size = sizeof(AcpiGedState), .instance_init = acpi_ged_initfn, .class_init = acpi_ged_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { } diff --git a/hw/acpi/piix4.c b/hw/acpi/piix4.c index 5860e8408b..b16d45f03e 100644 --- a/hw/acpi/piix4.c +++ b/hw/acpi/piix4.c @@ -657,7 +657,7 @@ static const TypeInfo piix4_pm_info = { .instance_init = piix4_pm_init, .instance_size = sizeof(PIIX4PMState), .class_init = piix4_pm_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, diff --git a/hw/arm/armsse.c b/hw/arm/armsse.c index 9403b65ddb..50ab7f4810 100644 --- a/hw/arm/armsse.c +++ b/hw/arm/armsse.c @@ -1713,7 +1713,7 @@ static const TypeInfo armsse_info = { .class_size = sizeof(ARMSSEClass), .instance_init = armsse_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IDAU_INTERFACE }, { } } diff --git a/hw/arm/mps2-tz.c b/hw/arm/mps2-tz.c index 8474549f5f..5dd87cc028 100644 --- a/hw/arm/mps2-tz.c +++ b/hw/arm/mps2-tz.c @@ -1453,7 +1453,7 @@ static const TypeInfo mps2tz_info = { .instance_size = sizeof(MPS2TZMachineState), .class_size = sizeof(MPS2TZMachineClass), .class_init = mps2tz_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IDAU_INTERFACE }, { } }, diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 17faf34aae..177f3dd22c 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3396,7 +3396,7 @@ static const TypeInfo virt_machine_info = { .class_size = sizeof(VirtMachineClass), .class_init = virt_machine_class_init, .instance_init = virt_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/audio/ac97.c b/hw/audio/ac97.c index 7454cc60de..669a0463cc 100644 --- a/hw/audio/ac97.c +++ b/hw/audio/ac97.c @@ -1351,7 +1351,7 @@ static const TypeInfo ac97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(AC97LinkState), .class_init = ac97_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/audio/es1370.c b/hw/audio/es1370.c index 322b779814..8efb969212 100644 --- a/hw/audio/es1370.c +++ b/hw/audio/es1370.c @@ -896,7 +896,7 @@ static const TypeInfo es1370_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof (ES1370State), .class_init = es1370_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c index 2f1b08e9c1..b256c8ccea 100644 --- a/hw/audio/intel-hda.c +++ b/hw/audio/intel-hda.c @@ -1262,7 +1262,7 @@ static const TypeInfo intel_hda_info = { .instance_size = sizeof(IntelHDAState), .class_init = intel_hda_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/audio/via-ac97.c b/hw/audio/via-ac97.c index 5feef663d8..1e0a5c7398 100644 --- a/hw/audio/via-ac97.c +++ b/hw/audio/via-ac97.c @@ -487,7 +487,7 @@ static const TypeInfo via_ac97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ViaAC97State), .class_init = via_ac97_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -522,7 +522,7 @@ static const TypeInfo via_mc97_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = via_mc97_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c index fbba2ab629..6d1790e0e6 100644 --- a/hw/block/fdc-isa.c +++ b/hw/block/fdc-isa.c @@ -331,7 +331,7 @@ static const TypeInfo isa_fdc_info = { .instance_size = sizeof(FDCtrlISABus), .class_init = isabus_fdc_class_init, .instance_init = isabus_fdc_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c index 9a623d680b..60f933191d 100644 --- a/hw/char/diva-gsp.c +++ b/hw/char/diva-gsp.c @@ -268,7 +268,7 @@ static const TypeInfo diva_aux_info = { .instance_size = sizeof(DivaAuxState), .instance_init = diva_aux_init, .class_init = diva_aux_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -282,7 +282,7 @@ static const TypeInfo diva_serial_pci_info = { .instance_size = sizeof(PCIDivaSerialState), .instance_init = diva_serial_init, .class_init = diva_serial_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/char/parallel.c b/hw/char/parallel.c index 217ddaf2e3..8732e4e9f9 100644 --- a/hw/char/parallel.c +++ b/hw/char/parallel.c @@ -627,7 +627,7 @@ static const TypeInfo parallel_isa_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(ISAParallelState), .class_init = parallel_isa_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/char/serial-isa.c b/hw/char/serial-isa.c index fe7fb1625b..0ea59a3d5c 100644 --- a/hw/char/serial-isa.c +++ b/hw/char/serial-isa.c @@ -146,7 +146,7 @@ static const TypeInfo serial_isa_info = { .instance_size = sizeof(ISASerialState), .instance_init = serial_isa_initfn, .class_init = serial_isa_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index ee1c0f7dc4..fb184c2e6d 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -194,7 +194,7 @@ static const TypeInfo multi_2x_serial_pci_info = { .instance_size = sizeof(PCIMultiSerialState), .instance_init = multi_serial_init, .class_init = multi_2x_serial_pci_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -206,7 +206,7 @@ static const TypeInfo multi_4x_serial_pci_info = { .instance_size = sizeof(PCIMultiSerialState), .instance_init = multi_serial_init, .class_init = multi_4x_serial_pci_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index bd38c7428c..8707e81914 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -115,7 +115,7 @@ static const TypeInfo serial_pci_info = { .instance_size = sizeof(PCISerialState), .instance_init = serial_pci_init, .class_init = serial_pci_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 00572873d2..eb79f5258b 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -1188,7 +1188,7 @@ static const TypeInfo virtio_device_info = { .parent = TYPE_VIRTIO_DEVICE, .instance_size = sizeof(VirtIOSerial), .class_init = virtio_serial_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/core/bus.c b/hw/core/bus.c index c3b431a014..bddfc22d38 100644 --- a/hw/core/bus.c +++ b/hw/core/bus.c @@ -260,7 +260,7 @@ static const TypeInfo bus_info = { .instance_init = qbus_initfn, .instance_finalize = qbus_finalize, .class_init = bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_RESETTABLE_INTERFACE }, { } }, diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 4a3760c101..f600226176 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -870,7 +870,7 @@ static const TypeInfo device_type_info = { .class_init = device_class_init, .abstract = true, .class_size = sizeof(DeviceClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_VMSTATE_IF }, { TYPE_RESETTABLE_INTERFACE }, { } diff --git a/hw/cxl/switch-mailbox-cci.c b/hw/cxl/switch-mailbox-cci.c index b92bbeb16e..223f220433 100644 --- a/hw/cxl/switch-mailbox-cci.c +++ b/hw/cxl/switch-mailbox-cci.c @@ -99,7 +99,7 @@ static const TypeInfo cswmbcci_info = { .parent = TYPE_PCI_DEVICE, .class_init = cswmbcci_class_init, .instance_size = sizeof(CSWMBCCIDev), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/display/apple-gfx-pci.m b/hw/display/apple-gfx-pci.m index 2f0d24f7fe..b0694f4cb8 100644 --- a/hw/display/apple-gfx-pci.m +++ b/hw/display/apple-gfx-pci.m @@ -147,7 +147,7 @@ static const TypeInfo apple_gfx_pci_types[] = { .instance_size = sizeof(AppleGFXPCIState), .class_init = apple_gfx_pci_class_init, .instance_init = apple_gfx_pci_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { }, }, diff --git a/hw/display/ati.c b/hw/display/ati.c index 4e88d09943..7de27732cd 100644 --- a/hw/display/ati.c +++ b/hw/display/ati.c @@ -1079,7 +1079,7 @@ static const TypeInfo ati_vga_info = { .instance_size = sizeof(ATIVGAState), .class_init = ati_vga_class_init, .instance_init = ati_vga_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/display/bochs-display.c b/hw/display/bochs-display.c index 1d329fc9cc..ad2821c974 100644 --- a/hw/display/bochs-display.c +++ b/hw/display/bochs-display.c @@ -374,7 +374,7 @@ static const TypeInfo bochs_display_type_info = { .instance_size = sizeof(BochsDisplayState), .instance_init = bochs_display_init, .class_init = bochs_display_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, diff --git a/hw/display/cirrus_vga.c b/hw/display/cirrus_vga.c index 4e5ae04af0..ef08694626 100644 --- a/hw/display/cirrus_vga.c +++ b/hw/display/cirrus_vga.c @@ -3013,7 +3013,7 @@ static const TypeInfo cirrus_vga_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCICirrusVGAState), .class_init = cirrus_vga_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 6c820bcdb5..18f482ca7f 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -2517,7 +2517,7 @@ static const TypeInfo qxl_pci_type_info = { .instance_size = sizeof(PCIQXLDevice), .abstract = true, .class_init = qxl_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/display/sm501.c b/hw/display/sm501.c index dcff1e978e..6d2f18684c 100644 --- a/hw/display/sm501.c +++ b/hw/display/sm501.c @@ -2196,7 +2196,7 @@ static const TypeInfo sm501_pci_info = { .instance_size = sizeof(SM501PCIState), .class_init = sm501_pci_class_init, .instance_init = sm501_pci_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/display/vga-pci.c b/hw/display/vga-pci.c index a860197274..b81f7fd2d0 100644 --- a/hw/display/vga-pci.c +++ b/hw/display/vga-pci.c @@ -369,7 +369,7 @@ static const TypeInfo vga_pci_type_info = { .instance_size = sizeof(PCIVGAState), .abstract = true, .class_init = vga_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { TYPE_ACPI_DEV_AML_IF }, { }, diff --git a/hw/display/virtio-gpu-pci-rutabaga.c b/hw/display/virtio-gpu-pci-rutabaga.c index abbb898c65..5fdff37f2c 100644 --- a/hw/display/virtio-gpu-pci-rutabaga.c +++ b/hw/display/virtio-gpu-pci-rutabaga.c @@ -34,7 +34,7 @@ static const TypeInfo virtio_gpu_rutabaga_pci_info[] = { .parent = TYPE_VIRTIO_GPU_PCI_BASE, .instance_size = sizeof(VirtIOGPURutabagaPCI), .instance_init = virtio_gpu_rutabaga_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, } diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index 7777deb17d..544bb65320 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -1363,7 +1363,7 @@ static const TypeInfo vmsvga_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(struct pci_vmsvga_state_s), .class_init = vmsvga_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/dma/i8257.c b/hw/dma/i8257.c index 1d67e50536..2463952ada 100644 --- a/hw/dma/i8257.c +++ b/hw/dma/i8257.c @@ -618,7 +618,7 @@ static const TypeInfo i8257_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(I8257State), .class_init = i8257_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ISADMA }, { } } diff --git a/hw/dma/xilinx_axidma.c b/hw/dma/xilinx_axidma.c index bf1b523ac8..2020399fd5 100644 --- a/hw/dma/xilinx_axidma.c +++ b/hw/dma/xilinx_axidma.c @@ -662,7 +662,7 @@ static const TypeInfo xilinx_axidma_data_stream_info = { .instance_size = sizeof(XilinxAXIDMAStreamSink), .class_init = xilinx_axidma_stream_class_init, .class_data = &xilinx_axidma_data_stream_class, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } @@ -674,7 +674,7 @@ static const TypeInfo xilinx_axidma_control_stream_info = { .instance_size = sizeof(XilinxAXIDMAStreamSink), .class_init = xilinx_axidma_stream_class_init, .class_data = &xilinx_axidma_control_stream_class, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 6943c927d0..3db3904d83 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -744,7 +744,7 @@ static const TypeInfo xlnx_csu_dma_info = { .class_init = xlnx_csu_dma_class_init, .class_size = sizeof(XlnxCSUDMAClass), .instance_init = xlnx_csu_dma_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c index 1812276678..dacedc5409 100644 --- a/hw/hppa/machine.c +++ b/hw/hppa/machine.c @@ -713,7 +713,7 @@ static const TypeInfo HP_B160L_machine_init_typeinfo = { .name = MACHINE_TYPE_NAME("B160L"), .parent = TYPE_MACHINE, .class_init = HP_B160L_machine_init_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { } }, @@ -749,7 +749,7 @@ static const TypeInfo HP_C3700_machine_init_typeinfo = { .name = MACHINE_TYPE_NAME("C3700"), .parent = TYPE_MACHINE, .class_init = HP_C3700_machine_init_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { } }, diff --git a/hw/i2c/smbus_ich9.c b/hw/i2c/smbus_ich9.c index f1fca30fea..956c9b59bb 100644 --- a/hw/i2c/smbus_ich9.c +++ b/hw/i2c/smbus_ich9.c @@ -145,7 +145,7 @@ static const TypeInfo ich9_smb_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ICH9SMBState), .class_init = ich9_smb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { TYPE_ACPI_DEV_AML_IF }, { }, diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index b94802e21a..2cf7e24a21 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1719,7 +1719,7 @@ static const TypeInfo amdvi_pci = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(AMDVIPCIState), .class_init = amdvi_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c index 14a918a531..e0daf0d4fc 100644 --- a/hw/i386/microvm.c +++ b/hw/i386/microvm.c @@ -726,7 +726,7 @@ static const TypeInfo microvm_machine_info = { .instance_init = microvm_machine_initfn, .class_size = sizeof(MicrovmMachineClass), .class_init = microvm_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 49753bf0b3..70656157ca 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1870,7 +1870,7 @@ static const TypeInfo pc_machine_info = { .instance_init = pc_machine_initfn, .class_size = sizeof(PCMachineClass), .class_init = pc_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/i386/sgx-epc.c b/hw/i386/sgx-epc.c index 8fb80900b7..2b3b2823b5 100644 --- a/hw/i386/sgx-epc.c +++ b/hw/i386/sgx-epc.c @@ -173,7 +173,7 @@ static const TypeInfo sgx_epc_info = { .instance_init = sgx_epc_init, .class_init = sgx_epc_class_init, .class_size = sizeof(DeviceClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_MEMORY_DEVICE }, { } }, diff --git a/hw/i386/x86.c b/hw/i386/x86.c index c8e2551b2b..e2d0409299 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -450,7 +450,7 @@ static const TypeInfo x86_machine_info = { .instance_init = x86_machine_initfn, .class_size = sizeof(X86MachineClass), .class_init = x86_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { } }, diff --git a/hw/i386/xen/xen_platform.c b/hw/i386/xen/xen_platform.c index 7c0d345f96..c8b852be0c 100644 --- a/hw/i386/xen/xen_platform.c +++ b/hw/i386/xen/xen_platform.c @@ -604,7 +604,7 @@ static const TypeInfo xen_platform_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIXenPlatformState), .class_init = xen_platform_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/i386/xen/xen_pvdevice.c b/hw/i386/xen/xen_pvdevice.c index 65868bd5e5..87a974ae5a 100644 --- a/hw/i386/xen/xen_pvdevice.c +++ b/hw/i386/xen/xen_pvdevice.c @@ -139,7 +139,7 @@ static const TypeInfo xen_pv_type_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(XenPVDevice), .class_init = xen_pv_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/ide/ich.c b/hw/ide/ich.c index f2773ab462..4cade0d121 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -197,7 +197,7 @@ static const TypeInfo ich_ahci_info = { .instance_size = sizeof(AHCIPCIState), .instance_init = pci_ich9_ahci_init, .class_init = ich_ahci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/ide/pci.c b/hw/ide/pci.c index 0ed72e4223..1e50bb9e48 100644 --- a/hw/ide/pci.c +++ b/hw/ide/pci.c @@ -625,7 +625,7 @@ static const TypeInfo pci_ide_type_info = { .instance_size = sizeof(PCIIDEState), .instance_init = pci_ide_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/input/pckbd.c b/hw/input/pckbd.c index 83930dd50c..71f5f976e9 100644 --- a/hw/input/pckbd.c +++ b/hw/input/pckbd.c @@ -958,7 +958,7 @@ static const TypeInfo i8042_info = { .instance_size = sizeof(ISAKBDState), .instance_init = i8042_initfn, .class_init = i8042_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/intc/arm_gic_common.c b/hw/intc/arm_gic_common.c index f61d1c1fe6..0f0c48d89a 100644 --- a/hw/intc/arm_gic_common.c +++ b/hw/intc/arm_gic_common.c @@ -382,7 +382,7 @@ static const TypeInfo arm_gic_common_type = { .class_size = sizeof(ARMGICCommonClass), .class_init = arm_gic_common_class_init, .abstract = true, - .interfaces = (InterfaceInfo []) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ARM_LINUX_BOOT_IF }, { }, }, diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c index dd86a50300..1cee68193c 100644 --- a/hw/intc/arm_gicv3_common.c +++ b/hw/intc/arm_gicv3_common.c @@ -644,7 +644,7 @@ static const TypeInfo arm_gicv3_common_type = { .class_init = arm_gicv3_common_class_init, .instance_finalize = arm_gicv3_finalize, .abstract = true, - .interfaces = (InterfaceInfo []) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ARM_LINUX_BOOT_IF }, { }, }, diff --git a/hw/intc/goldfish_pic.c b/hw/intc/goldfish_pic.c index b80538cdeb..2359861785 100644 --- a/hw/intc/goldfish_pic.c +++ b/hw/intc/goldfish_pic.c @@ -204,7 +204,7 @@ static const TypeInfo goldfish_pic_info = { .class_init = goldfish_pic_class_init, .instance_init = goldfish_pic_instance_init, .instance_size = sizeof(GoldfishPICState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, diff --git a/hw/intc/i8259_common.c b/hw/intc/i8259_common.c index 4a92e0da90..602e44c8ea 100644 --- a/hw/intc/i8259_common.c +++ b/hw/intc/i8259_common.c @@ -226,7 +226,7 @@ static const TypeInfo pic_common_type = { .class_size = sizeof(PICCommonClass), .class_init = pic_common_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, diff --git a/hw/intc/ioapic_common.c b/hw/intc/ioapic_common.c index b0381c7990..fce3486e51 100644 --- a/hw/intc/ioapic_common.c +++ b/hw/intc/ioapic_common.c @@ -215,7 +215,7 @@ static const TypeInfo ioapic_common_type = { .class_size = sizeof(IOAPICCommonClass), .class_init = ioapic_common_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index 126f13d12c..9e1589060c 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -196,7 +196,7 @@ static const TypeInfo loongarch_extioi_common_types[] = { .instance_size = sizeof(LoongArchExtIOICommonState), .class_size = sizeof(LoongArchExtIOICommonClass), .class_init = loongarch_extioi_common_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 4dad240689..2f8bb57828 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -162,7 +162,7 @@ static const TypeInfo loongarch_ipi_types[] = { .instance_size = sizeof(LoongarchIPIState), .class_size = sizeof(LoongarchIPIClass), .class_init = loongarch_ipi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/intc/m68k_irqc.c b/hw/intc/m68k_irqc.c index 215e1a6ed5..2532322618 100644 --- a/hw/intc/m68k_irqc.c +++ b/hw/intc/m68k_irqc.c @@ -110,7 +110,7 @@ static const TypeInfo m68k_irqc_type_info = { .instance_size = sizeof(M68KIRQCState), .instance_init = m68k_irqc_instance_init, .class_init = m68k_irqc_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { TYPE_INTERRUPT_STATS_PROVIDER }, { } diff --git a/hw/intc/pnv_xive.c b/hw/intc/pnv_xive.c index cd73881b5b..935c0e4742 100644 --- a/hw/intc/pnv_xive.c +++ b/hw/intc/pnv_xive.c @@ -2106,7 +2106,7 @@ static const TypeInfo pnv_xive_info = { .instance_size = sizeof(PnvXive), .class_init = pnv_xive_class_init, .class_size = sizeof(PnvXiveClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/intc/pnv_xive2.c b/hw/intc/pnv_xive2.c index 02437dddac..ec8b0c68f1 100644 --- a/hw/intc/pnv_xive2.c +++ b/hw/intc/pnv_xive2.c @@ -2547,7 +2547,7 @@ static const TypeInfo pnv_xive2_info = { .instance_size = sizeof(PnvXive2), .class_init = pnv_xive2_class_init, .class_size = sizeof(PnvXive2Class), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/intc/slavio_intctl.c b/hw/intc/slavio_intctl.c index 5776055a8b..00b80bb177 100644 --- a/hw/intc/slavio_intctl.c +++ b/hw/intc/slavio_intctl.c @@ -460,7 +460,7 @@ static const TypeInfo slavio_intctl_info = { .instance_size = sizeof(SLAVIO_INTCTLState), .instance_init = slavio_intctl_init, .class_init = slavio_intctl_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c index 7fde6059bf..440edb97d8 100644 --- a/hw/intc/spapr_xive.c +++ b/hw/intc/spapr_xive.c @@ -856,7 +856,7 @@ static const TypeInfo spapr_xive_info = { .instance_size = sizeof(SpaprXive), .class_init = spapr_xive_class_init, .class_size = sizeof(SpaprXiveClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_SPAPR_INTC }, { } }, diff --git a/hw/intc/xics_spapr.c b/hw/intc/xics_spapr.c index 9e465fb8f3..7663596a4a 100644 --- a/hw/intc/xics_spapr.c +++ b/hw/intc/xics_spapr.c @@ -461,7 +461,7 @@ static const TypeInfo ics_spapr_info = { .name = TYPE_ICS_SPAPR, .parent = TYPE_ICS, .class_init = ics_spapr_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_SPAPR_INTC }, { } }, diff --git a/hw/intc/xive.c b/hw/intc/xive.c index 069c1e9a5e..27b473e4d7 100644 --- a/hw/intc/xive.c +++ b/hw/intc/xive.c @@ -2108,7 +2108,7 @@ static const TypeInfo xive_router_info = { .instance_size = sizeof(XiveRouter), .class_size = sizeof(XiveRouterClass), .class_init = xive_router_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_NOTIFIER }, { TYPE_XIVE_PRESENTER }, { } diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c index 3337a943fb..a08cf906d0 100644 --- a/hw/intc/xive2.c +++ b/hw/intc/xive2.c @@ -1609,7 +1609,7 @@ static const TypeInfo xive2_router_info = { .instance_size = sizeof(Xive2Router), .class_size = sizeof(Xive2RouterClass), .class_init = xive2_router_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_NOTIFIER }, { TYPE_XIVE_PRESENTER }, { } diff --git a/hw/ipack/tpci200.c b/hw/ipack/tpci200.c index f6993330d2..40b30517c7 100644 --- a/hw/ipack/tpci200.c +++ b/hw/ipack/tpci200.c @@ -650,7 +650,7 @@ static const TypeInfo tpci200_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(TPCI200State), .class_init = tpci200_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/ipmi/isa_ipmi_bt.c b/hw/ipmi/isa_ipmi_bt.c index db539e68ae..0ad91ccf68 100644 --- a/hw/ipmi/isa_ipmi_bt.c +++ b/hw/ipmi/isa_ipmi_bt.c @@ -161,7 +161,7 @@ static const TypeInfo isa_ipmi_bt_info = { .instance_size = sizeof(ISAIPMIBTDevice), .instance_init = isa_ipmi_bt_init, .class_init = isa_ipmi_bt_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, { TYPE_ACPI_DEV_AML_IF }, { } diff --git a/hw/ipmi/isa_ipmi_kcs.c b/hw/ipmi/isa_ipmi_kcs.c index 4cbc6c577c..418d234e0f 100644 --- a/hw/ipmi/isa_ipmi_kcs.c +++ b/hw/ipmi/isa_ipmi_kcs.c @@ -167,7 +167,7 @@ static const TypeInfo isa_ipmi_kcs_info = { .instance_size = sizeof(ISAIPMIKCSDevice), .instance_init = isa_ipmi_kcs_init, .class_init = isa_ipmi_kcs_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, { TYPE_ACPI_DEV_AML_IF }, { } diff --git a/hw/ipmi/pci_ipmi_bt.c b/hw/ipmi/pci_ipmi_bt.c index 23f65c6886..905101dcaf 100644 --- a/hw/ipmi/pci_ipmi_bt.c +++ b/hw/ipmi/pci_ipmi_bt.c @@ -145,7 +145,7 @@ static const TypeInfo pci_ipmi_bt_info = { .instance_size = sizeof(PCIIPMIBTDevice), .instance_init = pci_ipmi_bt_instance_init, .class_init = pci_ipmi_bt_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/ipmi/pci_ipmi_kcs.c b/hw/ipmi/pci_ipmi_kcs.c index 4077b6a7b0..4d6cde826e 100644 --- a/hw/ipmi/pci_ipmi_kcs.c +++ b/hw/ipmi/pci_ipmi_kcs.c @@ -144,7 +144,7 @@ static const TypeInfo pci_ipmi_kcs_info = { .instance_size = sizeof(PCIIPMIKCSDevice), .instance_init = pci_ipmi_kcs_instance_init, .class_init = pci_ipmi_kcs_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/ipmi/smbus_ipmi.c b/hw/ipmi/smbus_ipmi.c index 7345844a3a..78c332de54 100644 --- a/hw/ipmi/smbus_ipmi.c +++ b/hw/ipmi/smbus_ipmi.c @@ -376,7 +376,7 @@ static const TypeInfo smbus_ipmi_info = { .instance_size = sizeof(SMBusIPMIDevice), .instance_init = smbus_ipmi_init, .class_init = smbus_ipmi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_IPMI_INTERFACE }, { TYPE_ACPI_DEV_AML_IF }, { } diff --git a/hw/isa/i82378.c b/hw/isa/i82378.c index 26c8ec4f77..06e8f0ce3e 100644 --- a/hw/isa/i82378.c +++ b/hw/isa/i82378.c @@ -142,7 +142,7 @@ static const TypeInfo i82378_type_info = { .instance_size = sizeof(I82378State), .instance_init = i82378_init, .class_init = i82378_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c index d3e623b1e8..71afb45b63 100644 --- a/hw/isa/lpc_ich9.c +++ b/hw/isa/lpc_ich9.c @@ -915,7 +915,7 @@ static const TypeInfo ich9_lpc_info = { .instance_size = sizeof(ICH9LPCState), .instance_init = ich9_lpc_initfn, .class_init = ich9_lpc_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, diff --git a/hw/isa/piix.c b/hw/isa/piix.c index 2c6e76f97c..52c14d3cd5 100644 --- a/hw/isa/piix.c +++ b/hw/isa/piix.c @@ -445,7 +445,7 @@ static const TypeInfo piix_pci_type_info = { .instance_init = pci_piix_init, .abstract = true, .class_init = pci_piix_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { TYPE_ACPI_DEV_AML_IF }, { }, diff --git a/hw/isa/vt82c686.c b/hw/isa/vt82c686.c index c62afc907b..337958617a 100644 --- a/hw/isa/vt82c686.c +++ b/hw/isa/vt82c686.c @@ -243,7 +243,7 @@ static const TypeInfo via_pm_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ViaPMState), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -634,7 +634,7 @@ static const TypeInfo via_isa_info = { .instance_size = sizeof(ViaISAState), .instance_init = via_isa_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index fde25e9409..779544fada 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -1186,7 +1186,7 @@ static const TypeInfo virt_machine_types[] = { .instance_size = sizeof(LoongArchVirtMachineState), .class_init = virt_class_init, .instance_init = virt_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/m68k/q800-glue.c b/hw/m68k/q800-glue.c index b428e7c833..36de67c328 100644 --- a/hw/m68k/q800-glue.c +++ b/hw/m68k/q800-glue.c @@ -248,7 +248,7 @@ static const TypeInfo glue_info_types[] = { .instance_init = glue_init, .instance_finalize = glue_finalize, .class_init = glue_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { } }, diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index c95722a2ae..bba923f8ea 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -2174,7 +2174,7 @@ static const TypeInfo ct3d_info = { .class_size = sizeof(struct CXLType3Class), .class_init = ct3_class_init, .instance_size = sizeof(CXLType3Dev), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CXL_DEVICE }, { INTERFACE_PCIE_DEVICE }, {} diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c index 6f68171442..f701d5b5f9 100644 --- a/hw/mem/pc-dimm.c +++ b/hw/mem/pc-dimm.c @@ -301,7 +301,7 @@ static const TypeInfo pc_dimm_info = { .instance_init = pc_dimm_init, .class_init = pc_dimm_class_init, .class_size = sizeof(PCDIMMDeviceClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_MEMORY_DEVICE }, { } }, diff --git a/hw/misc/applesmc.c b/hw/misc/applesmc.c index d83a81b60d..a015d4a9b8 100644 --- a/hw/misc/applesmc.c +++ b/hw/misc/applesmc.c @@ -393,7 +393,7 @@ static const TypeInfo applesmc_isa_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(AppleSMCState), .class_init = qdev_applesmc_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/misc/edu.c b/hw/misc/edu.c index 8224603593..cece633e11 100644 --- a/hw/misc/edu.c +++ b/hw/misc/edu.c @@ -436,7 +436,7 @@ static const TypeInfo edu_types[] = { .instance_size = sizeof(EduState), .instance_init = edu_instance_init, .class_init = edu_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/misc/ivshmem-pci.c b/hw/misc/ivshmem-pci.c index 2844b6f909..5a10bca633 100644 --- a/hw/misc/ivshmem-pci.c +++ b/hw/misc/ivshmem-pci.c @@ -1002,7 +1002,7 @@ static const TypeInfo ivshmem_common_info = { .instance_size = sizeof(IVShmemState), .abstract = true, .class_init = ivshmem_common_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/misc/macio/gpio.c b/hw/misc/macio/gpio.c index e5d1e1168e..990551f91f 100644 --- a/hw/misc/macio/gpio.c +++ b/hw/misc/macio/gpio.c @@ -210,7 +210,7 @@ static const TypeInfo macio_gpio_init_info = { .instance_size = sizeof(MacIOGPIOState), .instance_init = macio_gpio_init, .class_init = macio_gpio_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { } }, diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index b0418db49e..6710485d72 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -465,7 +465,7 @@ static const TypeInfo macio_type_info = { .instance_init = macio_instance_init, .abstract = true, .class_init = macio_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 0ea26451f1..3f6a8bba84 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -345,7 +345,7 @@ static const TypeInfo pci_testdev_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCITestDevState), .class_init = pci_testdev_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/misc/pvpanic-isa.c b/hw/misc/pvpanic-isa.c index 55522ee56c..f7b421c713 100644 --- a/hw/misc/pvpanic-isa.c +++ b/hw/misc/pvpanic-isa.c @@ -121,7 +121,7 @@ static const TypeInfo pvpanic_isa_info = { .instance_size = sizeof(PVPanicISAState), .instance_init = pvpanic_isa_initfn, .class_init = pvpanic_isa_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/misc/pvpanic-pci.c b/hw/misc/pvpanic-pci.c index 51ebf66107..2869b6a7ff 100644 --- a/hw/misc/pvpanic-pci.c +++ b/hw/misc/pvpanic-pci.c @@ -80,7 +80,7 @@ static const TypeInfo pvpanic_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PVPanicPCIState), .class_init = pvpanic_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/misc/xlnx-versal-cframe-reg.c b/hw/misc/xlnx-versal-cframe-reg.c index e28d569ebe..1ce083e240 100644 --- a/hw/misc/xlnx-versal-cframe-reg.c +++ b/hw/misc/xlnx-versal-cframe-reg.c @@ -833,7 +833,7 @@ static const TypeInfo cframe_reg_info = { .instance_size = sizeof(XlnxVersalCFrameReg), .class_init = cframe_reg_class_init, .instance_init = cframe_reg_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XLNX_CFI_IF }, { } } diff --git a/hw/misc/xlnx-versal-cfu.c b/hw/misc/xlnx-versal-cfu.c index 02e4fed05b..b920fc77c3 100644 --- a/hw/misc/xlnx-versal-cfu.c +++ b/hw/misc/xlnx-versal-cfu.c @@ -532,7 +532,7 @@ static const TypeInfo cfu_apb_info = { .instance_size = sizeof(XlnxVersalCFUAPB), .class_init = cfu_apb_class_init, .instance_init = cfu_apb_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XLNX_CFI_IF }, { } } @@ -545,7 +545,7 @@ static const TypeInfo cfu_fdro_info = { .class_init = cfu_fdro_class_init, .instance_init = cfu_fdro_init, .instance_finalize = cfu_fdro_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XLNX_CFI_IF }, { } } diff --git a/hw/net/can/can_kvaser_pci.c b/hw/net/can/can_kvaser_pci.c index c0bb598bae..be16769de2 100644 --- a/hw/net/can/can_kvaser_pci.c +++ b/hw/net/can/can_kvaser_pci.c @@ -305,7 +305,7 @@ static const TypeInfo kvaser_pci_info = { .instance_size = sizeof(KvaserPCIState), .class_init = kvaser_pci_class_init, .instance_init = kvaser_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/can_mioe3680_pci.c b/hw/net/can/can_mioe3680_pci.c index 9aac70dccd..44f3ba370d 100644 --- a/hw/net/can/can_mioe3680_pci.c +++ b/hw/net/can/can_mioe3680_pci.c @@ -248,7 +248,7 @@ static const TypeInfo mioe3680_pci_info = { .instance_size = sizeof(Mioe3680PCIState), .class_init = mioe3680_pci_class_init, .instance_init = mioe3680_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/can_pcm3680_pci.c b/hw/net/can/can_pcm3680_pci.c index b305f7e9b7..7296d63be7 100644 --- a/hw/net/can/can_pcm3680_pci.c +++ b/hw/net/can/can_pcm3680_pci.c @@ -249,7 +249,7 @@ static const TypeInfo pcm3680i_pci_info = { .instance_size = sizeof(Pcm3680iPCIState), .class_init = pcm3680i_pci_class_init, .instance_init = pcm3680i_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/can/ctucan_pci.c b/hw/net/can/ctucan_pci.c index 0dee9b59d1..bed6785433 100644 --- a/hw/net/can/ctucan_pci.c +++ b/hw/net/can/ctucan_pci.c @@ -262,7 +262,7 @@ static const TypeInfo ctucan_pci_info = { .instance_size = sizeof(CtuCanPCIState), .class_init = ctucan_pci_class_init, .instance_init = ctucan_pci_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 13814e84d1..cba4999e6d 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -1732,7 +1732,7 @@ static const TypeInfo e1000_base_info = { .instance_init = e1000_instance_init, .class_size = sizeof(E1000BaseClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index f38249a6a9..89e6d52ba0 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -721,7 +721,7 @@ static const TypeInfo e1000e_info = { .instance_size = sizeof(E1000EState), .class_init = e1000e_class_init, .instance_init = e1000e_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/eepro100.c b/hw/net/eepro100.c index ef0f9337a0..d47df5a97f 100644 --- a/hw/net/eepro100.c +++ b/hw/net/eepro100.c @@ -2094,7 +2094,7 @@ static void eepro100_register_types(void) type_info.class_init = eepro100_class_init; type_info.instance_size = sizeof(EEPRO100State); type_info.instance_init = eepro100_instance_init; - type_info.interfaces = (InterfaceInfo[]) { + type_info.interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }; diff --git a/hw/net/igb.c b/hw/net/igb.c index ba30433a50..e4c02365d6 100644 --- a/hw/net/igb.c +++ b/hw/net/igb.c @@ -635,7 +635,7 @@ static const TypeInfo igb_info = { .instance_size = sizeof(IGBState), .class_init = igb_class_init, .instance_init = igb_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/igbvf.c b/hw/net/igbvf.c index 91e7ccf931..31d72c4977 100644 --- a/hw/net/igbvf.c +++ b/hw/net/igbvf.c @@ -325,7 +325,7 @@ static const TypeInfo igbvf_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(IgbVfState), .class_init = igbvf_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/net/ne2000-pci.c b/hw/net/ne2000-pci.c index 2153973af4..ce937e1b61 100644 --- a/hw/net/ne2000-pci.c +++ b/hw/net/ne2000-pci.c @@ -122,7 +122,7 @@ static const TypeInfo ne2000_info = { .instance_size = sizeof(PCINE2000State), .class_init = ne2000_class_init, .instance_init = ne2000_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/pcnet-pci.c b/hw/net/pcnet-pci.c index 429c217180..0ca5bc2193 100644 --- a/hw/net/pcnet-pci.c +++ b/hw/net/pcnet-pci.c @@ -280,7 +280,7 @@ static const TypeInfo pcnet_info = { .instance_size = sizeof(PCIPCNetState), .class_init = pcnet_class_init, .instance_init = pcnet_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/rocker/rocker.c b/hw/net/rocker/rocker.c index 3d307f4ab1..cc49701dd3 100644 --- a/hw/net/rocker/rocker.c +++ b/hw/net/rocker/rocker.c @@ -1498,7 +1498,7 @@ static const TypeInfo rocker_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(Rocker), .class_init = rocker_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index ad812954cf..15b8f7501a 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -3438,7 +3438,7 @@ static const TypeInfo rtl8139_info = { .instance_size = sizeof(RTL8139State), .class_init = rtl8139_class_init, .instance_init = rtl8139_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 123d08ee8e..b405eb89fa 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -1477,7 +1477,7 @@ static const TypeInfo sungem_info = { .instance_size = sizeof(SunGEMState), .class_init = sungem_class_init, .instance_init = sungem_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index 46c9f5020b..c2f7a8483d 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -958,7 +958,7 @@ static const TypeInfo sunhme_info = { .class_init = sunhme_class_init, .instance_size = sizeof(SunHMEState), .instance_init = sunhme_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } } diff --git a/hw/net/tulip.c b/hw/net/tulip.c index fb3366d8ee..63fe513458 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -1035,7 +1035,7 @@ static const TypeInfo tulip_info = { .instance_size = sizeof(TULIPState), .class_init = tulip_class_init, .instance_init = tulip_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 4bcf1f902f..83d942af17 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2522,7 +2522,7 @@ static const TypeInfo vmxnet3_info = { .instance_size = sizeof(VMXNET3State), .class_init = vmxnet3_class_init, .instance_init = vmxnet3_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/net/xilinx_axienet.c b/hw/net/xilinx_axienet.c index e45bc048e0..1f5c748047 100644 --- a/hw/net/xilinx_axienet.c +++ b/hw/net/xilinx_axienet.c @@ -1045,7 +1045,7 @@ static const TypeInfo xilinx_enet_data_stream_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(XilinxAXIEnetStreamSink), .class_init = xilinx_enet_data_stream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } @@ -1056,7 +1056,7 @@ static const TypeInfo xilinx_enet_control_stream_info = { .parent = TYPE_OBJECT, .instance_size = sizeof(XilinxAXIEnetStreamSink), .class_init = xilinx_enet_control_stream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_STREAM_SINK }, { } } diff --git a/hw/nvme/ctrl.c b/hw/nvme/ctrl.c index e87295f5f8..fd935507bc 100644 --- a/hw/nvme/ctrl.c +++ b/hw/nvme/ctrl.c @@ -9221,7 +9221,7 @@ static const TypeInfo nvme_info = { .instance_size = sizeof(NvmeCtrl), .instance_init = nvme_instance_init, .class_init = nvme_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci-bridge/cxl_downstream.c b/hw/pci-bridge/cxl_downstream.c index ab3b550a88..1065245a8b 100644 --- a/hw/pci-bridge/cxl_downstream.c +++ b/hw/pci-bridge/cxl_downstream.c @@ -241,7 +241,7 @@ static const TypeInfo cxl_dsp_info = { .instance_size = sizeof(CXLDownstreamPort), .parent = TYPE_PCIE_SLOT, .class_init = cxl_dsp_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CXL_DEVICE }, { } diff --git a/hw/pci-bridge/cxl_root_port.c b/hw/pci-bridge/cxl_root_port.c index 8b1e149e9b..e6a4035d26 100644 --- a/hw/pci-bridge/cxl_root_port.c +++ b/hw/pci-bridge/cxl_root_port.c @@ -294,7 +294,7 @@ static const TypeInfo cxl_root_port_info = { .parent = TYPE_PCIE_ROOT_PORT, .instance_size = sizeof(CXLRootPort), .class_init = cxl_root_port_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CXL_DEVICE }, { } }, diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c index 822a828555..208e0c6172 100644 --- a/hw/pci-bridge/cxl_upstream.c +++ b/hw/pci-bridge/cxl_upstream.c @@ -394,7 +394,7 @@ static const TypeInfo cxl_usp_info = { .parent = TYPE_PCIE_PORT, .instance_size = sizeof(CXLUpstreamPort), .class_init = cxl_upstream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CXL_DEVICE }, { } diff --git a/hw/pci-bridge/i82801b11.c b/hw/pci-bridge/i82801b11.c index f2b294aee2..1d73c14c1f 100644 --- a/hw/pci-bridge/i82801b11.c +++ b/hw/pci-bridge/i82801b11.c @@ -107,7 +107,7 @@ static const TypeInfo i82801b11_bridge_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(I82801b11Bridge), .class_init = i82801b11_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-bridge/pci_bridge_dev.c b/hw/pci-bridge/pci_bridge_dev.c index 3b57583199..b328e50ab3 100644 --- a/hw/pci-bridge/pci_bridge_dev.c +++ b/hw/pci-bridge/pci_bridge_dev.c @@ -268,7 +268,7 @@ static const TypeInfo pci_bridge_dev_info = { .instance_size = sizeof(PCIBridgeDev), .class_init = pci_bridge_dev_class_init, .instance_finalize = pci_bridge_dev_instance_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/pci-bridge/pci_expander_bridge.c b/hw/pci-bridge/pci_expander_bridge.c index 1e2e394ee8..3a29dfefc2 100644 --- a/hw/pci-bridge/pci_expander_bridge.c +++ b/hw/pci-bridge/pci_expander_bridge.c @@ -449,7 +449,7 @@ static const TypeInfo pxb_dev_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PXBDev), .class_init = pxb_dev_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -486,7 +486,7 @@ static const TypeInfo pxb_pcie_dev_info = { .parent = TYPE_PXB_DEV, .instance_size = sizeof(PXBPCIEDev), .class_init = pxb_pcie_dev_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -537,7 +537,7 @@ static const TypeInfo pxb_cxl_dev_info = { .instance_size = sizeof(PXBCXLDev), .class_init = pxb_cxl_dev_class_init, .interfaces = - (InterfaceInfo[]){ + (const InterfaceInfo[]){ { INTERFACE_CONVENTIONAL_PCI_DEVICE }, {}, }, diff --git a/hw/pci-bridge/pcie_pci_bridge.c b/hw/pci-bridge/pcie_pci_bridge.c index 833fe35cd5..fce292a519 100644 --- a/hw/pci-bridge/pcie_pci_bridge.c +++ b/hw/pci-bridge/pcie_pci_bridge.c @@ -162,7 +162,7 @@ static const TypeInfo pcie_pci_bridge_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(PCIEPCIBridge), .class_init = pcie_pci_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { INTERFACE_PCIE_DEVICE }, { }, diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index 512c2ab305..22c2fdb71e 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -188,7 +188,7 @@ static const TypeInfo rp_info = { .class_init = rp_class_init, .abstract = true, .class_size = sizeof(PCIERootPortClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci-bridge/simba.c b/hw/pci-bridge/simba.c index c7565d9e94..bbae594e11 100644 --- a/hw/pci-bridge/simba.c +++ b/hw/pci-bridge/simba.c @@ -87,7 +87,7 @@ static const TypeInfo simba_pci_bridge_info = { .parent = TYPE_PCI_BRIDGE, .class_init = simba_pci_bridge_class_init, .instance_size = sizeof(SimbaPCIBridge), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index d85c23fe4a..dc7d1aa7d7 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -175,7 +175,7 @@ static const TypeInfo xio3130_downstream_info = { .name = TYPE_XIO3130_DOWNSTREAM, .parent = TYPE_PCIE_SLOT, .class_init = xio3130_downstream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci-bridge/xio3130_upstream.c b/hw/pci-bridge/xio3130_upstream.c index d7a2715812..40057b749b 100644 --- a/hw/pci-bridge/xio3130_upstream.c +++ b/hw/pci-bridge/xio3130_upstream.c @@ -144,7 +144,7 @@ static const TypeInfo xio3130_upstream_info = { .name = "x3130-upstream", .parent = TYPE_PCIE_PORT, .class_init = xio3130_upstream_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c index 043fb85e84..cc65aac2a8 100644 --- a/hw/pci-host/articia.c +++ b/hw/pci-host/articia.c @@ -273,7 +273,7 @@ static const TypeInfo articia_types[] = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(ArticiaHostState), .class_init = articia_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -283,7 +283,7 @@ static const TypeInfo articia_types[] = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = articia_pci_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/bonito.c b/hw/pci-host/bonito.c index 4508cdd21a..7d6251a78d 100644 --- a/hw/pci-host/bonito.c +++ b/hw/pci-host/bonito.c @@ -783,7 +783,7 @@ static const TypeInfo bonito_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIBonitoState), .class_init = bonito_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/designware.c b/hw/pci-host/designware.c index d03c998e3a..183f838392 100644 --- a/hw/pci-host/designware.c +++ b/hw/pci-host/designware.c @@ -769,7 +769,7 @@ static const TypeInfo designware_pcie_types[] = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(DesignwarePCIERoot), .class_init = designware_pcie_root_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci-host/gpex.c b/hw/pci-host/gpex.c index 7dcac4ee3c..b806a2286f 100644 --- a/hw/pci-host/gpex.c +++ b/hw/pci-host/gpex.c @@ -261,7 +261,7 @@ static const TypeInfo gpex_root_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(GPEXRootState), .class_init = gpex_root_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/grackle.c b/hw/pci-host/grackle.c index b48d44623d..f9da5a908c 100644 --- a/hw/pci-host/grackle.c +++ b/hw/pci-host/grackle.c @@ -116,7 +116,7 @@ static const TypeInfo grackle_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = grackle_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c index bd74b6e871..56a6ef93b7 100644 --- a/hw/pci-host/gt64120.c +++ b/hw/pci-host/gt64120.c @@ -1268,7 +1268,7 @@ static const TypeInfo gt64120_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = gt64120_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/i440fx.c b/hw/pci-host/i440fx.c index fcc9f3818a..e13bb1b53e 100644 --- a/hw/pci-host/i440fx.c +++ b/hw/pci-host/i440fx.c @@ -341,7 +341,7 @@ static const TypeInfo i440fx_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCII440FXState), .class_init = i440fx_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/mv64361.c b/hw/pci-host/mv64361.c index f51f385b22..e05b677010 100644 --- a/hw/pci-host/mv64361.c +++ b/hw/pci-host/mv64361.c @@ -46,7 +46,7 @@ static const TypeInfo mv64361_pcibridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = mv64361_pcibridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/pnv_phb3_pbcq.c b/hw/pci-host/pnv_phb3_pbcq.c index 4e24b1449d..1f7a149580 100644 --- a/hw/pci-host/pnv_phb3_pbcq.c +++ b/hw/pci-host/pnv_phb3_pbcq.c @@ -354,7 +354,7 @@ static const TypeInfo pnv_pbcq_type_info = { .instance_size = sizeof(PnvPBCQState), .instance_init = phb3_pbcq_instance_init, .class_init = pnv_pbcq_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/pci-host/pnv_phb4.c b/hw/pci-host/pnv_phb4.c index feb812dc1a..77ea35299d 100644 --- a/hw/pci-host/pnv_phb4.c +++ b/hw/pci-host/pnv_phb4.c @@ -1714,7 +1714,7 @@ static const TypeInfo pnv_phb4_type_info = { .instance_init = pnv_phb4_instance_init, .instance_size = sizeof(PnvPHB4), .class_init = pnv_phb4_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_NOTIFIER }, { }, } diff --git a/hw/pci-host/pnv_phb4_pec.c b/hw/pci-host/pnv_phb4_pec.c index cc46641cdf..5bac1c42ed 100644 --- a/hw/pci-host/pnv_phb4_pec.c +++ b/hw/pci-host/pnv_phb4_pec.c @@ -388,7 +388,7 @@ static const TypeInfo pnv_pec_type_info = { .instance_size = sizeof(PnvPhb4PecState), .class_init = pnv_pec_class_init, .class_size = sizeof(PnvPhb4PecClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } @@ -445,7 +445,7 @@ static const TypeInfo pnv_phb5_pec_type_info = { .instance_size = sizeof(PnvPhb4PecState), .class_init = pnv_phb5_pec_class_init, .class_size = sizeof(PnvPhb4PecClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/pci-host/ppc4xx_pci.c b/hw/pci-host/ppc4xx_pci.c index dcc4b78660..2547817688 100644 --- a/hw/pci-host/ppc4xx_pci.c +++ b/hw/pci-host/ppc4xx_pci.c @@ -370,7 +370,7 @@ static const TypeInfo ppc4xx_host_bridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = ppc4xx_host_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/ppce500.c b/hw/pci-host/ppce500.c index 2f6354c931..e97a515d5f 100644 --- a/hw/pci-host/ppce500.c +++ b/hw/pci-host/ppce500.c @@ -528,7 +528,7 @@ static const TypeInfo e500_pci_types[] = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PPCE500PCIBridgeState), .class_init = e500_host_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c index c2a71108f2..1951ae440c 100644 --- a/hw/pci-host/q35.c +++ b/hw/pci-host/q35.c @@ -703,7 +703,7 @@ static const TypeInfo mch_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MCHPCIState), .class_init = mch_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/raven.c b/hw/pci-host/raven.c index 3f158838a0..21f7ca65e0 100644 --- a/hw/pci-host/raven.c +++ b/hw/pci-host/raven.c @@ -416,7 +416,7 @@ static const TypeInfo raven_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(RavenPCIState), .class_init = raven_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/sabre.c b/hw/pci-host/sabre.c index f7086086f9..538624c507 100644 --- a/hw/pci-host/sabre.c +++ b/hw/pci-host/sabre.c @@ -477,7 +477,7 @@ static const TypeInfo sabre_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(SabrePCIState), .class_init = sabre_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/sh_pci.c b/hw/pci-host/sh_pci.c index 52bff66d6a..de8f6a84aa 100644 --- a/hw/pci-host/sh_pci.c +++ b/hw/pci-host/sh_pci.c @@ -186,7 +186,7 @@ static const TypeInfo sh_pcic_types[] = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = sh_pcic_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/uninorth.c b/hw/pci-host/uninorth.c index 7cb37e01d8..194037d6e7 100644 --- a/hw/pci-host/uninorth.c +++ b/hw/pci-host/uninorth.c @@ -333,7 +333,7 @@ static const TypeInfo unin_main_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_main_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -361,7 +361,7 @@ static const TypeInfo u3_agp_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = u3_agp_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -389,7 +389,7 @@ static const TypeInfo unin_agp_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_agp_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -418,7 +418,7 @@ static const TypeInfo unin_internal_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = unin_internal_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/versatile.c b/hw/pci-host/versatile.c index b333158e10..8ea26e3ff0 100644 --- a/hw/pci-host/versatile.c +++ b/hw/pci-host/versatile.c @@ -492,7 +492,7 @@ static const TypeInfo versatile_pci_host_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = versatile_pci_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/pci-host/xilinx-pcie.c b/hw/pci-host/xilinx-pcie.c index 70e9b2b981..c71492de9e 100644 --- a/hw/pci-host/xilinx-pcie.c +++ b/hw/pci-host/xilinx-pcie.c @@ -314,7 +314,7 @@ static const TypeInfo xilinx_pcie_root_info = { .parent = TYPE_PCI_BRIDGE, .instance_size = sizeof(XilinxPCIERoot), .class_init = xilinx_pcie_root_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/pci/pci.c b/hw/pci/pci.c index c60991def8..fe38c4c028 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -288,7 +288,7 @@ static const TypeInfo pci_bus_info = { .instance_size = sizeof(PCIBus), .class_size = sizeof(PCIBusClass), .class_init = pci_bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_CFG_DATA_GENERATOR_INTERFACE }, { } } diff --git a/hw/pci/pci_bridge.c b/hw/pci/pci_bridge.c index 0fe66e8b12..76255c4cd8 100644 --- a/hw/pci/pci_bridge.c +++ b/hw/pci/pci_bridge.c @@ -497,7 +497,7 @@ static const TypeInfo pci_bridge_type_info = { .instance_size = sizeof(PCIBridge), .class_init = pci_bridge_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/pci/pcie_port.c b/hw/pci/pcie_port.c index 8629b3aafd..54f639e3d4 100644 --- a/hw/pci/pcie_port.c +++ b/hw/pci/pcie_port.c @@ -230,7 +230,7 @@ static const TypeInfo pcie_slot_type_info = { .instance_size = sizeof(PCIESlot), .abstract = true, .class_init = pcie_slot_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index cd594eeb3e..775b9d8da0 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -107,7 +107,7 @@ static const TypeInfo e500plat_info = { .name = TYPE_E500PLAT_MACHINE, .parent = TYPE_PPCE500_MACHINE, .class_init = e500plat_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 92fe60b2a2..0b6e096116 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -639,7 +639,7 @@ static const TypeInfo core99_machine_info = { .class_init = core99_machine_class_init, .instance_init = core99_instance_init, .instance_size = sizeof(Core99MachineState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } }, diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 5c5bf99b4d..40ae936ad8 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -430,7 +430,7 @@ static const TypeInfo ppc_heathrow_machine_info = { .name = MACHINE_TYPE_NAME("g3beige"), .parent = TYPE_MACHINE, .class_init = heathrow_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } }, diff --git a/hw/ppc/pegasos2.c b/hw/ppc/pegasos2.c index bb6f94f502..e15cf96427 100644 --- a/hw/ppc/pegasos2.c +++ b/hw/ppc/pegasos2.c @@ -619,7 +619,7 @@ static const TypeInfo pegasos2_machine_info = { .parent = TYPE_MACHINE, .class_init = pegasos2_machine_class_init, .instance_size = sizeof(Pegasos2MachineState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PPC_VIRTUAL_HYPERVISOR }, { TYPE_VOF_MACHINE_IF }, { } diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 4590231f88..4a49e9d1a8 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -2973,7 +2973,7 @@ static const TypeInfo types[] = { .name = MACHINE_TYPE_NAME("powernv10"), .parent = TYPE_PNV_MACHINE, .class_init = pnv_machine_power10_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_FABRIC }, { }, }, @@ -2982,7 +2982,7 @@ static const TypeInfo types[] = { .name = MACHINE_TYPE_NAME("powernv9"), .parent = TYPE_PNV_MACHINE, .class_init = pnv_machine_power9_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_FABRIC }, { }, }, @@ -2991,7 +2991,7 @@ static const TypeInfo types[] = { .name = MACHINE_TYPE_NAME("powernv8"), .parent = TYPE_PNV_MACHINE, .class_init = pnv_machine_power8_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XICS_FABRIC }, { }, }, @@ -3003,7 +3003,7 @@ static const TypeInfo types[] = { .instance_size = sizeof(PnvMachineState), .class_init = pnv_machine_class_init, .class_size = sizeof(PnvMachineClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { TYPE_NMI }, { }, diff --git a/hw/ppc/pnv_adu.c b/hw/ppc/pnv_adu.c index f9620806ec..005fbda475 100644 --- a/hw/ppc/pnv_adu.c +++ b/hw/ppc/pnv_adu.c @@ -204,7 +204,7 @@ static const TypeInfo pnv_adu_type_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(PnvADU), .class_init = pnv_adu_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } }, }; diff --git a/hw/ppc/pnv_chiptod.c b/hw/ppc/pnv_chiptod.c index 4ca511a4de..b9e9c7ba3d 100644 --- a/hw/ppc/pnv_chiptod.c +++ b/hw/ppc/pnv_chiptod.c @@ -478,7 +478,7 @@ static const TypeInfo pnv_chiptod_power9_type_info = { .parent = TYPE_PNV_CHIPTOD, .instance_size = sizeof(PnvChipTOD), .class_init = pnv_chiptod_power9_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } @@ -514,7 +514,7 @@ static const TypeInfo pnv_chiptod_power10_type_info = { .parent = TYPE_PNV_CHIPTOD, .instance_size = sizeof(PnvChipTOD), .class_init = pnv_chiptod_power10_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/pnv_i2c.c b/hw/ppc/pnv_i2c.c index b2f372c874..60de479491 100644 --- a/hw/ppc/pnv_i2c.c +++ b/hw/ppc/pnv_i2c.c @@ -569,7 +569,7 @@ static const TypeInfo pnv_i2c_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(PnvI2C), .class_init = pnv_i2c_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/pnv_lpc.c b/hw/ppc/pnv_lpc.c index d92347bcd2..f6beba0917 100644 --- a/hw/ppc/pnv_lpc.c +++ b/hw/ppc/pnv_lpc.c @@ -732,7 +732,7 @@ static const TypeInfo pnv_lpc_power8_info = { .name = TYPE_PNV8_LPC, .parent = TYPE_PNV_LPC, .class_init = pnv_lpc_power8_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/pnv_n1_chiplet.c b/hw/ppc/pnv_n1_chiplet.c index 05e3fd6f73..053f6473f2 100644 --- a/hw/ppc/pnv_n1_chiplet.c +++ b/hw/ppc/pnv_n1_chiplet.c @@ -159,7 +159,7 @@ static const TypeInfo pnv_n1_chiplet_info = { .instance_init = pnv_n1_chiplet_instance_init, .instance_size = sizeof(PnvN1Chiplet), .class_init = pnv_n1_chiplet_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/pnv_nest_pervasive.c b/hw/ppc/pnv_nest_pervasive.c index b5182d54fa..1b1b14fed9 100644 --- a/hw/ppc/pnv_nest_pervasive.c +++ b/hw/ppc/pnv_nest_pervasive.c @@ -194,7 +194,7 @@ static const TypeInfo pnv_nest_pervasive_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(PnvNestChipletPervasive), .class_init = pnv_nest_pervasive_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/pnv_psi.c b/hw/ppc/pnv_psi.c index 0fd247e6ad..5d947d8b52 100644 --- a/hw/ppc/pnv_psi.c +++ b/hw/ppc/pnv_psi.c @@ -913,7 +913,7 @@ static const TypeInfo pnv_psi_power9_info = { .instance_size = sizeof(Pnv9Psi), .instance_init = pnv_psi_power9_instance_init, .class_init = pnv_psi_power9_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_XIVE_NOTIFIER }, { }, }, @@ -959,7 +959,7 @@ static const TypeInfo pnv_psi_info = { .class_init = pnv_psi_class_init, .class_size = sizeof(PnvPsiClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 02663851ae..702f774cda 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -4717,7 +4717,7 @@ static const TypeInfo spapr_machine_info = { .instance_finalize = spapr_machine_finalizefn, .class_size = sizeof(SpaprMachineClass), .class_init = spapr_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { TYPE_NMI }, { TYPE_HOTPLUG_HANDLER }, diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index d0468e3fe6..1ac1185825 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -2200,7 +2200,7 @@ static const TypeInfo spapr_phb_info = { .instance_size = sizeof(SpaprPhbState), .instance_finalize = spapr_phb_finalizefn, .class_init = spapr_phb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/remote/machine.c b/hw/remote/machine.c index 9fb92ec6f1..e4b47838ba 100644 --- a/hw/remote/machine.c +++ b/hw/remote/machine.c @@ -146,7 +146,7 @@ static const TypeInfo remote_machine = { .instance_size = sizeof(RemoteMachineState), .instance_init = remote_machine_instance_init, .class_init = remote_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/remote/proxy.c b/hw/remote/proxy.c index d2de48c9e3..b0165aa2a1 100644 --- a/hw/remote/proxy.c +++ b/hw/remote/proxy.c @@ -215,7 +215,7 @@ static const TypeInfo pci_proxy_dev_type_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIProxyDev), .class_init = pci_proxy_dev_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/remote/remote-obj.c b/hw/remote/remote-obj.c index 75f8d6df8a..85882902d7 100644 --- a/hw/remote/remote-obj.c +++ b/hw/remote/remote-obj.c @@ -188,7 +188,7 @@ static const TypeInfo remote_object_info = { .instance_finalize = remote_object_finalize, .class_size = sizeof(RemoteObjectClass), .class_init = remote_object_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/hw/remote/vfio-user-obj.c b/hw/remote/vfio-user-obj.c index b0ae403f06..ea6165ebdc 100644 --- a/hw/remote/vfio-user-obj.c +++ b/hw/remote/vfio-user-obj.c @@ -944,7 +944,7 @@ static const TypeInfo vfu_object_info = { .instance_finalize = vfu_object_finalize, .class_size = sizeof(VfuObjectClass), .class_init = vfu_object_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/hw/riscv/riscv-iommu-pci.c b/hw/riscv/riscv-iommu-pci.c index d93cf7521b..1f44eef74e 100644 --- a/hw/riscv/riscv-iommu-pci.c +++ b/hw/riscv/riscv-iommu-pci.c @@ -209,7 +209,7 @@ static const TypeInfo riscv_iommu_pci = { .class_init = riscv_iommu_pci_class_init, .instance_init = riscv_iommu_pci_init, .instance_size = sizeof(RISCVIOMMUStatePci), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { }, }, diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 557efd15a1..be1bf0f646 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1980,7 +1980,7 @@ static const TypeInfo virt_machine_typeinfo = { .class_init = virt_machine_class_init, .instance_init = virt_machine_instance_init, .instance_size = sizeof(RISCVVirtState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c index 4a7c0af9f0..9e2f6563a0 100644 --- a/hw/rtc/m48t59-isa.c +++ b/hw/rtc/m48t59-isa.c @@ -140,7 +140,7 @@ static const TypeInfo m48txx_isa_type_info = { .instance_size = sizeof(M48txxISAState), .abstract = true, .class_init = m48txx_isa_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NVRAM }, { } } diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c index 821472a680..68be2dad6f 100644 --- a/hw/rtc/m48t59.c +++ b/hw/rtc/m48t59.c @@ -658,7 +658,7 @@ static const TypeInfo m48txx_sysbus_type_info = { .instance_init = m48t59_init1, .abstract = true, .class_init = m48txx_sysbus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NVRAM }, { } } diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 93b632bdf4..6f787be7af 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -1038,7 +1038,7 @@ static const TypeInfo mc146818rtc_info = { .parent = TYPE_ISA_DEVICE, .instance_size = sizeof(MC146818RtcState), .class_init = rtc_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_ACPI_DEV_AML_IF }, { }, }, diff --git a/hw/s390x/ap-bridge.c b/hw/s390x/ap-bridge.c index 4aa7d5a90d..edeb3dbef3 100644 --- a/hw/s390x/ap-bridge.c +++ b/hw/s390x/ap-bridge.c @@ -75,7 +75,7 @@ static const TypeInfo ap_bridge_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = 0, .class_init = ap_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index 9d91e5a5fe..0f87b8c5c4 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -136,7 +136,7 @@ static const TypeInfo virtual_css_bridge_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(VirtualCssBridge), .class_init = virtual_css_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 838b7e6484..e6aa44531f 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -1393,7 +1393,7 @@ static const TypeInfo s390_pcihost_info = { .parent = TYPE_PCI_HOST_BRIDGE, .instance_size = sizeof(S390pciState), .class_init = s390_pcihost_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 00e9e46aef..94edd42dd2 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -875,7 +875,7 @@ static const TypeInfo ccw_machine_info = { .instance_init = s390_machine_initfn, .class_size = sizeof(S390CcwMachineClass), .class_init = ccw_machine_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_NMI }, { TYPE_HOTPLUG_HANDLER}, { TYPE_DUMP_SKEYS_INTERFACE}, diff --git a/hw/s390x/virtio-ccw-md.c b/hw/s390x/virtio-ccw-md.c index de333282df..0370f58450 100644 --- a/hw/s390x/virtio-ccw-md.c +++ b/hw/s390x/virtio-ccw-md.c @@ -140,7 +140,7 @@ static const TypeInfo virtio_ccw_md_info = { .instance_size = sizeof(VirtIOMDCcw), .class_size = sizeof(VirtIOMDCcwClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_MEMORY_DEVICE }, { } }, diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c index 74e9af0b5d..12c86eb7aa 100644 --- a/hw/scsi/esp-pci.c +++ b/hw/scsi/esp-pci.c @@ -450,7 +450,7 @@ static const TypeInfo esp_pci_info = { .instance_init = esp_pci_init, .instance_size = sizeof(PCIESPState), .class_init = esp_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 0ad61565bf..f4f2ef321e 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -2396,7 +2396,7 @@ static const TypeInfo lsi_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(LSIState), .class_init = lsi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c index a39e3e0e4f..55cd188bd5 100644 --- a/hw/scsi/megasas.c +++ b/hw/scsi/megasas.c @@ -2503,7 +2503,7 @@ static struct MegasasInfo megasas_devices[] = { .vmsd = &vmstate_megasas_gen1, .props = megasas_properties_gen1, .props_count = ARRAY_SIZE(megasas_properties_gen1), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -2520,7 +2520,7 @@ static struct MegasasInfo megasas_devices[] = { .vmsd = &vmstate_megasas_gen2, .props = megasas_properties_gen2, .props_count = ARRAY_SIZE(megasas_properties_gen2), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { } }, diff --git a/hw/scsi/mptsas.c b/hw/scsi/mptsas.c index 17f73ce381..1ebe0b82a7 100644 --- a/hw/scsi/mptsas.c +++ b/hw/scsi/mptsas.c @@ -1441,7 +1441,7 @@ static const TypeInfo mptsas_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MPTSASState), .class_init = mptsas1068_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 0456b4de0a..70be4a7367 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -2046,7 +2046,7 @@ static const TypeInfo scsi_bus_info = { .parent = TYPE_BUS, .instance_size = sizeof(SCSIBus), .class_init = scsi_bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index be5a416c1d..10fde8eee0 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -397,7 +397,7 @@ static const TypeInfo vhost_scsi_info = { .instance_size = sizeof(VHostSCSI), .class_init = vhost_scsi_class_init, .instance_init = vhost_scsi_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } }, diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 807a58ecf4..8298e8cc6d 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -422,7 +422,7 @@ static const TypeInfo vhost_user_scsi_info = { .instance_size = sizeof(VHostUserSCSI), .class_init = vhost_user_scsi_class_init, .instance_init = vhost_user_scsi_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } }, diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index ae67a7682a..34ae14f7bf 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -1438,7 +1438,7 @@ static const TypeInfo virtio_scsi_info = { .parent = TYPE_VIRTIO_SCSI_COMMON, .instance_size = sizeof(VirtIOSCSI), .class_init = virtio_scsi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index a8ea57ffad..d5825b6786 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1346,7 +1346,7 @@ static const TypeInfo pvscsi_info = { .class_size = sizeof(PVSCSIClass), .instance_size = sizeof(PVSCSIState), .class_init = pvscsi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, diff --git a/hw/sd/sdhci-pci.c b/hw/sd/sdhci-pci.c index 2a56fbf2cd..c18b91fe63 100644 --- a/hw/sd/sdhci-pci.c +++ b/hw/sd/sdhci-pci.c @@ -75,7 +75,7 @@ static const TypeInfo sdhci_pci_types[] = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(SDHCIState), .class_init = sdhci_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c index 0e5fb4e1b5..e9f9b0a4cb 100644 --- a/hw/sparc64/sun4u.c +++ b/hw/sparc64/sun4u.c @@ -391,7 +391,7 @@ static const TypeInfo ebus_info = { .parent = TYPE_PCI_DEVICE, .class_init = ebus_class_init, .instance_size = sizeof(EbusState), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, @@ -811,7 +811,7 @@ static const TypeInfo sun4u_type = { .name = MACHINE_TYPE_NAME("sun4u"), .parent = TYPE_MACHINE, .class_init = sun4u_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_FW_PATH_PROVIDER }, { } }, diff --git a/hw/ssi/pnv_spi.c b/hw/ssi/pnv_spi.c index 0bb6b0d935..f40e8836b9 100644 --- a/hw/ssi/pnv_spi.c +++ b/hw/ssi/pnv_spi.c @@ -1217,7 +1217,7 @@ static const TypeInfo pnv_spi_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(PnvSpi), .class_init = pnv_spi_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_PNV_XSCOM_INTERFACE }, { } } diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c index 9aff4d1a6f..bc7a78f898 100644 --- a/hw/tpm/tpm_crb.c +++ b/hw/tpm/tpm_crb.c @@ -337,7 +337,7 @@ static const TypeInfo tpm_crb_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(CRBState), .class_init = tpm_crb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c index 1cad9a88ea..ea608ba4c8 100644 --- a/hw/tpm/tpm_spapr.c +++ b/hw/tpm/tpm_spapr.c @@ -414,7 +414,7 @@ static const TypeInfo tpm_spapr_info = { .parent = TYPE_VIO_SPAPR_DEVICE, .instance_size = sizeof(SpaprTpmState), .class_init = tpm_spapr_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } diff --git a/hw/tpm/tpm_tis_i2c.c b/hw/tpm/tpm_tis_i2c.c index b97d768a5b..5ce84dc7a4 100644 --- a/hw/tpm/tpm_tis_i2c.c +++ b/hw/tpm/tpm_tis_i2c.c @@ -552,7 +552,7 @@ static const TypeInfo tpm_tis_i2c_info = { .parent = TYPE_I2C_SLAVE, .instance_size = sizeof(TPMStateI2C), .class_init = tpm_tis_i2c_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c index c0098a26e8..dce83057a9 100644 --- a/hw/tpm/tpm_tis_isa.c +++ b/hw/tpm/tpm_tis_isa.c @@ -189,7 +189,7 @@ static const TypeInfo tpm_tis_isa_info = { .instance_size = sizeof(TPMStateISA), .instance_init = tpm_tis_isa_initfn, .class_init = tpm_tis_isa_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { TYPE_ACPI_DEV_AML_IF }, { } diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c index 19abf0b948..2ffa85852a 100644 --- a/hw/tpm/tpm_tis_sysbus.c +++ b/hw/tpm/tpm_tis_sysbus.c @@ -145,7 +145,7 @@ static const TypeInfo tpm_tis_sysbus_info = { .instance_size = sizeof(TPMStateSysBus), .instance_init = tpm_tis_sysbus_initfn, .class_init = tpm_tis_sysbus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } diff --git a/hw/ufs/ufs.c b/hw/ufs/ufs.c index 749519760f..0577747f46 100644 --- a/hw/ufs/ufs.c +++ b/hw/ufs/ufs.c @@ -1892,7 +1892,7 @@ static const TypeInfo ufs_info = { .parent = TYPE_PCI_DEVICE, .class_init = ufs_class_init, .instance_size = sizeof(UfsHc), - .interfaces = (InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} }, + .interfaces = (const InterfaceInfo[]){ { INTERFACE_PCIE_DEVICE }, {} }, }; static const TypeInfo ufs_bus_info = { diff --git a/hw/usb/bus.c b/hw/usb/bus.c index d8446cf50e..8dd2ce415e 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -42,7 +42,7 @@ static const TypeInfo usb_bus_info = { .parent = TYPE_BUS, .instance_size = sizeof(USBBus), .class_init = usb_bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/usb/dev-smartcard-reader.c b/hw/usb/dev-smartcard-reader.c index 87018a3f01..6ce7154fee 100644 --- a/hw/usb/dev-smartcard-reader.c +++ b/hw/usb/dev-smartcard-reader.c @@ -1458,7 +1458,7 @@ static const TypeInfo ccid_info = { .parent = TYPE_USB_DEVICE, .instance_size = sizeof(USBCCIDState), .class_init = ccid_class_initfn, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c index 73122aa797..38ad3406b3 100644 --- a/hw/usb/hcd-ehci-pci.c +++ b/hw/usb/hcd-ehci-pci.c @@ -172,7 +172,7 @@ static const TypeInfo ehci_pci_type_info = { .instance_finalize = usb_ehci_pci_finalize, .abstract = true, .class_init = ehci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c index 3c82525a1e..94d1077eb9 100644 --- a/hw/usb/hcd-ohci-pci.c +++ b/hw/usb/hcd-ohci-pci.c @@ -149,7 +149,7 @@ static const TypeInfo ohci_pci_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(OHCIPCIState), .class_init = ohci_pci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c index 2b1aee1f21..4822c704f6 100644 --- a/hw/usb/hcd-uhci.c +++ b/hw/usb/hcd-uhci.c @@ -1278,7 +1278,7 @@ static const TypeInfo uhci_pci_type_info = { .class_size = sizeof(UHCIPCIDeviceClass), .abstract = true, .class_init = uhci_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/usb/hcd-xhci-pci.c b/hw/usb/hcd-xhci-pci.c index 6167bb9100..b93c80b09d 100644 --- a/hw/usb/hcd-xhci-pci.c +++ b/hw/usb/hcd-xhci-pci.c @@ -248,7 +248,7 @@ static const TypeInfo xhci_pci_info = { .class_init = xhci_class_init, .instance_init = xhci_instance_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/vfio/igd.c b/hw/vfio/igd.c index fd55b8d884..0a13b185fe 100644 --- a/hw/vfio/igd.c +++ b/hw/vfio/igd.c @@ -318,7 +318,7 @@ static const TypeInfo vfio_pci_igd_lpc_bridge_info = { .name = "vfio-pci-igd-lpc-bridge", .parent = TYPE_PCI_DEVICE, .class_init = vfio_pci_igd_lpc_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 0db9f03846..c3d9360710 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -3554,7 +3554,7 @@ static const TypeInfo vfio_pci_dev_info = { .class_init = vfio_pci_dev_class_init, .instance_init = vfio_instance_init, .instance_finalize = vfio_instance_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } diff --git a/hw/virtio/virtio-md-pci.c b/hw/virtio/virtio-md-pci.c index 9ec5067662..9278b32cf8 100644 --- a/hw/virtio/virtio-md-pci.c +++ b/hw/virtio/virtio-md-pci.c @@ -138,7 +138,7 @@ static const TypeInfo virtio_md_pci_info = { .instance_size = sizeof(VirtIOMDPCI), .class_size = sizeof(VirtIOMDPCIClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_MEMORY_DEVICE }, { } }, diff --git a/hw/virtio/virtio-mem.c b/hw/virtio/virtio-mem.c index 0e14dd37d6..a3d1a676e7 100644 --- a/hw/virtio/virtio-mem.c +++ b/hw/virtio/virtio-mem.c @@ -1907,7 +1907,7 @@ static const TypeInfo virtio_mem_info = { .instance_finalize = virtio_mem_instance_finalize, .class_init = virtio_mem_class_init, .class_size = sizeof(VirtIOMEMClass), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_RAM_DISCARD_MANAGER }, { } }, diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 95bf7ddd97..0fa8fe4955 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2481,7 +2481,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) .name = t->generic_name, .parent = base_type_info.name, .class_init = virtio_pci_generic_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } @@ -2516,7 +2516,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) .name = t->non_transitional_name, .parent = base_type_info.name, .instance_init = virtio_pci_non_transitional_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_PCIE_DEVICE }, { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { } @@ -2530,7 +2530,7 @@ void virtio_pci_types_register(const VirtioPCIDeviceTypeInfo *t) .name = t->transitional_name, .parent = base_type_info.name, .instance_init = virtio_pci_transitional_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { /* * Transitional virtio devices work only as Conventional PCI * devices because they require PIO ports. diff --git a/hw/watchdog/wdt_i6300esb.c b/hw/watchdog/wdt_i6300esb.c index 1536e1fe03..bb8a2766b6 100644 --- a/hw/watchdog/wdt_i6300esb.c +++ b/hw/watchdog/wdt_i6300esb.c @@ -480,7 +480,7 @@ static const TypeInfo i6300esb_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(I6300State), .class_init = i6300esb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/hw/xen/xen-bus.c b/hw/xen/xen-bus.c index e6272282cd..6bd2e546f6 100644 --- a/hw/xen/xen-bus.c +++ b/hw/xen/xen-bus.c @@ -399,7 +399,7 @@ static const TypeInfo xen_bus_type_info = { .instance_size = sizeof(XenBus), .class_size = sizeof(XenBusClass), .class_init = xen_bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } }, diff --git a/hw/xen/xen-legacy-backend.c b/hw/xen/xen-legacy-backend.c index d6fe7d4f3e..5ed53f8943 100644 --- a/hw/xen/xen-legacy-backend.c +++ b/hw/xen/xen-legacy-backend.c @@ -661,7 +661,7 @@ static const TypeInfo xensysbus_info = { .name = TYPE_XENSYSBUS, .parent = TYPE_BUS, .class_init = xen_sysbus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { } } diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 7f9c351d96..9d16644d82 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -1079,7 +1079,7 @@ static const TypeInfo xen_pci_passthrough_info = { .class_init = xen_pci_passthrough_class_init, .class_size = sizeof(XenPTDeviceClass), .instance_init = xen_pci_passthrough_instance_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { INTERFACE_PCIE_DEVICE }, { }, diff --git a/hw/xen/xen_pt_graphics.c b/hw/xen/xen_pt_graphics.c index 264851ece3..2c0cec9723 100644 --- a/hw/xen/xen_pt_graphics.c +++ b/hw/xen/xen_pt_graphics.c @@ -363,7 +363,7 @@ static const TypeInfo isa_bridge_info = { .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PCIDevice), .class_init = isa_bridge_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, { }, }, diff --git a/include/qom/object.h b/include/qom/object.h index 26a45f638c..1d5b033724 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -294,7 +294,7 @@ struct Object .class_size = CLASS_SIZE, \ .class_init = module_obj_name##_class_init, \ .abstract = ABSTRACT, \ - .interfaces = (InterfaceInfo[]) { __VA_ARGS__ } , \ + .interfaces = (const InterfaceInfo[]) { __VA_ARGS__ } , \ }; \ \ static void \ diff --git a/net/can/can_core.c b/net/can/can_core.c index e16e15c036..77fe2b8ba4 100644 --- a/net/can/can_core.c +++ b/net/can/can_core.c @@ -162,7 +162,7 @@ static const TypeInfo can_bus_info = { .instance_size = sizeof(CanBusState), .instance_init = can_bus_instance_init, .class_init = can_bus_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/net/can/can_host.c b/net/can/can_host.c index ca5fcf1ea1..3f9bb33e47 100644 --- a/net/can/can_host.c +++ b/net/can/can_host.c @@ -92,7 +92,7 @@ static const TypeInfo can_host_info = { .class_size = sizeof(CanHostClass), .abstract = true, .class_init = can_host_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/net/colo-compare.c b/net/colo-compare.c index 425eb6e971..0e1844ee4c 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -1476,7 +1476,7 @@ static const TypeInfo colo_compare_info = { .instance_finalize = colo_compare_finalize, .class_size = sizeof(CompareClass), .class_init = colo_compare_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/net/filter.c b/net/filter.c index 03b3c793f7..c7cc6615dc 100644 --- a/net/filter.c +++ b/net/filter.c @@ -363,7 +363,7 @@ static const TypeInfo netfilter_info = { .instance_size = sizeof(NetFilterState), .instance_init = netfilter_init, .instance_finalize = netfilter_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/scripts/codeconverter/codeconverter/test_regexps.py b/scripts/codeconverter/codeconverter/test_regexps.py index 08857c5008..4526268ae8 100644 --- a/scripts/codeconverter/codeconverter/test_regexps.py +++ b/scripts/codeconverter/codeconverter/test_regexps.py @@ -77,8 +77,8 @@ static const TypeInfo char_file_type_info = { assert fullmatch(RE_ARRAY_ITEM, '{ TYPE_HOTPLUG_HANDLER },') assert fullmatch(RE_ARRAY_ITEM, '{ TYPE_ACPI_DEVICE_IF },') assert fullmatch(RE_ARRAY_ITEM, '{ }') - assert fullmatch(RE_ARRAY_CAST, '(InterfaceInfo[])') - assert fullmatch(RE_ARRAY, '''(InterfaceInfo[]) { + assert fullmatch(RE_ARRAY_CAST, '(const InterfaceInfo[])') + assert fullmatch(RE_ARRAY, '''(const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { } @@ -98,7 +98,7 @@ static const TypeInfo char_file_type_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(CRBState), .class_init = tpm_crb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } @@ -134,7 +134,7 @@ static const TypeInfo char_file_type_info = { .instance_size = sizeof(AcpiGedState), .instance_init = acpi_ged_initfn, .class_init = acpi_ged_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { TYPE_ACPI_DEVICE_IF }, { } @@ -164,7 +164,7 @@ static const TypeInfo char_file_type_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(CRBState), .class_init = tpm_crb_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TPM_IF }, { } } diff --git a/scsi/pr-manager.c b/scsi/pr-manager.c index 1977d99ce0..40e1210eb2 100644 --- a/scsi/pr-manager.c +++ b/scsi/pr-manager.c @@ -77,7 +77,7 @@ static const TypeInfo pr_manager_info = { .name = TYPE_PR_MANAGER, .class_size = sizeof(PRManagerClass), .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/system/qtest.c b/system/qtest.c index b7689088a4..ade3eb3221 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -1012,7 +1012,7 @@ static const TypeInfo qtest_info = { .parent = TYPE_OBJECT, .class_init = qtest_class_init, .instance_size = sizeof(QTest), - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/target/i386/sev.c b/target/i386/sev.c index 7ef4801d5f..7ee700d6a3 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -2089,7 +2089,7 @@ static const TypeInfo sev_common_info = { .class_size = sizeof(SevCommonStateClass), .class_init = sev_common_class_init, .abstract = true, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 90b21b9c93..aed9e26599 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7570,7 +7570,7 @@ static const TypeInfo ppc_cpu_type_info = { .class_size = sizeof(PowerPCCPUClass), .class_init = ppc_cpu_class_init, #ifndef CONFIG_USER_ONLY - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_INTERRUPT_STATS_PROVIDER }, { } }, diff --git a/tests/unit/check-qom-interface.c b/tests/unit/check-qom-interface.c index 4e1c4d6729..86ae5f6c3b 100644 --- a/tests/unit/check-qom-interface.c +++ b/tests/unit/check-qom-interface.c @@ -52,7 +52,7 @@ static const TypeInfo direct_impl_info = { .name = TYPE_DIRECT_IMPL, .parent = TYPE_OBJECT, .class_init = test_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_TEST_IF }, { } } diff --git a/tests/unit/check-qom-proplist.c b/tests/unit/check-qom-proplist.c index f1de1618f6..ee3c6fb32b 100644 --- a/tests/unit/check-qom-proplist.c +++ b/tests/unit/check-qom-proplist.c @@ -164,7 +164,7 @@ static const TypeInfo dummy_info = { .instance_finalize = dummy_finalize, .class_size = sizeof(DummyObjectClass), .class_init = dummy_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/ui/dbus.c b/ui/dbus.c index 0c0f86eaa6..dd0336702d 100644 --- a/ui/dbus.c +++ b/ui/dbus.c @@ -514,7 +514,7 @@ static const TypeInfo dbus_display_info = { .instance_init = dbus_display_init, .instance_finalize = dbus_display_finalize, .class_init = dbus_display_class_init, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/ui/input-barrier.c b/ui/input-barrier.c index 9dce31ea9a..9793258aac 100644 --- a/ui/input-barrier.c +++ b/ui/input-barrier.c @@ -732,7 +732,7 @@ static const TypeInfo input_barrier_info = { .instance_size = sizeof(InputBarrier), .instance_init = input_barrier_instance_init, .instance_finalize = input_barrier_instance_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/ui/input-linux.c b/ui/input-linux.c index 2f5adb82d2..92e1a1aa64 100644 --- a/ui/input-linux.c +++ b/ui/input-linux.c @@ -522,7 +522,7 @@ static const TypeInfo input_linux_info = { .instance_size = sizeof(InputLinux), .instance_init = input_linux_instance_init, .instance_finalize = input_linux_instance_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } diff --git a/util/thread-context.c b/util/thread-context.c index 95228a3d4f..0146154fa5 100644 --- a/util/thread-context.c +++ b/util/thread-context.c @@ -319,7 +319,7 @@ static const TypeInfo thread_context_info = { .instance_size = sizeof(ThreadContext), .instance_init = thread_context_instance_init, .instance_finalize = thread_context_instance_finalize, - .interfaces = (InterfaceInfo[]) { + .interfaces = (const InterfaceInfo[]) { { TYPE_USER_CREATABLE }, { } } From 7748cdbae899f54f672e2e5ecd2c556c256b2b08 Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Tue, 22 Apr 2025 14:27:06 +0900 Subject: [PATCH 0312/2760] qom/object: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Emscripten, function pointer casts can result in runtime failures due to strict function signature checks. This affects the use of g_list_sort and g_slist_sort, which internally perform function pointer casts that are not supported by Emscripten. To avoid these issues, g_list_sort_with_data and g_slist_sort_with_data should be used instead, as they do not rely on function pointer casting. Signed-off-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Message-ID: <8ca13f4e2b9eba9d1f6030b0afb442a24330e463.1745295397.git.ktokunaga.mail@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- qom/object.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qom/object.c b/qom/object.c index 425ee2f0ee..664f0f24ae 100644 --- a/qom/object.c +++ b/qom/object.c @@ -1191,7 +1191,7 @@ GSList *object_class_get_list(const char *implements_type, return list; } -static gint object_class_cmp(gconstpointer a, gconstpointer b) +static gint object_class_cmp(gconstpointer a, gconstpointer b, gpointer d) { return strcasecmp(object_class_get_name((ObjectClass *)a), object_class_get_name((ObjectClass *)b)); @@ -1200,8 +1200,9 @@ static gint object_class_cmp(gconstpointer a, gconstpointer b) GSList *object_class_get_list_sorted(const char *implements_type, bool include_abstract) { - return g_slist_sort(object_class_get_list(implements_type, include_abstract), - object_class_cmp); + return g_slist_sort_with_data( + object_class_get_list(implements_type, include_abstract), + object_class_cmp, NULL); } Object *object_ref(void *objptr) From d5f241834be1b323ea697a469ff0f1335a1823fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 22 Apr 2025 10:32:31 +0200 Subject: [PATCH 0313/2760] hw/core: Get default_cpu_type calling machine_class_default_cpu_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 62b4a227a33 the default cpu type can come from the valid_cpu_types[] array. Call the machine_class_default_cpu_type() instead of accessing MachineClass::default_cpu_type field. Cc: qemu-stable@nongnu.org Fixes: 62b4a227a33 ("hw/core: Add machine_class_default_cpu_type()") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Pierrick Bouvier Reviewed-by: Zhao Liu Message-Id: <20250422084114.39499-1-philmd@linaro.org> --- hw/core/machine-qmp-cmds.c | 5 +++-- target/ppc/cpu_init.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index fd8b4e0b44..9447e345b3 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -73,6 +73,7 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props, for (el = machines; el; el = el->next) { MachineClass *mc = el->data; + const char *default_cpu_type = machine_class_default_cpu_type(mc); MachineInfo *info; info = g_malloc0(sizeof(*info)); @@ -91,8 +92,8 @@ MachineInfoList *qmp_query_machines(bool has_compat_props, bool compat_props, info->numa_mem_supported = mc->numa_mem_supported; info->deprecated = !!mc->deprecation_reason; info->acpi = !!object_class_property_find(OBJECT_CLASS(mc), "acpi"); - if (mc->default_cpu_type) { - info->default_cpu_type = g_strdup(mc->default_cpu_type); + if (default_cpu_type) { + info->default_cpu_type = g_strdup(default_cpu_type); } if (mc->default_ram_id) { info->default_ram_id = g_strdup(mc->default_ram_id); diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index aed9e26599..b0973b6df9 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7082,7 +7082,7 @@ ObjectClass *ppc_cpu_class_by_name(const char *name) if (strcmp(name, "max") == 0) { MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); if (mc) { - return object_class_by_name(mc->default_cpu_type); + return object_class_by_name(machine_class_default_cpu_type(mc)); } } #endif From 56a9f0d4c4a483ce217e5290db69cb1788586787 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Mar 2025 14:28:11 +0000 Subject: [PATCH 0314/2760] hw/core/cpu: gdb_arch_name string should not be freed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The documentation for the CPUClass::gdb_arch_name method claims that the returned string should be freed with g_free(). This is not correct: in commit a650683871ba728 we changed this method to instead return a simple constant string, but forgot to update the documentation. Make the documentation match the new semantics. Fixes: a650683871ba728 ("hw/core/cpu: Return static value with gdb_arch_name()") Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250317142819.900029-2-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/hw/core/cpu.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 5b645df59f..6ea246514e 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -134,7 +134,8 @@ struct SysemuCPUOps; * @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop * before the insn which triggers a watchpoint rather than after it. * @gdb_arch_name: Optional callback that returns the architecture name known - * to GDB. The caller must free the returned string with g_free. + * to GDB. The returned value is expected to be a simple constant string: + * the caller will not g_free() it. * @disas_set_info: Setup architecture specific components of disassembly info * @adjust_watchpoint_address: Perform a target-specific adjustment to an * address before attempting to match it against watchpoints. From a1f728ecc90cf6c6db24df53cc951713fca8b94d Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Mar 2025 14:28:12 +0000 Subject: [PATCH 0315/2760] gdbstub: Allow gdb_core_xml_file to be set at runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the CPUClass:gdb_core_xml_file setting is a simple 'const char *' which the CPU class must set to a fixed string. Allow the CPU class to instead set a new method gdb_get_core_xml_file() which returns this string. This will allow Arm CPUs to use different XML files for AArch32 vs AArch64 without having to have an extra AArch64-specific class type purely to give somewhere to set cc->gdb_core_xml_file differently. Signed-off-by: Peter Maydell Acked-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250317142819.900029-3-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- gdbstub/gdbstub.c | 23 +++++++++++++++++++---- include/hw/core/cpu.h | 5 +++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/gdbstub/gdbstub.c b/gdbstub/gdbstub.c index 282e13e163..565f6b33a9 100644 --- a/gdbstub/gdbstub.c +++ b/gdbstub/gdbstub.c @@ -565,15 +565,30 @@ static void gdb_register_feature(CPUState *cpu, int base_reg, g_array_append_val(cpu->gdb_regs, s); } +static const char *gdb_get_core_xml_file(CPUState *cpu) +{ + CPUClass *cc = cpu->cc; + + /* + * The CPU class can provide the XML filename via a method, + * or as a simple fixed string field. + */ + if (cc->gdb_get_core_xml_file) { + return cc->gdb_get_core_xml_file(cpu); + } + return cc->gdb_core_xml_file; +} + void gdb_init_cpu(CPUState *cpu) { CPUClass *cc = cpu->cc; const GDBFeature *feature; + const char *xmlfile = gdb_get_core_xml_file(cpu); cpu->gdb_regs = g_array_new(false, false, sizeof(GDBRegisterState)); - if (cc->gdb_core_xml_file) { - feature = gdb_find_static_feature(cc->gdb_core_xml_file); + if (xmlfile) { + feature = gdb_find_static_feature(xmlfile); gdb_register_feature(cpu, 0, cc->gdb_read_register, cc->gdb_write_register, feature); @@ -1644,7 +1659,7 @@ void gdb_extend_qsupported_features(char *qflags) static void handle_query_supported(GArray *params, void *user_ctx) { g_string_printf(gdbserver_state.str_buf, "PacketSize=%x", MAX_PACKET_LENGTH); - if (first_cpu->cc->gdb_core_xml_file) { + if (gdb_get_core_xml_file(first_cpu)) { g_string_append(gdbserver_state.str_buf, ";qXfer:features:read+"); } @@ -1701,7 +1716,7 @@ static void handle_query_xfer_features(GArray *params, void *user_ctx) } process = gdb_get_cpu_process(gdbserver_state.g_cpu); - if (!gdbserver_state.g_cpu->cc->gdb_core_xml_file) { + if (!gdb_get_core_xml_file(gdbserver_state.g_cpu)) { gdb_put_packet(""); return; } diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 6ea246514e..2a02d4f078 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -131,6 +131,10 @@ struct SysemuCPUOps; * @gdb_num_core_regs: Number of core registers accessible to GDB or 0 to infer * from @gdb_core_xml_file. * @gdb_core_xml_file: File name for core registers GDB XML description. + * @gdb_get_core_xml_file: Optional callback that returns the file name for + * the core registers GDB XML description. The returned value is expected to + * be a simple constant string: the caller will not g_free() it. If this + * is NULL then @gdb_core_xml_file will be used instead. * @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop * before the insn which triggers a watchpoint rather than after it. * @gdb_arch_name: Optional callback that returns the architecture name known @@ -166,6 +170,7 @@ struct CPUClass { const char *gdb_core_xml_file; const gchar * (*gdb_arch_name)(CPUState *cpu); + const char * (*gdb_get_core_xml_file)(CPUState *cpu); void (*disas_set_info)(CPUState *cpu, disassemble_info *info); From bae9fb4b016b1927f6e0cdea9213e33e3a70c9ae Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Mar 2025 14:28:13 +0000 Subject: [PATCH 0316/2760] target/arm: Handle AArch64 in TYPE_ARM_CPU gdb_arch_name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having the TYPE_AARCH64_CPU subclass set CPUClass::gdb_arch_name to a different function, make the TYPE_ARM_CPU implementation of the method handle AArch64. For the moment we make the "is this AArch64?" function test "is the CPU of TYPE_AARCH64_CPU?", so that this produces no behavioural change. When we've moved all the gdbstub related methods across to the base class, we will be able to change this to be "does the CPU have the ARM_FEATURE_AARCH64 feature?". Signed-off-by: Peter Maydell Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250317142819.900029-4-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- target/arm/cpu.c | 3 +++ target/arm/cpu64.c | 6 ------ target/arm/internals.h | 6 ++++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 00577f97eb..bed0e58f3c 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2649,6 +2649,9 @@ static const gchar *arm_gdb_arch_name(CPUState *cs) ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; + if (arm_gdbstub_is_aarch64(cpu)) { + return "aarch64"; + } if (arm_feature(env, ARM_FEATURE_IWMMXT)) { return "iwmmxt"; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index eaf5705cdc..fbb7e7b3d6 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -813,11 +813,6 @@ static void aarch64_cpu_finalizefn(Object *obj) { } -static const gchar *aarch64_gdb_arch_name(CPUState *cs) -{ - return "aarch64"; -} - static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) { CPUClass *cc = CPU_CLASS(oc); @@ -825,7 +820,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) cc->gdb_read_register = aarch64_cpu_gdb_read_register; cc->gdb_write_register = aarch64_cpu_gdb_write_register; cc->gdb_core_xml_file = "aarch64-core.xml"; - cc->gdb_arch_name = aarch64_gdb_arch_name; object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, aarch64_cpu_set_aarch64); diff --git a/target/arm/internals.h b/target/arm/internals.h index d24acdd672..08f4bd1679 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1826,6 +1826,12 @@ void aarch64_add_pauth_properties(Object *obj); void aarch64_add_sve_properties(Object *obj); void aarch64_add_sme_properties(Object *obj); +/* Return true if the gdbstub is presenting an AArch64 CPU */ +static inline bool arm_gdbstub_is_aarch64(ARMCPU *cpu) +{ + return object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU); +} + /* Read the CONTROL register as the MRS instruction would. */ uint32_t arm_v7m_mrs_control(CPUARMState *env, uint32_t secure); From 984ea94818000618c4ff95d0b63f63aba8f2a95e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Mar 2025 14:28:14 +0000 Subject: [PATCH 0317/2760] target/arm: Handle gdb_core_xml_file in TYPE_ARM_CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having the TYPE_AARCH64_CPU subclass set CPUClass:gdb_core_xml_file to a different value from that that TYPE_ARM_CPU uses, implement the gdb_get_core_xml_file method in the TYPE_ARM_CPU class to return either the AArch64 or AArch32 XML file name. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250317142819.900029-5-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- target/arm/cpu.c | 16 +++++++++++++++- target/arm/cpu64.c | 1 - target/arm/tcg/cpu-v7m.c | 1 - 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index bed0e58f3c..5e951675c6 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2658,6 +2658,20 @@ static const gchar *arm_gdb_arch_name(CPUState *cs) return "arm"; } +static const char *arm_gdb_get_core_xml_file(CPUState *cs) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + if (arm_gdbstub_is_aarch64(cpu)) { + return "aarch64-core.xml"; + } + if (arm_feature(env, ARM_FEATURE_M)) { + return "arm-m-profile.xml"; + } + return "arm-core.xml"; +} + #ifndef CONFIG_USER_ONLY #include "hw/core/sysemu-cpu-ops.h" @@ -2727,6 +2741,7 @@ static void arm_cpu_class_init(ObjectClass *oc, const void *data) cc->sysemu_ops = &arm_sysemu_ops; #endif cc->gdb_arch_name = arm_gdb_arch_name; + cc->gdb_get_core_xml_file = arm_gdb_get_core_xml_file; cc->gdb_stop_before_watchpoint = true; cc->disas_set_info = arm_disas_set_info; @@ -2749,7 +2764,6 @@ static void cpu_register_class_init(ObjectClass *oc, const void *data) CPUClass *cc = CPU_CLASS(acc); acc->info = data; - cc->gdb_core_xml_file = "arm-core.xml"; if (acc->info->deprecation_note) { cc->deprecation_note = acc->info->deprecation_note; } diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index fbb7e7b3d6..5135ef63cb 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -819,7 +819,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) cc->gdb_read_register = aarch64_cpu_gdb_read_register; cc->gdb_write_register = aarch64_cpu_gdb_write_register; - cc->gdb_core_xml_file = "aarch64-core.xml"; object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, aarch64_cpu_set_aarch64); diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 7426aac0dc..b34b657857 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -266,7 +266,6 @@ static void arm_v7m_class_init(ObjectClass *oc, const void *data) acc->info = data; cc->tcg_ops = &arm_v7m_tcg_ops; - cc->gdb_core_xml_file = "arm-m-profile.xml"; } static const ARMCPUInfo arm_v7m_cpus[] = { From 4b6f74d86c4d4f179643ae2c5f7bbfcf7c1a7725 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 17 Mar 2025 14:28:15 +0000 Subject: [PATCH 0318/2760] target/arm: Handle AArch64 gdb read/write regs in TYPE_ARM_CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having the TYPE_AARCH64_CPU subclass set CPUClass::gdb_read_register and ::gdb_write_register to different methods from those of the TYPE_ARM_CPU parent class, have the TYPE_ARM_CPU methods handle either AArch32 or AArch64 at runtime. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250317142819.900029-6-peter.maydell@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- target/arm/cpu64.c | 5 ----- target/arm/gdbstub.c | 12 ++++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 5135ef63cb..00629a5d1d 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -815,11 +815,6 @@ static void aarch64_cpu_finalizefn(Object *obj) static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) { - CPUClass *cc = CPU_CLASS(oc); - - cc->gdb_read_register = aarch64_cpu_gdb_read_register; - cc->gdb_write_register = aarch64_cpu_gdb_write_register; - object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, aarch64_cpu_set_aarch64); object_class_property_set_description(oc, "aarch64", diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 30068c2262..ce4497ad7c 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -44,6 +44,12 @@ int arm_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; +#ifdef TARGET_AARCH64 + if (arm_gdbstub_is_aarch64(cpu)) { + return aarch64_cpu_gdb_read_register(cs, mem_buf, n); + } +#endif + if (n < 16) { /* Core integer register. */ return gdb_get_reg32(mem_buf, env->regs[n]); @@ -66,6 +72,12 @@ int arm_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) CPUARMState *env = &cpu->env; uint32_t tmp; +#ifdef TARGET_AARCH64 + if (arm_gdbstub_is_aarch64(cpu)) { + return aarch64_cpu_gdb_write_register(cs, mem_buf, n); + } +#endif + tmp = ldl_p(mem_buf); /* From 35ca9d14c173bf7593367d19048ce7784fd122c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 00:19:59 +0200 Subject: [PATCH 0319/2760] target/arm: Replace target_ulong -> hwaddr in ARMMMUFaultInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-Id: <20250415172246.79470-2-philmd@linaro.org> --- target/arm/internals.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 08f4bd1679..0818de530b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -25,6 +25,7 @@ #ifndef TARGET_ARM_INTERNALS_H #define TARGET_ARM_INTERNALS_H +#include "exec/hwaddr.h" #include "exec/breakpoint.h" #include "hw/registerfields.h" #include "tcg/tcg-gvec-desc.h" @@ -726,8 +727,8 @@ typedef struct ARMMMUFaultInfo ARMMMUFaultInfo; struct ARMMMUFaultInfo { ARMFaultType type; ARMGPCF gpcf; - target_ulong s2addr; - target_ulong paddr; + hwaddr s2addr; + hwaddr paddr; ARMSecuritySpace paddr_space; int level; int domain; From 6fa103069d13edb0875242e10dbcc47df19ba412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 4 Apr 2025 00:25:06 +0200 Subject: [PATCH 0320/2760] target/arm: Replace target_ulong -> vaddr for CPUWatchpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPUWatchpoint::vaddr/len are of type vaddr. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-Id: <20250415172246.79470-4-philmd@linaro.org> --- target/arm/hyp_gdbstub.c | 8 ++++---- target/arm/internals.h | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c index 1e861263b3..0512d67f8c 100644 --- a/target/arm/hyp_gdbstub.c +++ b/target/arm/hyp_gdbstub.c @@ -125,7 +125,7 @@ int delete_hw_breakpoint(target_ulong pc) * need to ensure you mask the address as required and set BAS=0xff */ -int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type) +int insert_hw_watchpoint(vaddr addr, vaddr len, int type) { HWWatchpoint wp = { .wcr = R_DBGWCR_E_MASK, /* E=1, enable */ @@ -182,7 +182,7 @@ int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type) return 0; } -bool check_watchpoint_in_range(int i, target_ulong addr) +bool check_watchpoint_in_range(int i, vaddr addr) { HWWatchpoint *wp = get_hw_wp(i); uint64_t addr_top, addr_bottom = wp->wvr; @@ -214,7 +214,7 @@ bool check_watchpoint_in_range(int i, target_ulong addr) * Delete a breakpoint and shuffle any above down */ -int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type) +int delete_hw_watchpoint(vaddr addr, vaddr len, int type) { int i; for (i = 0; i < cur_hw_wps; i++) { @@ -239,7 +239,7 @@ bool find_hw_breakpoint(CPUState *cpu, target_ulong pc) return false; } -CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr) +CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, vaddr addr) { int i; diff --git a/target/arm/internals.h b/target/arm/internals.h index 0818de530b..4d3d84ffeb 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -26,6 +26,7 @@ #define TARGET_ARM_INTERNALS_H #include "exec/hwaddr.h" +#include "exec/vaddr.h" #include "exec/breakpoint.h" #include "hw/registerfields.h" #include "tcg/tcg-gvec-desc.h" @@ -1952,10 +1953,10 @@ bool find_hw_breakpoint(CPUState *cpu, target_ulong pc); int insert_hw_breakpoint(target_ulong pc); int delete_hw_breakpoint(target_ulong pc); -bool check_watchpoint_in_range(int i, target_ulong addr); -CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr); -int insert_hw_watchpoint(target_ulong addr, target_ulong len, int type); -int delete_hw_watchpoint(target_ulong addr, target_ulong len, int type); +bool check_watchpoint_in_range(int i, vaddr addr); +CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, vaddr addr); +int insert_hw_watchpoint(vaddr addr, vaddr len, int type); +int delete_hw_watchpoint(vaddr addr, vaddr len, int type); /* Return the current value of the system counter in ticks */ uint64_t gt_get_countervalue(CPUARMState *env); From d4a785ba30ce6d8acf0206f049fb4a7494e0898a Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 12 Apr 2025 21:40:03 +0200 Subject: [PATCH 0321/2760] target/mips: Fix MIPS16e translation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a wrong conversion to gen_op_addr_addi(). The framesize should be added like it was done before. This bug broke booting OpenWrt MIPS32 BE malta Linux system images generated by OpenWrt. Cc: qemu-stable@nongnu.org Fixes: d0b24b7f50e1 ("target/mips: Use gen_op_addr_addi() when possible") Signed-off-by: Hauke Mehrtens Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250412194003.181411-1-hauke@hauke-m.de> Signed-off-by: Philippe Mathieu-Daudé --- target/mips/tcg/mips16e_translate.c.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/mips/tcg/mips16e_translate.c.inc b/target/mips/tcg/mips16e_translate.c.inc index a9af8f1e74..97da3456ea 100644 --- a/target/mips/tcg/mips16e_translate.c.inc +++ b/target/mips/tcg/mips16e_translate.c.inc @@ -306,7 +306,7 @@ static void gen_mips16_restore(DisasContext *ctx, int astatic; TCGv t0 = tcg_temp_new(); - gen_op_addr_addi(ctx, t0, cpu_gpr[29], -framesize); + gen_op_addr_addi(ctx, t0, cpu_gpr[29], framesize); if (do_ra) { decr_and_load(ctx, 31, t0); @@ -386,7 +386,7 @@ static void gen_mips16_restore(DisasContext *ctx, } } - gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], -framesize); + gen_op_addr_addi(ctx, cpu_gpr[29], cpu_gpr[29], framesize); } #if defined(TARGET_MIPS64) From b939b8e42acedc2ff35534f96fae026f8fe2efcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 09:31:24 +0200 Subject: [PATCH 0322/2760] exec: Rename target_words_bigendian() -> target_big_endian() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 98ed8ecfc9d ("exec: introduce target_words_bigendian() helper") target_words_bigendian() was matching the definition it was depending on (TARGET_WORDS_BIGENDIAN). Later in commit ee3eb3a7ce7 ("Replace TARGET_WORDS_BIGENDIAN") the definition was renamed as TARGET_BIG_ENDIAN but we didn't update the helper. Do it now mechanically using: $ sed -i -e s/target_words_bigendian/target_big_endian/g \ $(git grep -wl target_words_bigendian) Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Michael S. Tsirkin Reviewed-by: Pierrick Bouvier Message-Id: <20250417210025.68322-1-philmd@linaro.org> --- cpu-target.c | 4 ++-- hw/core/cpu-system.c | 2 +- hw/display/vga.c | 2 +- hw/virtio/virtio.c | 2 +- include/exec/tswap.h | 12 ++++++------ system/memory-internal.h | 2 +- system/memory.c | 4 ++-- system/qtest.c | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index c99d208a7c..d68cbab5da 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -160,8 +160,8 @@ void cpu_abort(CPUState *cpu, const char *fmt, ...) abort(); } -#undef target_words_bigendian -bool target_words_bigendian(void) +#undef target_big_endian +bool target_big_endian(void) { return TARGET_BIG_ENDIAN; } diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c index 82b68b8927..3c84176a0c 100644 --- a/hw/core/cpu-system.c +++ b/hw/core/cpu-system.c @@ -133,7 +133,7 @@ bool cpu_virtio_is_big_endian(CPUState *cpu) if (cpu->cc->sysemu_ops->virtio_is_big_endian) { return cpu->cc->sysemu_ops->virtio_is_big_endian(cpu); } - return target_words_bigendian(); + return target_big_endian(); } GuestPanicInformation *cpu_get_crash_info(CPUState *cpu) diff --git a/hw/display/vga.c b/hw/display/vga.c index b01f67c65f..20475ebbd3 100644 --- a/hw/display/vga.c +++ b/hw/display/vga.c @@ -2264,7 +2264,7 @@ bool vga_common_init(VGACommonState *s, Object *obj, Error **errp) * into a device attribute set by the machine/platform to remove * all target endian dependencies from this file. */ - s->default_endian_fb = target_words_bigendian(); + s->default_endian_fb = target_big_endian(); s->big_endian_fb = s->default_endian_fb; vga_dirty_log_start(s); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index f0fa36f8ce..480c2e5036 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2248,7 +2248,7 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) static enum virtio_device_endian virtio_default_endian(void) { - if (target_words_bigendian()) { + if (target_big_endian()) { return VIRTIO_DEVICE_ENDIAN_BIG; } else { return VIRTIO_DEVICE_ENDIAN_LITTLE; diff --git a/include/exec/tswap.h b/include/exec/tswap.h index 84060a4999..49511f2611 100644 --- a/include/exec/tswap.h +++ b/include/exec/tswap.h @@ -11,15 +11,15 @@ #include "qemu/bswap.h" /** - * target_words_bigendian: + * target_big_endian: * Returns true if the (default) endianness of the target is big endian, * false otherwise. Common code should normally never need to know about the * endianness of the target, so please do *not* use this function unless you * know very well what you are doing! */ -bool target_words_bigendian(void); +bool target_big_endian(void); #ifdef COMPILING_PER_TARGET -#define target_words_bigendian() TARGET_BIG_ENDIAN +#define target_big_endian() TARGET_BIG_ENDIAN #endif /* @@ -29,7 +29,7 @@ bool target_words_bigendian(void); #ifdef COMPILING_PER_TARGET #define target_needs_bswap() (HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN) #else -#define target_needs_bswap() (HOST_BIG_ENDIAN != target_words_bigendian()) +#define target_needs_bswap() (HOST_BIG_ENDIAN != target_big_endian()) #endif /* COMPILING_PER_TARGET */ static inline uint16_t tswap16(uint16_t s) @@ -83,7 +83,7 @@ static inline void tswap64s(uint64_t *s) /* Return ld{word}_{le,be}_p following target endianness. */ #define LOAD_IMPL(word, args...) \ do { \ - if (target_words_bigendian()) { \ + if (target_big_endian()) { \ return glue(glue(ld, word), _be_p)(args); \ } else { \ return glue(glue(ld, word), _le_p)(args); \ @@ -120,7 +120,7 @@ static inline uint64_t ldn_p(const void *ptr, int sz) /* Call st{word}_{le,be}_p following target endianness. */ #define STORE_IMPL(word, args...) \ do { \ - if (target_words_bigendian()) { \ + if (target_big_endian()) { \ glue(glue(st, word), _be_p)(args); \ } else { \ glue(glue(st, word), _le_p)(args); \ diff --git a/system/memory-internal.h b/system/memory-internal.h index 085e81a9fe..29717b3c58 100644 --- a/system/memory-internal.h +++ b/system/memory-internal.h @@ -45,7 +45,7 @@ static inline bool devend_big_endian(enum device_endian end) DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); if (end == DEVICE_NATIVE_ENDIAN) { - return target_words_bigendian(); + return target_big_endian(); } return end == DEVICE_BIG_ENDIAN; } diff --git a/system/memory.c b/system/memory.c index 7e2f16f4e9..67e433095b 100644 --- a/system/memory.c +++ b/system/memory.c @@ -2575,7 +2575,7 @@ void memory_region_add_eventfd(MemoryRegion *mr, unsigned i; if (size) { - MemOp mop = (target_words_bigendian() ? MO_BE : MO_LE) | size_memop(size); + MemOp mop = (target_big_endian() ? MO_BE : MO_LE) | size_memop(size); adjust_endianness(mr, &mrfd.data, mop); } memory_region_transaction_begin(); @@ -2611,7 +2611,7 @@ void memory_region_del_eventfd(MemoryRegion *mr, unsigned i; if (size) { - MemOp mop = (target_words_bigendian() ? MO_BE : MO_LE) | size_memop(size); + MemOp mop = (target_big_endian() ? MO_BE : MO_LE) | size_memop(size); adjust_endianness(mr, &mrfd.data, mop); } memory_region_transaction_begin(); diff --git a/system/qtest.c b/system/qtest.c index ade3eb3221..301b03be2d 100644 --- a/system/qtest.c +++ b/system/qtest.c @@ -693,7 +693,7 @@ static void qtest_process_command(CharBackend *chr, gchar **words) qtest_send(chr, "OK\n"); } else if (strcmp(words[0], "endianness") == 0) { - if (target_words_bigendian()) { + if (target_big_endian()) { qtest_sendf(chr, "OK big\n"); } else { qtest_sendf(chr, "OK little\n"); From aca4967567aaa168ce51d54145ba970aafb135de Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 18 Apr 2025 14:51:48 +0900 Subject: [PATCH 0323/2760] hw/usb/hcd-xhci: Unmap canceled packet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the Stop Endpoint Command is received, packets running asynchronously are canceled and then all packets are cleaned up. Packets running asynchronously hold the DMA mapping so cleaning the packets leak the mapping. Remove the mapping after canceling packets to fix the leak. Fixes: 62c6ae04cf43 ("xhci: Initial xHCI implementation") Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250418-xhc-v1-1-bb32dab6a67e@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/usb/hcd-xhci.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index b3785b8ba6..292c378bfc 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1187,6 +1187,12 @@ static void xhci_ep_free_xfer(XHCITransfer *xfer) g_free(xfer); } +static void xhci_xfer_unmap(XHCITransfer *xfer) +{ + usb_packet_unmap(&xfer->packet, &xfer->sgl); + qemu_sglist_destroy(&xfer->sgl); +} + static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) { int killed = 0; @@ -1198,6 +1204,7 @@ static int xhci_ep_nuke_one_xfer(XHCITransfer *t, TRBCCode report) if (t->running_async) { usb_cancel_packet(&t->packet); + xhci_xfer_unmap(t); t->running_async = 0; killed = 1; } @@ -1480,12 +1487,6 @@ err: return -1; } -static void xhci_xfer_unmap(XHCITransfer *xfer) -{ - usb_packet_unmap(&xfer->packet, &xfer->sgl); - qemu_sglist_destroy(&xfer->sgl); -} - static void xhci_xfer_report(XHCITransfer *xfer) { uint32_t edtla = 0; From 8cd3b84c8aa8d22c130377ac65e2aac7151a8d27 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 23 Apr 2025 12:11:25 +0200 Subject: [PATCH 0324/2760] hw/intc/i8259: Remove unused DEBUG_PIC define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The debug printfs were converted to traces so this define is now unused. Fixes: 0880a87300 (i8259: convert DPRINTFs into trace) Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-ID: <20250423101125.B243A55C592@zero.eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé --- hw/intc/i8259.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c index 2359dd8253..b6f96bf208 100644 --- a/hw/intc/i8259.c +++ b/hw/intc/i8259.c @@ -32,10 +32,7 @@ #include "trace.h" #include "qom/object.h" -/* debug PIC */ -//#define DEBUG_PIC - -//#define DEBUG_IRQ_LATENCY +/*#define DEBUG_IRQ_LATENCY*/ #define TYPE_I8259 "isa-i8259" typedef struct PICClass PICClass; From 604ac1d87bd650db2c25adcac238577c6aeb5bee Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Tue, 22 Apr 2025 14:27:05 +0900 Subject: [PATCH 0325/2760] hw/core/loader: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Emscripten, function pointer casts can result in runtime failures due to strict function signature checks. This affects the use of g_list_sort and g_slist_sort, which internally perform function pointer casts that are not supported by Emscripten. To avoid these issues, g_list_sort_with_data and g_slist_sort_with_data should be used instead, as they do not rely on function pointer casting. Signed-off-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Message-ID: <26dfe9191154ca65dca6ef51ce768ad2a0c30d5f.1745295397.git.ktokunaga.mail@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/core/loader.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index a3aa62d132..b792a54bb0 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1410,7 +1410,7 @@ typedef struct RomSec { * work, but this way saves a little work later by avoiding * dealing with "gaps" of 0 length. */ -static gint sort_secs(gconstpointer a, gconstpointer b) +static gint sort_secs(gconstpointer a, gconstpointer b, gpointer d) { RomSec *ra = (RomSec *) a; RomSec *rb = (RomSec *) b; @@ -1463,7 +1463,7 @@ RomGap rom_find_largest_gap_between(hwaddr base, size_t size) /* sentinel */ secs = add_romsec_to_list(secs, base + size, 1); - secs = g_list_sort(secs, sort_secs); + secs = g_list_sort_with_data(secs, sort_secs, NULL); for (it = g_list_first(secs); it; it = g_list_next(it)) { cand = (RomSec *) it->data; From ed1aef171671ef49761017cb1d8d10bf67d05c57 Mon Sep 17 00:00:00 2001 From: Sunny Zhu Date: Tue, 22 Apr 2025 02:21:26 +0800 Subject: [PATCH 0326/2760] block: Remove unused callback function *bdrv_aio_pdiscard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bytes type in *bdrv_aio_pdiscard should be int64_t rather than int. There are no drivers implementing the *bdrv_aio_pdiscard() callback, it appears to be an unused function. Therefore, we'll simply remove it instead of fixing it. Additionally, coroutine-based callbacks are preferred. If someone needs to implement bdrv_aio_pdiscard, a coroutine-based version would be straightforward to implement. Signed-off-by: Sunny Zhu Message-ID: Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/io.c | 20 ++------------------ include/block/block_int-common.h | 4 ---- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/block/io.c b/block/io.c index ccec11386b..6d98b0abb9 100644 --- a/block/io.c +++ b/block/io.c @@ -3102,7 +3102,7 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, return 0; } - if (!bs->drv->bdrv_co_pdiscard && !bs->drv->bdrv_aio_pdiscard) { + if (!bs->drv->bdrv_co_pdiscard) { return 0; } @@ -3162,24 +3162,8 @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, ret = -ENOMEDIUM; goto out; } - if (bs->drv->bdrv_co_pdiscard) { - ret = bs->drv->bdrv_co_pdiscard(bs, offset, num); - } else { - BlockAIOCB *acb; - CoroutineIOCompletion co = { - .coroutine = qemu_coroutine_self(), - }; - acb = bs->drv->bdrv_aio_pdiscard(bs, offset, num, - bdrv_co_io_em_complete, &co); - if (acb == NULL) { - ret = -EIO; - goto out; - } else { - qemu_coroutine_yield(); - ret = co.ret; - } - } + ret = bs->drv->bdrv_co_pdiscard(bs, offset, num); if (ret && ret != -ENOTSUP) { if (ret == -EINVAL && (offset % align != 0 || num % align != 0)) { /* Silently skip rejected unaligned head/tail requests */ diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index ebb4e56a50..0d8187f656 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -506,10 +506,6 @@ struct BlockDriver { BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_flush)( BlockDriverState *bs, BlockCompletionFunc *cb, void *opaque); - BlockAIOCB * GRAPH_RDLOCK_PTR (*bdrv_aio_pdiscard)( - BlockDriverState *bs, int64_t offset, int bytes, - BlockCompletionFunc *cb, void *opaque); - int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_readv)(BlockDriverState *bs, int64_t sector_num, int nb_sectors, QEMUIOVector *qiov); From 141af1b31b10764dcc03a5854ff767b692545e7c Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Tue, 22 Apr 2025 14:27:11 +0900 Subject: [PATCH 0327/2760] hw/net/can: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Emscripten, function pointer casts can result in runtime failures due to strict function signature checks. This affects the use of g_list_sort and g_slist_sort, which internally perform function pointer casts that are not supported by Emscripten. To avoid these issues, g_list_sort_with_data and g_slist_sort_with_data should be used instead, as they do not rely on function pointer casting. Signed-off-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Acked-by: Francisco Iglesias Message-ID: <4d47a75c5768c9a6dc5d8b3504e78837577ad70d.1745295397.git.ktokunaga.mail@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- hw/net/can/xlnx-versal-canfd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/net/can/xlnx-versal-canfd.c b/hw/net/can/xlnx-versal-canfd.c index 79ccc10098..3eb111949f 100644 --- a/hw/net/can/xlnx-versal-canfd.c +++ b/hw/net/can/xlnx-versal-canfd.c @@ -1278,7 +1278,7 @@ static void tx_fifo_stamp(XlnxVersalCANFDState *s, uint32_t tb0_regid) } } -static gint g_cmp_ids(gconstpointer data1, gconstpointer data2) +static gint g_cmp_ids(gconstpointer data1, gconstpointer data2, gpointer d) { tx_ready_reg_info *tx_reg_1 = (tx_ready_reg_info *) data1; tx_ready_reg_info *tx_reg_2 = (tx_ready_reg_info *) data2; @@ -1316,7 +1316,7 @@ static GSList *prepare_tx_data(XlnxVersalCANFDState *s) temp->can_id = s->regs[reg_num]; temp->reg_num = reg_num; list = g_slist_prepend(list, temp); - list = g_slist_sort(list, g_cmp_ids); + list = g_slist_sort_with_data(list, g_cmp_ids, NULL); } reg_ready >>= 1; From 01499add2ae6529589002860e1880ff193a6578a Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Tue, 22 Apr 2025 14:27:10 +0900 Subject: [PATCH 0328/2760] contrib/plugins: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Emscripten, function pointer casts can result in runtime failures due to strict function signature checks. This affects the use of g_list_sort and g_slist_sort, which internally perform function pointer casts that are not supported by Emscripten. To avoid these issues, g_list_sort_with_data and g_slist_sort_with_data should be used instead, as they do not rely on function pointer casting. Signed-off-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Message-ID: <0fcddfca16ca8da2bdaa7b2c114476f5b73d032b.1745295397.git.ktokunaga.mail@gmail.com> Signed-off-by: Philippe Mathieu-Daudé --- contrib/plugins/cache.c | 12 ++++++------ contrib/plugins/cflow.c | 10 +++++----- contrib/plugins/hotblocks.c | 4 ++-- contrib/plugins/hotpages.c | 4 ++-- contrib/plugins/howvec.c | 4 ++-- contrib/plugins/hwprofile.c | 8 ++++---- tests/tcg/plugins/mem.c | 4 ++-- tests/tcg/plugins/syscall.c | 4 ++-- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/contrib/plugins/cache.c b/contrib/plugins/cache.c index 7cfd3df249..56508587d3 100644 --- a/contrib/plugins/cache.c +++ b/contrib/plugins/cache.c @@ -576,7 +576,7 @@ static void sum_stats(void) } } -static int dcmp(gconstpointer a, gconstpointer b) +static int dcmp(gconstpointer a, gconstpointer b, gpointer d) { InsnData *insn_a = (InsnData *) a; InsnData *insn_b = (InsnData *) b; @@ -584,7 +584,7 @@ static int dcmp(gconstpointer a, gconstpointer b) return insn_a->l1_dmisses < insn_b->l1_dmisses ? 1 : -1; } -static int icmp(gconstpointer a, gconstpointer b) +static int icmp(gconstpointer a, gconstpointer b, gpointer d) { InsnData *insn_a = (InsnData *) a; InsnData *insn_b = (InsnData *) b; @@ -592,7 +592,7 @@ static int icmp(gconstpointer a, gconstpointer b) return insn_a->l1_imisses < insn_b->l1_imisses ? 1 : -1; } -static int l2_cmp(gconstpointer a, gconstpointer b) +static int l2_cmp(gconstpointer a, gconstpointer b, gpointer d) { InsnData *insn_a = (InsnData *) a; InsnData *insn_b = (InsnData *) b; @@ -645,7 +645,7 @@ static void log_top_insns(void) InsnData *insn; miss_insns = g_hash_table_get_values(miss_ht); - miss_insns = g_list_sort(miss_insns, dcmp); + miss_insns = g_list_sort_with_data(miss_insns, dcmp, NULL); g_autoptr(GString) rep = g_string_new(""); g_string_append_printf(rep, "%s", "address, data misses, instruction\n"); @@ -659,7 +659,7 @@ static void log_top_insns(void) insn->l1_dmisses, insn->disas_str); } - miss_insns = g_list_sort(miss_insns, icmp); + miss_insns = g_list_sort_with_data(miss_insns, icmp, NULL); g_string_append_printf(rep, "%s", "\naddress, fetch misses, instruction\n"); for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { @@ -676,7 +676,7 @@ static void log_top_insns(void) goto finish; } - miss_insns = g_list_sort(miss_insns, l2_cmp); + miss_insns = g_list_sort_with_data(miss_insns, l2_cmp, NULL); g_string_append_printf(rep, "%s", "\naddress, L2 misses, instruction\n"); for (curr = miss_insns, i = 0; curr && i < limit; i++, curr = curr->next) { diff --git a/contrib/plugins/cflow.c b/contrib/plugins/cflow.c index 930ecb46fc..b5e33f25f9 100644 --- a/contrib/plugins/cflow.c +++ b/contrib/plugins/cflow.c @@ -98,7 +98,7 @@ static GHashTable *nodes; struct qemu_plugin_scoreboard *state; /* SORT_HOTTEST */ -static gint hottest(gconstpointer a, gconstpointer b) +static gint hottest(gconstpointer a, gconstpointer b, gpointer d) { NodeData *na = (NodeData *) a; NodeData *nb = (NodeData *) b; @@ -107,7 +107,7 @@ static gint hottest(gconstpointer a, gconstpointer b) na->dest_count == nb->dest_count ? 0 : 1; } -static gint exception(gconstpointer a, gconstpointer b) +static gint exception(gconstpointer a, gconstpointer b, gpointer d) { NodeData *na = (NodeData *) a; NodeData *nb = (NodeData *) b; @@ -116,7 +116,7 @@ static gint exception(gconstpointer a, gconstpointer b) na->early_exit == nb->early_exit ? 0 : 1; } -static gint popular(gconstpointer a, gconstpointer b) +static gint popular(gconstpointer a, gconstpointer b, gpointer d) { NodeData *na = (NodeData *) a; NodeData *nb = (NodeData *) b; @@ -138,7 +138,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) { g_autoptr(GString) result = g_string_new("collected "); GList *data; - GCompareFunc sort = &hottest; + GCompareDataFunc sort = &hottest; int i = 0; g_mutex_lock(&node_lock); @@ -162,7 +162,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) break; } - data = g_list_sort(data, sort); + data = g_list_sort_with_data(data, sort, NULL); for (GList *l = data; l != NULL && i < topn; diff --git a/contrib/plugins/hotblocks.c b/contrib/plugins/hotblocks.c index f12bfb7a26..98404b6885 100644 --- a/contrib/plugins/hotblocks.c +++ b/contrib/plugins/hotblocks.c @@ -39,7 +39,7 @@ typedef struct { unsigned long insns; } ExecCount; -static gint cmp_exec_count(gconstpointer a, gconstpointer b) +static gint cmp_exec_count(gconstpointer a, gconstpointer b, gpointer d) { ExecCount *ea = (ExecCount *) a; ExecCount *eb = (ExecCount *) b; @@ -79,7 +79,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_string_append_printf(report, "%d entries in the hash table\n", g_hash_table_size(hotblocks)); counts = g_hash_table_get_values(hotblocks); - it = g_list_sort(counts, cmp_exec_count); + it = g_list_sort_with_data(counts, cmp_exec_count, NULL); if (it) { g_string_append_printf(report, "pc, tcount, icount, ecount\n"); diff --git a/contrib/plugins/hotpages.c b/contrib/plugins/hotpages.c index c6e6493719..9d48ac969e 100644 --- a/contrib/plugins/hotpages.c +++ b/contrib/plugins/hotpages.c @@ -48,7 +48,7 @@ typedef struct { static GMutex lock; static GHashTable *pages; -static gint cmp_access_count(gconstpointer a, gconstpointer b) +static gint cmp_access_count(gconstpointer a, gconstpointer b, gpointer d) { PageCounters *ea = (PageCounters *) a; PageCounters *eb = (PageCounters *) b; @@ -83,7 +83,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) if (counts && g_list_next(counts)) { GList *it; - it = g_list_sort(counts, cmp_access_count); + it = g_list_sort_with_data(counts, cmp_access_count, NULL); for (i = 0; i < limit && it->next; i++, it = it->next) { PageCounters *rec = (PageCounters *) it->data; diff --git a/contrib/plugins/howvec.c b/contrib/plugins/howvec.c index 2aa9029c3f..42bddb6566 100644 --- a/contrib/plugins/howvec.c +++ b/contrib/plugins/howvec.c @@ -155,7 +155,7 @@ static ClassSelector class_tables[] = { static InsnClassExecCount *class_table; static int class_table_sz; -static gint cmp_exec_count(gconstpointer a, gconstpointer b) +static gint cmp_exec_count(gconstpointer a, gconstpointer b, gpointer d) { InsnExecCount *ea = (InsnExecCount *) a; InsnExecCount *eb = (InsnExecCount *) b; @@ -208,7 +208,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) counts = g_hash_table_get_values(insns); if (counts && g_list_next(counts)) { g_string_append_printf(report, "Individual Instructions:\n"); - counts = g_list_sort(counts, cmp_exec_count); + counts = g_list_sort_with_data(counts, cmp_exec_count, NULL); for (i = 0; i < limit && g_list_next(counts); i++, counts = g_list_next(counts)) { diff --git a/contrib/plugins/hwprofile.c b/contrib/plugins/hwprofile.c index 2a4cbc47d4..a9838ccc87 100644 --- a/contrib/plugins/hwprofile.c +++ b/contrib/plugins/hwprofile.c @@ -71,7 +71,7 @@ static void plugin_init(void) devices = g_hash_table_new(NULL, NULL); } -static gint sort_cmp(gconstpointer a, gconstpointer b) +static gint sort_cmp(gconstpointer a, gconstpointer b, gpointer d) { DeviceCounts *ea = (DeviceCounts *) a; DeviceCounts *eb = (DeviceCounts *) b; @@ -79,7 +79,7 @@ static gint sort_cmp(gconstpointer a, gconstpointer b) eb->totals.reads + eb->totals.writes ? -1 : 1; } -static gint sort_loc(gconstpointer a, gconstpointer b) +static gint sort_loc(gconstpointer a, gconstpointer b, gpointer d) { IOLocationCounts *ea = (IOLocationCounts *) a; IOLocationCounts *eb = (IOLocationCounts *) b; @@ -126,13 +126,13 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) if (counts && g_list_next(counts)) { GList *it; - it = g_list_sort(counts, sort_cmp); + it = g_list_sort_with_data(counts, sort_cmp, NULL); while (it) { DeviceCounts *rec = (DeviceCounts *) it->data; if (rec->detail) { GList *accesses = g_hash_table_get_values(rec->detail); - GList *io_it = g_list_sort(accesses, sort_loc); + GList *io_it = g_list_sort_with_data(accesses, sort_loc, NULL); const char *prefix = pattern ? "off" : "pc"; g_string_append_printf(report, "%s @ 0x%"PRIx64"\n", rec->name, rec->base); diff --git a/tests/tcg/plugins/mem.c b/tests/tcg/plugins/mem.c index d87d6628e0..ca4e8883dd 100644 --- a/tests/tcg/plugins/mem.c +++ b/tests/tcg/plugins/mem.c @@ -67,7 +67,7 @@ static enum qemu_plugin_mem_rw rw = QEMU_PLUGIN_MEM_RW; static GMutex lock; static GHashTable *regions; -static gint addr_order(gconstpointer a, gconstpointer b) +static gint addr_order(gconstpointer a, gconstpointer b, gpointer d) { RegionInfo *na = (RegionInfo *) a; RegionInfo *nb = (RegionInfo *) b; @@ -94,7 +94,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) if (do_region_summary) { GList *counts = g_hash_table_get_values(regions); - counts = g_list_sort(counts, addr_order); + counts = g_list_sort_with_data(counts, addr_order, NULL); g_string_printf(out, "Region Base, Reads, Writes, Seen all\n"); diff --git a/tests/tcg/plugins/syscall.c b/tests/tcg/plugins/syscall.c index 47aad55fc1..42801f5c86 100644 --- a/tests/tcg/plugins/syscall.c +++ b/tests/tcg/plugins/syscall.c @@ -180,7 +180,7 @@ static void print_entry(gpointer val, gpointer user_data) qemu_plugin_outs(out); } -static gint comp_func(gconstpointer ea, gconstpointer eb) +static gint comp_func(gconstpointer ea, gconstpointer eb, gpointer d) { SyscallStats *ent_a = (SyscallStats *) ea; SyscallStats *ent_b = (SyscallStats *) eb; @@ -197,7 +197,7 @@ static void plugin_exit(qemu_plugin_id_t id, void *p) g_mutex_lock(&lock); GList *entries = g_hash_table_get_values(statistics); - entries = g_list_sort(entries, comp_func); + entries = g_list_sort_with_data(entries, comp_func, NULL); qemu_plugin_outs("syscall no. calls errors\n"); g_list_foreach(entries, print_entry, NULL); From 16704598bf3fa8578880e7146a0196d9411ea098 Mon Sep 17 00:00:00 2001 From: Kohei Tokunaga Date: Tue, 22 Apr 2025 14:27:07 +0900 Subject: [PATCH 0329/2760] system/vl: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Emscripten, function pointer casts can result in runtime failures due to strict function signature checks. This affects the use of g_list_sort and g_slist_sort, which internally perform function pointer casts that are not supported by Emscripten. To avoid these issues, g_list_sort_with_data and g_slist_sort_with_data should be used instead, as they do not rely on function pointer casting. Signed-off-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Message-ID: Signed-off-by: Philippe Mathieu-Daudé --- system/vl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/vl.c b/system/vl.c index c17945c493..4ab2001df7 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1524,7 +1524,7 @@ static bool debugcon_parse(const char *devname, Error **errp) return true; } -static gint machine_class_cmp(gconstpointer a, gconstpointer b) +static gint machine_class_cmp(gconstpointer a, gconstpointer b, gpointer d) { const MachineClass *mc1 = a, *mc2 = b; int res; @@ -1574,7 +1574,7 @@ static void machine_help_func(const QDict *qdict) } printf("Supported machines are:\n"); - machines = g_slist_sort(machines, machine_class_cmp); + machines = g_slist_sort_with_data(machines, machine_class_cmp, NULL); for (el = machines; el; el = el->next) { MachineClass *mc = el->data; if (mc->alias) { From 8af0e52b28c553c901e7c564c3380cd56d363053 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 23 Apr 2025 13:11:31 +0200 Subject: [PATCH 0330/2760] system/memory: Remove DEVICE_HOST_ENDIAN definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the previous commit ("exec/memory.h: make devend_memop "target defines" agnostic") there is a single use of the DEVICE_HOST_ENDIAN definition in ram_device_mem_ops: inline it and remove its definition altogether. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: David Hildenbrand Reviewed-by: Richard Henderson Message-Id: <20250423111625.10424-1-philmd@linaro.org> --- include/exec/cpu-common.h | 6 ------ system/memory-internal.h | 3 --- system/memory.c | 2 +- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/include/exec/cpu-common.h b/include/exec/cpu-common.h index 9b83fd7ac8..dab1e7e580 100644 --- a/include/exec/cpu-common.h +++ b/include/exec/cpu-common.h @@ -44,12 +44,6 @@ enum device_endian { DEVICE_LITTLE_ENDIAN, }; -#if HOST_BIG_ENDIAN -#define DEVICE_HOST_ENDIAN DEVICE_BIG_ENDIAN -#else -#define DEVICE_HOST_ENDIAN DEVICE_LITTLE_ENDIAN -#endif - /* address in the RAM (different from a physical address) */ #if defined(CONFIG_XEN_BACKEND) typedef uint64_t ram_addr_t; diff --git a/system/memory-internal.h b/system/memory-internal.h index 29717b3c58..46f758fa7e 100644 --- a/system/memory-internal.h +++ b/system/memory-internal.h @@ -41,9 +41,6 @@ void mtree_print_dispatch(struct AddressSpaceDispatch *d, /* returns true if end is big endian. */ static inline bool devend_big_endian(enum device_endian end) { - QEMU_BUILD_BUG_ON(DEVICE_HOST_ENDIAN != DEVICE_LITTLE_ENDIAN && - DEVICE_HOST_ENDIAN != DEVICE_BIG_ENDIAN); - if (end == DEVICE_NATIVE_ENDIAN) { return target_big_endian(); } diff --git a/system/memory.c b/system/memory.c index 67e433095b..71434e7ad0 100644 --- a/system/memory.c +++ b/system/memory.c @@ -1382,7 +1382,7 @@ static void memory_region_ram_device_write(void *opaque, hwaddr addr, static const MemoryRegionOps ram_device_mem_ops = { .read = memory_region_ram_device_read, .write = memory_region_ram_device_write, - .endianness = DEVICE_HOST_ENDIAN, + .endianness = HOST_BIG_ENDIAN ? DEVICE_BIG_ENDIAN : DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, .max_access_size = 8, From fcb1ad456c58ba2304127b0131ac0b48895b2a3b Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 23 Apr 2025 12:02:20 +0200 Subject: [PATCH 0331/2760] system/datadir: Add new type constant for DTB files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently DTB files are mixed with ROMs under BIOS type. Separate them under a new type constant and turn defines into an enum while at it. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-ID: Signed-off-by: Philippe Mathieu-Daudé --- hw/microblaze/boot.c | 2 +- hw/ppc/ppc440_bamboo.c | 2 +- hw/ppc/sam460ex.c | 2 +- hw/ppc/virtex_ml507.c | 2 +- include/qemu/datadir.h | 11 ++++++++--- system/datadir.c | 3 ++- 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/hw/microblaze/boot.c b/hw/microblaze/boot.c index 60b4ef0abe..4a9c9df318 100644 --- a/hw/microblaze/boot.c +++ b/hw/microblaze/boot.c @@ -130,7 +130,7 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, bool is_little_endian, dtb_arg = current_machine->dtb; /* default to pcbios dtb as passed by machine_init */ if (!dtb_arg && dtb_filename) { - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, dtb_filename); + filename = qemu_find_file(QEMU_FILE_TYPE_DTB, dtb_filename); } boot_info.machine_cpu_reset = machine_cpu_reset; diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c index 099fda3909..6fff0d8afb 100644 --- a/hw/ppc/ppc440_bamboo.c +++ b/hw/ppc/ppc440_bamboo.c @@ -64,7 +64,7 @@ static int bamboo_load_device_tree(MachineState *machine, uint32_t tb_freq = 400000000; uint32_t clock_freq = 400000000; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + filename = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE); if (!filename) { return -1; } diff --git a/hw/ppc/sam460ex.c b/hw/ppc/sam460ex.c index a070de23cf..ee31bd8f34 100644 --- a/hw/ppc/sam460ex.c +++ b/hw/ppc/sam460ex.c @@ -142,7 +142,7 @@ static int sam460ex_load_device_tree(MachineState *machine, uint32_t clock_freq = CPU_FREQ; int offset; - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + filename = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE); if (!filename) { error_report("Couldn't find dtb file `%s'", BINARY_DEVICE_TREE_FILE); exit(1); diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c index 17115be74d..c9969ae48a 100644 --- a/hw/ppc/virtex_ml507.c +++ b/hw/ppc/virtex_ml507.c @@ -146,7 +146,7 @@ static int xilinx_load_device_tree(MachineState *machine, /* Try the local "ppc.dtb" override. */ fdt = load_device_tree("ppc.dtb", &fdt_size); if (!fdt) { - path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE); + path = qemu_find_file(QEMU_FILE_TYPE_DTB, BINARY_DEVICE_TREE_FILE); if (path) { fdt = load_device_tree(path, &fdt_size); g_free(path); diff --git a/include/qemu/datadir.h b/include/qemu/datadir.h index 21f9097f58..cca32af300 100644 --- a/include/qemu/datadir.h +++ b/include/qemu/datadir.h @@ -1,11 +1,16 @@ #ifndef QEMU_DATADIR_H #define QEMU_DATADIR_H -#define QEMU_FILE_TYPE_BIOS 0 -#define QEMU_FILE_TYPE_KEYMAP 1 +typedef enum { + QEMU_FILE_TYPE_BIOS, + QEMU_FILE_TYPE_DTB, + QEMU_FILE_TYPE_KEYMAP, +} QemuFileType; + /** * qemu_find_file: * @type: QEMU_FILE_TYPE_BIOS (for BIOS, VGA BIOS) + * QEMU_FILE_TYPE_DTB (for device tree blobs) * or QEMU_FILE_TYPE_KEYMAP (for keymaps). * @name: Relative or absolute file name * @@ -20,7 +25,7 @@ * * Returns: a path that can access @name, or NULL if no matching file exists. */ -char *qemu_find_file(int type, const char *name); +char *qemu_find_file(QemuFileType type, const char *name); void qemu_add_default_firmwarepath(void); void qemu_add_data_dir(char *path); void qemu_list_data_dirs(void); diff --git a/system/datadir.c b/system/datadir.c index c9237cb5d4..e450b84ce9 100644 --- a/system/datadir.c +++ b/system/datadir.c @@ -30,7 +30,7 @@ static const char *data_dir[16]; static int data_dir_idx; -char *qemu_find_file(int type, const char *name) +char *qemu_find_file(QemuFileType type, const char *name) { int i; const char *subdir; @@ -44,6 +44,7 @@ char *qemu_find_file(int type, const char *name) switch (type) { case QEMU_FILE_TYPE_BIOS: + case QEMU_FILE_TYPE_DTB: subdir = ""; break; case QEMU_FILE_TYPE_KEYMAP: From 12963e79ca461db7b098c8eb00bb21cf88a250a4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Wed, 23 Apr 2025 12:02:21 +0200 Subject: [PATCH 0332/2760] pc-bios: Move device tree files in their own subdir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We have several device tree files already and may have more in the future so add a new dtb subdirectory and move device tree files there so they are not mixed with ROM binaries. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Message-ID: <57f179bd3904c1f2ca062ca4d4ff9592bb4f4daa.1745402140.git.balaton@eik.bme.hu> Signed-off-by: Philippe Mathieu-Daudé --- MAINTAINERS | 2 +- pc-bios/{ => dtb}/bamboo.dtb | Bin pc-bios/{ => dtb}/bamboo.dts | 0 pc-bios/{ => dtb}/canyonlands.dtb | Bin pc-bios/{ => dtb}/canyonlands.dts | 0 pc-bios/dtb/meson.build | 23 +++++++++++++++++++++ pc-bios/{ => dtb}/petalogix-ml605.dtb | Bin pc-bios/{ => dtb}/petalogix-ml605.dts | 0 pc-bios/{ => dtb}/petalogix-s3adsp1800.dtb | Bin pc-bios/{ => dtb}/petalogix-s3adsp1800.dts | 0 pc-bios/meson.build | 23 +-------------------- qemu.nsi | 2 +- system/datadir.c | 4 +++- 13 files changed, 29 insertions(+), 25 deletions(-) rename pc-bios/{ => dtb}/bamboo.dtb (100%) rename pc-bios/{ => dtb}/bamboo.dts (100%) rename pc-bios/{ => dtb}/canyonlands.dtb (100%) rename pc-bios/{ => dtb}/canyonlands.dts (100%) create mode 100644 pc-bios/dtb/meson.build rename pc-bios/{ => dtb}/petalogix-ml605.dtb (100%) rename pc-bios/{ => dtb}/petalogix-ml605.dts (100%) rename pc-bios/{ => dtb}/petalogix-s3adsp1800.dtb (100%) rename pc-bios/{ => dtb}/petalogix-s3adsp1800.dts (100%) diff --git a/MAINTAINERS b/MAINTAINERS index 661a47db5a..d82d962f1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1581,7 +1581,7 @@ F: hw/pci-host/ppc440_pcix.c F: hw/display/sm501* F: hw/ide/sii3112.c F: hw/rtc/m41t80.c -F: pc-bios/canyonlands.dt[sb] +F: pc-bios/dtb/canyonlands.dt[sb] F: pc-bios/u-boot-sam460ex-20100605.bin F: roms/u-boot-sam460ex F: docs/system/ppc/amigang.rst diff --git a/pc-bios/bamboo.dtb b/pc-bios/dtb/bamboo.dtb similarity index 100% rename from pc-bios/bamboo.dtb rename to pc-bios/dtb/bamboo.dtb diff --git a/pc-bios/bamboo.dts b/pc-bios/dtb/bamboo.dts similarity index 100% rename from pc-bios/bamboo.dts rename to pc-bios/dtb/bamboo.dts diff --git a/pc-bios/canyonlands.dtb b/pc-bios/dtb/canyonlands.dtb similarity index 100% rename from pc-bios/canyonlands.dtb rename to pc-bios/dtb/canyonlands.dtb diff --git a/pc-bios/canyonlands.dts b/pc-bios/dtb/canyonlands.dts similarity index 100% rename from pc-bios/canyonlands.dts rename to pc-bios/dtb/canyonlands.dts diff --git a/pc-bios/dtb/meson.build b/pc-bios/dtb/meson.build new file mode 100644 index 0000000000..7a71835bca --- /dev/null +++ b/pc-bios/dtb/meson.build @@ -0,0 +1,23 @@ +dtbs = [ + 'bamboo.dtb', + 'canyonlands.dtb', + 'petalogix-ml605.dtb', + 'petalogix-s3adsp1800.dtb', +] + +dtc = find_program('dtc', required: false) +if dtc.found() + foreach out : dtbs + f = fs.replace_suffix(out, '.dts') + custom_target(f, + build_by_default: have_system, + input: files(f), + output: out, + install: get_option('install_blobs'), + install_dir: qemu_datadir / 'dtb', + command: [ dtc, '-q', '-I', 'dts', '-O', 'dtb', + '-o', '@OUTPUT@', '@INPUT0@' ]) + endforeach +else + install_data(dtbs, install_dir: qemu_datadir / 'dtb') +endif diff --git a/pc-bios/petalogix-ml605.dtb b/pc-bios/dtb/petalogix-ml605.dtb similarity index 100% rename from pc-bios/petalogix-ml605.dtb rename to pc-bios/dtb/petalogix-ml605.dtb diff --git a/pc-bios/petalogix-ml605.dts b/pc-bios/dtb/petalogix-ml605.dts similarity index 100% rename from pc-bios/petalogix-ml605.dts rename to pc-bios/dtb/petalogix-ml605.dts diff --git a/pc-bios/petalogix-s3adsp1800.dtb b/pc-bios/dtb/petalogix-s3adsp1800.dtb similarity index 100% rename from pc-bios/petalogix-s3adsp1800.dtb rename to pc-bios/dtb/petalogix-s3adsp1800.dtb diff --git a/pc-bios/petalogix-s3adsp1800.dts b/pc-bios/dtb/petalogix-s3adsp1800.dts similarity index 100% rename from pc-bios/petalogix-s3adsp1800.dts rename to pc-bios/dtb/petalogix-s3adsp1800.dts diff --git a/pc-bios/meson.build b/pc-bios/meson.build index 34d6616c32..34d8cc4f33 100644 --- a/pc-bios/meson.build +++ b/pc-bios/meson.build @@ -86,31 +86,10 @@ blobs = [ 'vof-nvram.bin', ] -dtc = find_program('dtc', required: false) -foreach f : [ - 'bamboo.dts', - 'canyonlands.dts', - 'petalogix-s3adsp1800.dts', - 'petalogix-ml605.dts', -] - out = fs.replace_suffix(f, '.dtb') - if dtc.found() - custom_target(f, - build_by_default: have_system, - input: files(f), - output: out, - install: get_option('install_blobs'), - install_dir: qemu_datadir, - command: [ dtc, '-q', '-I', 'dts', '-O', 'dtb', - '-o', '@OUTPUT@', '@INPUT0@' ]) - else - blobs += out - endif -endforeach - if get_option('install_blobs') install_data(blobs, install_dir: qemu_datadir) endif subdir('descriptors') +subdir('dtb') subdir('keymaps') diff --git a/qemu.nsi b/qemu.nsi index b186f223e1..d419986ca0 100644 --- a/qemu.nsi +++ b/qemu.nsi @@ -204,7 +204,6 @@ Section "Uninstall" Delete "$INSTDIR\*.bmp" Delete "$INSTDIR\*.bin" Delete "$INSTDIR\*.dll" - Delete "$INSTDIR\*.dtb" Delete "$INSTDIR\*.fd" Delete "$INSTDIR\*.img" Delete "$INSTDIR\*.lid" @@ -215,6 +214,7 @@ Section "Uninstall" Delete "$INSTDIR\qemu-io.exe" Delete "$INSTDIR\qemu.exe" Delete "$INSTDIR\qemu-system-*.exe" + RMDir /r "$INSTDIR\dtb" RMDir /r "$INSTDIR\doc" RMDir /r "$INSTDIR\share" ; Remove generated files diff --git a/system/datadir.c b/system/datadir.c index e450b84ce9..f96f8fc264 100644 --- a/system/datadir.c +++ b/system/datadir.c @@ -44,9 +44,11 @@ char *qemu_find_file(QemuFileType type, const char *name) switch (type) { case QEMU_FILE_TYPE_BIOS: - case QEMU_FILE_TYPE_DTB: subdir = ""; break; + case QEMU_FILE_TYPE_DTB: + subdir = "dtb/"; + break; case QEMU_FILE_TYPE_KEYMAP: subdir = "keymaps/"; break; From 563cd698dffb977eea0ccfef3b95f6f9786766f3 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 24 Apr 2025 13:50:11 +0900 Subject: [PATCH 0333/2760] meson: Use has_header_symbol() to check getcpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The use of gnu_source_prefix in the detection of getcpu() was ineffective because the header file that declares getcpu() when _GNU_SOURCE is defined was not included. Pass sched.h to has_header_symbol() so that the existence of the declaration will be properly checked. Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20250424-buildsys-v1-1-97655e3b25d7@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index bcb9d39a38..f77a9ce569 100644 --- a/meson.build +++ b/meson.build @@ -2635,7 +2635,6 @@ config_host_data.set('CONFIG_CLOCK_ADJTIME', cc.has_function('clock_adjtime')) config_host_data.set('CONFIG_DUP3', cc.has_function('dup3')) config_host_data.set('CONFIG_FALLOCATE', cc.has_function('fallocate')) config_host_data.set('CONFIG_POSIX_FALLOCATE', cc.has_function('posix_fallocate')) -config_host_data.set('CONFIG_GETCPU', cc.has_function('getcpu', prefix: gnu_source_prefix)) config_host_data.set('CONFIG_SCHED_GETCPU', cc.has_function('sched_getcpu', prefix: '#include ')) # Note that we need to specify prefix: here to avoid incorrectly # thinking that Windows has posix_memalign() @@ -2713,6 +2712,8 @@ config_host_data.set('CONFIG_FALLOCATE_ZERO_RANGE', config_host_data.set('CONFIG_FIEMAP', cc.has_header('linux/fiemap.h') and cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP')) +config_host_data.set('CONFIG_GETCPU', + cc.has_header_symbol('sched.h', 'getcpu', prefix: gnu_source_prefix)) config_host_data.set('CONFIG_GETRANDOM', cc.has_function('getrandom') and cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) From 6804b89fb531f5dd49c1e038214c89272383e220 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 24 Apr 2025 13:50:12 +0900 Subject: [PATCH 0334/2760] meson: Remove CONFIG_STATX and CONFIG_STATX_MNT_ID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CONFIG_STATX and CONFIG_STATX_MNT_ID are not used since commit e0dc2631ec4 ("virtiofsd: Remove source"). Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20250424-buildsys-v1-2-97655e3b25d7@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- meson.build | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/meson.build b/meson.build index f77a9ce569..35dcec8ce5 100644 --- a/meson.build +++ b/meson.build @@ -2191,14 +2191,6 @@ gnu_source_prefix = ''' #endif ''' -# Check whether the glibc provides STATX_BASIC_STATS - -has_statx = cc.has_header_symbol('sys/stat.h', 'STATX_BASIC_STATS', prefix: gnu_source_prefix) - -# Check whether statx() provides mount ID information - -has_statx_mnt_id = cc.has_header_symbol('sys/stat.h', 'STATX_MNT_ID', prefix: gnu_source_prefix) - have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ .require(host_os == 'linux', error_message: 'vhost_user_blk_server requires linux') \ @@ -2560,8 +2552,6 @@ config_host_data.set('CONFIG_CRYPTO_SM3', crypto_sm3.found()) config_host_data.set('CONFIG_HOGWEED', hogweed.found()) config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private') config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim) -config_host_data.set('CONFIG_STATX', has_statx) -config_host_data.set('CONFIG_STATX_MNT_ID', has_statx_mnt_id) config_host_data.set('CONFIG_ZSTD', zstd.found()) config_host_data.set('CONFIG_QPL', qpl.found()) config_host_data.set('CONFIG_UADK', uadk.found()) From 797150d69d2edba8b1bd4a7d8c7ba2df1219c503 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 24 Apr 2025 13:50:13 +0900 Subject: [PATCH 0335/2760] meson: Share common C source prefixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gnu_source_prefix defines _GNU_SOURCE for compiler object functions. The definition is universally available in the code base. docs/devel/style.rst also says that the "qemu/osdep.h" header is always included, so files included in the file is also universally available in the code base. Rename gnu_source_prefix to osdep_prefix, and add #include directives that are referred by the users of gnu_source_prefix and contained in qemu/osdep.h to safely de-duplicate #include directives. Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20250424-buildsys-v1-3-97655e3b25d7@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- meson.build | 68 +++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/meson.build b/meson.build index 35dcec8ce5..d93dbde194 100644 --- a/meson.build +++ b/meson.build @@ -2185,10 +2185,21 @@ if not has_malloc_trim and get_option('malloc_trim').enabled() endif endif -gnu_source_prefix = ''' +osdep_prefix = ''' #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif + + #include + #include + + #include + /* Put unistd.h before time.h as that triggers localtime_r/gmtime_r + * function availability on recentish Mingw-w64 platforms. */ + #include + #include + #include + #include ''' have_vhost_user_blk_server = get_option('vhost_user_blk_server') \ @@ -2703,7 +2714,7 @@ config_host_data.set('CONFIG_FIEMAP', cc.has_header('linux/fiemap.h') and cc.has_header_symbol('linux/fs.h', 'FS_IOC_FIEMAP')) config_host_data.set('CONFIG_GETCPU', - cc.has_header_symbol('sched.h', 'getcpu', prefix: gnu_source_prefix)) + cc.has_header_symbol('sched.h', 'getcpu', prefix: osdep_prefix)) config_host_data.set('CONFIG_GETRANDOM', cc.has_function('getrandom') and cc.has_header_symbol('sys/random.h', 'GRND_NONBLOCK')) @@ -2748,8 +2759,7 @@ config_host_data.set('HAVE_UTMPX', config_host_data.set('CONFIG_EVENTFD', cc.links(''' #include int main(void) { return eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); }''')) -config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + ''' - #include +config_host_data.set('CONFIG_FDATASYNC', cc.links(osdep_prefix + ''' int main(void) { #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 return fdatasync(0); @@ -2758,10 +2768,8 @@ config_host_data.set('CONFIG_FDATASYNC', cc.links(gnu_source_prefix + ''' #endif }''')) -has_madvise = cc.links(gnu_source_prefix + ''' - #include +has_madvise = cc.links(osdep_prefix + ''' #include - #include int main(void) { return madvise(NULL, 0, MADV_DONTNEED); }''') missing_madvise_proto = false if has_madvise @@ -2771,21 +2779,18 @@ if has_madvise # missing-prototype case, we try again with a definitely-bogus prototype. # This will only compile if the system headers don't provide the prototype; # otherwise the conflicting prototypes will cause a compiler error. - missing_madvise_proto = cc.links(gnu_source_prefix + ''' - #include + missing_madvise_proto = cc.links(osdep_prefix + '''> #include - #include extern int madvise(int); int main(void) { return madvise(0); }''') endif config_host_data.set('CONFIG_MADVISE', has_madvise) config_host_data.set('HAVE_MADVISE_WITHOUT_PROTOTYPE', missing_madvise_proto) -config_host_data.set('CONFIG_MEMFD', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_MEMFD', cc.links(osdep_prefix + ''' #include int main(void) { return memfd_create("foo", MFD_ALLOW_SEALING); }''')) -config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + ''' - #include +config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(osdep_prefix + ''' #if !defined(AT_EMPTY_PATH) # error missing definition #else @@ -2796,13 +2801,12 @@ config_host_data.set('CONFIG_OPEN_BY_HANDLE', cc.links(gnu_source_prefix + ''' # i.e. errno is set and -1 is returned. That's not really how POSIX defines the # function. On the flip side, it has madvise() which is preferred anyways. if host_os != 'darwin' - config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(gnu_source_prefix + ''' + config_host_data.set('CONFIG_POSIX_MADVISE', cc.links(osdep_prefix + ''' #include - #include int main(void) { return posix_madvise(NULL, 0, POSIX_MADV_DONTNEED); }''')) endif -config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(osdep_prefix + ''' #include static void *f(void *p) { return NULL; } @@ -2813,7 +2817,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_W_TID', cc.links(gnu_source_pref pthread_setname_np(thread, "QEMU"); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(osdep_prefix + ''' #include static void *f(void *p) { pthread_setname_np("QEMU"); return NULL; } @@ -2823,7 +2827,7 @@ config_host_data.set('CONFIG_PTHREAD_SETNAME_NP_WO_TID', cc.links(gnu_source_pre pthread_create(&thread, 0, f, 0); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(osdep_prefix + ''' #include #include @@ -2835,9 +2839,8 @@ config_host_data.set('CONFIG_PTHREAD_SET_NAME_NP', cc.links(gnu_source_prefix + pthread_set_name_np(thread, "QEMU"); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(osdep_prefix + ''' #include - #include int main(void) { @@ -2846,7 +2849,7 @@ config_host_data.set('CONFIG_PTHREAD_CONDATTR_SETCLOCK', cc.links(gnu_source_pre pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(osdep_prefix + ''' #include static void *f(void *p) { return NULL; } @@ -2863,15 +2866,10 @@ config_host_data.set('CONFIG_PTHREAD_AFFINITY_NP', cc.links(gnu_source_prefix + CPU_FREE(cpuset); return 0; }''', dependencies: threads)) -config_host_data.set('CONFIG_SIGNALFD', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_SIGNALFD', cc.links(osdep_prefix + ''' #include - #include int main(void) { return signalfd(-1, NULL, SFD_CLOEXEC); }''')) -config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + ''' - #include - #include - #include - +config_host_data.set('CONFIG_SPLICE', cc.links(osdep_prefix + ''' int main(void) { int len, fd = 0; @@ -2880,13 +2878,13 @@ config_host_data.set('CONFIG_SPLICE', cc.links(gnu_source_prefix + ''' return 0; }''')) -config_host_data.set('HAVE_MLOCKALL', cc.links(gnu_source_prefix + ''' +config_host_data.set('HAVE_MLOCKALL', cc.links(osdep_prefix + ''' #include int main(void) { return mlockall(MCL_FUTURE); }''')) -config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + ''' +config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(osdep_prefix + ''' #include int main(void) { return mlockall(MCL_FUTURE | MCL_ONFAULT); @@ -2895,7 +2893,7 @@ config_host_data.set('HAVE_MLOCK_ONFAULT', cc.links(gnu_source_prefix + ''' have_l2tpv3 = false if get_option('l2tpv3').allowed() and have_system have_l2tpv3 = cc.has_type('struct mmsghdr', - prefix: gnu_source_prefix + ''' + prefix: osdep_prefix + ''' #include #include ''') endif @@ -3011,13 +3009,13 @@ if has_int128_type endif endif -config_host_data.set('CONFIG_GETAUXVAL', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_GETAUXVAL', cc.links(osdep_prefix + ''' #include int main(void) { return getauxval(AT_HWCAP) == 0; }''')) -config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(gnu_source_prefix + ''' +config_host_data.set('CONFIG_ELF_AUX_INFO', cc.links(osdep_prefix + ''' #include int main(void) { unsigned long hwcap = 0; @@ -3130,9 +3128,7 @@ config_host_data.set('CONFIG_MEMBARRIER', get_option('membarrier') \ .allowed()) have_afalg = get_option('crypto_afalg') \ - .require(cc.compiles(gnu_source_prefix + ''' - #include - #include + .require(cc.compiles(osdep_prefix + ''' #include #include int main(void) { From a5b30be534538dc6e44a68ce9734e45dd08f52ec Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Thu, 24 Apr 2025 13:50:14 +0900 Subject: [PATCH 0336/2760] meson: Use osdep_prefix for strchrnul() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS SDK may have the symbol of strchrnul(), but it is actually available only on macOS 15.4 or later and that fact is codified in string.h. Include the header file using osdep_prefix to check if the function is available on the deployment target. Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Message-ID: <20250424-buildsys-v1-4-97655e3b25d7@daynix.com> Signed-off-by: Philippe Mathieu-Daudé --- meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d93dbde194..c736a6f4c4 100644 --- a/meson.build +++ b/meson.build @@ -2193,6 +2193,7 @@ osdep_prefix = ''' #include #include + #include #include /* Put unistd.h before time.h as that triggers localtime_r/gmtime_r * function availability on recentish Mingw-w64 platforms. */ @@ -2657,7 +2658,7 @@ config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs')) config_host_data.set('HAVE_GLIB_WITH_SLICE_ALLOCATOR', glib_has_gslice) config_host_data.set('HAVE_GLIB_WITH_ALIGNED_ALLOC', glib_has_aligned_alloc) config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util)) -config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul')) +config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul', prefix: osdep_prefix)) config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include ')) if rbd.found() config_host_data.set('HAVE_RBD_NAMESPACE_EXISTS', From 2ef9faf03720a40eae7fc8956f1941dddfb0eea7 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 24 Apr 2025 16:28:28 -0700 Subject: [PATCH 0337/2760] system/kvm: make functions accessible from common code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250424232829.141163-8-pierrick.bouvier@linaro.org> Signed-off-by: Philippe Mathieu-Daudé --- include/system/kvm.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/system/kvm.h b/include/system/kvm.h index 18811cad6f..b690dda137 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -210,6 +210,10 @@ bool kvm_arm_supports_user_irq(void); int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr); int kvm_on_sigbus(int code, void *addr); +int kvm_check_extension(KVMState *s, unsigned int extension); + +int kvm_vm_ioctl(KVMState *s, unsigned long type, ...); + void kvm_flush_coalesced_mmio_buffer(void); #ifdef COMPILING_PER_TARGET @@ -237,8 +241,6 @@ static inline int kvm_update_guest_debug(CPUState *cpu, unsigned long reinject_t int kvm_ioctl(KVMState *s, unsigned long type, ...); -int kvm_vm_ioctl(KVMState *s, unsigned long type, ...); - int kvm_vcpu_ioctl(CPUState *cpu, unsigned long type, ...); /** @@ -441,8 +443,6 @@ void kvm_arch_update_guest_debug(CPUState *cpu, struct kvm_guest_debug *dbg); bool kvm_arch_stop_on_emulation_error(CPUState *cpu); -int kvm_check_extension(KVMState *s, unsigned int extension); - int kvm_vm_check_extension(KVMState *s, unsigned int extension); #define kvm_vm_enable_cap(s, capability, cap_flags, ...) \ From 58bc9db84af4e1bf3a8c55fa18277acbfaeb1caf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 09:48:42 +0200 Subject: [PATCH 0338/2760] accel/tcg: Correct list of included headers in tcg-stub.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 3549118b498 we moved cpu_loop_exit*() declarations to "exec/cpu-common.h" but neglected to update tcg-stub.c. We missed it because "exec/cpu-common.h" is indirectly pulled in via "exec/exec-all.h" -> "exec/translation-block.h". Include it directly instead of the not necessary "exec/exec-all.h". Commit bb6cf6f0168 ("accel/tcg: Factor tcg_cpu_reset_hold() out") removed the need for "exec/tb-flush.h", so remote it too. Fixes: 3549118b498 ("exec: Move cpu_loop_foo() functions to 'cpu-common.h'") Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Message-Id: <20250424094653.35932-4-philmd@linaro.org> --- accel/stubs/tcg-stub.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c index b2b9881bdf..3b76b8b17c 100644 --- a/accel/stubs/tcg-stub.c +++ b/accel/stubs/tcg-stub.c @@ -11,8 +11,7 @@ */ #include "qemu/osdep.h" -#include "exec/tb-flush.h" -#include "exec/exec-all.h" +#include "exec/cpu-common.h" G_NORETURN void cpu_loop_exit(CPUState *cpu) { From f56159e82885bb7cbbe5d28698a486c7ccbfb2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 10:18:58 +0200 Subject: [PATCH 0339/2760] target/hexagon: Include missing 'accel/tcg/getpc.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the macros.h headers call GETPC(), they need to include "accel/tcg/getpc.h", which defines it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Reviewed-by: Brian Cain Message-Id: <20250424094653.35932-9-philmd@linaro.org> --- target/hexagon/macros.h | 1 + target/hexagon/mmvec/macros.h | 1 + 2 files changed, 2 insertions(+) diff --git a/target/hexagon/macros.h b/target/hexagon/macros.h index e5eb31e671..9ba9be408d 100644 --- a/target/hexagon/macros.h +++ b/target/hexagon/macros.h @@ -21,6 +21,7 @@ #include "cpu.h" #include "hex_regs.h" #include "reg_fields.h" +#include "accel/tcg/getpc.h" #define GET_FIELD(FIELD, REGIN) \ fEXTRACTU_BITS(REGIN, reg_field_info[FIELD].width, \ diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index bcd4a1e897..c1a88392c0 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -21,6 +21,7 @@ #include "qemu/host-utils.h" #include "arch.h" #include "mmvec/system_ext_mmvec.h" +#include "accel/tcg/getpc.h" #ifndef QEMU_GENERATE #define VdV (*(MMVector *restrict)(VdV_void)) From 4e442406fde1957a8c4eebbcd878fb5f25cc49c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 10:38:10 +0200 Subject: [PATCH 0340/2760] linux-user/elfload: Use target_needs_bswap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check whether we need to swap at runtime using target_needs_bswap(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-2-philmd@linaro.org> --- linux-user/elfload.c | 63 +++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 24 deletions(-) diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 99811af5e7..fbfdec2f17 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -12,6 +12,7 @@ #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "exec/translation-block.h" +#include "exec/tswap.h" #include "user/guest-base.h" #include "user-internals.h" #include "signal-common.h" @@ -2122,9 +2123,12 @@ static inline void memcpy_fromfs(void * to, const void * from, unsigned long n) memcpy(to, from, n); } -#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN static void bswap_ehdr(struct elfhdr *ehdr) { + if (!target_needs_bswap()) { + return; + } + bswap16s(&ehdr->e_type); /* Object file type */ bswap16s(&ehdr->e_machine); /* Architecture */ bswap32s(&ehdr->e_version); /* Object file version */ @@ -2142,8 +2146,11 @@ static void bswap_ehdr(struct elfhdr *ehdr) static void bswap_phdr(struct elf_phdr *phdr, int phnum) { - int i; - for (i = 0; i < phnum; ++i, ++phdr) { + if (!target_needs_bswap()) { + return; + } + + for (int i = 0; i < phnum; ++i, ++phdr) { bswap32s(&phdr->p_type); /* Segment type */ bswap32s(&phdr->p_flags); /* Segment flags */ bswaptls(&phdr->p_offset); /* Segment file offset */ @@ -2157,8 +2164,11 @@ static void bswap_phdr(struct elf_phdr *phdr, int phnum) static void bswap_shdr(struct elf_shdr *shdr, int shnum) { - int i; - for (i = 0; i < shnum; ++i, ++shdr) { + if (!target_needs_bswap()) { + return; + } + + for (int i = 0; i < shnum; ++i, ++shdr) { bswap32s(&shdr->sh_name); bswap32s(&shdr->sh_type); bswaptls(&shdr->sh_flags); @@ -2174,6 +2184,10 @@ static void bswap_shdr(struct elf_shdr *shdr, int shnum) static void bswap_sym(struct elf_sym *sym) { + if (!target_needs_bswap()) { + return; + } + bswap32s(&sym->st_name); bswaptls(&sym->st_value); bswaptls(&sym->st_size); @@ -2183,6 +2197,10 @@ static void bswap_sym(struct elf_sym *sym) #ifdef TARGET_MIPS static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { + if (!target_needs_bswap()) { + return; + } + bswap16s(&abiflags->version); bswap32s(&abiflags->ases); bswap32s(&abiflags->isa_ext); @@ -2190,15 +2208,6 @@ static void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) bswap32s(&abiflags->flags2); } #endif -#else -static inline void bswap_ehdr(struct elfhdr *ehdr) { } -static inline void bswap_phdr(struct elf_phdr *phdr, int phnum) { } -static inline void bswap_shdr(struct elf_shdr *shdr, int shnum) { } -static inline void bswap_sym(struct elf_sym *sym) { } -#ifdef TARGET_MIPS -static inline void bswap_mips_abiflags(Mips_elf_abiflags_v0 *abiflags) { } -#endif -#endif #ifdef USE_ELF_CORE_DUMP static int elf_core_dump(int, const CPUArchState *); @@ -3144,11 +3153,11 @@ static bool parse_elf_properties(const ImageSource *src, * The contents of a valid PT_GNU_PROPERTY is a sequence of uint32_t. * Swap most of them now, beyond the header and namesz. */ -#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN - for (int i = 4; i < n / 4; i++) { - bswap32s(note.data + i); + if (target_needs_bswap()) { + for (int i = 4; i < n / 4; i++) { + bswap32s(note.data + i); + } } -#endif /* * Note that nhdr is 3 words, and that the "name" described by namesz @@ -4000,9 +4009,12 @@ struct target_elf_prpsinfo { char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ }; -#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN static void bswap_prstatus(struct target_elf_prstatus *prstatus) { + if (!target_needs_bswap()) { + return; + } + prstatus->pr_info.si_signo = tswap32(prstatus->pr_info.si_signo); prstatus->pr_info.si_code = tswap32(prstatus->pr_info.si_code); prstatus->pr_info.si_errno = tswap32(prstatus->pr_info.si_errno); @@ -4020,6 +4032,10 @@ static void bswap_prstatus(struct target_elf_prstatus *prstatus) static void bswap_psinfo(struct target_elf_prpsinfo *psinfo) { + if (!target_needs_bswap()) { + return; + } + psinfo->pr_flag = tswapal(psinfo->pr_flag); psinfo->pr_uid = tswap16(psinfo->pr_uid); psinfo->pr_gid = tswap16(psinfo->pr_gid); @@ -4031,15 +4047,14 @@ static void bswap_psinfo(struct target_elf_prpsinfo *psinfo) static void bswap_note(struct elf_note *en) { + if (!target_needs_bswap()) { + return; + } + bswap32s(&en->n_namesz); bswap32s(&en->n_descsz); bswap32s(&en->n_type); } -#else -static inline void bswap_prstatus(struct target_elf_prstatus *p) { } -static inline void bswap_psinfo(struct target_elf_prpsinfo *p) {} -static inline void bswap_note(struct elf_note *en) { } -#endif /* HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN */ /* * Calculate file (dump) size of given memory region. From 56f8fb6886c49a99962d50912a8dde9e8dbfc306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 10:37:53 +0200 Subject: [PATCH 0341/2760] accel/kvm: Use target_needs_bswap() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check whether we need to swap at runtime using target_needs_bswap(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-3-philmd@linaro.org> --- accel/kvm/kvm-all.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index b8c68c7819..278a50690c 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -33,6 +33,7 @@ #include "system/cpus.h" #include "system/accel-blocker.h" #include "qemu/bswap.h" +#include "exec/tswap.h" #include "system/memory.h" #include "system/ram_addr.h" #include "qemu/event_notifier.h" @@ -1318,21 +1319,22 @@ bool kvm_hwpoisoned_mem(void) static uint32_t adjust_ioeventfd_endianness(uint32_t val, uint32_t size) { -#if HOST_BIG_ENDIAN != TARGET_BIG_ENDIAN - /* The kernel expects ioeventfd values in HOST_BIG_ENDIAN - * endianness, but the memory core hands them in target endianness. - * For example, PPC is always treated as big-endian even if running - * on KVM and on PPC64LE. Correct here. - */ - switch (size) { - case 2: - val = bswap16(val); - break; - case 4: - val = bswap32(val); - break; + if (target_needs_bswap()) { + /* + * The kernel expects ioeventfd values in HOST_BIG_ENDIAN + * endianness, but the memory core hands them in target endianness. + * For example, PPC is always treated as big-endian even if running + * on KVM and on PPC64LE. Correct here, swapping back. + */ + switch (size) { + case 2: + val = bswap16(val); + break; + case 4: + val = bswap32(val); + break; + } } -#endif return val; } From 33fa8f02a91986c6c3e7de748964a312c14a5a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 10:47:00 +0200 Subject: [PATCH 0342/2760] target/mips: Check CPU endianness at runtime using env_is_bigendian() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since CPU endianness can be toggled at runtime before resetting, checking the endianness at build time preprocessing the TARGET_BIG_ENDIAN definition isn't correct. We have to call mips_env_is_bigendian() to get the CPU endianness at runtime. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-4-philmd@linaro.org> --- target/mips/tcg/msa_helper.c | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index 14de4a71ff..e349344647 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -8212,7 +8212,6 @@ void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, /* Element-by-element access macros */ #define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) -#if TARGET_BIG_ENDIAN static inline uint64_t bswap16x4(uint64_t x) { uint64_t m = 0x00ff00ff00ff00ffull; @@ -8223,7 +8222,6 @@ static inline uint64_t bswap32x2(uint64_t x) { return ror64(bswap64(x), 32); } -#endif void helper_msa_ld_b(CPUMIPSState *env, uint32_t wd, target_ulong addr) @@ -8252,10 +8250,10 @@ void helper_msa_ld_h(CPUMIPSState *env, uint32_t wd, */ d0 = cpu_ldq_le_data_ra(env, addr + 0, ra); d1 = cpu_ldq_le_data_ra(env, addr + 8, ra); -#if TARGET_BIG_ENDIAN - d0 = bswap16x4(d0); - d1 = bswap16x4(d1); -#endif + if (mips_env_is_bigendian(env)) { + d0 = bswap16x4(d0); + d1 = bswap16x4(d1); + } pwd->d[0] = d0; pwd->d[1] = d1; } @@ -8273,10 +8271,10 @@ void helper_msa_ld_w(CPUMIPSState *env, uint32_t wd, */ d0 = cpu_ldq_le_data_ra(env, addr + 0, ra); d1 = cpu_ldq_le_data_ra(env, addr + 8, ra); -#if TARGET_BIG_ENDIAN - d0 = bswap32x2(d0); - d1 = bswap32x2(d1); -#endif + if (mips_env_is_bigendian(env)) { + d0 = bswap32x2(d0); + d1 = bswap32x2(d1); + } pwd->d[0] = d0; pwd->d[1] = d1; } @@ -8339,10 +8337,10 @@ void helper_msa_st_h(CPUMIPSState *env, uint32_t wd, /* Store 8 bytes at a time. See helper_msa_ld_h. */ d0 = pwd->d[0]; d1 = pwd->d[1]; -#if TARGET_BIG_ENDIAN - d0 = bswap16x4(d0); - d1 = bswap16x4(d1); -#endif + if (mips_env_is_bigendian(env)) { + d0 = bswap16x4(d0); + d1 = bswap16x4(d1); + } cpu_stq_le_data_ra(env, addr + 0, d0, ra); cpu_stq_le_data_ra(env, addr + 8, d1, ra); } @@ -8360,10 +8358,10 @@ void helper_msa_st_w(CPUMIPSState *env, uint32_t wd, /* Store 8 bytes at a time. See helper_msa_ld_w. */ d0 = pwd->d[0]; d1 = pwd->d[1]; -#if TARGET_BIG_ENDIAN - d0 = bswap32x2(d0); - d1 = bswap32x2(d1); -#endif + if (mips_env_is_bigendian(env)) { + d0 = bswap32x2(d0); + d1 = bswap32x2(d1); + } cpu_stq_le_data_ra(env, addr + 0, d0, ra); cpu_stq_le_data_ra(env, addr + 8, d1, ra); } From 770f2e64b6a6ae13c00cd1cc083eaf9728c0f934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 10:40:29 +0200 Subject: [PATCH 0343/2760] target/xtensa: Evaluate TARGET_BIG_ENDIAN at compile time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than evaluating TARGET_BIG_ENDIAN at preprocessing time via #ifdef'ry, do it in C at compile time Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-6-philmd@linaro.org> --- target/xtensa/translate.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 5ebd4a512c..2af83c07c2 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -1395,11 +1395,11 @@ static void translate_bbi(DisasContext *dc, const OpcodeArg arg[], const uint32_t par[]) { TCGv_i32 tmp = tcg_temp_new_i32(); -#if TARGET_BIG_ENDIAN - tcg_gen_andi_i32(tmp, arg[0].in, 0x80000000u >> arg[1].imm); -#else - tcg_gen_andi_i32(tmp, arg[0].in, 0x00000001u << arg[1].imm); -#endif + if (TARGET_BIG_ENDIAN) { + tcg_gen_andi_i32(tmp, arg[0].in, 0x80000000u >> arg[1].imm); + } else { + tcg_gen_andi_i32(tmp, arg[0].in, 0x00000001u << arg[1].imm); + } gen_brcondi(dc, par[0], tmp, 0, arg[2].imm); } From 1b079a6eebb879d14da193919afafc303e938427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 16 Apr 2025 14:33:06 +0200 Subject: [PATCH 0344/2760] hw/mips: Evaluate TARGET_BIG_ENDIAN at compile time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than evaluating TARGET_BIG_ENDIAN at preprocessing time via #ifdef'ry, do it in C at compile time Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-7-philmd@linaro.org> --- hw/mips/jazz.c | 11 ++++------- hw/mips/malta.c | 21 ++++++--------------- hw/mips/mipssim.c | 11 ++++------- 3 files changed, 14 insertions(+), 29 deletions(-) diff --git a/hw/mips/jazz.c b/hw/mips/jazz.c index cee92e1825..7fb0b97a38 100644 --- a/hw/mips/jazz.c +++ b/hw/mips/jazz.c @@ -59,12 +59,6 @@ enum jazz_model_e { JAZZ_PICA61, }; -#if TARGET_BIG_ENDIAN -#define BIOS_FILENAME "mips_bios.bin" -#else -#define BIOS_FILENAME "mipsel_bios.bin" -#endif - static void main_cpu_reset(void *opaque) { MIPSCPU *cpu = opaque; @@ -168,6 +162,8 @@ static void mips_jazz_init_net(IOMMUMemoryRegion *rc4030_dma_mr, static void mips_jazz_init(MachineState *machine, enum jazz_model_e jazz_model) { + const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin" + : "mipsel_bios.bin"; MemoryRegion *address_space = get_system_memory(); char *filename; int bios_size, n; @@ -245,7 +241,8 @@ static void mips_jazz_init(MachineState *machine, memory_region_add_subregion(address_space, 0xfff00000LL, bios2); /* load the BIOS image. */ - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware ?: BIOS_FILENAME); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, + machine->firmware ?: bios_name); if (filename) { bios_size = load_image_targphys(filename, 0xfff00000LL, MAGNUM_BIOS_SIZE); diff --git a/hw/mips/malta.c b/hw/mips/malta.c index 8e9cea70b1..cbdbb21056 100644 --- a/hw/mips/malta.c +++ b/hw/mips/malta.c @@ -94,12 +94,6 @@ typedef struct { bool display_inited; } MaltaFPGAState; -#if TARGET_BIG_ENDIAN -#define BIOS_FILENAME "mips_bios.bin" -#else -#define BIOS_FILENAME "mipsel_bios.bin" -#endif - #define TYPE_MIPS_MALTA "mips-malta" OBJECT_DECLARE_SIMPLE_TYPE(MaltaState, MIPS_MALTA) @@ -383,11 +377,7 @@ static uint64_t malta_fpga_read(void *opaque, hwaddr addr, /* STATUS Register */ case 0x00208: -#if TARGET_BIG_ENDIAN - val = 0x00000012; -#else - val = 0x00000010; -#endif + val = TARGET_BIG_ENDIAN ? 0x00000012 : 0x00000010; break; /* JMPRS Register */ @@ -1177,9 +1167,12 @@ void mips_malta_init(MachineState *machine) target_long bios_size = FLASH_SIZE; /* Load firmware from flash. */ if (!dinfo) { + const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin" + : "mipsel_bios.bin"; + /* Load a BIOS image. */ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, - machine->firmware ?: BIOS_FILENAME); + machine->firmware ?: bios_name); if (filename) { bios_size = load_image_targphys(filename, FLASH_ADDRESS, BIOS_SIZE); @@ -1197,8 +1190,7 @@ void mips_malta_init(MachineState *machine) * In little endian mode the 32bit words in the bios are swapped, * a neat trick which allows bi-endian firmware. */ -#if !TARGET_BIG_ENDIAN - { + if (!TARGET_BIG_ENDIAN) { uint32_t *end, *addr; const size_t swapsize = MIN(bios_size, 0x3e0000); addr = rom_ptr(FLASH_ADDRESS, swapsize); @@ -1211,7 +1203,6 @@ void mips_malta_init(MachineState *machine) addr++; } } -#endif } /* diff --git a/hw/mips/mipssim.c b/hw/mips/mipssim.c index b6dabf2893..e843307b9b 100644 --- a/hw/mips/mipssim.c +++ b/hw/mips/mipssim.c @@ -46,12 +46,6 @@ #define BIOS_SIZE (4 * MiB) -#if TARGET_BIG_ENDIAN -#define BIOS_FILENAME "mips_bios.bin" -#else -#define BIOS_FILENAME "mipsel_bios.bin" -#endif - static struct _loaderparams { int ram_size; const char *kernel_filename; @@ -143,6 +137,8 @@ mips_mipssim_init(MachineState *machine) const char *kernel_filename = machine->kernel_filename; const char *kernel_cmdline = machine->kernel_cmdline; const char *initrd_filename = machine->initrd_filename; + const char *bios_name = TARGET_BIG_ENDIAN ? "mips_bios.bin" + : "mipsel_bios.bin"; char *filename; MemoryRegion *address_space_mem = get_system_memory(); MemoryRegion *isa = g_new(MemoryRegion, 1); @@ -179,7 +175,8 @@ mips_mipssim_init(MachineState *machine) /* Map the BIOS / boot exception handler. */ memory_region_add_subregion(address_space_mem, 0x1fc00000LL, bios); /* Load a BIOS / boot exception handler image. */ - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, machine->firmware ?: BIOS_FILENAME); + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, + machine->firmware ?: bios_name); if (filename) { bios_size = load_image_targphys(filename, 0x1fc00000LL, BIOS_SIZE); g_free(filename); From eb3020b6ed2baca63c2a3fad012335670841ead6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 10:18:35 +0200 Subject: [PATCH 0345/2760] hw/microblaze: Evaluate TARGET_BIG_ENDIAN at compile time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than evaluating TARGET_BIG_ENDIAN at preprocessing time via #ifdef'ry, do it in C at compile time Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-Id: <20250417131004.47205-8-philmd@linaro.org> --- hw/microblaze/petalogix_ml605_mmu.c | 12 ++++++------ hw/microblaze/xlnx-zynqmp-pmu.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index c887c7a99e..bea6b689fd 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -218,12 +218,12 @@ petalogix_ml605_init(MachineState *machine) static void petalogix_ml605_machine_init(MachineClass *mc) { -#if TARGET_BIG_ENDIAN - mc->desc = "PetaLogix linux refdesign for xilinx ml605 (big endian)"; - mc->deprecation_reason = "big endian support is not tested"; -#else - mc->desc = "PetaLogix linux refdesign for xilinx ml605 (little endian)"; -#endif + if (TARGET_BIG_ENDIAN) { + mc->desc = "PetaLogix linux refdesign for xilinx ml605 (big endian)"; + mc->deprecation_reason = "big endian support is not tested"; + } else { + mc->desc = "PetaLogix linux refdesign for xilinx ml605 (little endian)"; + } mc->init = petalogix_ml605_init; } diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index ea1430f408..ed40b5f2e0 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -181,12 +181,12 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) static void xlnx_zynqmp_pmu_machine_init(MachineClass *mc) { -#if TARGET_BIG_ENDIAN - mc->desc = "Xilinx ZynqMP PMU machine (big endian)"; - mc->deprecation_reason = "big endian support is not tested"; -#else - mc->desc = "Xilinx ZynqMP PMU machine (little endian)"; -#endif + if (TARGET_BIG_ENDIAN) { + mc->desc = "Xilinx ZynqMP PMU machine (big endian)"; + mc->deprecation_reason = "big endian support is not tested"; + } else { + mc->desc = "Xilinx ZynqMP PMU machine (little endian)"; + } mc->init = xlnx_zynqmp_pmu_init; } From 0c9d76f519c0f67506d276c0ee5637bac0b40121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 16 Apr 2025 13:25:23 +0200 Subject: [PATCH 0346/2760] qapi: Rename TargetInfo structure as QemuTargetInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QAPI-generated 'TargetInfo' structure name is only used in a single file. We want to heavily use another structure similarly named. Rename the QAPI one, since structure names are not part of the public API. Suggested-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Reviewed-by: Markus Armbruster Message-Id: <20250422145502.70770-2-philmd@linaro.org> --- hw/core/machine-qmp-cmds.c | 4 ++-- qapi/machine.json | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index 9447e345b3..a5e635152d 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -134,9 +134,9 @@ CurrentMachineParams *qmp_query_current_machine(Error **errp) return params; } -TargetInfo *qmp_query_target(Error **errp) +QemuTargetInfo *qmp_query_target(Error **errp) { - TargetInfo *info = g_malloc0(sizeof(*info)); + QemuTargetInfo *info = g_malloc0(sizeof(*info)); info->arch = qapi_enum_parse(&SysEmuTarget_lookup, target_name(), -1, &error_abort); diff --git a/qapi/machine.json b/qapi/machine.json index a9ff807631..c8feb9fe17 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -275,15 +275,15 @@ { 'command': 'query-current-machine', 'returns': 'CurrentMachineParams' } ## -# @TargetInfo: +# @QemuTargetInfo: # -# Information describing the QEMU target. +# Information on the target configuration built into the QEMU binary. # # @arch: the target architecture # # Since: 1.2 ## -{ 'struct': 'TargetInfo', +{ 'struct': 'QemuTargetInfo', 'data': { 'arch': 'SysEmuTarget' } } ## @@ -291,11 +291,11 @@ # # Return information about the target for this QEMU # -# Returns: TargetInfo +# Returns: QemuTargetInfo # # Since: 1.2 ## -{ 'command': 'query-target', 'returns': 'TargetInfo' } +{ 'command': 'query-target', 'returns': 'QemuTargetInfo' } ## # @UuidInfo: From 2b7ae6e0f645f3c3676152f3aa7b8c50a091c486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 17 Apr 2025 17:59:35 +0200 Subject: [PATCH 0347/2760] qemu: Introduce target_cpu_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce the target_cpu_type() helper to access the CPU_RESOLVING_TYPE target-specific definition from target-agnostic code. Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250417165430.58213-2-philmd@linaro.org> --- MAINTAINERS | 2 ++ include/qemu/target-info.h | 19 +++++++++++++++++++ meson.build | 2 ++ target-info-stub.c | 16 ++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 include/qemu/target-info.h create mode 100644 target-info-stub.c diff --git a/MAINTAINERS b/MAINTAINERS index d82d962f1a..28b1e9ba44 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -496,6 +496,7 @@ F: include/exec/cpu*.h F: include/exec/exec-all.h F: include/exec/target_long.h F: include/qemu/accel.h +F: include/qemu/target-info*.h F: include/system/accel-*.h F: include/system/cpus.h F: include/accel/accel-cpu-target.h @@ -504,6 +505,7 @@ F: accel/Makefile.objs F: accel/stubs/Makefile.objs F: cpu-common.c F: cpu-target.c +F: target-info*.c F: system/cpus.c Apple Silicon HVF CPUs diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h new file mode 100644 index 0000000000..b4cc4888ca --- /dev/null +++ b/include/qemu/target-info.h @@ -0,0 +1,19 @@ +/* + * QEMU target info API + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QEMU_TARGET_INFO_H +#define QEMU_TARGET_INFO_H + +/** + * target_cpu_type: + * + * Returns: target CPU base QOM type name (i.e. TYPE_X86_CPU). + */ +const char *target_cpu_type(void); + +#endif diff --git a/meson.build b/meson.build index c736a6f4c4..185c2fb0d1 100644 --- a/meson.build +++ b/meson.build @@ -3795,6 +3795,8 @@ endif common_ss.add(pagevary) specific_ss.add(files('page-target.c', 'page-vary-target.c')) +specific_ss.add(files('target-info-stub.c')) + subdir('backends') subdir('disas') subdir('migration') diff --git a/target-info-stub.c b/target-info-stub.c new file mode 100644 index 0000000000..e5d2195e89 --- /dev/null +++ b/target-info-stub.c @@ -0,0 +1,16 @@ +/* + * QEMU target info stubs (target specific) + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/target-info.h" +#include "cpu.h" + +const char *target_cpu_type(void) +{ + return CPU_RESOLVING_TYPE; +} From 5e15bb7d66d63cbcd863b6b3f69d3fa6715fb75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 17:42:37 +0100 Subject: [PATCH 0348/2760] cpus: Replace CPU_RESOLVING_TYPE -> target_cpu_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the target-specific CPU_RESOLVING_TYPE definition by a call to the target-agnostic target_cpu_type() runtime helper. Since the big "cpu.h" is not required anymore in tcg-all.c, remove it, using the tinier "cpu-param.h" header. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-Id: <20250417165430.58213-3-philmd@linaro.org> --- accel/accel-target.c | 6 ++++-- accel/tcg/tcg-all.c | 5 +++-- cpu-target.c | 7 ++++--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/accel/accel-target.c b/accel/accel-target.c index 33a539b4cb..08d4e450bd 100644 --- a/accel/accel-target.c +++ b/accel/accel-target.c @@ -25,6 +25,7 @@ #include "qemu/osdep.h" #include "qemu/accel.h" +#include "qemu/target-info.h" #include "cpu.h" #include "accel/accel-cpu-target.h" @@ -88,17 +89,18 @@ static void accel_init_cpu_interfaces(AccelClass *ac) const char *ac_name; /* AccelClass name */ char *acc_name; /* AccelCPUClass name */ ObjectClass *acc; /* AccelCPUClass */ + const char *cpu_resolving_type = target_cpu_type(); ac_name = object_class_get_name(OBJECT_CLASS(ac)); g_assert(ac_name != NULL); - acc_name = g_strdup_printf("%s-%s", ac_name, CPU_RESOLVING_TYPE); + acc_name = g_strdup_printf("%s-%s", ac_name, cpu_resolving_type); acc = object_class_by_name(acc_name); g_free(acc_name); if (acc) { object_class_foreach(accel_init_cpu_int_aux, - CPU_RESOLVING_TYPE, false, acc); + cpu_resolving_type, false, acc); } } diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 40d7364979..0ce34ac912 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -35,6 +35,7 @@ #include "qapi/qapi-types-common.h" #include "qapi/qapi-builtin-visit.h" #include "qemu/units.h" +#include "qemu/target-info.h" #if defined(CONFIG_USER_ONLY) #include "hw/qdev-core.h" #else @@ -43,7 +44,7 @@ #endif #include "accel/tcg/cpu-ops.h" #include "internal-common.h" -#include "cpu.h" +#include "cpu-param.h" struct TCGState { @@ -89,7 +90,7 @@ static int tcg_init_machine(MachineState *ms) unsigned max_threads = 1; #ifndef CONFIG_USER_ONLY - CPUClass *cc = CPU_CLASS(object_class_by_name(CPU_RESOLVING_TYPE)); + CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type())); bool mttcg_supported = cc->tcg_ops->mttcg_supported; switch (s->mttcg_enabled) { diff --git a/cpu-target.c b/cpu-target.c index d68cbab5da..c2dd590d48 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -22,6 +22,7 @@ #include "qapi/error.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" +#include "qemu/target-info.h" #include "system/accel-ops.h" #include "system/cpus.h" #include "exec/cpu-common.h" @@ -37,7 +38,7 @@ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); char *cpu_model_from_type(const char *typename) { - const char *suffix = "-" CPU_RESOLVING_TYPE; + g_autofree char *suffix = g_strdup_printf("-%s", target_cpu_type()); if (!object_class_by_name(typename)) { return NULL; @@ -63,7 +64,7 @@ const char *parse_cpu_option(const char *cpu_option) exit(1); } - oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces[0]); + oc = cpu_class_by_name(target_cpu_type(), model_pieces[0]); if (oc == NULL) { error_report("unable to find CPU model '%s'", model_pieces[0]); g_strfreev(model_pieces); @@ -92,7 +93,7 @@ static void cpu_list_entry(gpointer data, gpointer user_data) void list_cpus(void) { - CPUClass *cc = CPU_CLASS(object_class_by_name(CPU_RESOLVING_TYPE)); + CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type())); if (cc->list_cpus) { cc->list_cpus(); From 2492008d0de0380ee910730dc10159a8e29b13a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 2 Apr 2025 05:32:03 +0200 Subject: [PATCH 0349/2760] cpus: Move target-agnostic methods out of cpu-target.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various methods of cpu-target.c don't use any target-specific knowledge at all and can be built once in the target-agnostic cpu-common.c file. Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250417165430.58213-4-philmd@linaro.org> --- cpu-target.c | 77 +------------------------------------------- hw/core/cpu-common.c | 74 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 76 deletions(-) diff --git a/cpu-target.c b/cpu-target.c index c2dd590d48..b5645ff0db 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -19,94 +19,19 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/qemu-print.h" -#include "qemu/target-info.h" #include "system/accel-ops.h" #include "system/cpus.h" #include "exec/cpu-common.h" #include "exec/tswap.h" #include "exec/replay-core.h" #include "exec/log.h" -#include "accel/accel-cpu-target.h" +#include "hw/core/cpu.h" #include "trace/trace-root.h" /* Validate correct placement of CPUArchState. */ QEMU_BUILD_BUG_ON(offsetof(ArchCPU, parent_obj) != 0); QEMU_BUILD_BUG_ON(offsetof(ArchCPU, env) != sizeof(CPUState)); -char *cpu_model_from_type(const char *typename) -{ - g_autofree char *suffix = g_strdup_printf("-%s", target_cpu_type()); - - if (!object_class_by_name(typename)) { - return NULL; - } - - if (g_str_has_suffix(typename, suffix)) { - return g_strndup(typename, strlen(typename) - strlen(suffix)); - } - - return g_strdup(typename); -} - -const char *parse_cpu_option(const char *cpu_option) -{ - ObjectClass *oc; - CPUClass *cc; - gchar **model_pieces; - const char *cpu_type; - - model_pieces = g_strsplit(cpu_option, ",", 2); - if (!model_pieces[0]) { - error_report("-cpu option cannot be empty"); - exit(1); - } - - oc = cpu_class_by_name(target_cpu_type(), model_pieces[0]); - if (oc == NULL) { - error_report("unable to find CPU model '%s'", model_pieces[0]); - g_strfreev(model_pieces); - exit(EXIT_FAILURE); - } - - cpu_type = object_class_get_name(oc); - cc = CPU_CLASS(oc); - cc->parse_features(cpu_type, model_pieces[1], &error_fatal); - g_strfreev(model_pieces); - return cpu_type; -} - -static void cpu_list_entry(gpointer data, gpointer user_data) -{ - CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data)); - const char *typename = object_class_get_name(OBJECT_CLASS(data)); - g_autofree char *model = cpu_model_from_type(typename); - - if (cc->deprecation_note) { - qemu_printf(" %s (deprecated)\n", model); - } else { - qemu_printf(" %s\n", model); - } -} - -void list_cpus(void) -{ - CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type())); - - if (cc->list_cpus) { - cc->list_cpus(); - } else { - GSList *list; - - list = object_class_get_list_sorted(TYPE_CPU, false); - qemu_printf("Available CPUs:\n"); - g_slist_foreach(list, cpu_list_entry, NULL); - g_slist_free(list); - } -} - /* enable or disable single step mode. EXCP_DEBUG is returned by the CPU loop after each instruction */ void cpu_single_step(CPUState *cpu, int enabled) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 1fb6ea3892..92c40b6bf8 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -25,6 +25,9 @@ #include "qemu/log.h" #include "qemu/main-loop.h" #include "qemu/lockcnt.h" +#include "qemu/error-report.h" +#include "qemu/qemu-print.h" +#include "qemu/target-info.h" #include "exec/log.h" #include "exec/gdbstub.h" #include "system/tcg.h" @@ -152,6 +155,21 @@ ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model) return NULL; } +char *cpu_model_from_type(const char *typename) +{ + g_autofree char *suffix = g_strdup_printf("-%s", target_cpu_type()); + + if (!object_class_by_name(typename)) { + return NULL; + } + + if (g_str_has_suffix(typename, suffix)) { + return g_strndup(typename, strlen(typename) - strlen(suffix)); + } + + return g_strdup(typename); +} + static void cpu_common_parse_features(const char *typename, char *features, Error **errp) { @@ -183,6 +201,33 @@ static void cpu_common_parse_features(const char *typename, char *features, } } +const char *parse_cpu_option(const char *cpu_option) +{ + ObjectClass *oc; + CPUClass *cc; + gchar **model_pieces; + const char *cpu_type; + + model_pieces = g_strsplit(cpu_option, ",", 2); + if (!model_pieces[0]) { + error_report("-cpu option cannot be empty"); + exit(1); + } + + oc = cpu_class_by_name(target_cpu_type(), model_pieces[0]); + if (oc == NULL) { + error_report("unable to find CPU model '%s'", model_pieces[0]); + g_strfreev(model_pieces); + exit(EXIT_FAILURE); + } + + cpu_type = object_class_get_name(oc); + cc = CPU_CLASS(oc); + cc->parse_features(cpu_type, model_pieces[1], &error_fatal); + g_strfreev(model_pieces); + return cpu_type; +} + bool cpu_exec_realizefn(CPUState *cpu, Error **errp) { if (!accel_cpu_common_realize(cpu, errp)) { @@ -359,3 +404,32 @@ static void cpu_register_types(void) } type_init(cpu_register_types) + +static void cpu_list_entry(gpointer data, gpointer user_data) +{ + CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data)); + const char *typename = object_class_get_name(OBJECT_CLASS(data)); + g_autofree char *model = cpu_model_from_type(typename); + + if (cc->deprecation_note) { + qemu_printf(" %s (deprecated)\n", model); + } else { + qemu_printf(" %s\n", model); + } +} + +void list_cpus(void) +{ + CPUClass *cc = CPU_CLASS(object_class_by_name(target_cpu_type())); + + if (cc->list_cpus) { + cc->list_cpus(); + } else { + GSList *list; + + list = object_class_get_list_sorted(TYPE_CPU, false); + qemu_printf("Available CPUs:\n"); + g_slist_foreach(list, cpu_list_entry, NULL); + g_slist_free(list); + } +} From 64cbcf1d9782c340cf59868a1be97f0054c4ec44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 18:17:15 +0100 Subject: [PATCH 0350/2760] accel: Implement accel_init_ops_interfaces() for both system/user mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to build more common code, moving objects from meson's specific_ss[] set to common_ss[]. Since the CONFIG_USER_ONLY definitions isn't applied on the common_ss[] set, it is simpler to add an empty accel_init_ops_interfaces() stub on user emulation, removing any CONFIG_USER_ONLY use in accel-target.c. Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250417165430.58213-5-philmd@linaro.org> --- MAINTAINERS | 2 +- accel/{accel-system.h => accel-internal.h} | 8 ++++---- accel/accel-system.c | 4 ++-- accel/accel-target.c | 10 ++-------- accel/accel-user.c | 6 ++++++ 5 files changed, 15 insertions(+), 15 deletions(-) rename accel/{accel-system.h => accel-internal.h} (56%) diff --git a/MAINTAINERS b/MAINTAINERS index 28b1e9ba44..07711cfd38 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -500,7 +500,7 @@ F: include/qemu/target-info*.h F: include/system/accel-*.h F: include/system/cpus.h F: include/accel/accel-cpu-target.h -F: accel/accel-*.c +F: accel/accel-*.? F: accel/Makefile.objs F: accel/stubs/Makefile.objs F: cpu-common.c diff --git a/accel/accel-system.h b/accel/accel-internal.h similarity index 56% rename from accel/accel-system.h rename to accel/accel-internal.h index 2d37c73c97..03426aa21e 100644 --- a/accel/accel-system.h +++ b/accel/accel-internal.h @@ -1,5 +1,5 @@ /* - * QEMU System Emulation accel internal functions + * QEMU accel internal functions * * Copyright 2021 SUSE LLC * @@ -7,9 +7,9 @@ * See the COPYING file in the top-level directory. */ -#ifndef ACCEL_SYSTEM_H -#define ACCEL_SYSTEM_H +#ifndef ACCEL_INTERNAL_H +#define ACCEL_INTERNAL_H -void accel_system_init_ops_interfaces(AccelClass *ac); +void accel_init_ops_interfaces(AccelClass *ac); #endif /* ACCEL_SYSTEM_H */ diff --git a/accel/accel-system.c b/accel/accel-system.c index 5df49fbe83..a0f562ae9f 100644 --- a/accel/accel-system.c +++ b/accel/accel-system.c @@ -29,7 +29,7 @@ #include "system/accel-ops.h" #include "system/cpus.h" #include "qemu/error-report.h" -#include "accel-system.h" +#include "accel-internal.h" int accel_init_machine(AccelState *accel, MachineState *ms) { @@ -63,7 +63,7 @@ void accel_setup_post(MachineState *ms) } /* initialize the arch-independent accel operation interfaces */ -void accel_system_init_ops_interfaces(AccelClass *ac) +void accel_init_ops_interfaces(AccelClass *ac) { const char *ac_name; char *ops_name; diff --git a/accel/accel-target.c b/accel/accel-target.c index 08d4e450bd..7f3bbf31a8 100644 --- a/accel/accel-target.c +++ b/accel/accel-target.c @@ -29,10 +29,7 @@ #include "cpu.h" #include "accel/accel-cpu-target.h" - -#ifndef CONFIG_USER_ONLY -#include "accel-system.h" -#endif /* !CONFIG_USER_ONLY */ +#include "accel-internal.h" static const TypeInfo accel_type = { .name = TYPE_ACCEL, @@ -106,10 +103,7 @@ static void accel_init_cpu_interfaces(AccelClass *ac) void accel_init_interfaces(AccelClass *ac) { -#ifndef CONFIG_USER_ONLY - accel_system_init_ops_interfaces(ac); -#endif /* !CONFIG_USER_ONLY */ - + accel_init_ops_interfaces(ac); accel_init_cpu_interfaces(ac); } diff --git a/accel/accel-user.c b/accel/accel-user.c index 22b6a1a1a8..7d192306a6 100644 --- a/accel/accel-user.c +++ b/accel/accel-user.c @@ -9,6 +9,12 @@ #include "qemu/osdep.h" #include "qemu/accel.h" +#include "accel-internal.h" + +void accel_init_ops_interfaces(AccelClass *ac) +{ + /* nothing */ +} AccelState *current_accel(void) { From 559fe89916a3e000317ba7fa8ca495c620a17beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 18:29:31 +0100 Subject: [PATCH 0351/2760] accel: Include missing 'qemu/accel.h' header in accel-internal.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "qemu/accel.h" header is implicitly pulled in. Include it explicitly in order to avoid when refactoring unrelated headers: accel/accel-internal.h:13:32: error: unknown type name 'AccelClass' 13 | void accel_init_ops_interfaces(AccelClass *ac); | ^ Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250417165430.58213-6-philmd@linaro.org> --- accel/accel-internal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/accel/accel-internal.h b/accel/accel-internal.h index 03426aa21e..d3a4422cbf 100644 --- a/accel/accel-internal.h +++ b/accel/accel-internal.h @@ -10,6 +10,8 @@ #ifndef ACCEL_INTERNAL_H #define ACCEL_INTERNAL_H +#include "qemu/accel.h" + void accel_init_ops_interfaces(AccelClass *ac); #endif /* ACCEL_SYSTEM_H */ From 44246e717018b30ee40db45fe2dd34765df61c7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 18:18:24 +0100 Subject: [PATCH 0352/2760] accel: Make AccelCPUClass structure target-agnostic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the target-agnostic parts of "accel/accel-cpu-target.h" to "accel/accel-cpu.h". Doing so we need to include missing "hw/core/cpu.h" header in "accel/accel-cpu.h" otherwise we get: include/accel/accel-cpu-target.h:39:28: error: unknown type name 'CPUClass' 39 | void (*cpu_class_init)(CPUClass *cc); | ^ Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Message-Id: <20250417165430.58213-7-philmd@linaro.org> --- MAINTAINERS | 2 +- accel/accel-target.c | 1 - include/accel/accel-cpu-target.h | 12 +----------- include/accel/accel-cpu.h | 23 +++++++++++++++++++++++ 4 files changed, 25 insertions(+), 13 deletions(-) create mode 100644 include/accel/accel-cpu.h diff --git a/MAINTAINERS b/MAINTAINERS index 07711cfd38..59d9712819 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -499,7 +499,7 @@ F: include/qemu/accel.h F: include/qemu/target-info*.h F: include/system/accel-*.h F: include/system/cpus.h -F: include/accel/accel-cpu-target.h +F: include/accel/accel-cpu*.h F: accel/accel-*.? F: accel/Makefile.objs F: accel/stubs/Makefile.objs diff --git a/accel/accel-target.c b/accel/accel-target.c index 7f3bbf31a8..82a29e6147 100644 --- a/accel/accel-target.c +++ b/accel/accel-target.c @@ -27,7 +27,6 @@ #include "qemu/accel.h" #include "qemu/target-info.h" -#include "cpu.h" #include "accel/accel-cpu-target.h" #include "accel-internal.h" diff --git a/include/accel/accel-cpu-target.h b/include/accel/accel-cpu-target.h index 37dde7fae3..6feb344e29 100644 --- a/include/accel/accel-cpu-target.h +++ b/include/accel/accel-cpu-target.h @@ -21,21 +21,11 @@ */ #include "qom/object.h" +#include "accel/accel-cpu.h" #include "cpu.h" #define TYPE_ACCEL_CPU "accel-" CPU_RESOLVING_TYPE #define ACCEL_CPU_NAME(name) (name "-" TYPE_ACCEL_CPU) -typedef struct AccelCPUClass AccelCPUClass; DECLARE_CLASS_CHECKERS(AccelCPUClass, ACCEL_CPU, TYPE_ACCEL_CPU) -typedef struct AccelCPUClass { - /*< private >*/ - ObjectClass parent_class; - /*< public >*/ - - void (*cpu_class_init)(CPUClass *cc); - void (*cpu_instance_init)(CPUState *cpu); - bool (*cpu_target_realize)(CPUState *cpu, Error **errp); -} AccelCPUClass; - #endif /* ACCEL_CPU_H */ diff --git a/include/accel/accel-cpu.h b/include/accel/accel-cpu.h new file mode 100644 index 0000000000..9e7eede7c3 --- /dev/null +++ b/include/accel/accel-cpu.h @@ -0,0 +1,23 @@ +/* + * Accelerator interface, specializes CPUClass + * + * Copyright 2021 SUSE LLC + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef ACCEL_CPU_H +#define ACCEL_CPU_H + +#include "qom/object.h" +#include "hw/core/cpu.h" + +typedef struct AccelCPUClass { + ObjectClass parent_class; + + void (*cpu_class_init)(CPUClass *cc); + void (*cpu_instance_init)(CPUState *cpu); + bool (*cpu_target_realize)(CPUState *cpu, Error **errp); +} AccelCPUClass; + +#endif /* ACCEL_CPU_H */ From 802c4daf331339085823f2fc81917967da4b4c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 18:20:40 +0100 Subject: [PATCH 0353/2760] accel: Move target-agnostic code from accel-target.c -> accel-common.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various methods of accel-target.c don't use any target-specific knowledge at all and can be built once in the target-agnostic accel-common.c file. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-Id: <20250417165430.58213-8-philmd@linaro.org> --- accel/accel-common.c | 142 +++++++++++++++++++++++++++++++++++++++++++ accel/accel-target.c | 129 --------------------------------------- accel/meson.build | 1 + 3 files changed, 143 insertions(+), 129 deletions(-) create mode 100644 accel/accel-common.c diff --git a/accel/accel-common.c b/accel/accel-common.c new file mode 100644 index 0000000000..4894b98d64 --- /dev/null +++ b/accel/accel-common.c @@ -0,0 +1,142 @@ +/* + * QEMU accel class, components common to system emulation and user mode + * + * Copyright (c) 2003-2008 Fabrice Bellard + * Copyright (c) 2014 Red Hat Inc. + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "qemu/accel.h" +#include "qemu/target-info.h" +#include "accel/accel-cpu.h" +#include "accel-internal.h" + +/* Lookup AccelClass from opt_name. Returns NULL if not found */ +AccelClass *accel_find(const char *opt_name) +{ + char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name); + AccelClass *ac = ACCEL_CLASS(module_object_class_by_name(class_name)); + g_free(class_name); + return ac; +} + +/* Return the name of the current accelerator */ +const char *current_accel_name(void) +{ + AccelClass *ac = ACCEL_GET_CLASS(current_accel()); + + return ac->name; +} + +static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque) +{ + CPUClass *cc = CPU_CLASS(klass); + AccelCPUClass *accel_cpu = opaque; + + /* + * The first callback allows accel-cpu to run initializations + * for the CPU, customizing CPU behavior according to the accelerator. + * + * The second one allows the CPU to customize the accel-cpu + * behavior according to the CPU. + * + * The second is currently only used by TCG, to specialize the + * TCGCPUOps depending on the CPU type. + */ + cc->accel_cpu = accel_cpu; + if (accel_cpu->cpu_class_init) { + accel_cpu->cpu_class_init(cc); + } + if (cc->init_accel_cpu) { + cc->init_accel_cpu(accel_cpu, cc); + } +} + +/* initialize the arch-specific accel CpuClass interfaces */ +static void accel_init_cpu_interfaces(AccelClass *ac) +{ + const char *ac_name; /* AccelClass name */ + char *acc_name; /* AccelCPUClass name */ + ObjectClass *acc; /* AccelCPUClass */ + const char *cpu_resolving_type = target_cpu_type(); + + ac_name = object_class_get_name(OBJECT_CLASS(ac)); + g_assert(ac_name != NULL); + + acc_name = g_strdup_printf("%s-%s", ac_name, cpu_resolving_type); + acc = object_class_by_name(acc_name); + g_free(acc_name); + + if (acc) { + object_class_foreach(accel_init_cpu_int_aux, + cpu_resolving_type, false, acc); + } +} + +void accel_init_interfaces(AccelClass *ac) +{ + accel_init_ops_interfaces(ac); + accel_init_cpu_interfaces(ac); +} + +void accel_cpu_instance_init(CPUState *cpu) +{ + if (cpu->cc->accel_cpu && cpu->cc->accel_cpu->cpu_instance_init) { + cpu->cc->accel_cpu->cpu_instance_init(cpu); + } +} + +bool accel_cpu_common_realize(CPUState *cpu, Error **errp) +{ + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + + /* target specific realization */ + if (cpu->cc->accel_cpu + && cpu->cc->accel_cpu->cpu_target_realize + && !cpu->cc->accel_cpu->cpu_target_realize(cpu, errp)) { + return false; + } + + /* generic realization */ + if (acc->cpu_common_realize && !acc->cpu_common_realize(cpu, errp)) { + return false; + } + + return true; +} + +void accel_cpu_common_unrealize(CPUState *cpu) +{ + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + + /* generic unrealization */ + if (acc->cpu_common_unrealize) { + acc->cpu_common_unrealize(cpu); + } +} + +int accel_supported_gdbstub_sstep_flags(void) +{ + AccelState *accel = current_accel(); + AccelClass *acc = ACCEL_GET_CLASS(accel); + if (acc->gdbstub_supported_sstep_flags) { + return acc->gdbstub_supported_sstep_flags(); + } + return 0; +} + +static const TypeInfo accel_types[] = { + { + .name = TYPE_ACCEL, + .parent = TYPE_OBJECT, + .class_size = sizeof(AccelClass), + .instance_size = sizeof(AccelState), + .abstract = true, + }, +}; + +DEFINE_TYPES(accel_types) diff --git a/accel/accel-target.c b/accel/accel-target.c index 82a29e6147..7fd392fbc4 100644 --- a/accel/accel-target.c +++ b/accel/accel-target.c @@ -24,135 +24,7 @@ */ #include "qemu/osdep.h" -#include "qemu/accel.h" -#include "qemu/target-info.h" - #include "accel/accel-cpu-target.h" -#include "accel-internal.h" - -static const TypeInfo accel_type = { - .name = TYPE_ACCEL, - .parent = TYPE_OBJECT, - .class_size = sizeof(AccelClass), - .instance_size = sizeof(AccelState), - .abstract = true, -}; - -/* Lookup AccelClass from opt_name. Returns NULL if not found */ -AccelClass *accel_find(const char *opt_name) -{ - char *class_name = g_strdup_printf(ACCEL_CLASS_NAME("%s"), opt_name); - AccelClass *ac = ACCEL_CLASS(module_object_class_by_name(class_name)); - g_free(class_name); - return ac; -} - -/* Return the name of the current accelerator */ -const char *current_accel_name(void) -{ - AccelClass *ac = ACCEL_GET_CLASS(current_accel()); - - return ac->name; -} - -static void accel_init_cpu_int_aux(ObjectClass *klass, void *opaque) -{ - CPUClass *cc = CPU_CLASS(klass); - AccelCPUClass *accel_cpu = opaque; - - /* - * The first callback allows accel-cpu to run initializations - * for the CPU, customizing CPU behavior according to the accelerator. - * - * The second one allows the CPU to customize the accel-cpu - * behavior according to the CPU. - * - * The second is currently only used by TCG, to specialize the - * TCGCPUOps depending on the CPU type. - */ - cc->accel_cpu = accel_cpu; - if (accel_cpu->cpu_class_init) { - accel_cpu->cpu_class_init(cc); - } - if (cc->init_accel_cpu) { - cc->init_accel_cpu(accel_cpu, cc); - } -} - -/* initialize the arch-specific accel CpuClass interfaces */ -static void accel_init_cpu_interfaces(AccelClass *ac) -{ - const char *ac_name; /* AccelClass name */ - char *acc_name; /* AccelCPUClass name */ - ObjectClass *acc; /* AccelCPUClass */ - const char *cpu_resolving_type = target_cpu_type(); - - ac_name = object_class_get_name(OBJECT_CLASS(ac)); - g_assert(ac_name != NULL); - - acc_name = g_strdup_printf("%s-%s", ac_name, cpu_resolving_type); - acc = object_class_by_name(acc_name); - g_free(acc_name); - - if (acc) { - object_class_foreach(accel_init_cpu_int_aux, - cpu_resolving_type, false, acc); - } -} - -void accel_init_interfaces(AccelClass *ac) -{ - accel_init_ops_interfaces(ac); - accel_init_cpu_interfaces(ac); -} - -void accel_cpu_instance_init(CPUState *cpu) -{ - if (cpu->cc->accel_cpu && cpu->cc->accel_cpu->cpu_instance_init) { - cpu->cc->accel_cpu->cpu_instance_init(cpu); - } -} - -bool accel_cpu_common_realize(CPUState *cpu, Error **errp) -{ - AccelState *accel = current_accel(); - AccelClass *acc = ACCEL_GET_CLASS(accel); - - /* target specific realization */ - if (cpu->cc->accel_cpu - && cpu->cc->accel_cpu->cpu_target_realize - && !cpu->cc->accel_cpu->cpu_target_realize(cpu, errp)) { - return false; - } - - /* generic realization */ - if (acc->cpu_common_realize && !acc->cpu_common_realize(cpu, errp)) { - return false; - } - - return true; -} - -void accel_cpu_common_unrealize(CPUState *cpu) -{ - AccelState *accel = current_accel(); - AccelClass *acc = ACCEL_GET_CLASS(accel); - - /* generic unrealization */ - if (acc->cpu_common_unrealize) { - acc->cpu_common_unrealize(cpu); - } -} - -int accel_supported_gdbstub_sstep_flags(void) -{ - AccelState *accel = current_accel(); - AccelClass *acc = ACCEL_GET_CLASS(accel); - if (acc->gdbstub_supported_sstep_flags) { - return acc->gdbstub_supported_sstep_flags(); - } - return 0; -} static const TypeInfo accel_cpu_type = { .name = TYPE_ACCEL_CPU, @@ -163,7 +35,6 @@ static const TypeInfo accel_cpu_type = { static void register_accel_types(void) { - type_register_static(&accel_type); type_register_static(&accel_cpu_type); } diff --git a/accel/meson.build b/accel/meson.build index 5eaeb68338..52909314bf 100644 --- a/accel/meson.build +++ b/accel/meson.build @@ -1,3 +1,4 @@ +common_ss.add(files('accel-common.c')) specific_ss.add(files('accel-target.c')) system_ss.add(files('accel-system.c', 'accel-blocker.c')) user_ss.add(files('accel-user.c')) From 3d881164d4fb2b0f6791cf28d9725926b8ded0d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 12:47:37 +0100 Subject: [PATCH 0354/2760] qemu: Convert target_name() to TargetInfo API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Have target_name() be a target-agnostic method, dispatching to a per-target TargetInfo singleton structure. By default a stub singleton is used. No logical change expected. Inspired-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-Id: <20250424222112.36194-3-philmd@linaro.org> --- MAINTAINERS | 9 +++++++-- cpu-target.c | 5 ----- hw/core/machine-qmp-cmds.c | 1 + include/hw/core/cpu.h | 2 -- include/qemu/target-info-impl.h | 26 ++++++++++++++++++++++++++ include/qemu/target-info.h | 7 +++++++ meson.build | 1 + plugins/loader.c | 2 +- system/vl.c | 2 +- target-info-stub.c | 10 ++++++++++ target-info.c | 16 ++++++++++++++++ 11 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 include/qemu/target-info-impl.h create mode 100644 target-info.c diff --git a/MAINTAINERS b/MAINTAINERS index 59d9712819..f8fee87c70 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -496,7 +496,6 @@ F: include/exec/cpu*.h F: include/exec/exec-all.h F: include/exec/target_long.h F: include/qemu/accel.h -F: include/qemu/target-info*.h F: include/system/accel-*.h F: include/system/cpus.h F: include/accel/accel-cpu*.h @@ -505,7 +504,6 @@ F: accel/Makefile.objs F: accel/stubs/Makefile.objs F: cpu-common.c F: cpu-target.c -F: target-info*.c F: system/cpus.c Apple Silicon HVF CPUs @@ -1928,6 +1926,13 @@ F: tests/functional/test_empty_cpu_model.py F: tests/unit/test-smp-parse.c T: git https://gitlab.com/ehabkost/qemu.git machine-next +TargetInfo API +M: Pierrick Bouvier +M: Philippe Mathieu-Daudé +S: Supported +F: include/qemu/target-info*.h +F: target-info*.c + Xtensa Machines --------------- sim diff --git a/cpu-target.c b/cpu-target.c index b5645ff0db..1c90a30759 100644 --- a/cpu-target.c +++ b/cpu-target.c @@ -91,8 +91,3 @@ bool target_big_endian(void) { return TARGET_BIG_ENDIAN; } - -const char *target_name(void) -{ - return TARGET_NAME; -} diff --git a/hw/core/machine-qmp-cmds.c b/hw/core/machine-qmp-cmds.c index a5e635152d..d82043e1c6 100644 --- a/hw/core/machine-qmp-cmds.c +++ b/hw/core/machine-qmp-cmds.c @@ -19,6 +19,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/type-helpers.h" #include "qemu/uuid.h" +#include "qemu/target-info.h" #include "qom/qom-qobject.h" #include "system/hostmem.h" #include "system/hw_accel.h" diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h index 2a02d4f078..12b2ff1f7d 100644 --- a/include/hw/core/cpu.h +++ b/include/hw/core/cpu.h @@ -1121,8 +1121,6 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp); void cpu_exec_unrealizefn(CPUState *cpu); void cpu_exec_reset_hold(CPUState *cpu); -const char *target_name(void); - #ifdef COMPILING_PER_TARGET extern const VMStateDescription vmstate_cpu_common; diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h new file mode 100644 index 0000000000..d30805f7f2 --- /dev/null +++ b/include/qemu/target-info-impl.h @@ -0,0 +1,26 @@ +/* + * QEMU TargetInfo structure definition + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef QEMU_TARGET_INFO_IMPL_H +#define QEMU_TARGET_INFO_IMPL_H + +#include "qemu/target-info.h" + +typedef struct TargetInfo { + /* runtime equivalent of TARGET_NAME definition */ + const char *target_name; +} TargetInfo; + +/** + * target_info: + * + * Returns: The TargetInfo structure definition for this target binary. + */ +const TargetInfo *target_info(void); + +#endif diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index b4cc4888ca..58d4136897 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -9,6 +9,13 @@ #ifndef QEMU_TARGET_INFO_H #define QEMU_TARGET_INFO_H +/** + * target_name: + * + * Returns: Canonical target name (i.e. "i386"). + */ +const char *target_name(void); + /** * target_cpu_type: * diff --git a/meson.build b/meson.build index 185c2fb0d1..8ae70dbe45 100644 --- a/meson.build +++ b/meson.build @@ -3795,6 +3795,7 @@ endif common_ss.add(pagevary) specific_ss.add(files('page-target.c', 'page-vary-target.c')) +common_ss.add(files('target-info.c')) specific_ss.add(files('target-info-stub.c')) subdir('backends') diff --git a/plugins/loader.c b/plugins/loader.c index 0d6e082e17..8f0d75c904 100644 --- a/plugins/loader.c +++ b/plugins/loader.c @@ -29,7 +29,7 @@ #include "qemu/xxhash.h" #include "qemu/plugin.h" #include "qemu/memalign.h" -#include "hw/core/cpu.h" +#include "qemu/target-info.h" #include "exec/tb-flush.h" #include "plugin.h" diff --git a/system/vl.c b/system/vl.c index 4ab2001df7..520956f4a1 100644 --- a/system/vl.c +++ b/system/vl.c @@ -40,6 +40,7 @@ #include "qemu/help_option.h" #include "qemu/hw-version.h" #include "qemu/uuid.h" +#include "qemu/target-info.h" #include "system/reset.h" #include "system/runstate.h" #include "system/runstate-action.h" @@ -79,7 +80,6 @@ #include "hw/block/block.h" #include "hw/i386/x86.h" #include "hw/i386/pc.h" -#include "hw/core/cpu.h" #include "migration/cpr.h" #include "migration/misc.h" #include "migration/snapshot.h" diff --git a/target-info-stub.c b/target-info-stub.c index e5d2195e89..773a10188c 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -8,8 +8,18 @@ #include "qemu/osdep.h" #include "qemu/target-info.h" +#include "qemu/target-info-impl.h" #include "cpu.h" +static const TargetInfo target_info_stub = { + .target_name = TARGET_NAME, +}; + +const TargetInfo *target_info(void) +{ + return &target_info_stub; +} + const char *target_cpu_type(void) { return CPU_RESOLVING_TYPE; diff --git a/target-info.c b/target-info.c new file mode 100644 index 0000000000..84b18931e7 --- /dev/null +++ b/target-info.c @@ -0,0 +1,16 @@ +/* + * QEMU target info helpers + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/target-info.h" +#include "qemu/target-info-impl.h" + +const char *target_name(void) +{ + return target_info()->target_name; +} From 2b689db0bedd24eda8b491cb1fcfb015dfec5a31 Mon Sep 17 00:00:00 2001 From: Denis Rastyogin Date: Thu, 27 Mar 2025 19:24:23 +0300 Subject: [PATCH 0355/2760] qemu-img: improve queue depth validation in img_bench This error was discovered by fuzzing qemu-img. Currently, running `qemu-img bench -d 0` in img_bench is allowed, which is a pointless operation and causes qemu-img to hang. Signed-off-by: Denis Rastyogin Message-ID: <20250327162423.25154-5-gerben@altlinux.org> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- qemu-img.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu-img.c b/qemu-img.c index 2044c22a4c..76ac5d3028 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4571,7 +4571,7 @@ static int img_bench(int argc, char **argv) { unsigned long res; - if (qemu_strtoul(optarg, NULL, 0, &res) < 0 || res > INT_MAX) { + if (qemu_strtoul(optarg, NULL, 0, &res) <= 0 || res > INT_MAX) { error_report("Invalid queue depth specified"); return 1; } From a079836005fb92eb1fee19e59654b337a41fd0ff Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 18:23:36 +0000 Subject: [PATCH 0356/2760] tcg/loongarch64: Fix vec_val computation in tcg_target_const_match MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only use vece for a vector constant. This avoids an assertion failure in sextract64 when vece contains garbage. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index cbd7642b58..740b7c264d 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -211,12 +211,14 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { return true; } - int64_t vec_val = sextract64(val, 0, 8 << vece); - if ((ct & TCG_CT_CONST_VCMP) && -0x10 <= vec_val && vec_val <= 0x1f) { - return true; - } - if ((ct & TCG_CT_CONST_VADD) && -0x1f <= vec_val && vec_val <= 0x1f) { - return true; + if (ct & (TCG_CT_CONST_VCMP | TCG_CT_CONST_VADD)) { + int64_t vec_val = sextract64(val, 0, 8 << vece); + if ((ct & TCG_CT_CONST_VCMP) && -0x10 <= vec_val && vec_val <= 0x1f) { + return true; + } + if ((ct & TCG_CT_CONST_VADD) && -0x1f <= vec_val && vec_val <= 0x1f) { + return true; + } } return false; } From 911f7328e9e9de80bf6b1a4697ecf83cc3661f5f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 18:45:28 +0000 Subject: [PATCH 0357/2760] tcg/loongarch64: Improve constraints for TCG_CT_CONST_VCMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the TCGCond given to tcg_target_const_match to exactly match the supported constant. Adjust the code generation to assume this has been done -- recall that encode_*_insn contain assertions that the constants are valid. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 38 ++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 740b7c264d..879f66f255 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -213,8 +213,18 @@ static bool tcg_target_const_match(int64_t val, int ct, } if (ct & (TCG_CT_CONST_VCMP | TCG_CT_CONST_VADD)) { int64_t vec_val = sextract64(val, 0, 8 << vece); - if ((ct & TCG_CT_CONST_VCMP) && -0x10 <= vec_val && vec_val <= 0x1f) { - return true; + if (ct & TCG_CT_CONST_VCMP) { + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_LE: + case TCG_COND_LT: + return -0x10 <= vec_val && vec_val <= 0x0f; + case TCG_COND_LEU: + case TCG_COND_LTU: + return 0x00 <= vec_val && vec_val <= 0x1f; + default: + return false; + } } if ((ct & TCG_CT_CONST_VADD) && -0x1f <= vec_val && vec_val <= 0x1f) { return true; @@ -2029,28 +2039,22 @@ static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, * Try vseqi/vslei/vslti */ int64_t value = sextract64(a2, 0, 8 << vece); - if ((cond == TCG_COND_EQ || - cond == TCG_COND_LE || - cond == TCG_COND_LT) && - (-0x10 <= value && value <= 0x0f)) { + switch (cond) { + case TCG_COND_EQ: + case TCG_COND_LE: + case TCG_COND_LT: insn = cmp_vec_imm_insn[cond][lasx][vece]; tcg_out32(s, encode_vdvjsk5_insn(insn, a0, a1, value)); break; - } else if ((cond == TCG_COND_LEU || - cond == TCG_COND_LTU) && - (0x00 <= value && value <= 0x1f)) { + case TCG_COND_LEU: + case TCG_COND_LTU: insn = cmp_vec_imm_insn[cond][lasx][vece]; tcg_out32(s, encode_vdvjuk5_insn(insn, a0, a1, value)); break; + default: + g_assert_not_reached(); } - - /* - * Fallback to: - * dupi_vec temp, a2 - * cmp_vec a0, a1, temp, cond - */ - tcg_out_dupi_vec(s, type, vece, TCG_VEC_TMP0, a2); - a2 = TCG_VEC_TMP0; + break; } insn = cmp_vec_insn[cond][lasx][vece]; From a3c1c579baf511a2b95f7b233187a981b6ef46ea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 21 Apr 2025 11:05:29 -0700 Subject: [PATCH 0358/2760] tcg/optimize: Introduce opt_insert_{before,after} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consolidate the places we call tcg_op_insert_{before,after} within the optimization pass. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index f922f86a1d..a4d4ad3005 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -344,6 +344,18 @@ static TCGArg arg_new_temp(OptContext *ctx) return temp_arg(ts); } +static TCGOp *opt_insert_after(OptContext *ctx, TCGOp *op, + TCGOpcode opc, unsigned narg) +{ + return tcg_op_insert_after(ctx->tcg, op, opc, narg); +} + +static TCGOp *opt_insert_before(OptContext *ctx, TCGOp *op, + TCGOpcode opc, unsigned narg) +{ + return tcg_op_insert_before(ctx->tcg, op, opc, narg); +} + static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src) { TCGTemp *dst_ts = arg_temp(dst); @@ -808,7 +820,7 @@ static int do_constant_folding_cond1(OptContext *ctx, TCGOp *op, TCGArg dest, if (!TCG_TARGET_HAS_tst) { TCGOpcode and_opc = (ctx->type == TCG_TYPE_I32 ? INDEX_op_and_i32 : INDEX_op_and_i64); - TCGOp *op2 = tcg_op_insert_before(ctx->tcg, op, and_opc, 3); + TCGOp *op2 = opt_insert_before(ctx, op, and_opc, 3); TCGArg tmp = arg_new_temp(ctx); op2->args[0] = tmp; @@ -901,8 +913,8 @@ static int do_constant_folding_cond2(OptContext *ctx, TCGOp *op, TCGArg *args) /* Expand to AND with a temporary if no backend support. */ if (!TCG_TARGET_HAS_tst && is_tst_cond(c)) { - TCGOp *op1 = tcg_op_insert_before(ctx->tcg, op, INDEX_op_and_i32, 3); - TCGOp *op2 = tcg_op_insert_before(ctx->tcg, op, INDEX_op_and_i32, 3); + TCGOp *op1 = opt_insert_before(ctx, op, INDEX_op_and_i32, 3); + TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and_i32, 3); TCGArg t1 = arg_new_temp(ctx); TCGArg t2 = arg_new_temp(ctx); @@ -1263,7 +1275,7 @@ static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) rh = op->args[1]; /* The proper opcode is supplied by tcg_opt_gen_mov. */ - op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); + op2 = opt_insert_before(ctx, op, 0, 2); tcg_opt_gen_movi(ctx, op, rl, al); tcg_opt_gen_movi(ctx, op2, rh, ah); @@ -2096,7 +2108,7 @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op) rh = op->args[1]; /* The proper opcode is supplied by tcg_opt_gen_mov. */ - op2 = tcg_op_insert_before(ctx->tcg, op, 0, 2); + op2 = opt_insert_before(ctx, op, 0, 2); tcg_opt_gen_movi(ctx, op, rl, l); tcg_opt_gen_movi(ctx, op2, rh, h); @@ -2406,7 +2418,7 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op->args[3] = 1; } else { if (sh) { - op2 = tcg_op_insert_before(ctx->tcg, op, shr_opc, 3); + op2 = opt_insert_before(ctx, op, shr_opc, 3); op2->args[0] = ret; op2->args[1] = src1; op2->args[2] = arg_new_constant(ctx, sh); @@ -2418,17 +2430,17 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } if (neg && inv) { - op2 = tcg_op_insert_after(ctx->tcg, op, sub_opc, 3); + op2 = opt_insert_after(ctx, op, sub_opc, 3); op2->args[0] = ret; op2->args[1] = ret; op2->args[2] = arg_new_constant(ctx, 1); } else if (inv) { - op2 = tcg_op_insert_after(ctx->tcg, op, xor_opc, 3); + op2 = opt_insert_after(ctx, op, xor_opc, 3); op2->args[0] = ret; op2->args[1] = ret; op2->args[2] = arg_new_constant(ctx, 1); } else if (neg) { - op2 = tcg_op_insert_after(ctx->tcg, op, neg_opc, 2); + op2 = opt_insert_after(ctx, op, neg_opc, 2); op2->args[0] = ret; op2->args[1] = ret; } From cf5c9f697f2025880e8555467ddb6debc6349cd8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Jan 2025 20:34:41 -0800 Subject: [PATCH 0359/2760] tcg: Add TCGType to tcg_op_insert_{after,before} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot rely on the value copied from TCGOP_TYPE(op), because the relevant op could be typeless, such as INDEX_op_call. Fixes: fb744ece3a78 ("tcg: Copy TCGOP_TYPE in tcg_op_insert_{after,before}") Suggested-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 4 ++-- tcg/tcg-internal.h | 4 ++-- tcg/tcg.c | 17 ++++++++++------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index a4d4ad3005..3bd4ee4d58 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -347,13 +347,13 @@ static TCGArg arg_new_temp(OptContext *ctx) static TCGOp *opt_insert_after(OptContext *ctx, TCGOp *op, TCGOpcode opc, unsigned narg) { - return tcg_op_insert_after(ctx->tcg, op, opc, narg); + return tcg_op_insert_after(ctx->tcg, op, opc, ctx->type, narg); } static TCGOp *opt_insert_before(OptContext *ctx, TCGOp *op, TCGOpcode opc, unsigned narg) { - return tcg_op_insert_before(ctx->tcg, op, opc, narg); + return tcg_op_insert_before(ctx->tcg, op, opc, ctx->type, narg); } static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src) diff --git a/tcg/tcg-internal.h b/tcg/tcg-internal.h index ff85fb23fa..d6a12afe06 100644 --- a/tcg/tcg-internal.h +++ b/tcg/tcg-internal.h @@ -107,8 +107,8 @@ void vec_gen_6(TCGOpcode opc, TCGType type, unsigned vece, TCGArg r, TCGArg a, TCGArg b, TCGArg c, TCGArg d, TCGArg e); TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *op, - TCGOpcode opc, unsigned nargs); + TCGOpcode, TCGType, unsigned nargs); TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *op, - TCGOpcode opc, unsigned nargs); + TCGOpcode, TCGType, unsigned nargs); #endif /* TCG_INTERNAL_H */ diff --git a/tcg/tcg.c b/tcg/tcg.c index ec7f6743d7..198d6181d9 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3449,21 +3449,21 @@ TCGOp *tcg_emit_op(TCGOpcode opc, unsigned nargs) } TCGOp *tcg_op_insert_before(TCGContext *s, TCGOp *old_op, - TCGOpcode opc, unsigned nargs) + TCGOpcode opc, TCGType type, unsigned nargs) { TCGOp *new_op = tcg_op_alloc(opc, nargs); - TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); + TCGOP_TYPE(new_op) = type; QTAILQ_INSERT_BEFORE(old_op, new_op, link); return new_op; } TCGOp *tcg_op_insert_after(TCGContext *s, TCGOp *old_op, - TCGOpcode opc, unsigned nargs) + TCGOpcode opc, TCGType type, unsigned nargs) { TCGOp *new_op = tcg_op_alloc(opc, nargs); - TCGOP_TYPE(new_op) = TCGOP_TYPE(old_op); + TCGOP_TYPE(new_op) = type; QTAILQ_INSERT_AFTER(&s->ops, old_op, new_op, link); return new_op; } @@ -4214,7 +4214,8 @@ liveness_pass_2(TCGContext *s) TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 ? INDEX_op_ld_i32 : INDEX_op_ld_i64); - TCGOp *lop = tcg_op_insert_before(s, op, lopc, 3); + TCGOp *lop = tcg_op_insert_before(s, op, lopc, + arg_ts->type, 3); lop->args[0] = temp_arg(dir_ts); lop->args[1] = temp_arg(arg_ts->mem_base); @@ -4277,7 +4278,8 @@ liveness_pass_2(TCGContext *s) TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 ? INDEX_op_st_i32 : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); + TCGOp *sop = tcg_op_insert_after(s, op, sopc, + arg_ts->type, 3); TCGTemp *out_ts = dir_ts; if (IS_DEAD_ARG(0)) { @@ -4313,7 +4315,8 @@ liveness_pass_2(TCGContext *s) TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 ? INDEX_op_st_i32 : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc, 3); + TCGOp *sop = tcg_op_insert_after(s, op, sopc, + arg_ts->type, 3); sop->args[0] = temp_arg(dir_ts); sop->args[1] = temp_arg(arg_ts->mem_base); From 5500bd9e2ec5ec85858fcca06c04a57337aa14c7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 3 Jan 2025 14:55:56 -0800 Subject: [PATCH 0360/2760] tcg: Add all_outop[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add infrastructure for more consolidated output of opcodes. The base structure allows for constraints to be either static or dynamic, and for the existence of those constraints to replace TCG_TARGET_HAS_* and the bulk of tcg_op_supported. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 198d6181d9..5090cdb3c6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -861,6 +861,7 @@ static int tcg_out_pool_finalize(TCGContext *s) #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4), typedef enum { + C_Dynamic = -2, C_NotImplemented = -1, #include "tcg-target-con-set.h" } TCGConstraintSetIndex; @@ -954,6 +955,29 @@ static const TCGConstraintSet constraint_sets[] = { #define C_O2_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_o2_i4_, O1, O2, I1, I2, I3, I4) #define C_N1_O1_I4(O1, O2, I1, I2, I3, I4) C_PFX6(c_n1_o1_i4_, O1, O2, I1, I2, I3, I4) +/* + * TCGOutOp is the base class for a set of structures that describe how + * to generate code for a given TCGOpcode. + * + * @static_constraint: + * C_NotImplemented: The TCGOpcode is not supported by the backend. + * C_Dynamic: Use @dynamic_constraint to select a constraint set + * based on any of @type, @flags, or host isa. + * Otherwise: The register allocation constrains for the TCGOpcode. + * + * Subclasses of TCGOutOp will define a set of output routines that may + * be used. Such routines will often be selected by the set of registers + * and constants that come out of register allocation. The set of + * routines that are provided will guide the set of constraints that are + * legal. In particular, assume that tcg_optimize() has done its job in + * swapping commutative operands and folding operations for which all + * operands are constant. + */ +typedef struct TCGOutOp { + TCGConstraintSetIndex static_constraint; + TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags); +} TCGOutOp; + #include "tcg-target.c.inc" #ifndef CONFIG_TCG_INTERPRETER @@ -963,6 +987,10 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - < MIN_TLB_MASK_TABLE_OFS); #endif +/* Register allocation descriptions for every TCGOpcode. */ +static const TCGOutOp * const all_outop[NB_OPS] = { +}; + /* * All TCG threads except the parent (i.e. the one that called tcg_context_init * and registered the target's TCG globals) must register with this function @@ -2416,8 +2444,32 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return has_type && TCG_TARGET_HAS_cmpsel_vec; default: - tcg_debug_assert(op > INDEX_op_last_generic && op < NB_OPS); + if (op < INDEX_op_last_generic) { + const TCGOutOp *outop; + TCGConstraintSetIndex con_set; + + if (!has_type) { + return false; + } + + outop = all_outop[op]; + tcg_debug_assert(outop != NULL); + + con_set = outop->static_constraint; + if (con_set == C_Dynamic) { + con_set = outop->dynamic_constraint(type, flags); + } + if (con_set >= 0) { + return true; + } + tcg_debug_assert(con_set == C_NotImplemented); + return false; + } + tcg_debug_assert(op < NB_OPS); return true; + + case INDEX_op_last_generic: + g_assert_not_reached(); } } @@ -3335,19 +3387,27 @@ static void process_constraint_sets(void) static const TCGArgConstraint *opcode_args_ct(const TCGOp *op) { - const TCGOpDef *def = &tcg_op_defs[op->opc]; + TCGOpcode opc = op->opc; + TCGType type = TCGOP_TYPE(op); + unsigned flags = TCGOP_FLAGS(op); + const TCGOpDef *def = &tcg_op_defs[opc]; + const TCGOutOp *outop = all_outop[opc]; TCGConstraintSetIndex con_set; -#ifdef CONFIG_DEBUG_TCG - assert(tcg_op_supported(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op))); -#endif - if (def->flags & TCG_OPF_NOT_PRESENT) { return empty_cts; } - con_set = tcg_target_op_def(op->opc, TCGOP_TYPE(op), TCGOP_FLAGS(op)); - tcg_debug_assert(con_set >= 0 && con_set < ARRAY_SIZE(constraint_sets)); + if (outop) { + con_set = outop->static_constraint; + if (con_set == C_Dynamic) { + con_set = outop->dynamic_constraint(type, flags); + } + } else { + con_set = tcg_target_op_def(opc, type, flags); + } + tcg_debug_assert(con_set >= 0); + tcg_debug_assert(con_set < ARRAY_SIZE(constraint_sets)); /* The constraint arguments must match TCGOpcode arguments. */ tcg_debug_assert(constraint_sets[con_set].nb_oargs == def->nb_oargs); From 2225fa242c5d95c5cd83bb6f8566d43dd7a00211 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 22 Feb 2025 09:36:21 -0800 Subject: [PATCH 0361/2760] tcg: Use extract2 for cross-word 64-bit extract on 32-bit host MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index fec6d678a2..f68c4f9702 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2804,9 +2804,18 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, tcg_gen_movi_i32(TCGV_HIGH(ret), 0); return; } - /* The field is split across two words. One double-word - shift is better than two double-word shifts. */ - goto do_shift_and; + + /* The field is split across two words. */ + tcg_gen_extract2_i32(TCGV_LOW(ret), TCGV_LOW(arg), + TCGV_HIGH(arg), ofs); + if (len <= 32) { + tcg_gen_extract_i32(TCGV_LOW(ret), TCGV_LOW(ret), 0, len); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + } else { + tcg_gen_extract_i32(TCGV_HIGH(ret), TCGV_HIGH(arg), + ofs, len - 32); + } + return; } if (TCG_TARGET_extract_valid(TCG_TYPE_I64, ofs, len)) { @@ -2844,7 +2853,6 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, so that we get ext8u, ext16u, and ext32u. */ switch (len) { case 1 ... 8: case 16: case 32: - do_shift_and: tcg_gen_shri_i64(ret, arg, ofs); tcg_gen_andi_i64(ret, ret, (1ull << len) - 1); break; From 48e8de684aff7ad112aafcf74f776d2a66ef192e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 26 Dec 2024 12:01:57 -0800 Subject: [PATCH 0362/2760] tcg: Remove INDEX_op_ext{8,16,32}* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the fully general extract opcodes instead. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 14 -- include/tcg/tcg-opc.h | 10 - tcg/aarch64/tcg-target-has.h | 10 - tcg/aarch64/tcg-target.c.inc | 22 +- tcg/arm/tcg-target-has.h | 4 - tcg/arm/tcg-target.c.inc | 7 - tcg/i386/tcg-target-has.h | 10 - tcg/i386/tcg-target.c.inc | 24 +- tcg/loongarch64/tcg-target-has.h | 10 - tcg/loongarch64/tcg-target.c.inc | 22 +- tcg/mips/tcg-target-has.h | 13 - tcg/mips/tcg-target.c.inc | 20 +- tcg/optimize.c | 61 +---- tcg/ppc/tcg-target-has.h | 12 - tcg/ppc/tcg-target.c.inc | 17 +- tcg/riscv/tcg-target-has.h | 10 - tcg/riscv/tcg-target.c.inc | 22 +- tcg/s390x/tcg-target-has.h | 10 - tcg/s390x/tcg-target.c.inc | 22 +- tcg/sparc64/tcg-target-has.h | 10 - tcg/sparc64/tcg-target.c.inc | 14 +- tcg/tcg-has.h | 6 - tcg/tcg-op.c | 414 +++++++------------------------ tcg/tcg.c | 46 ---- tcg/tci.c | 36 --- tcg/tci/tcg-target-has.h | 10 - tcg/tci/tcg-target.c.inc | 102 +++----- 27 files changed, 135 insertions(+), 823 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 688984fd39..3db7b81637 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -396,20 +396,6 @@ Misc - | *t0* = *t1* | Move *t1* to *t0* (both operands must have the same type). - * - ext8s_i32/i64 *t0*, *t1* - - ext8u_i32/i64 *t0*, *t1* - - ext16s_i32/i64 *t0*, *t1* - - ext16u_i32/i64 *t0*, *t1* - - ext32s_i64 *t0*, *t1* - - ext32u_i64 *t0*, *t1* - - - | 8, 16 or 32 bit sign/zero extension (both operands must have the same type) - * - bswap16_i32/i64 *t0*, *t1*, *flags* - | 16 bit byte swap on the low bits of a 32/64 bit input. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 5bf78b0764..c26cffaa3f 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -85,10 +85,6 @@ DEF(mulsh_i32, 1, 2, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) -DEF(ext8s_i32, 1, 1, 0, 0) -DEF(ext16s_i32, 1, 1, 0, 0) -DEF(ext8u_i32, 1, 1, 0, 0) -DEF(ext16u_i32, 1, 1, 0, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) @@ -149,12 +145,6 @@ DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) -DEF(ext8s_i64, 1, 1, 0, 0) -DEF(ext16s_i64, 1, 1, 0, 0) -DEF(ext32s_i64, 1, 1, 0, 0) -DEF(ext8u_i64, 1, 1, 0, 0) -DEF(ext16u_i64, 1, 1, 0, 0) -DEF(ext32u_i64, 1, 1, 0, 0) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 39f01c14cd..bfd587c0fc 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -15,10 +15,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 @@ -44,12 +40,6 @@ #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 4645242d85..b8b26c1c93 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2493,17 +2493,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2979,16 +2969,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_ext8s_i32: - case INDEX_op_ext16s_i32: - case INDEX_op_ext8u_i32: - case INDEX_op_ext16u_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext16s_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index e3510a8f7a..8398c80c8e 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,10 +24,6 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 0 /* and r0, r1, #0xff */ -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index cec3d761d4..0e48f790f9 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2113,10 +2113,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8u_i32: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16u_i32: default: g_assert_not_reached(); } @@ -2138,9 +2134,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: - case INDEX_op_ext8s_i32: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16u_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: return C_O1_I1(r, r); diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 63768ff058..bbf55c86b6 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -28,10 +28,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_div2_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 @@ -57,12 +53,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 33d303a123..02024018cb 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3016,17 +3016,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -3663,18 +3653,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - return C_O1_I1(r, q); - - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 188b00799f..166c9d7e41 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -22,10 +22,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 @@ -47,12 +43,6 @@ #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 879f66f255..6e77d3e79b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1707,17 +1707,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2243,16 +2233,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_brcond_i64: return C_O0_I2(rz, rz); - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index df6960fe9a..fd96905484 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -80,8 +80,6 @@ extern bool use_mips32r2_instructions; /* optional instructions detected at runtime */ #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_ext8s_i32 use_mips32r2_instructions -#define TCG_TARGET_HAS_ext16s_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_rot_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i32 0 @@ -93,23 +91,12 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_ext8s_i64 use_mips32r2_instructions -#define TCG_TARGET_HAS_ext16s_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_rot_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #endif -/* optional instructions automatically implemented */ -#define TCG_TARGET_HAS_ext8u_i32 0 /* andi rt, rs, 0xff */ -#define TCG_TARGET_HAS_ext16u_i32 0 /* andi rt, rs, 0xffff */ - -#if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_ext8u_i64 0 /* andi rt, rs, 0xff */ -#define TCG_TARGET_HAS_ext16u_i64 0 /* andi rt, rs, 0xffff */ -#endif - #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index f8c105ba37..f77159bdc7 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -647,7 +647,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { - tcg_debug_assert(TCG_TARGET_HAS_ext8s_i32); + tcg_debug_assert(use_mips32r2_instructions); tcg_out_opc_reg(s, OPC_SEB, rd, TCG_REG_ZERO, rs); } @@ -658,7 +658,7 @@ static void tcg_out_ext8u(TCGContext *s, TCGReg rd, TCGReg rs) static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { - tcg_debug_assert(TCG_TARGET_HAS_ext16s_i32); + tcg_debug_assert(use_mips32r2_instructions); tcg_out_opc_reg(s, OPC_SEH, rd, TCG_REG_ZERO, rs); } @@ -2106,15 +2106,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2138,8 +2130,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: - case INDEX_op_ext8s_i32: - case INDEX_op_ext16s_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: @@ -2154,10 +2144,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_ext8s_i64: - case INDEX_op_ext16s_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: diff --git a/tcg/optimize.c b/tcg/optimize.c index 3bd4ee4d58..e9e654597d 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -513,18 +513,6 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_ctpop_i64: return ctpop64(x); - CASE_OP_32_64(ext8s): - return (int8_t)x; - - CASE_OP_32_64(ext16s): - return (int16_t)x; - - CASE_OP_32_64(ext8u): - return (uint8_t)x; - - CASE_OP_32_64(ext16u): - return (uint16_t)x; - CASE_OP_32_64(bswap16): x = bswap16(x); return y & TCG_BSWAP_OS ? (int16_t)x : x; @@ -537,12 +525,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) return bswap64(x); case INDEX_op_ext_i32_i64: - case INDEX_op_ext32s_i64: return (int32_t)x; case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: - case INDEX_op_ext32u_i64: return (uint32_t)x; case INDEX_op_extrh_i64_i32: @@ -1869,8 +1855,7 @@ static bool fold_extract2(OptContext *ctx, TCGOp *op) static bool fold_exts(OptContext *ctx, TCGOp *op) { - uint64_t s_mask_old, s_mask, z_mask; - bool type_change = false; + uint64_t s_mask, z_mask; TempOptInfo *t1; if (fold_const1(ctx, op)) { @@ -1880,72 +1865,38 @@ static bool fold_exts(OptContext *ctx, TCGOp *op) t1 = arg_info(op->args[1]); z_mask = t1->z_mask; s_mask = t1->s_mask; - s_mask_old = s_mask; switch (op->opc) { - CASE_OP_32_64(ext8s): - s_mask |= INT8_MIN; - z_mask = (int8_t)z_mask; - break; - CASE_OP_32_64(ext16s): - s_mask |= INT16_MIN; - z_mask = (int16_t)z_mask; - break; case INDEX_op_ext_i32_i64: - type_change = true; - QEMU_FALLTHROUGH; - case INDEX_op_ext32s_i64: s_mask |= INT32_MIN; z_mask = (int32_t)z_mask; break; default: g_assert_not_reached(); } - - if (!type_change && fold_affected_mask(ctx, op, s_mask & ~s_mask_old)) { - return true; - } - return fold_masks_zs(ctx, op, z_mask, s_mask); } static bool fold_extu(OptContext *ctx, TCGOp *op) { - uint64_t z_mask_old, z_mask; - bool type_change = false; + uint64_t z_mask; if (fold_const1(ctx, op)) { return true; } - z_mask_old = z_mask = arg_info(op->args[1])->z_mask; - + z_mask = arg_info(op->args[1])->z_mask; switch (op->opc) { - CASE_OP_32_64(ext8u): - z_mask = (uint8_t)z_mask; - break; - CASE_OP_32_64(ext16u): - z_mask = (uint16_t)z_mask; - break; case INDEX_op_extrl_i64_i32: case INDEX_op_extu_i32_i64: - type_change = true; - QEMU_FALLTHROUGH; - case INDEX_op_ext32u_i64: z_mask = (uint32_t)z_mask; break; case INDEX_op_extrh_i64_i32: - type_change = true; z_mask >>= 32; break; default: g_assert_not_reached(); } - - if (!type_change && fold_affected_mask(ctx, op, z_mask_old ^ z_mask)) { - return true; - } - return fold_masks_z(ctx, op, z_mask); } @@ -2948,15 +2899,9 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(extract2): done = fold_extract2(&ctx, op); break; - CASE_OP_32_64(ext8s): - CASE_OP_32_64(ext16s): - case INDEX_op_ext32s_i64: case INDEX_op_ext_i32_i64: done = fold_exts(&ctx, op); break; - CASE_OP_32_64(ext8u): - CASE_OP_32_64(ext16u): - case INDEX_op_ext32u_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 6db91f78ce..9acfc574c5 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -16,16 +16,10 @@ #define have_altivec (cpuinfo & CPUINFO_ALTIVEC) #define have_vsx (cpuinfo & CPUINFO_VSX) -/* optional instructions automatically implemented */ -#define TCG_TARGET_HAS_ext8u_i32 0 /* andi */ -#define TCG_TARGET_HAS_ext16u_i32 0 - /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 have_isa_3_00 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 @@ -52,12 +46,6 @@ #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 have_isa_3_00 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 0 -#define TCG_TARGET_HAS_ext16u_i64 0 -#define TCG_TARGET_HAS_ext32u_i64 0 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 822925a19b..e10c1c5162 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3473,17 +3473,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -4109,8 +4099,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctpop_i32: case INDEX_op_neg_i32: case INDEX_op_not_i32: - case INDEX_op_ext8s_i32: - case INDEX_op_ext16s_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: @@ -4125,9 +4113,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctpop_i64: case INDEX_op_neg_i64: case INDEX_op_not_i64: - case INDEX_op_ext8s_i64: - case INDEX_op_ext16s_i64: - case INDEX_op_ext32s_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 98081084f2..fc62049c78 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -22,10 +22,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 @@ -46,12 +42,6 @@ #define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f7e1ca5a56..d525df4e1d 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2385,17 +2385,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2643,17 +2633,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_not_i64: case INDEX_op_neg_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32u_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext32s_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index e99e671642..aea805455f 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -31,10 +31,6 @@ extern uint64_t s390_facilities[3]; /* optional instructions */ #define TCG_TARGET_HAS_div2_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) @@ -59,12 +55,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index b2e1cd60ff..8421320928 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2781,17 +2781,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -3340,16 +3330,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 2f46df8c61..ad6f35da17 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -17,10 +17,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 0 -#define TCG_TARGET_HAS_ext8s_i32 0 -#define TCG_TARGET_HAS_ext16s_i32 0 -#define TCG_TARGET_HAS_ext8u_i32 0 -#define TCG_TARGET_HAS_ext16u_i32 0 #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 @@ -46,12 +42,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 -#define TCG_TARGET_HAS_ext8s_i64 0 -#define TCG_TARGET_HAS_ext16s_i64 0 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 0 -#define TCG_TARGET_HAS_ext16u_i64 0 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 7c722f59a8..787e0d896c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1517,17 +1517,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: default: g_assert_not_reached(); @@ -1557,8 +1547,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i64: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 418e4673eb..4ccdc6bbee 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -16,12 +16,6 @@ #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 0 -#define TCG_TARGET_HAS_ext8s_i64 0 -#define TCG_TARGET_HAS_ext16s_i64 0 -#define TCG_TARGET_HAS_ext32s_i64 0 -#define TCG_TARGET_HAS_ext8u_i64 0 -#define TCG_TARGET_HAS_ext16u_i64 0 -#define TCG_TARGET_HAS_ext32u_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index f68c4f9702..48793ed439 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -414,17 +414,19 @@ void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) case -1: tcg_gen_mov_i32(ret, arg1); return; - case 0xff: - /* Don't recurse with tcg_gen_ext8u_i32. */ - if (TCG_TARGET_HAS_ext8u_i32) { - tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg1); - return; - } - break; - case 0xffff: - if (TCG_TARGET_HAS_ext16u_i32) { - tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg1); - return; + default: + /* + * Canonicalize on extract, if valid. This aids x86 with its + * 2 operand MOVZBL and 2 operand AND, selecting the TCGOpcode + * which does not require matching operands. Other backends can + * trivially expand the extract to AND during code generation. + */ + if (!(arg2 & (arg2 + 1))) { + unsigned len = ctz32(~arg2); + if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, len)) { + tcg_gen_extract_i32(ret, arg1, 0, len); + return; + } } break; } @@ -955,40 +957,20 @@ void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len); } else { - /* To help two-operand hosts we prefer to zero-extend first, - which allows ARG to stay live. */ - switch (len) { - case 16: - if (TCG_TARGET_HAS_ext16u_i32) { - tcg_gen_ext16u_i32(ret, arg); - tcg_gen_shli_i32(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i32) { - tcg_gen_ext8u_i32(ret, arg); - tcg_gen_shli_i32(ret, ret, ofs); - return; - } - break; + /* + * To help two-operand hosts we prefer to zero-extend first, + * which allows ARG to stay live. + */ + if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, len)) { + tcg_gen_extract_i32(ret, arg, 0, len); + tcg_gen_shli_i32(ret, ret, ofs); + return; } /* Otherwise prefer zero-extension over AND for code size. */ - switch (ofs + len) { - case 16: - if (TCG_TARGET_HAS_ext16u_i32) { - tcg_gen_shli_i32(ret, arg, ofs); - tcg_gen_ext16u_i32(ret, ret); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i32) { - tcg_gen_shli_i32(ret, arg, ofs); - tcg_gen_ext8u_i32(ret, ret); - return; - } - break; + if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, ofs + len)) { + tcg_gen_shli_i32(ret, arg, ofs); + tcg_gen_extract_i32(ret, ret, 0, ofs + len); + return; } tcg_gen_andi_i32(ret, arg, (1u << len) - 1); tcg_gen_shli_i32(ret, ret, ofs); @@ -1008,32 +990,21 @@ void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, tcg_gen_shri_i32(ret, arg, 32 - len); return; } - if (ofs == 0) { - tcg_gen_andi_i32(ret, arg, (1u << len) - 1); - return; - } if (TCG_TARGET_extract_valid(TCG_TYPE_I32, ofs, len)) { tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len); return; } + if (ofs == 0) { + tcg_gen_andi_i32(ret, arg, (1u << len) - 1); + return; + } /* Assume that zero-extension, if available, is cheaper than a shift. */ - switch (ofs + len) { - case 16: - if (TCG_TARGET_HAS_ext16u_i32) { - tcg_gen_ext16u_i32(ret, arg); - tcg_gen_shri_i32(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i32) { - tcg_gen_ext8u_i32(ret, arg); - tcg_gen_shri_i32(ret, ret, ofs); - return; - } - break; + if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, ofs + len)) { + tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, 0, ofs + len); + tcg_gen_shri_i32(ret, ret, ofs); + return; } /* ??? Ideally we'd know what values are available for immediate AND. @@ -1064,16 +1035,6 @@ void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, tcg_gen_sari_i32(ret, arg, 32 - len); return; } - if (ofs == 0) { - switch (len) { - case 16: - tcg_gen_ext16s_i32(ret, arg); - return; - case 8: - tcg_gen_ext8s_i32(ret, arg); - return; - } - } if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, ofs, len)) { tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len); @@ -1081,37 +1042,15 @@ void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, } /* Assume that sign-extension, if available, is cheaper than a shift. */ - switch (ofs + len) { - case 16: - if (TCG_TARGET_HAS_ext16s_i32) { - tcg_gen_ext16s_i32(ret, arg); - tcg_gen_sari_i32(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8s_i32) { - tcg_gen_ext8s_i32(ret, arg); - tcg_gen_sari_i32(ret, ret, ofs); - return; - } - break; + if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, 0, ofs + len)) { + tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, 0, ofs + len); + tcg_gen_sari_i32(ret, ret, ofs); + return; } - switch (len) { - case 16: - if (TCG_TARGET_HAS_ext16s_i32) { - tcg_gen_shri_i32(ret, arg, ofs); - tcg_gen_ext16s_i32(ret, ret); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8s_i32) { - tcg_gen_shri_i32(ret, arg, ofs); - tcg_gen_ext8s_i32(ret, ret); - return; - } - break; + if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, 0, len)) { + tcg_gen_shri_i32(ret, arg, ofs); + tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, ret, 0, len); + return; } tcg_gen_shli_i32(ret, arg, 32 - len - ofs); @@ -1281,40 +1220,22 @@ void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_ext8s_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_ext8s_i32) { - tcg_gen_op2_i32(INDEX_op_ext8s_i32, ret, arg); - } else { - tcg_gen_shli_i32(ret, arg, 24); - tcg_gen_sari_i32(ret, ret, 24); - } + tcg_gen_sextract_i32(ret, arg, 0, 8); } void tcg_gen_ext16s_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_ext16s_i32) { - tcg_gen_op2_i32(INDEX_op_ext16s_i32, ret, arg); - } else { - tcg_gen_shli_i32(ret, arg, 16); - tcg_gen_sari_i32(ret, ret, 16); - } + tcg_gen_sextract_i32(ret, arg, 0, 16); } void tcg_gen_ext8u_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_ext8u_i32) { - tcg_gen_op2_i32(INDEX_op_ext8u_i32, ret, arg); - } else { - tcg_gen_andi_i32(ret, arg, 0xffu); - } + tcg_gen_extract_i32(ret, arg, 0, 8); } void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_ext16u_i32) { - tcg_gen_op2_i32(INDEX_op_ext16u_i32, ret, arg); - } else { - tcg_gen_andi_i32(ret, arg, 0xffffu); - } + tcg_gen_extract_i32(ret, arg, 0, 16); } /* @@ -1794,23 +1715,19 @@ void tcg_gen_andi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) case -1: tcg_gen_mov_i64(ret, arg1); return; - case 0xff: - /* Don't recurse with tcg_gen_ext8u_i64. */ - if (TCG_TARGET_HAS_ext8u_i64) { - tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg1); - return; - } - break; - case 0xffff: - if (TCG_TARGET_HAS_ext16u_i64) { - tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg1); - return; - } - break; - case 0xffffffffu: - if (TCG_TARGET_HAS_ext32u_i64) { - tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg1); - return; + default: + /* + * Canonicalize on extract, if valid. This aids x86 with its + * 2 operand MOVZBL and 2 operand AND, selecting the TCGOpcode + * which does not require matching operands. Other backends can + * trivially expand the extract to AND during code generation. + */ + if (!(arg2 & (arg2 + 1))) { + unsigned len = ctz64(~arg2); + if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, len)) { + tcg_gen_extract_i64(ret, arg1, 0, len); + return; + } } break; } @@ -2118,77 +2035,32 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_ext8s_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_ext8s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); - } else if (TCG_TARGET_HAS_ext8s_i64) { - tcg_gen_op2_i64(INDEX_op_ext8s_i64, ret, arg); - } else { - tcg_gen_shli_i64(ret, arg, 56); - tcg_gen_sari_i64(ret, ret, 56); - } + tcg_gen_sextract_i64(ret, arg, 0, 8); } void tcg_gen_ext16s_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_ext16s_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); - } else if (TCG_TARGET_HAS_ext16s_i64) { - tcg_gen_op2_i64(INDEX_op_ext16s_i64, ret, arg); - } else { - tcg_gen_shli_i64(ret, arg, 48); - tcg_gen_sari_i64(ret, ret, 48); - } + tcg_gen_sextract_i64(ret, arg, 0, 16); } void tcg_gen_ext32s_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); - } else if (TCG_TARGET_HAS_ext32s_i64) { - tcg_gen_op2_i64(INDEX_op_ext32s_i64, ret, arg); - } else { - tcg_gen_shli_i64(ret, arg, 32); - tcg_gen_sari_i64(ret, ret, 32); - } + tcg_gen_sextract_i64(ret, arg, 0, 32); } void tcg_gen_ext8u_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_ext8u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_movi_i32(TCGV_HIGH(ret), 0); - } else if (TCG_TARGET_HAS_ext8u_i64) { - tcg_gen_op2_i64(INDEX_op_ext8u_i64, ret, arg); - } else { - tcg_gen_andi_i64(ret, arg, 0xffu); - } + tcg_gen_extract_i64(ret, arg, 0, 8); } void tcg_gen_ext16u_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_ext16u_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_movi_i32(TCGV_HIGH(ret), 0); - } else if (TCG_TARGET_HAS_ext16u_i64) { - tcg_gen_op2_i64(INDEX_op_ext16u_i64, ret, arg); - } else { - tcg_gen_andi_i64(ret, arg, 0xffffu); - } + tcg_gen_extract_i64(ret, arg, 0, 16); } void tcg_gen_ext32u_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_REG_BITS == 32) { - tcg_gen_mov_i32(TCGV_LOW(ret), TCGV_LOW(arg)); - tcg_gen_movi_i32(TCGV_HIGH(ret), 0); - } else if (TCG_TARGET_HAS_ext32u_i64) { - tcg_gen_op2_i64(INDEX_op_ext32u_i64, ret, arg); - } else { - tcg_gen_andi_i64(ret, arg, 0xffffffffu); - } + tcg_gen_extract_i64(ret, arg, 0, 32); } /* @@ -2720,54 +2592,20 @@ void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, return; } } - /* To help two-operand hosts we prefer to zero-extend first, - which allows ARG to stay live. */ - switch (len) { - case 32: - if (TCG_TARGET_HAS_ext32u_i64) { - tcg_gen_ext32u_i64(ret, arg); - tcg_gen_shli_i64(ret, ret, ofs); - return; - } - break; - case 16: - if (TCG_TARGET_HAS_ext16u_i64) { - tcg_gen_ext16u_i64(ret, arg); - tcg_gen_shli_i64(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i64) { - tcg_gen_ext8u_i64(ret, arg); - tcg_gen_shli_i64(ret, ret, ofs); - return; - } - break; + /* + * To help two-operand hosts we prefer to zero-extend first, + * which allows ARG to stay live. + */ + if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, len)) { + tcg_gen_extract_i64(ret, arg, 0, len); + tcg_gen_shli_i64(ret, ret, ofs); + return; } /* Otherwise prefer zero-extension over AND for code size. */ - switch (ofs + len) { - case 32: - if (TCG_TARGET_HAS_ext32u_i64) { - tcg_gen_shli_i64(ret, arg, ofs); - tcg_gen_ext32u_i64(ret, ret); - return; - } - break; - case 16: - if (TCG_TARGET_HAS_ext16u_i64) { - tcg_gen_shli_i64(ret, arg, ofs); - tcg_gen_ext16u_i64(ret, ret); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i64) { - tcg_gen_shli_i64(ret, arg, ofs); - tcg_gen_ext8u_i64(ret, ret); - return; - } - break; + if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, ofs + len)) { + tcg_gen_shli_i64(ret, arg, ofs); + tcg_gen_extract_i64(ret, ret, 0, ofs + len); + return; } tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); tcg_gen_shli_i64(ret, ret, ofs); @@ -2787,10 +2625,6 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, tcg_gen_shri_i64(ret, arg, 64 - len); return; } - if (ofs == 0) { - tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); - return; - } if (TCG_TARGET_REG_BITS == 32) { /* Look for a 32-bit extract within one of the two words. */ @@ -2822,30 +2656,16 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len); return; } + if (ofs == 0) { + tcg_gen_andi_i64(ret, arg, (1ull << len) - 1); + return; + } /* Assume that zero-extension, if available, is cheaper than a shift. */ - switch (ofs + len) { - case 32: - if (TCG_TARGET_HAS_ext32u_i64) { - tcg_gen_ext32u_i64(ret, arg); - tcg_gen_shri_i64(ret, ret, ofs); - return; - } - break; - case 16: - if (TCG_TARGET_HAS_ext16u_i64) { - tcg_gen_ext16u_i64(ret, arg); - tcg_gen_shri_i64(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8u_i64) { - tcg_gen_ext8u_i64(ret, arg); - tcg_gen_shri_i64(ret, ret, ofs); - return; - } - break; + if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, ofs + len)) { + tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, 0, ofs + len); + tcg_gen_shri_i64(ret, ret, ofs); + return; } /* ??? Ideally we'd know what values are available for immediate AND. @@ -2876,19 +2696,6 @@ void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, tcg_gen_sari_i64(ret, arg, 64 - len); return; } - if (ofs == 0) { - switch (len) { - case 32: - tcg_gen_ext32s_i64(ret, arg); - return; - case 16: - tcg_gen_ext16s_i64(ret, arg); - return; - case 8: - tcg_gen_ext8s_i64(ret, arg); - return; - } - } if (TCG_TARGET_REG_BITS == 32) { /* Look for a 32-bit extract within one of the two words. */ @@ -2928,52 +2735,17 @@ void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, } /* Assume that sign-extension, if available, is cheaper than a shift. */ - switch (ofs + len) { - case 32: - if (TCG_TARGET_HAS_ext32s_i64) { - tcg_gen_ext32s_i64(ret, arg); - tcg_gen_sari_i64(ret, ret, ofs); - return; - } - break; - case 16: - if (TCG_TARGET_HAS_ext16s_i64) { - tcg_gen_ext16s_i64(ret, arg); - tcg_gen_sari_i64(ret, ret, ofs); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8s_i64) { - tcg_gen_ext8s_i64(ret, arg); - tcg_gen_sari_i64(ret, ret, ofs); - return; - } - break; + if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, 0, ofs + len)) { + tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, 0, ofs + len); + tcg_gen_sari_i64(ret, ret, ofs); + return; } - switch (len) { - case 32: - if (TCG_TARGET_HAS_ext32s_i64) { - tcg_gen_shri_i64(ret, arg, ofs); - tcg_gen_ext32s_i64(ret, ret); - return; - } - break; - case 16: - if (TCG_TARGET_HAS_ext16s_i64) { - tcg_gen_shri_i64(ret, arg, ofs); - tcg_gen_ext16s_i64(ret, ret); - return; - } - break; - case 8: - if (TCG_TARGET_HAS_ext8s_i64) { - tcg_gen_shri_i64(ret, arg, ofs); - tcg_gen_ext8s_i64(ret, ret); - return; - } - break; + if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, 0, len)) { + tcg_gen_shri_i64(ret, arg, ofs); + tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, ret, 0, len); + return; } + tcg_gen_shli_i64(ret, arg, 64 - len - ofs); tcg_gen_sari_i64(ret, ret, 64 - len); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 5090cdb3c6..e8fd89e4c8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2242,14 +2242,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_muluh_i32; case INDEX_op_mulsh_i32: return TCG_TARGET_HAS_mulsh_i32; - case INDEX_op_ext8s_i32: - return TCG_TARGET_HAS_ext8s_i32; - case INDEX_op_ext16s_i32: - return TCG_TARGET_HAS_ext16s_i32; - case INDEX_op_ext8u_i32: - return TCG_TARGET_HAS_ext8u_i32; - case INDEX_op_ext16u_i32: - return TCG_TARGET_HAS_ext16u_i32; case INDEX_op_bswap16_i32: return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: @@ -2328,18 +2320,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return TCG_TARGET_HAS_extr_i64_i32; - case INDEX_op_ext8s_i64: - return TCG_TARGET_HAS_ext8s_i64; - case INDEX_op_ext16s_i64: - return TCG_TARGET_HAS_ext16s_i64; - case INDEX_op_ext32s_i64: - return TCG_TARGET_HAS_ext32s_i64; - case INDEX_op_ext8u_i64: - return TCG_TARGET_HAS_ext8u_i64; - case INDEX_op_ext16u_i64: - return TCG_TARGET_HAS_ext16u_i64; - case INDEX_op_ext32u_i64: - return TCG_TARGET_HAS_ext32u_i64; case INDEX_op_bswap16_i64: return TCG_TARGET_HAS_bswap16_i64; case INDEX_op_bswap32_i64: @@ -5430,32 +5410,6 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* emit instruction */ switch (op->opc) { - case INDEX_op_ext8s_i32: - tcg_out_ext8s(s, TCG_TYPE_I32, new_args[0], new_args[1]); - break; - case INDEX_op_ext8s_i64: - tcg_out_ext8s(s, TCG_TYPE_I64, new_args[0], new_args[1]); - break; - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - tcg_out_ext8u(s, new_args[0], new_args[1]); - break; - case INDEX_op_ext16s_i32: - tcg_out_ext16s(s, TCG_TYPE_I32, new_args[0], new_args[1]); - break; - case INDEX_op_ext16s_i64: - tcg_out_ext16s(s, TCG_TYPE_I64, new_args[0], new_args[1]); - break; - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - tcg_out_ext16u(s, new_args[0], new_args[1]); - break; - case INDEX_op_ext32s_i64: - tcg_out_ext32s(s, new_args[0], new_args[1]); - break; - case INDEX_op_ext32u_i64: - tcg_out_ext32u(s, new_args[0], new_args[1]); - break; case INDEX_op_ext_i32_i64: tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); break; diff --git a/tcg/tci.c b/tcg/tci.c index d223258efe..531cd83aae 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -689,31 +689,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, tmp64); break; #endif -#if TCG_TARGET_HAS_ext8s_i32 || TCG_TARGET_HAS_ext8s_i64 - CASE_32_64(ext8s) - tci_args_rr(insn, &r0, &r1); - regs[r0] = (int8_t)regs[r1]; - break; -#endif -#if TCG_TARGET_HAS_ext16s_i32 || TCG_TARGET_HAS_ext16s_i64 || \ - TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 - CASE_32_64(ext16s) - tci_args_rr(insn, &r0, &r1); - regs[r0] = (int16_t)regs[r1]; - break; -#endif -#if TCG_TARGET_HAS_ext8u_i32 || TCG_TARGET_HAS_ext8u_i64 - CASE_32_64(ext8u) - tci_args_rr(insn, &r0, &r1); - regs[r0] = (uint8_t)regs[r1]; - break; -#endif -#if TCG_TARGET_HAS_ext16u_i32 || TCG_TARGET_HAS_ext16u_i64 - CASE_32_64(ext16u) - tci_args_rr(insn, &r0, &r1); - regs[r0] = (uint16_t)regs[r1]; - break; -#endif #if TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 CASE_32_64(bswap16) tci_args_rr(insn, &r0, &r1); @@ -864,12 +839,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tb_ptr = ptr; } break; - case INDEX_op_ext32s_i64: case INDEX_op_ext_i32_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = (int32_t)regs[r1]; break; - case INDEX_op_ext32u_i64: case INDEX_op_extu_i32_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = (uint32_t)regs[r1]; @@ -1092,15 +1065,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_mov_i32: case INDEX_op_mov_i64: - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index c8785ca8dc..cb0964c3d4 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -11,10 +11,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_ext8s_i32 1 -#define TCG_TARGET_HAS_ext16s_i32 1 -#define TCG_TARGET_HAS_ext8u_i32 1 -#define TCG_TARGET_HAS_ext16u_i32 1 #define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_eqv_i32 1 @@ -40,12 +36,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_ext8s_i64 1 -#define TCG_TARGET_HAS_ext16s_i64 1 -#define TCG_TARGET_HAS_ext32s_i64 1 -#define TCG_TARGET_HAS_ext8u_i64 1 -#define TCG_TARGET_HAS_ext16u_i64 1 -#define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 36e018dd19..6f8f1dd8ae 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -59,16 +59,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_not_i64: case INDEX_op_neg_i32: case INDEX_op_neg_i64: - case INDEX_op_ext8s_i32: - case INDEX_op_ext8s_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: @@ -535,76 +525,54 @@ static void tcg_out_movi(TCGContext *s, TCGType type, } } +static void tcg_out_extract(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rs, unsigned pos, unsigned len) +{ + TCGOpcode opc = type == TCG_TYPE_I32 ? + INDEX_op_extract_i32 : + INDEX_op_extract_i64; + tcg_out_op_rrbb(s, opc, rd, rs, pos, len); +} + +static void tcg_out_sextract(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rs, unsigned pos, unsigned len) +{ + TCGOpcode opc = type == TCG_TYPE_I32 ? + INDEX_op_sextract_i32 : + INDEX_op_sextract_i64; + tcg_out_op_rrbb(s, opc, rd, rs, pos, len); +} + static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { - switch (type) { - case TCG_TYPE_I32: - tcg_debug_assert(TCG_TARGET_HAS_ext8s_i32); - tcg_out_op_rr(s, INDEX_op_ext8s_i32, rd, rs); - break; -#if TCG_TARGET_REG_BITS == 64 - case TCG_TYPE_I64: - tcg_debug_assert(TCG_TARGET_HAS_ext8s_i64); - tcg_out_op_rr(s, INDEX_op_ext8s_i64, rd, rs); - break; -#endif - default: - g_assert_not_reached(); - } + tcg_out_sextract(s, type, rd, rs, 0, 8); } static void tcg_out_ext8u(TCGContext *s, TCGReg rd, TCGReg rs) { - if (TCG_TARGET_REG_BITS == 64) { - tcg_debug_assert(TCG_TARGET_HAS_ext8u_i64); - tcg_out_op_rr(s, INDEX_op_ext8u_i64, rd, rs); - } else { - tcg_debug_assert(TCG_TARGET_HAS_ext8u_i32); - tcg_out_op_rr(s, INDEX_op_ext8u_i32, rd, rs); - } + tcg_out_extract(s, TCG_TYPE_REG, rd, rs, 0, 8); } static void tcg_out_ext16s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { - switch (type) { - case TCG_TYPE_I32: - tcg_debug_assert(TCG_TARGET_HAS_ext16s_i32); - tcg_out_op_rr(s, INDEX_op_ext16s_i32, rd, rs); - break; -#if TCG_TARGET_REG_BITS == 64 - case TCG_TYPE_I64: - tcg_debug_assert(TCG_TARGET_HAS_ext16s_i64); - tcg_out_op_rr(s, INDEX_op_ext16s_i64, rd, rs); - break; -#endif - default: - g_assert_not_reached(); - } + tcg_out_sextract(s, type, rd, rs, 0, 16); } static void tcg_out_ext16u(TCGContext *s, TCGReg rd, TCGReg rs) { - if (TCG_TARGET_REG_BITS == 64) { - tcg_debug_assert(TCG_TARGET_HAS_ext16u_i64); - tcg_out_op_rr(s, INDEX_op_ext16u_i64, rd, rs); - } else { - tcg_debug_assert(TCG_TARGET_HAS_ext16u_i32); - tcg_out_op_rr(s, INDEX_op_ext16u_i32, rd, rs); - } + tcg_out_extract(s, TCG_TYPE_REG, rd, rs, 0, 16); } static void tcg_out_ext32s(TCGContext *s, TCGReg rd, TCGReg rs) { tcg_debug_assert(TCG_TARGET_REG_BITS == 64); - tcg_debug_assert(TCG_TARGET_HAS_ext32s_i64); - tcg_out_op_rr(s, INDEX_op_ext32s_i64, rd, rs); + tcg_out_sextract(s, TCG_TYPE_I64, rd, rs, 0, 32); } static void tcg_out_ext32u(TCGContext *s, TCGReg rd, TCGReg rs) { tcg_debug_assert(TCG_TARGET_REG_BITS == 64); - tcg_debug_assert(TCG_TARGET_HAS_ext32u_i64); - tcg_out_op_rr(s, INDEX_op_ext32u_i64, rd, rs); + tcg_out_extract(s, TCG_TYPE_I64, rd, rs, 0, 32); } static void tcg_out_exts_i32_i64(TCGContext *s, TCGReg rd, TCGReg rs) @@ -690,7 +658,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGOpcode exts; + int width; switch (opc) { case INDEX_op_goto_ptr: @@ -777,18 +745,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; case INDEX_op_bswap16_i32: /* Optional (TCG_TARGET_HAS_bswap16_i32). */ - exts = INDEX_op_ext16s_i32; - goto do_bswap; case INDEX_op_bswap16_i64: /* Optional (TCG_TARGET_HAS_bswap16_i64). */ - exts = INDEX_op_ext16s_i64; + width = 16; goto do_bswap; case INDEX_op_bswap32_i64: /* Optional (TCG_TARGET_HAS_bswap32_i64). */ - exts = INDEX_op_ext32s_i64; + width = 32; do_bswap: /* The base tci bswaps zero-extend, and ignore high bits. */ tcg_out_op_rr(s, opc, args[0], args[1]); if (args[2] & TCG_BSWAP_OS) { - tcg_out_op_rr(s, exts, args[0], args[0]); + tcg_out_sextract(s, TCG_TYPE_REG, args[0], args[0], 0, width); } break; @@ -838,17 +804,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext8s_i32: /* Always emitted via tcg_reg_alloc_op. */ - case INDEX_op_ext8s_i64: - case INDEX_op_ext8u_i32: - case INDEX_op_ext8u_i64: - case INDEX_op_ext16s_i32: - case INDEX_op_ext16s_i64: - case INDEX_op_ext16u_i32: - case INDEX_op_ext16u_i64: - case INDEX_op_ext32s_i64: - case INDEX_op_ext32u_i64: - case INDEX_op_ext_i32_i64: + case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: From b5701261da6607e61ef1fe605d85bf31806fcd34 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 28 Dec 2024 15:58:24 -0800 Subject: [PATCH 0363/2760] tcg: Merge INDEX_op_mov_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Begin to rely on TCGOp.type to discriminate operations, rather than two different opcodes. Convert mov first. Introduce TCG_OPF_INT in order to keep opcode dumps the same. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 4 ++-- include/tcg/tcg.h | 2 ++ tcg/aarch64/tcg-target.c.inc | 2 -- tcg/arm/tcg-target.c.inc | 1 - tcg/i386/tcg-target.c.inc | 2 -- tcg/loongarch64/tcg-target.c.inc | 2 -- tcg/mips/tcg-target.c.inc | 2 -- tcg/optimize.c | 7 +++---- tcg/ppc/tcg-target.c.inc | 2 -- tcg/riscv/tcg-target.c.inc | 2 -- tcg/s390x/tcg-target.c.inc | 2 -- tcg/sparc64/tcg-target.c.inc | 2 -- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 32 ++++++++++++++++++-------------- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 15 +-------------- 17 files changed, 32 insertions(+), 58 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 3db7b81637..e6ccc78fa1 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -391,10 +391,10 @@ Misc .. list-table:: - * - mov_i32/i64 *t0*, *t1* + * - mov *t0*, *t1* - | *t0* = *t1* - | Move *t1* to *t0* (both operands must have the same type). + | Move *t1* to *t0*. * - bswap16_i32/i64 *t0*, *t1*, *flags* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index c26cffaa3f..766fd00d99 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -37,7 +37,8 @@ DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) DEF(mb, 0, 0, 1, TCG_OPF_NOT_PRESENT) -DEF(mov_i32, 1, 1, 0, TCG_OPF_NOT_PRESENT) +DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) + DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) DEF(movcond_i32, 1, 4, 1, 0) @@ -98,7 +99,6 @@ DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) -DEF(mov_i64, 1, 1, 0, TCG_OPF_NOT_PRESENT) DEF(setcond_i64, 1, 2, 1, 0) DEF(negsetcond_i64, 1, 2, 1, 0) DEF(movcond_i64, 1, 4, 1, 0) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 84d99508b6..c6b50b5226 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -741,6 +741,8 @@ enum { /* Instruction has side effects: it cannot be removed if its outputs are not used, and might trigger exceptions. */ TCG_OPF_SIDE_EFFECTS = 0x08, + /* Instruction operands may be I32 or I64 */ + TCG_OPF_INT = 0x10, /* Instruction is optional and not implemented by the host, or insn is generic and should not be implemented by the host. */ TCG_OPF_NOT_PRESENT = 0x20, diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index b8b26c1c93..466042a577 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2488,8 +2488,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_mb(s, a0); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0e48f790f9..0fafe97230 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2109,7 +2109,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, args[0]); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 02024018cb..75c8665d74 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3011,8 +3011,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_mb: tcg_out_mb(s, a0); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 6e77d3e79b..b0a4ec4c13 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1702,8 +1702,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, a0, a1, a2, a3, false); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index f77159bdc7..4d52e0bde0 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2101,8 +2101,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_mb: tcg_out_mb(s, a0); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/optimize.c b/tcg/optimize.c index e9e654597d..8d5bad07aa 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -375,10 +375,8 @@ static bool tcg_opt_gen_mov(OptContext *ctx, TCGOp *op, TCGArg dst, TCGArg src) switch (ctx->type) { case TCG_TYPE_I32: - new_op = INDEX_op_mov_i32; - break; case TCG_TYPE_I64: - new_op = INDEX_op_mov_i64; + new_op = INDEX_op_mov; break; case TCG_TYPE_V64: case TCG_TYPE_V128: @@ -2933,7 +2931,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_mb: done = fold_mb(&ctx, op); break; - CASE_OP_32_64_VEC(mov): + case INDEX_op_mov: + case INDEX_op_mov_vec: done = fold_mov(&ctx, op); break; CASE_OP_32_64(movcond): diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index e10c1c5162..11dcfe66f3 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3468,8 +3468,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, args[0]); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index d525df4e1d..6f9d87df48 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2380,8 +2380,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 8421320928..30fa26e884 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2776,8 +2776,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 787e0d896c..cb5e8d554d 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1512,8 +1512,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_arithi(s, a0, a1, a2, SHIFT_SRA); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 48793ed439..108dc61e9a 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -351,7 +351,7 @@ void tcg_gen_discard_i32(TCGv_i32 arg) void tcg_gen_mov_i32(TCGv_i32 ret, TCGv_i32 arg) { if (ret != arg) { - tcg_gen_op2_i32(INDEX_op_mov_i32, ret, arg); + tcg_gen_op2_i32(INDEX_op_mov, ret, arg); } } @@ -1411,7 +1411,7 @@ void tcg_gen_mov_i64(TCGv_i64 ret, TCGv_i64 arg) return; } if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op2_i64(INDEX_op_mov_i64, ret, arg); + tcg_gen_op2_i64(INDEX_op_mov, ret, arg); } else { TCGTemp *ts = tcgv_i64_temp(arg); diff --git a/tcg/tcg.c b/tcg/tcg.c index e8fd89e4c8..7ff211081d 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2187,7 +2187,9 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return TCG_TARGET_HAS_qemu_ldst_i128; - case INDEX_op_mov_i32: + case INDEX_op_mov: + return has_type; + case INDEX_op_setcond_i32: case INDEX_op_brcond_i32: case INDEX_op_movcond_i32: @@ -2269,7 +2271,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; - case INDEX_op_mov_i64: case INDEX_op_setcond_i64: case INDEX_op_brcond_i64: case INDEX_op_movcond_i64: @@ -2840,18 +2841,23 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) col += ne_fprintf(f, ",%s", t); } } else { - col += ne_fprintf(f, " %s ", def->name); + if (def->flags & TCG_OPF_INT) { + col += ne_fprintf(f, " %s_i%d ", + def->name, + 8 * tcg_type_size(TCGOP_TYPE(op))); + } else if (def->flags & TCG_OPF_VECTOR) { + col += ne_fprintf(f, "%s v%d,e%d,", + def->name, + 8 * tcg_type_size(TCGOP_TYPE(op)), + 8 << TCGOP_VECE(op)); + } else { + col += ne_fprintf(f, " %s ", def->name); + } nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; nb_cargs = def->nb_cargs; - if (def->flags & TCG_OPF_VECTOR) { - col += ne_fprintf(f, "v%d,e%d,", - 8 * tcg_type_size(TCGOP_TYPE(op)), - 8 << TCGOP_VECE(op)); - } - k = 0; for (i = 0; i < nb_oargs; i++) { const char *sep = k ? "," : ""; @@ -4144,8 +4150,7 @@ liveness_pass_1(TCGContext *s) /* Incorporate constraints for this operand. */ switch (opc) { - case INDEX_op_mov_i32: - case INDEX_op_mov_i64: + case INDEX_op_mov: /* Note that these are TCG_OPF_NOT_PRESENT and do not have proper constraints. That said, special case moves to propagate preferences backward. */ @@ -4304,7 +4309,7 @@ liveness_pass_2(TCGContext *s) } /* Outputs become available. */ - if (opc == INDEX_op_mov_i32 || opc == INDEX_op_mov_i64) { + if (opc == INDEX_op_mov) { arg_ts = arg_temp(op->args[0]); dir_ts = arg_ts->state_ptr; if (dir_ts) { @@ -6435,8 +6440,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) TCGOpcode opc = op->opc; switch (opc) { - case INDEX_op_mov_i32: - case INDEX_op_mov_i64: + case INDEX_op_mov: case INDEX_op_mov_vec: tcg_reg_alloc_mov(s, op); break; diff --git a/tcg/tci.c b/tcg/tci.c index 531cd83aae..78183ea47d 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -463,7 +463,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = regs[tmp32 ? r3 : r4]; break; #endif - CASE_32_64(mov) + case INDEX_op_mov: tci_args_rr(insn, &r0, &r1); regs[r0] = regs[r1]; break; @@ -1063,8 +1063,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), s2); break; - case INDEX_op_mov_i32: - case INDEX_op_mov_i64: + case INDEX_op_mov: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 6f8f1dd8ae..9a5d3c2875 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -483,18 +483,7 @@ static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg val, TCGReg base, static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) { - switch (type) { - case TCG_TYPE_I32: - tcg_out_op_rr(s, INDEX_op_mov_i32, ret, arg); - break; -#if TCG_TARGET_REG_BITS == 64 - case TCG_TYPE_I64: - tcg_out_op_rr(s, INDEX_op_mov_i64, ret, arg); - break; -#endif - default: - g_assert_not_reached(); - } + tcg_out_op_rr(s, INDEX_op_mov, ret, arg); return true; } @@ -799,8 +788,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_v(s, opc); break; - case INDEX_op_mov_i32: /* Always emitted via tcg_out_mov. */ - case INDEX_op_mov_i64: case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ From 662cdbcf0073c4de8456f5e573523571e3d9da5b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 09:00:07 -0800 Subject: [PATCH 0364/2760] tcg: Convert add to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop all backend support for an immediate as the first operand. This should never happen in any case, as we swap commutative operands to place immediates as the second operand. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 51 +++++++------- tcg/arm/tcg-target.c.inc | 43 ++++++++---- tcg/i386/tcg-target.c.inc | 56 +++++++++------- tcg/loongarch64/tcg-target.c.inc | 38 +++++------ tcg/mips/tcg-target.c.inc | 31 ++++++--- tcg/ppc/tcg-target.c.inc | 47 +++++++------ tcg/riscv/tcg-target.c.inc | 39 ++++++----- tcg/s390x/tcg-target.c.inc | 110 +++++++++++++++---------------- tcg/sparc64/tcg-target-con-set.h | 1 + tcg/sparc64/tcg-target.c.inc | 25 +++++-- tcg/tcg.c | 41 +++++++++++- tcg/tci/tcg-target.c.inc | 15 ++++- 12 files changed, 302 insertions(+), 195 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 466042a577..a181b7e65a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1592,16 +1592,6 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) tcg_out_mov(s, TCG_TYPE_I32, rd, rn); } -static void tcg_out_addsubi(TCGContext *s, int ext, TCGReg rd, - TCGReg rn, int64_t aimm) -{ - if (aimm >= 0) { - tcg_out_insn(s, 3401, ADDI, ext, rd, rn, aimm); - } else { - tcg_out_insn(s, 3401, SUBI, ext, rd, rn, -aimm); - } -} - static void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl, TCGReg rh, TCGReg al, TCGReg ah, tcg_target_long bl, tcg_target_long bh, @@ -2115,6 +2105,30 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, flush_idcache_range(jmp_rx, jmp_rw, 4); } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3502, ADD, type, a0, a1, a2); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 >= 0) { + tcg_out_insn(s, 3401, ADDI, type, a0, a1, a2); + } else { + tcg_out_insn(s, 3401, SUBI, type, a0, a1, -a2); + } +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rA), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2181,23 +2195,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_add_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_add_i64: - if (c2) { - tcg_out_addsubi(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3502, ADD, ext, a0, a1, a2); - } - break; - case INDEX_op_sub_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ case INDEX_op_sub_i64: if (c2) { - tcg_out_addsubi(s, ext, a0, a1, -a2); + tgen_addi(s, ext, a0, a1, -a2); } else { tcg_out_insn(s, 3502, SUB, ext, a0, a1, a2); } @@ -2984,8 +2985,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add_i32: - case INDEX_op_add_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: return C_O1_I2(r, r, rA); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0fafe97230..a1f2184ac4 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -890,6 +890,17 @@ static void tcg_out_dat_rIK(TCGContext *s, ARMCond cond, ARMInsn opc, } } +static void tcg_out_dat_IN(TCGContext *s, ARMCond cond, ARMInsn opc, + ARMInsn opneg, TCGReg dst, TCGReg lhs, TCGArg rhs) +{ + int imm12 = encode_imm(rhs); + if (imm12 < 0) { + imm12 = encode_imm_nofail(-rhs); + opc = opneg; + } + tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); +} + static void tcg_out_dat_rIN(TCGContext *s, ARMCond cond, ARMInsn opc, ARMInsn opneg, TCGReg dst, TCGReg lhs, TCGArg rhs, bool rhs_is_const) @@ -898,12 +909,7 @@ static void tcg_out_dat_rIN(TCGContext *s, ARMCond cond, ARMInsn opc, * rhs must satisfy the "rIN" constraint. */ if (rhs_is_const) { - int imm12 = encode_imm(rhs); - if (imm12 < 0) { - imm12 = encode_imm_nofail(-rhs); - opc = opneg; - } - tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); + tcg_out_dat_IN(s, cond, opc, opneg, dst, lhs, rhs); } else { tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); } @@ -1821,6 +1827,26 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, flush_idcache_range(jmp_rx, jmp_rw, 4); } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_ADD, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IN(s, COND_AL, ARITH_ADD, ARITH_SUB, a0, a1, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rIN), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1869,10 +1895,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[c], ARITH_MOV, ARITH_MVN, args[0], 0, args[3], const_args[3]); break; - case INDEX_op_add_i32: - tcg_out_dat_rIN(s, COND_AL, ARITH_ADD, ARITH_SUB, - args[0], args[1], args[2], const_args[2]); - break; case INDEX_op_sub_i32: if (const_args[1]) { if (const_args[2]) { @@ -2142,7 +2164,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_add_i32: case INDEX_op_sub_i32: case INDEX_op_setcond_i32: case INDEX_op_negsetcond_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 75c8665d74..1115d1e38d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2562,6 +2562,40 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, /* no need to flush icache explicitly */ } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + if (a0 == a1) { + tgen_arithr(s, ARITH_ADD + rexw, a0, a2); + } else if (a0 == a2) { + tgen_arithr(s, ARITH_ADD + rexw, a0, a1); + } else { + tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, 0); + } +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + if (a0 == a1) { + tgen_arithi(s, ARITH_ADD + rexw, a0, a2, false); + } else { + tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, -1, 0, a2); + } +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, re), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2642,24 +2676,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(add): - /* For 3-operand addition, use LEA. */ - if (a0 != a1) { - TCGArg c3 = 0; - if (const_a2) { - c3 = a2, a2 = -1; - } else if (a0 == a2) { - /* Watch out for dest = src + dest, since we've removed - the matching constraint on the add. */ - tgen_arithr(s, ARITH_ADD + rexw, a0, a1); - break; - } - - tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a2, 0, c3); - break; - } - c = ARITH_ADD; - goto gen_arith; OP_32_64(sub): c = ARITH_SUB; goto gen_arith; @@ -3599,10 +3615,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_add_i32: - case INDEX_op_add_i64: - return C_O1_I2(r, r, re); - case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b0a4ec4c13..fee5e7c577 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1286,6 +1286,24 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, flush_idcache_range(jmp_rx, jmp_rw, 4); } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_add_w(s, a0, a1, a2); + } else { + tcg_out_opc_add_d(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_add, + .out_rri = tcg_out_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1544,21 +1562,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_add_i32: - if (c2) { - tcg_out_addi(s, TCG_TYPE_I32, a0, a1, a2); - } else { - tcg_out_opc_add_w(s, a0, a1, a2); - } - break; - case INDEX_op_add_i64: - if (c2) { - tcg_out_addi(s, TCG_TYPE_I64, a0, a1, a2); - } else { - tcg_out_opc_add_d(s, a0, a1, a2); - } - break; - case INDEX_op_sub_i32: if (c2) { tcg_out_addi(s, TCG_TYPE_I32, a0, a1, -a2); @@ -2287,11 +2290,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_add_i32: - return C_O1_I2(r, r, ri); - case INDEX_op_add_i64: - return C_O1_I2(r, r, rJ); - case INDEX_op_and_i32: case INDEX_op_and_i64: case INDEX_op_nor_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 4d52e0bde0..263e7e66c9 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1655,6 +1655,28 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, /* Always indirect, nothing to do */ } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_ADDU : OPC_DADDU; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_ADDIU : OPC_DADDIU; + tcg_out_opc_imm(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1727,12 +1749,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_add_i32: - i1 = OPC_ADDU, i2 = OPC_ADDIU; - goto do_binary; - case INDEX_op_add_i64: - i1 = OPC_DADDU, i2 = OPC_DADDIU; - goto do_binary; case INDEX_op_or_i32: case INDEX_op_or_i64: i1 = OPC_OR, i2 = OPC_ORI; @@ -2159,9 +2175,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add_i32: - case INDEX_op_add_i64: - return C_O1_I2(r, r, rJ); case INDEX_op_sub_i32: case INDEX_op_sub_i64: return C_O1_I2(r, rz, rN); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 11dcfe66f3..6b27238499 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2902,6 +2902,26 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, flush_idcache_range(jmp_rx, jmp_rw, 4); } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, ADD | TAB(a0, a1, a2)); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rT), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2971,15 +2991,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_add_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - do_addi_32: - tcg_out_mem_long(s, ADDI, ADD, a0, a1, (int32_t)a2); - } else { - tcg_out32(s, ADD | TAB(a0, a1, a2)); - } - break; case INDEX_op_sub_i32: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[1]) { @@ -2989,8 +3000,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, SUBFIC | TAI(a0, a2, a1)); } } else if (const_args[2]) { - a2 = -a2; - goto do_addi_32; + tgen_addi(s, type, a0, a1, (int32_t)-a2); } else { tcg_out32(s, SUBF | TAB(a0, a2, a1)); } @@ -3185,15 +3195,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, NOR | SAB(args[1], args[0], args[1])); break; - case INDEX_op_add_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - do_addi_64: - tcg_out_mem_long(s, ADDI, ADD, a0, a1, a2); - } else { - tcg_out32(s, ADD | TAB(a0, a1, a2)); - } - break; case INDEX_op_sub_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[1]) { @@ -3203,8 +3204,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, SUBFIC | TAI(a0, a2, a1)); } } else if (const_args[2]) { - a2 = -a2; - goto do_addi_64; + tgen_addi(s, type, a0, a1, -a2); } else { tcg_out32(s, SUBF | TAB(a0, a2, a1)); } @@ -4129,7 +4129,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_add_i32: case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: @@ -4176,8 +4175,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: return C_O1_I2(r, rI, ri); - case INDEX_op_add_i64: - return C_O1_I2(r, r, rT); case INDEX_op_or_i64: case INDEX_op_xor_i64: return C_O1_I2(r, r, rU); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 6f9d87df48..135137ff53 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1957,6 +1957,28 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, flush_idcache_range(jmp_rx, jmp_rw, 4); } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_ADDW : OPC_ADD; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_ADDIW : OPC_ADDI; + tcg_out_opc_imm(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2019,21 +2041,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_add_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_ADDIW, a0, a1, a2); - } else { - tcg_out_opc_reg(s, OPC_ADDW, a0, a1, a2); - } - break; - case INDEX_op_add_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ADDI, a0, a1, a2); - } else { - tcg_out_opc_reg(s, OPC_ADD, a0, a1, a2); - } - break; - case INDEX_op_sub_i32: if (c2) { tcg_out_opc_imm(s, OPC_ADDIW, a0, a1, -a2); @@ -2657,11 +2664,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add_i32: case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: - case INDEX_op_add_i64: case INDEX_op_and_i64: case INDEX_op_or_i64: case INDEX_op_xor_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 30fa26e884..f5441d2033 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2145,6 +2145,58 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, /* no need to flush icache explicitly */ } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (a0 != a1) { + tcg_out_insn(s, RX, LA, a0, a1, a2, 0); + } else if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, AR, a0, a2); + } else { + tcg_out_insn(s, RRE, AGR, a0, a2); + } +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a0 == a1) { + if (type == TCG_TYPE_I32) { + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, AHI, a0, a2); + } else { + tcg_out_insn(s, RIL, AFI, a0, a2); + } + return; + } + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, AGHI, a0, a2); + return; + } + if (a2 == (int32_t)a2) { + tcg_out_insn(s, RIL, AGFI, a0, a2); + return; + } + if (a2 == (uint32_t)a2) { + tcg_out_insn(s, RIL, ALGFI, a0, a2); + return; + } + if (-a2 == (uint32_t)-a2) { + tcg_out_insn(s, RIL, SLGFI, a0, -a2); + return; + } + } + tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ case glue(glue(INDEX_op_,x),_i64) @@ -2201,30 +2253,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_add_i32: - a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; - if (const_args[2]) { - do_addi_32: - if (a0 == a1) { - if (a2 == (int16_t)a2) { - tcg_out_insn(s, RI, AHI, a0, a2); - break; - } - tcg_out_insn(s, RIL, AFI, a0, a2); - break; - } - tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RR, AR, a0, a2); - } else { - tcg_out_insn(s, RX, LA, a0, a1, a2, 0); - } - break; case INDEX_op_sub_i32: - a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; + a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { - a2 = -a2; - goto do_addi_32; + tgen_addi(s, type, a0, a1, (int32_t)-a2); } else if (a0 == a1) { tcg_out_insn(s, RR, SR, a0, a2); } else { @@ -2494,40 +2526,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_add_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - do_addi_64: - if (a0 == a1) { - if (a2 == (int16_t)a2) { - tcg_out_insn(s, RI, AGHI, a0, a2); - break; - } - if (a2 == (int32_t)a2) { - tcg_out_insn(s, RIL, AGFI, a0, a2); - break; - } - if (a2 == (uint32_t)a2) { - tcg_out_insn(s, RIL, ALGFI, a0, a2); - break; - } - if (-a2 == (uint32_t)-a2) { - tcg_out_insn(s, RIL, SLGFI, a0, -a2); - break; - } - } - tcg_out_mem(s, RX_LA, RXY_LAY, a0, a1, TCG_REG_NONE, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RRE, AGR, a0, a2); - } else { - tcg_out_insn(s, RX, LA, a0, a1, a2, 0); - } - break; case INDEX_op_sub_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { - a2 = -a2; - goto do_addi_64; + tgen_addi(s, type, a0, a1, -a2); } else { tcg_out_insn(s, RRFa, SGRK, a0, a1, a2); } @@ -3253,8 +3255,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_add_i32: - case INDEX_op_add_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index 61f9fa3d9f..d90ba11443 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -14,6 +14,7 @@ C_O0_I2(rz, r) C_O0_I2(rz, rJ) C_O1_I1(r, r) C_O1_I2(r, r, r) +C_O1_I2(r, r, rJ) C_O1_I2(r, rz, rJ) C_O1_I4(r, rz, rJ, rI, 0) C_O2_I2(r, r, rz, rJ) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index cb5e8d554d..f43d95b025 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1285,6 +1285,26 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, { } + +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_ADD); +} + +static void tgen_addi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_ADD); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_add, + .out_rri = tgen_addi, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1338,9 +1358,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st32_i64: tcg_out_ldst(s, a0, a1, a2, STW); break; - OP_32_64(add): - c = ARITH_ADD; - goto gen_arith; OP_32_64(sub): c = ARITH_SUB; goto gen_arith; @@ -1564,8 +1581,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add_i32: - case INDEX_op_add_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: case INDEX_op_div_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 7ff211081d..18b2981c79 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -978,6 +978,14 @@ typedef struct TCGOutOp { TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags); } TCGOutOp; +typedef struct TCGOutOpBinary { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2); + void (*out_rri)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2); +} TCGOutOpBinary; + #include "tcg-target.c.inc" #ifndef CONFIG_TCG_INTERPRETER @@ -987,10 +995,21 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - < MIN_TLB_MASK_TABLE_OFS); #endif +/* + * Register V as the TCGOutOp for O. + * This verifies that V is of type T, otherwise give a nice compiler error. + * This prevents trivial mistakes within each arch/tcg-target.c.inc. + */ +#define OUTOP(O, T, V) [O] = _Generic(V, T: &V.base) + /* Register allocation descriptions for every TCGOpcode. */ static const TCGOutOp * const all_outop[NB_OPS] = { + OUTOP(INDEX_op_add_i32, TCGOutOpBinary, outop_add), + OUTOP(INDEX_op_add_i64, TCGOutOpBinary, outop_add), }; +#undef OUTOP + /* * All TCG threads except the parent (i.e. the one that called tcg_context_init * and registered the target's TCG globals) must register with this function @@ -5414,6 +5433,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } /* emit instruction */ + TCGType type = TCGOP_TYPE(op); switch (op->opc) { case INDEX_op_ext_i32_i64: tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); @@ -5424,12 +5444,29 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_extrl_i64_i32: tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); break; + + case INDEX_op_add_i32: + case INDEX_op_add_i64: + { + const TCGOutOpBinary *out = + container_of(all_outop[op->opc], TCGOutOpBinary, base); + + /* Constants should never appear in the first source operand. */ + tcg_debug_assert(!const_args[1]); + if (const_args[2]) { + out->out_rri(s, type, new_args[0], new_args[1], new_args[2]); + } else { + out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); + } + } + break; + default: if (def->flags & TCG_OPF_VECTOR) { - tcg_out_vec_op(s, op->opc, TCGOP_TYPE(op) - TCG_TYPE_V64, + tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, TCGOP_VECE(op), new_args, const_args); } else { - tcg_out_op(s, op->opc, TCGOP_TYPE(op), new_args, const_args); + tcg_out_op(s, op->opc, type, new_args, const_args); } break; } diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 9a5d3c2875..e6ec31e351 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -91,8 +91,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: - case INDEX_op_add_i32: - case INDEX_op_add_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: @@ -643,6 +641,18 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, /* Always indirect, nothing to do */ } +static void tgen_add(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_add_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_add = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_add, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -684,7 +694,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(add) CASE_32_64(sub) CASE_32_64(mul) CASE_32_64(and) From 79602f632a20228fc963161cd53f7d5f6a3bd953 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 09:11:39 -0800 Subject: [PATCH 0365/2760] tcg: Merge INDEX_op_add_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rely on TCGOP_TYPE instead of opcodes specific to each type. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 4 ++-- target/sh4/translate.c | 6 +++--- tcg/optimize.c | 13 +++++-------- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 15 +++++---------- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 6 ++---- 8 files changed, 22 insertions(+), 33 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index e6ccc78fa1..67387bfddf 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -261,7 +261,7 @@ Arithmetic .. list-table:: - * - add_i32/i64 *t0*, *t1*, *t2* + * - add *t0*, *t1*, *t2* - | *t0* = *t1* + *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 766fd00d99..0282779468 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -39,6 +39,8 @@ DEF(mb, 0, 0, 1, TCG_OPF_NOT_PRESENT) DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) +DEF(add, 1, 2, 0, TCG_OPF_INT) + DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) DEF(movcond_i32, 1, 4, 1, 0) @@ -52,7 +54,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(add_i32, 1, 2, 0, 0) DEF(sub_i32, 1, 2, 0, 0) DEF(mul_i32, 1, 2, 0, 0) DEF(div_i32, 1, 2, 0, 0) @@ -115,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(add_i64, 1, 2, 0, 0) DEF(sub_i64, 1, 2, 0, 0) DEF(mul_i64, 1, 2, 0, 0) DEF(div_i64, 1, 2, 0, 0) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index d796ad52c4..c20204cb52 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1940,7 +1940,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) NEXT_INSN; switch (ctx->opcode & 0xf00f) { case 0x300c: /* add Rm,Rn */ - op_opc = INDEX_op_add_i32; + op_opc = INDEX_op_add; goto do_reg_op; case 0x2009: /* and Rm,Rn */ op_opc = INDEX_op_and_i32; @@ -1984,7 +1984,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) if (op_dst != B11_8 || mv_src >= 0) { goto fail; } - op_opc = INDEX_op_add_i32; + op_opc = INDEX_op_add; op_arg = tcg_constant_i32(B7_0s); break; @@ -2087,7 +2087,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) ctx->memidx, ld_mop); break; - case INDEX_op_add_i32: + case INDEX_op_add: if (op_dst != st_src) { goto fail; } diff --git a/tcg/optimize.c b/tcg/optimize.c index 8d5bad07aa..a53e4f4675 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -424,7 +424,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) uint64_t l64, h64; switch (op) { - CASE_OP_32_64(add): + case INDEX_op_add: return x + y; CASE_OP_32_64(sub): @@ -2261,7 +2261,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) break; } if (convert) { - TCGOpcode add_opc, xor_opc, neg_opc; + TCGOpcode xor_opc, neg_opc; if (!inv && !neg) { return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]); @@ -2269,12 +2269,10 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - add_opc = INDEX_op_add_i32; neg_opc = INDEX_op_neg_i32; xor_opc = INDEX_op_xor_i32; break; case TCG_TYPE_I64: - add_opc = INDEX_op_add_i64; neg_opc = INDEX_op_neg_i64; xor_opc = INDEX_op_xor_i64; break; @@ -2285,7 +2283,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) if (!inv) { op->opc = neg_opc; } else if (neg) { - op->opc = add_opc; + op->opc = INDEX_op_add; op->args[2] = arg_new_constant(ctx, -1); } else { op->opc = xor_opc; @@ -2650,8 +2648,7 @@ static bool fold_sub(OptContext *ctx, TCGOp *op) if (arg_is_const(op->args[2])) { uint64_t val = arg_info(op->args[2])->val; - op->opc = (ctx->type == TCG_TYPE_I32 - ? INDEX_op_add_i32 : INDEX_op_add_i64); + op->opc = INDEX_op_add; op->args[2] = arg_new_constant(ctx, -val); } return finish_folding(ctx, op); @@ -2842,7 +2839,7 @@ void tcg_optimize(TCGContext *s) * Sorted alphabetically by opcode as much as possible. */ switch (opc) { - CASE_OP_32_64(add): + case INDEX_op_add: done = fold_add(&ctx, op); break; case INDEX_op_add_vec: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 108dc61e9a..344d490966 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -362,7 +362,7 @@ void tcg_gen_movi_i32(TCGv_i32 ret, int32_t arg) void tcg_gen_add_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_add_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_add, ret, arg1, arg2); } void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1555,7 +1555,7 @@ void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_add_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_add, ret, arg1, arg2); } else { tcg_gen_add2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); diff --git a/tcg/tcg.c b/tcg/tcg.c index 18b2981c79..0f0a3f56d8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1004,8 +1004,7 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - /* Register allocation descriptions for every TCGOpcode. */ static const TCGOutOp * const all_outop[NB_OPS] = { - OUTOP(INDEX_op_add_i32, TCGOutOpBinary, outop_add), - OUTOP(INDEX_op_add_i64, TCGOutOpBinary, outop_add), + OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), }; #undef OUTOP @@ -2206,6 +2205,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return TCG_TARGET_HAS_qemu_ldst_i128; + case INDEX_op_add: case INDEX_op_mov: return has_type; @@ -2220,7 +2220,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_add_i32: case INDEX_op_sub_i32: case INDEX_op_neg_i32: case INDEX_op_mul_i32: @@ -2304,7 +2303,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_add_i64: case INDEX_op_sub_i64: case INDEX_op_neg_i64: case INDEX_op_mul_i64: @@ -4015,14 +4013,12 @@ liveness_pass_1(TCGContext *s) break; case INDEX_op_add2_i32: - opc_new = INDEX_op_add_i32; + case INDEX_op_add2_i64: + opc_new = INDEX_op_add; goto do_addsub2; case INDEX_op_sub2_i32: opc_new = INDEX_op_sub_i32; goto do_addsub2; - case INDEX_op_add2_i64: - opc_new = INDEX_op_add_i64; - goto do_addsub2; case INDEX_op_sub2_i64: opc_new = INDEX_op_sub_i64; do_addsub2: @@ -5445,8 +5441,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); break; - case INDEX_op_add_i32: - case INDEX_op_add_i64: + case INDEX_op_add: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 78183ea47d..ceb791a735 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -523,7 +523,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Arithmetic operations (mixed 32/64 bit). */ - CASE_32_64(add) + case INDEX_op_add: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] + regs[r2]; break; @@ -1082,8 +1082,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1)); break; - case INDEX_op_add_i32: - case INDEX_op_add_i64: + case INDEX_op_add: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index e6ec31e351..726b645da8 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -453,9 +453,7 @@ static void tcg_out_ldst(TCGContext *s, TCGOpcode op, TCGReg val, stack_bounds_check(base, offset); if (offset != sextract32(offset, 0, 16)) { tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, offset); - tcg_out_op_rrr(s, (TCG_TARGET_REG_BITS == 32 - ? INDEX_op_add_i32 : INDEX_op_add_i64), - TCG_REG_TMP, TCG_REG_TMP, base); + tcg_out_op_rrr(s, INDEX_op_add, TCG_REG_TMP, TCG_REG_TMP, base); base = TCG_REG_TMP; offset = 0; } @@ -644,7 +642,7 @@ void tb_target_set_jmp_target(const TranslationBlock *tb, int n, static void tgen_add(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_add_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_add, a0, a1, a2); } static const TCGOutOpBinary outop_add = { From bf40f915fc24b97e27e852f0eae5f59eaf63de59 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 10:22:29 -0800 Subject: [PATCH 0366/2760] tcg: Convert and to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop all backend support for an immediate as the first operand. This should never happen in any case, as we swap commutative operands to place immediates as the second operand. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 31 ++++++++++-------- tcg/arm/tcg-target.c.inc | 41 +++++++++++++++++------- tcg/i386/tcg-target.c.inc | 27 ++++++++++++---- tcg/loongarch64/tcg-target.c.inc | 29 ++++++++++------- tcg/mips/tcg-target.c.inc | 55 +++++++++++++++++++------------- tcg/ppc/tcg-target.c.inc | 40 ++++++++++++----------- tcg/riscv/tcg-target.c.inc | 29 ++++++++++------- tcg/s390x/tcg-target.c.inc | 48 +++++++++++++++------------- tcg/sparc64/tcg-target.c.inc | 23 ++++++++++--- tcg/tcg.c | 4 +++ tcg/tci/tcg-target.c.inc | 14 ++++++-- 11 files changed, 216 insertions(+), 125 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index a181b7e65a..b7d11887e3 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2128,6 +2128,24 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, AND, type, a0, a1, a2); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_logicali(s, I3404_ANDI, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rL), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2209,17 +2227,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_and_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_and_i64: - if (c2) { - tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3510, AND, ext, a0, a1, a2); - } - break; - case INDEX_op_andc_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3009,8 +3016,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); - case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_or_i32: case INDEX_op_or_i64: case INDEX_op_xor_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index a1f2184ac4..cb4b2becef 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -874,17 +874,23 @@ static void tcg_out_dat_rI(TCGContext *s, ARMCond cond, ARMInsn opc, * Emit either the reg,imm or reg,reg form of a data-processing insn. * rhs must satisfy the "rIK" constraint. */ +static void tcg_out_dat_IK(TCGContext *s, ARMCond cond, ARMInsn opc, + ARMInsn opinv, TCGReg dst, TCGReg lhs, TCGArg rhs) +{ + int imm12 = encode_imm(rhs); + if (imm12 < 0) { + imm12 = encode_imm_nofail(~rhs); + opc = opinv; + } + tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); +} + static void tcg_out_dat_rIK(TCGContext *s, ARMCond cond, ARMInsn opc, ARMInsn opinv, TCGReg dst, TCGReg lhs, TCGArg rhs, bool rhs_is_const) { if (rhs_is_const) { - int imm12 = encode_imm(rhs); - if (imm12 < 0) { - imm12 = encode_imm_nofail(~rhs); - opc = opinv; - } - tcg_out_dat_imm(s, cond, opc, dst, lhs, imm12); + tcg_out_dat_IK(s, cond, opc, opinv, dst, lhs, rhs); } else { tcg_out_dat_reg(s, cond, opc, dst, lhs, rhs, SHIFT_IMM_LSL(0)); } @@ -1846,6 +1852,24 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_AND, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IK(s, COND_AL, ARITH_AND, ARITH_BIC, a0, a1, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rIK), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1908,10 +1932,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[0], args[1], args[2], const_args[2]); } break; - case INDEX_op_and_i32: - tcg_out_dat_rIK(s, COND_AL, ARITH_AND, ARITH_BIC, - args[0], args[1], args[2], const_args[2]); - break; case INDEX_op_andc_i32: tcg_out_dat_rIK(s, COND_AL, ARITH_BIC, ARITH_AND, args[0], args[1], args[2], const_args[2]); @@ -2169,7 +2189,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); - case INDEX_op_and_i32: case INDEX_op_andc_i32: case INDEX_op_clz_i32: case INDEX_op_ctz_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1115d1e38d..4f4c5ebbb1 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2595,6 +2595,26 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_AND + rexw, a0, a2); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_AND + rexw, a0, a2, false); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, 0, reZ), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2679,9 +2699,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(and): - c = ARITH_AND; - goto gen_arith; OP_32_64(or): c = ARITH_OR; goto gen_arith; @@ -3625,10 +3642,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor_i64: return C_O1_I2(r, 0, re); - case INDEX_op_and_i32: - case INDEX_op_and_i64: - return C_O1_I2(r, 0, reZ); - case INDEX_op_andc_i32: case INDEX_op_andc_i64: return C_O1_I2(r, r, rI); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index fee5e7c577..b9c6e0d017 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1303,6 +1303,24 @@ static const TCGOutOpBinary outop_add = { .out_rri = tcg_out_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_and(s, a0, a1, a2); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_andi(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rU), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1373,15 +1391,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_and_i32: - case INDEX_op_and_i64: - if (c2) { - tcg_out_opc_andi(s, a0, a1, a2); - } else { - tcg_out_opc_and(s, a0, a1, a2); - } - break; - case INDEX_op_or_i32: case INDEX_op_or_i64: if (c2) { @@ -2290,8 +2299,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: case INDEX_op_or_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 263e7e66c9..460f73d06a 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1676,6 +1676,38 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_AND, a0, a1, a2); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int msb; + + if (a2 == (uint16_t)a2) { + tcg_out_opc_imm(s, OPC_ANDI, a0, a1, a2); + return; + } + + tcg_debug_assert(use_mips32r2_instructions); + tcg_debug_assert(is_p2m1(a2)); + msb = ctz64(~a2) - 1; + if (type == TCG_TYPE_I32) { + tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0); + } else { + tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1, msb, 0); + } +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rIK), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1776,26 +1808,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; } goto do_binaryv; - case INDEX_op_and_i32: - if (c2 && a2 != (uint16_t)a2) { - int msb = ctz32(~a2) - 1; - tcg_debug_assert(use_mips32r2_instructions); - tcg_debug_assert(is_p2m1(a2)); - tcg_out_opc_bf(s, OPC_EXT, a0, a1, msb, 0); - break; - } - i1 = OPC_AND, i2 = OPC_ANDI; - goto do_binary; - case INDEX_op_and_i64: - if (c2 && a2 != (uint16_t)a2) { - int msb = ctz64(~a2) - 1; - tcg_debug_assert(use_mips32r2_instructions); - tcg_debug_assert(is_p2m1(a2)); - tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, a0, a1, msb, 0); - break; - } - i1 = OPC_AND, i2 = OPC_ANDI; - goto do_binary; case INDEX_op_nor_i32: case INDEX_op_nor_i64: i1 = OPC_NOR; @@ -2202,9 +2214,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_and_i32: - case INDEX_op_and_i64: - return C_O1_I2(r, r, rIK); case INDEX_op_or_i32: case INDEX_op_xor_i32: case INDEX_op_or_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 6b27238499..3d34edfa79 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2921,6 +2921,28 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, AND | SAB(a1, a0, a2)); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_andi32(s, a0, a1, a2); + } else { + tcg_out_andi64(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3006,22 +3028,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_and_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_andi32(s, a0, a1, a2); - } else { - tcg_out32(s, AND | SAB(a1, a0, a2)); - } - break; - case INDEX_op_and_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_andi64(s, a0, a1, a2); - } else { - tcg_out32(s, AND | SAB(a1, a0, a2)); - } - break; case INDEX_op_or_i64: case INDEX_op_or_i32: a0 = args[0], a1 = args[1], a2 = args[2]; @@ -4129,7 +4135,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: case INDEX_op_andc_i32: @@ -4140,7 +4145,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_and_i64: case INDEX_op_andc_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 135137ff53..7f585bc4f9 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1978,6 +1978,24 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_AND, a0, a1, a2); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_imm(s, OPC_ANDI, a0, a1, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2056,15 +2074,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_and_i32: - case INDEX_op_and_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ANDI, a0, a1, a2); - } else { - tcg_out_opc_reg(s, OPC_AND, a0, a1, a2); - } - break; - case INDEX_op_or_i32: case INDEX_op_or_i64: if (c2) { @@ -2664,10 +2673,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: - case INDEX_op_and_i64: case INDEX_op_or_i64: case INDEX_op_xor_i64: case INDEX_op_setcond_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index f5441d2033..d60bdaba25 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2196,6 +2196,31 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, NGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, NR, a0, a2); + } else { + tcg_out_insn(s, RRFa, NRK, a0, a1, a2); + } +} + +static void tgen_andi_3(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + tgen_andi(s, type, a0, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rNKR), + .out_rrr = tgen_and, + .out_rri = tgen_andi_3, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2264,17 +2289,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_and_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_andi(s, TCG_TYPE_I32, a0, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RR, NR, a0, a2); - } else { - tcg_out_insn(s, RRFa, NRK, a0, a1, a2); - } - break; case INDEX_op_or_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { @@ -2535,15 +2549,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_and_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_andi(s, TCG_TYPE_I64, args[0], args[2]); - } else { - tcg_out_insn(s, RRFa, NGRK, a0, a1, a2); - } - break; case INDEX_op_or_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { @@ -3274,12 +3279,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: return C_O1_I2(r, r, ri); - case INDEX_op_and_i64: - return C_O1_I2(r, r, rNKR); case INDEX_op_or_i64: case INDEX_op_xor_i64: return C_O1_I2(r, r, rK); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index f43d95b025..b3fbe127c0 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1304,6 +1304,24 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_AND); +} + +static void tgen_andi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_AND); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_and, + .out_rri = tgen_andi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1361,9 +1379,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(and): - c = ARITH_AND; - goto gen_arith; OP_32_64(andc): c = ARITH_ANDN; goto gen_arith; @@ -1589,8 +1604,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_andc_i32: case INDEX_op_andc_i64: case INDEX_op_or_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 0f0a3f56d8..94574c90c5 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1005,6 +1005,8 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - /* Register allocation descriptions for every TCGOpcode. */ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), + OUTOP(INDEX_op_and_i32, TCGOutOpBinary, outop_and), + OUTOP(INDEX_op_and_i64, TCGOutOpBinary, outop_and), }; #undef OUTOP @@ -5442,6 +5444,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_add: + case INDEX_op_and_i32: + case INDEX_op_and_i64: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 726b645da8..fd38ecad39 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -95,8 +95,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_andc_i32: case INDEX_op_andc_i64: case INDEX_op_eqv_i32: @@ -650,6 +648,17 @@ static const TCGOutOpBinary outop_add = { .out_rrr = tgen_add, }; +static void tgen_and(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_and_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_and = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_and, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -694,7 +703,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(and) CASE_32_64(or) CASE_32_64(xor) CASE_32_64(andc) /* Optional (TCG_TARGET_HAS_andc_*). */ From c3b920b3d6a685484904d3060f3eb69401051bf0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 10:32:44 -0800 Subject: [PATCH 0367/2760] tcg: Merge INDEX_op_and_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- target/sh4/translate.c | 4 ++-- tcg/optimize.c | 40 ++++++++++++---------------------------- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 9 +++------ tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 8 files changed, 24 insertions(+), 45 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 67387bfddf..6a8025c0bf 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -303,7 +303,7 @@ Logical .. list-table:: - * - and_i32/i64 *t0*, *t1*, *t2* + * - and *t0*, *t1*, *t2* - | *t0* = *t1* & *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 0282779468..f45029caa7 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -40,6 +40,7 @@ DEF(mb, 0, 0, 1, TCG_OPF_NOT_PRESENT) DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) +DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) @@ -62,7 +63,6 @@ DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) DEF(div2_i32, 2, 3, 0, 0) DEF(divu2_i32, 2, 3, 0, 0) -DEF(and_i32, 1, 2, 0, 0) DEF(or_i32, 1, 2, 0, 0) DEF(xor_i32, 1, 2, 0, 0) /* shifts/rotates */ @@ -124,7 +124,6 @@ DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) DEF(div2_i64, 2, 3, 0, 0) DEF(divu2_i64, 2, 3, 0, 0) -DEF(and_i64, 1, 2, 0, 0) DEF(or_i64, 1, 2, 0, 0) DEF(xor_i64, 1, 2, 0, 0) /* shifts/rotates */ diff --git a/target/sh4/translate.c b/target/sh4/translate.c index c20204cb52..3d0eda2128 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1943,7 +1943,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) op_opc = INDEX_op_add; goto do_reg_op; case 0x2009: /* and Rm,Rn */ - op_opc = INDEX_op_and_i32; + op_opc = INDEX_op_and; goto do_reg_op; case 0x200a: /* xor Rm,Rn */ op_opc = INDEX_op_xor_i32; @@ -2105,7 +2105,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) } break; - case INDEX_op_and_i32: + case INDEX_op_and: if (op_dst != st_src) { goto fail; } diff --git a/tcg/optimize.c b/tcg/optimize.c index a53e4f4675..20cde598fb 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -433,7 +433,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) CASE_OP_32_64(mul): return x * y; - CASE_OP_32_64_VEC(and): + case INDEX_op_and: + case INDEX_op_and_vec: return x & y; CASE_OP_32_64_VEC(or): @@ -802,9 +803,7 @@ static int do_constant_folding_cond1(OptContext *ctx, TCGOp *op, TCGArg dest, /* Expand to AND with a temporary if no backend support. */ if (!TCG_TARGET_HAS_tst) { - TCGOpcode and_opc = (ctx->type == TCG_TYPE_I32 - ? INDEX_op_and_i32 : INDEX_op_and_i64); - TCGOp *op2 = opt_insert_before(ctx, op, and_opc, 3); + TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and, 3); TCGArg tmp = arg_new_temp(ctx); op2->args[0] = tmp; @@ -897,8 +896,8 @@ static int do_constant_folding_cond2(OptContext *ctx, TCGOp *op, TCGArg *args) /* Expand to AND with a temporary if no backend support. */ if (!TCG_TARGET_HAS_tst && is_tst_cond(c)) { - TCGOp *op1 = opt_insert_before(ctx, op, INDEX_op_and_i32, 3); - TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and_i32, 3); + TCGOp *op1 = opt_insert_before(ctx, op, INDEX_op_and, 3); + TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_and, 3); TCGArg t1 = arg_new_temp(ctx); TCGArg t2 = arg_new_temp(ctx); @@ -1709,8 +1708,7 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op) TempOptInfo *t2 = arg_info(op->args[2]); int ofs = op->args[3]; int len = op->args[4]; - int width; - TCGOpcode and_opc; + int width = 8 * tcg_type_size(ctx->type); uint64_t z_mask, s_mask; if (ti_is_const(t1) && ti_is_const(t2)) { @@ -1719,24 +1717,11 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op) ti_const_val(t2))); } - switch (ctx->type) { - case TCG_TYPE_I32: - and_opc = INDEX_op_and_i32; - width = 32; - break; - case TCG_TYPE_I64: - and_opc = INDEX_op_and_i64; - width = 64; - break; - default: - g_assert_not_reached(); - } - /* Inserting a value into zero at offset 0. */ if (ti_is_const_val(t1, 0) && ofs == 0) { uint64_t mask = MAKE_64BIT_MASK(0, len); - op->opc = and_opc; + op->opc = INDEX_op_and; op->args[1] = op->args[2]; op->args[2] = arg_new_constant(ctx, mask); return fold_and(ctx, op); @@ -1746,7 +1731,7 @@ static bool fold_deposit(OptContext *ctx, TCGOp *op) if (ti_is_const_val(t2, 0)) { uint64_t mask = deposit64(-1, ofs, len, 0); - op->opc = and_opc; + op->opc = INDEX_op_and; op->args[2] = arg_new_constant(ctx, mask); return fold_and(ctx, op); } @@ -2297,7 +2282,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode and_opc, sub_opc, xor_opc, neg_opc, shr_opc; + TCGOpcode sub_opc, xor_opc, neg_opc, shr_opc; TCGOpcode uext_opc = 0, sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; @@ -2319,7 +2304,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - and_opc = INDEX_op_and_i32; sub_opc = INDEX_op_sub_i32; xor_opc = INDEX_op_xor_i32; shr_opc = INDEX_op_shr_i32; @@ -2332,7 +2316,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } break; case TCG_TYPE_I64: - and_opc = INDEX_op_and_i64; sub_opc = INDEX_op_sub_i64; xor_opc = INDEX_op_xor_i64; shr_opc = INDEX_op_shr_i64; @@ -2371,7 +2354,7 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op2->args[2] = arg_new_constant(ctx, sh); src1 = ret; } - op->opc = and_opc; + op->opc = INDEX_op_and; op->args[1] = src1; op->args[2] = arg_new_constant(ctx, 1); } @@ -2848,7 +2831,8 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(add2): done = fold_add2(&ctx, op); break; - CASE_OP_32_64_VEC(and): + case INDEX_op_and: + case INDEX_op_and_vec: done = fold_and(&ctx, op); break; CASE_OP_32_64_VEC(andc): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 344d490966..82f3ad501f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -401,7 +401,7 @@ void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_and_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_and, ret, arg1, arg2); } void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1575,7 +1575,7 @@ void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_and_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_and, ret, arg1, arg2); } else { tcg_gen_and_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_and_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); diff --git a/tcg/tcg.c b/tcg/tcg.c index 94574c90c5..d60427eb7f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1005,8 +1005,7 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - /* Register allocation descriptions for every TCGOpcode. */ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), - OUTOP(INDEX_op_and_i32, TCGOutOpBinary, outop_and), - OUTOP(INDEX_op_and_i64, TCGOutOpBinary, outop_and), + OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), }; #undef OUTOP @@ -2208,6 +2207,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_qemu_ldst_i128; case INDEX_op_add: + case INDEX_op_and: case INDEX_op_mov: return has_type; @@ -2225,7 +2225,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_neg_i32: case INDEX_op_mul_i32: - case INDEX_op_and_i32: case INDEX_op_or_i32: case INDEX_op_xor_i32: case INDEX_op_shl_i32: @@ -2308,7 +2307,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_neg_i64: case INDEX_op_mul_i64: - case INDEX_op_and_i64: case INDEX_op_or_i64: case INDEX_op_xor_i64: case INDEX_op_shl_i64: @@ -5444,8 +5442,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_add: - case INDEX_op_and_i32: - case INDEX_op_and_i64: + case INDEX_op_and: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index ceb791a735..8762a99fb6 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -535,7 +535,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] * regs[r2]; break; - CASE_32_64(and) + case INDEX_op_and: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & regs[r2]; break; @@ -1083,12 +1083,11 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_add: + case INDEX_op_and: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_and_i32: - case INDEX_op_and_i64: case INDEX_op_or_i32: case INDEX_op_or_i64: case INDEX_op_xor_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index fd38ecad39..b0141f8ed6 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -651,7 +651,7 @@ static const TCGOutOpBinary outop_add = { static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_and_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_and, a0, a1, a2); } static const TCGOutOpBinary outop_and = { From 899281c8f589cce55951e13307661a7253eb4909 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Nov 2023 11:18:55 -0800 Subject: [PATCH 0368/2760] tcg/optimize: Fold andc with immediate to and MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tcg/optimize.c b/tcg/optimize.c index 20cde598fb..1f6fdee734 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1343,6 +1343,25 @@ static bool fold_andc(OptContext *ctx, TCGOp *op) t2 = arg_info(op->args[2]); z_mask = t1->z_mask; + if (ti_is_const(t2)) { + /* Fold andc r,x,i to and r,x,~i. */ + switch (ctx->type) { + case TCG_TYPE_I32: + case TCG_TYPE_I64: + op->opc = INDEX_op_and; + break; + case TCG_TYPE_V64: + case TCG_TYPE_V128: + case TCG_TYPE_V256: + op->opc = INDEX_op_and_vec; + break; + default: + g_assert_not_reached(); + } + op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2)); + return fold_and(ctx, op); + } + /* * Known-zeros does not imply known-ones. Therefore unless * arg2 is constant, we can't infer anything from it. From 93a9ddb84ae534a04e8d7764caa9e29b8285b2b1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 22:06:08 -0800 Subject: [PATCH 0369/2760] tcg/optimize: Emit add r,r,-1 in fold_setcond_tst_pow2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We canonicalize subtract with constant to add with constant. Fix this missed instance. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 1f6fdee734..6c7b6af624 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2301,7 +2301,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode sub_opc, xor_opc, neg_opc, shr_opc; + TCGOpcode xor_opc, neg_opc, shr_opc; TCGOpcode uext_opc = 0, sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; @@ -2323,7 +2323,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - sub_opc = INDEX_op_sub_i32; xor_opc = INDEX_op_xor_i32; shr_opc = INDEX_op_shr_i32; neg_opc = INDEX_op_neg_i32; @@ -2335,7 +2334,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } break; case TCG_TYPE_I64: - sub_opc = INDEX_op_sub_i64; xor_opc = INDEX_op_xor_i64; shr_opc = INDEX_op_shr_i64; neg_opc = INDEX_op_neg_i64; @@ -2379,10 +2377,10 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } if (neg && inv) { - op2 = opt_insert_after(ctx, op, sub_opc, 3); + op2 = opt_insert_after(ctx, op, INDEX_op_add, 3); op2->args[0] = ret; op2->args[1] = ret; - op2->args[2] = arg_new_constant(ctx, 1); + op2->args[2] = arg_new_constant(ctx, -1); } else if (inv) { op2 = opt_insert_after(ctx, op, xor_opc, 3); op2->args[0] = ret; From a341c84e8153b7282b083e871ca534f15fa70898 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 12:26:28 -0800 Subject: [PATCH 0370/2760] tcg: Convert andc to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, drop all backend support for immediate operands, as we now transform andc to and during optimize. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 24 ++++++++-------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 16 +++++++---- tcg/i386/tcg-target-con-set.h | 2 +- tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 31 +++++++++++--------- tcg/loongarch64/tcg-target-con-set.h | 1 + tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 23 ++++++++------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 4 +++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 29 ++++++++----------- tcg/riscv/tcg-target-con-set.h | 1 + tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 27 +++++++++++------- tcg/s390x/tcg-target-con-set.h | 1 - tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 42 ++++++++++++++-------------- tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 16 +++++++---- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 +-- tcg/tcg.c | 8 +++--- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 14 ++++++++-- 28 files changed, 135 insertions(+), 130 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index bfd587c0fc..851f6b01b4 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 0 @@ -45,7 +44,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index b7d11887e3..c7167cad15 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2146,6 +2146,17 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, BIC, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2227,17 +2238,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_andc_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_andc_i64: - if (c2) { - tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, ~a2); - } else { - tcg_out_insn(s, 3510, BIC, ext, a0, a1, a2); - } - break; - case INDEX_op_or_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3020,8 +3020,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: case INDEX_op_eqv_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 8398c80c8e..0268858a3b 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index cb4b2becef..feea82145a 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1870,6 +1870,17 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_BIC, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1932,10 +1943,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[0], args[1], args[2], const_args[2]); } break; - case INDEX_op_andc_i32: - tcg_out_dat_rIK(s, COND_AL, ARITH_BIC, ARITH_AND, - args[0], args[1], args[2], const_args[2]); - break; case INDEX_op_or_i32: c = ARITH_ORR; goto gen_arith; @@ -2189,7 +2196,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); - case INDEX_op_andc_i32: case INDEX_op_clz_i32: case INDEX_op_ctz_i32: return C_O1_I2(r, r, rIK); diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h index 06e6521001..0ae9775944 100644 --- a/tcg/i386/tcg-target-con-set.h +++ b/tcg/i386/tcg-target-con-set.h @@ -42,9 +42,9 @@ C_O1_I2(r, 0, reZ) C_O1_I2(r, 0, ri) C_O1_I2(r, 0, rI) C_O1_I2(r, L, L) +C_O1_I2(r, r, r) C_O1_I2(r, r, re) C_O1_I2(r, r, ri) -C_O1_I2(r, r, rI) C_O1_I2(x, x, x) C_N1_I2(r, r, r) C_N1_I2(r, r, rW) diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index bbf55c86b6..b29b70357a 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -31,7 +31,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_andc_i32 have_bmi1 #define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 @@ -57,7 +56,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_andc_i64 have_bmi1 #define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 4f4c5ebbb1..33c1fcc717 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2615,6 +2615,24 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_vex_modrm(s, OPC_ANDN + rexw, a0, a2, a1); +} + +static TCGConstraintSetIndex cset_andc(TCGType type, unsigned flags) +{ + return have_bmi1 ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_andc, + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2713,15 +2731,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(andc): - if (const_a2) { - tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, a0, a1); - tgen_arithi(s, ARITH_AND + rexw, a0, ~a2, 0); - } else { - tcg_out_vex_modrm(s, OPC_ANDN + rexw, a0, a2, a1); - } - break; - OP_32_64(mul): if (const_a2) { int32_t val; @@ -3642,10 +3651,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor_i64: return C_O1_I2(r, 0, re); - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: - return C_O1_I2(r, r, rI); - case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index 8afaee9476..b7c9b89e9e 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -22,6 +22,7 @@ C_O0_I3(r, r, r) C_O1_I1(r, r) C_O1_I1(w, r) C_O1_I1(w, w) +C_O1_I2(r, r, r) C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 166c9d7e41..71d91fec19 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 @@ -47,7 +46,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b9c6e0d017..b7d2984a8a 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1321,6 +1321,17 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_andn(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1371,16 +1382,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: - if (c2) { - /* guaranteed to fit due to constraint */ - tcg_out_opc_andi(s, a0, a1, ~a2); - } else { - tcg_out_opc_andn(s, a0, a1, a2); - } - break; - case INDEX_op_orc_i32: case INDEX_op_orc_i64: if (c2) { @@ -2276,8 +2277,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: /* diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index fd96905484..6a6d4377e7 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_nor_i32 1 -#define TCG_TARGET_HAS_andc_i32 0 #define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 @@ -63,7 +62,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_nor_i64 1 -#define TCG_TARGET_HAS_andc_i64 0 #define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 460f73d06a..ab57c78095 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1708,6 +1708,10 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 9acfc574c5..63bb66f446 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -23,7 +23,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 1 @@ -50,7 +49,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 3d34edfa79..7b1a82c9fa 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2943,6 +2943,17 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, ANDC | SAB(a1, a0, a2)); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3046,22 +3057,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, XOR | SAB(a1, a0, a2)); } break; - case INDEX_op_andc_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_andi32(s, a0, a1, ~a2); - } else { - tcg_out32(s, ANDC | SAB(a1, a0, a2)); - } - break; - case INDEX_op_andc_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_andi64(s, a0, a1, ~a2); - } else { - tcg_out32(s, ANDC | SAB(a1, a0, a2)); - } - break; case INDEX_op_orc_i32: if (const_args[2]) { tcg_out_ori32(s, args[0], args[1], ~args[2]); @@ -4137,7 +4132,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_or_i32: case INDEX_op_xor_i32: - case INDEX_op_andc_i32: case INDEX_op_orc_i32: case INDEX_op_eqv_i32: case INDEX_op_shl_i32: @@ -4145,7 +4139,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_andc_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index e92e815491..f1f5d415f7 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -13,6 +13,7 @@ C_O0_I1(r) C_O0_I2(rz, r) C_O0_I2(rz, rz) C_O1_I1(r, r) +C_O1_I2(r, r, r) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) C_O1_I2(r, r, rJ) diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index fc62049c78..a3918bf7f5 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_andc_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_orc_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_eqv_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i32 0 @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_andc_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_orc_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_eqv_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 7f585bc4f9..f637604e98 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1996,6 +1996,23 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_ANDN, a0, a1, a2); +} + +static TCGConstraintSetIndex cset_zbb_rrr(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBB ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2092,14 +2109,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ANDI, a0, a1, ~a2); - } else { - tcg_out_opc_reg(s, OPC_ANDN, a0, a1, a2); - } - break; case INDEX_op_orc_i32: case INDEX_op_orc_i64: if (c2) { @@ -2683,8 +2692,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: case INDEX_op_eqv_i32: diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index 370e4b1295..39903a60ad 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -31,7 +31,6 @@ C_O1_I2(r, r, rC) C_O1_I2(r, r, rI) C_O1_I2(r, r, rJ) C_O1_I2(r, r, rK) -C_O1_I2(r, r, rKR) C_O1_I2(r, r, rNK) C_O1_I2(r, r, rNKR) C_O1_I2(r, rZ, r) diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index aea805455f..15ec0dc2ff 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -34,7 +34,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_andc_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_orc_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_eqv_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3) @@ -59,7 +58,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_andc_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_orc_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_eqv_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index d60bdaba25..e4b60d1924 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2221,6 +2221,27 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi_3, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, NCRK, a0, a1, a2); + } else { + tcg_out_insn(s, RRFa, NCGRK, a0, a1, a2); + } +} + +static TCGConstraintSetIndex cset_misc3_rrr(TCGType type, unsigned flags) +{ + return HAVE_FACILITY(MISC_INSN_EXT3) ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_misc3_rrr, + .out_rrr = tgen_andc, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2312,15 +2333,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_andc_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_andi(s, TCG_TYPE_I32, a0, (uint32_t)~a2); - } else { - tcg_out_insn(s, RRFa, NCRK, a0, a1, a2); - } - break; case INDEX_op_orc_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { @@ -2568,15 +2580,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_andc_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_andi(s, TCG_TYPE_I64, a0, ~a2); - } else { - tcg_out_insn(s, RRFa, NCGRK, a0, a1, a2); - } - break; case INDEX_op_orc_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { @@ -3286,12 +3289,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor_i64: return C_O1_I2(r, r, rK); - case INDEX_op_andc_i32: case INDEX_op_orc_i32: case INDEX_op_eqv_i32: return C_O1_I2(r, r, ri); - case INDEX_op_andc_i64: - return C_O1_I2(r, r, rKR); case INDEX_op_orc_i64: case INDEX_op_eqv_i64: return C_O1_I2(r, r, rNK); diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index ad6f35da17..510b9e64a4 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 @@ -46,7 +45,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index b3fbe127c0..fe9175aa1a 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1322,6 +1322,17 @@ static const TCGOutOpBinary outop_and = { .out_rri = tgen_andi, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_ANDN); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1379,9 +1390,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(andc): - c = ARITH_ANDN; - goto gen_arith; OP_32_64(or): c = ARITH_OR; goto gen_arith; @@ -1604,8 +1612,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_or_i32: case INDEX_op_or_i64: case INDEX_op_orc_i32: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 4ccdc6bbee..7e4301521e 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 0 -#define TCG_TARGET_HAS_andc_i64 0 #define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 82f3ad501f..68818cbb0c 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -668,7 +668,7 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_andc_i32) { + if (tcg_op_supported(INDEX_op_andc_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2264,7 +2264,7 @@ void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (TCG_TARGET_HAS_andc_i64) { + } else if (tcg_op_supported(INDEX_op_andc_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index d60427eb7f..3d6dc9d1ca 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1006,6 +1006,8 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), + OUTOP(INDEX_op_andc_i32, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_andc_i64, TCGOutOpBinary, outop_andc), }; #undef OUTOP @@ -2269,8 +2271,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_not_i32: return TCG_TARGET_HAS_not_i32; - case INDEX_op_andc_i32: - return TCG_TARGET_HAS_andc_i32; case INDEX_op_orc_i32: return TCG_TARGET_HAS_orc_i32; case INDEX_op_eqv_i32: @@ -2346,8 +2346,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_not_i64: return TCG_TARGET_HAS_not_i64; - case INDEX_op_andc_i64: - return TCG_TARGET_HAS_andc_i64; case INDEX_op_orc_i64: return TCG_TARGET_HAS_orc_i64; case INDEX_op_eqv_i64: @@ -5443,6 +5441,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: + case INDEX_op_andc_i32: + case INDEX_op_andc_i64: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 8762a99fb6..95a61e9df1 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -547,12 +547,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ^ regs[r2]; break; -#if TCG_TARGET_HAS_andc_i32 || TCG_TARGET_HAS_andc_i64 CASE_32_64(andc) tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & ~regs[r2]; break; -#endif #if TCG_TARGET_HAS_orc_i32 || TCG_TARGET_HAS_orc_i64 CASE_32_64(orc) tci_args_rrr(insn, &r0, &r1, &r2); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index cb0964c3d4..e09d366517 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -11,7 +11,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_andc_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 1 @@ -36,7 +35,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_andc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index b0141f8ed6..fb7c648b63 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -95,8 +95,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: case INDEX_op_nand_i32: @@ -659,6 +657,17 @@ static const TCGOutOpBinary outop_and = { .out_rrr = tgen_and, }; +static void tgen_andc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_andc_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_andc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_andc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -705,7 +714,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(mul) CASE_32_64(or) CASE_32_64(xor) - CASE_32_64(andc) /* Optional (TCG_TARGET_HAS_andc_*). */ CASE_32_64(orc) /* Optional (TCG_TARGET_HAS_orc_*). */ CASE_32_64(eqv) /* Optional (TCG_TARGET_HAS_eqv_*). */ CASE_32_64(nand) /* Optional (TCG_TARGET_HAS_nand_*). */ From 46f96bff163512f9f8f9959de4a18c0799001422 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 12:37:02 -0800 Subject: [PATCH 0371/2760] tcg: Merge INDEX_op_andc_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- target/arm/tcg/translate-a64.c | 2 +- target/tricore/translate.c | 2 +- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 9 files changed, 17 insertions(+), 19 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 6a8025c0bf..116a0438b1 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -319,7 +319,7 @@ Logical - | *t0* = ~\ *t1* - * - andc_i32/i64 *t0*, *t1*, *t2* + * - andc *t0*, *t1*, *t2* - | *t0* = *t1* & ~\ *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index f45029caa7..9bc511992d 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -41,6 +41,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) +DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) @@ -91,7 +92,6 @@ DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) DEF(neg_i32, 1, 1, 0, 0) -DEF(andc_i32, 1, 2, 0, 0) DEF(orc_i32, 1, 2, 0, 0) DEF(eqv_i32, 1, 2, 0, 0) DEF(nand_i32, 1, 2, 0, 0) @@ -149,7 +149,6 @@ DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) DEF(neg_i64, 1, 1, 0, 0) -DEF(andc_i64, 1, 2, 0, 0) DEF(orc_i64, 1, 2, 0, 0) DEF(eqv_i64, 1, 2, 0, 0) DEF(nand_i64, 1, 2, 0, 0) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 43408c71bb..e076d4aa05 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -8600,7 +8600,7 @@ static bool trans_CCMP(DisasContext *s, arg_CCMP *a) tcg_gen_subi_i32(tcg_t2, tcg_t0, 1); nzcv = a->nzcv; - has_andc = tcg_op_supported(INDEX_op_andc_i32, TCG_TYPE_I32, 0); + has_andc = tcg_op_supported(INDEX_op_andc, TCG_TYPE_I32, 0); if (nzcv & 8) { /* N */ tcg_gen_or_i32(cpu_NF, cpu_NF, tcg_t1); } else { diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 7cd26d8eab..2d0cde0268 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -3981,7 +3981,7 @@ static void decode_bit_andacc(DisasContext *ctx) pos1, pos2, &tcg_gen_andc_tl, &tcg_gen_and_tl); break; case OPC2_32_BIT_AND_NOR_T: - if (tcg_op_supported(INDEX_op_andc_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_andc, TCG_TYPE_I32, 0)) { gen_bit_2op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl, &tcg_gen_andc_tl); } else { diff --git a/tcg/optimize.c b/tcg/optimize.c index 6c7b6af624..875d80c254 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -479,7 +479,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) CASE_OP_32_64(neg): return -x; - CASE_OP_32_64_VEC(andc): + case INDEX_op_andc: + case INDEX_op_andc_vec: return x & ~y; CASE_OP_32_64_VEC(orc): @@ -2852,7 +2853,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_and_vec: done = fold_and(&ctx, op); break; - CASE_OP_32_64_VEC(andc): + case INDEX_op_andc: + case INDEX_op_andc_vec: done = fold_andc(&ctx, op); break; CASE_OP_32_64(brcond): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 68818cbb0c..d87bd13375 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -668,8 +668,8 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_andc_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_andc_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_andc, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_andc, ret, arg1, arg2); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_not_i32(t0, arg2); @@ -2264,8 +2264,8 @@ void tcg_gen_andc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_andc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_andc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (tcg_op_supported(INDEX_op_andc_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_andc_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_andc, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_andc, ret, arg1, arg2); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_not_i64(t0, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 3d6dc9d1ca..38b2dd1c44 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1006,8 +1006,7 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), - OUTOP(INDEX_op_andc_i32, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_andc_i64, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), }; #undef OUTOP @@ -5441,8 +5440,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: + case INDEX_op_andc: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 95a61e9df1..e4a0408fec 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -547,7 +547,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ^ regs[r2]; break; - CASE_32_64(andc) + case INDEX_op_andc: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & ~regs[r2]; break; @@ -1082,6 +1082,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_add: case INDEX_op_and: + case INDEX_op_andc: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: @@ -1090,8 +1091,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: - case INDEX_op_andc_i32: - case INDEX_op_andc_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: case INDEX_op_eqv_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index fb7c648b63..92c588305a 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -660,7 +660,7 @@ static const TCGOutOpBinary outop_and = { static void tgen_andc(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_andc_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_andc, a0, a1, a2); } static const TCGOutOpBinary outop_andc = { From 6497af5b0d76819475839de9ea1ef9faad6215c0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 13:54:22 -0800 Subject: [PATCH 0372/2760] tcg: Convert or to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 31 ++++++++++++--------- tcg/arm/tcg-target.c.inc | 24 ++++++++++++---- tcg/i386/tcg-target.c.inc | 25 +++++++++++++---- tcg/loongarch64/tcg-target.c.inc | 29 ++++++++++++-------- tcg/mips/tcg-target.c.inc | 25 ++++++++++++----- tcg/ppc/tcg-target.c.inc | 29 ++++++++++++-------- tcg/riscv/tcg-target.c.inc | 29 ++++++++++++-------- tcg/s390x/tcg-target.c.inc | 47 +++++++++++++++++--------------- tcg/sparc64/tcg-target.c.inc | 23 ++++++++++++---- tcg/tcg.c | 4 +++ tcg/tci/tcg-target.c.inc | 14 ++++++++-- 11 files changed, 186 insertions(+), 94 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index c7167cad15..4b62e4e382 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2157,6 +2157,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, ORR, type, a0, a1, a2); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_logicali(s, I3404_ORRI, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rL), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2238,17 +2256,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_or_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_or_i64: - if (c2) { - tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3510, ORR, ext, a0, a1, a2); - } - break; - case INDEX_op_orc_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3016,8 +3023,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: case INDEX_op_orc_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index feea82145a..0575d397c9 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1881,6 +1881,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_ORR, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_ORR, a0, a1, encode_imm_nofail(a2)); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1943,13 +1961,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[0], args[1], args[2], const_args[2]); } break; - case INDEX_op_or_i32: - c = ARITH_ORR; - goto gen_arith; case INDEX_op_xor_i32: c = ARITH_EOR; - /* Fall through. */ - gen_arith: tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]); break; case INDEX_op_add2_i32: @@ -2209,7 +2222,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_or_i32: case INDEX_op_xor_i32: return C_O1_I2(r, r, rI); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 33c1fcc717..813092622c 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2633,6 +2633,26 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_OR + rexw, a0, a2); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_OR + rexw, a0, a2, false); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2717,9 +2737,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(or): - c = ARITH_OR; - goto gen_arith; OP_32_64(xor): c = ARITH_XOR; goto gen_arith; @@ -3645,8 +3662,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: return C_O1_I2(r, 0, re); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b7d2984a8a..a7ead51263 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1332,6 +1332,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_or(s, a0, a1, a2); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_ori(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rU), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1392,15 +1410,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_or_i32: - case INDEX_op_or_i64: - if (c2) { - tcg_out_opc_ori(s, a0, a1, a2); - } else { - tcg_out_opc_or(s, a0, a1, a2); - } - break; - case INDEX_op_xor_i32: case INDEX_op_xor_i64: if (c2) { @@ -2300,8 +2309,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nor_i32: case INDEX_op_nor_i64: - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: /* LoongArch reg-imm bitops have their imms ZERO-extended */ diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index ab57c78095..74eef1d3b3 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1712,6 +1712,24 @@ static const TCGOutOpBinary outop_andc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_OR, a0, a1, a2); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_imm(s, OPC_ORI, a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1785,14 +1803,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_or_i32: - case INDEX_op_or_i64: - i1 = OPC_OR, i2 = OPC_ORI; - goto do_binary; case INDEX_op_xor_i32: case INDEX_op_xor_i64: i1 = OPC_XOR, i2 = OPC_XORI; - do_binary: if (c2) { tcg_out_opc_imm(s, i2, a0, a1, a2); break; @@ -2218,9 +2231,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_or_i32: case INDEX_op_xor_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i64: return C_O1_I2(r, r, rI); case INDEX_op_shl_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 7b1a82c9fa..b638a5f813 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2954,6 +2954,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, OR | SAB(a1, a0, a2)); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_ori32(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rU), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3039,15 +3057,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_or_i64: - case INDEX_op_or_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_ori32(s, a0, a1, a2); - } else { - tcg_out32(s, OR | SAB(a1, a0, a2)); - } - break; case INDEX_op_xor_i64: case INDEX_op_xor_i32: a0 = args[0], a1 = args[1], a2 = args[2]; @@ -4130,7 +4139,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_or_i32: case INDEX_op_xor_i32: case INDEX_op_orc_i32: case INDEX_op_eqv_i32: @@ -4172,7 +4180,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: return C_O1_I2(r, rI, ri); - case INDEX_op_or_i64: case INDEX_op_xor_i64: return C_O1_I2(r, r, rU); case INDEX_op_sub_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f637604e98..9bacd109d4 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2013,6 +2013,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_OR, a0, a1, a2); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_imm(s, OPC_ORI, a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2091,15 +2109,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_or_i32: - case INDEX_op_or_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ORI, a0, a1, a2); - } else { - tcg_out_opc_reg(s, OPC_OR, a0, a1, a2); - } - break; - case INDEX_op_xor_i32: case INDEX_op_xor_i64: if (c2) { @@ -2682,9 +2691,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_or_i32: case INDEX_op_xor_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e4b60d1924..9267aef544 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2242,6 +2242,31 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, OGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, OR, a0, a2); + } else { + tcg_out_insn(s, RRFa, ORK, a0, a1, a2); + } +} + +static void tgen_ori_3(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + tgen_ori(s, a0, type == TCG_TYPE_I32 ? (uint32_t)a2 : a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rK), + .out_rrr = tgen_or, + .out_rri = tgen_ori_3, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2310,17 +2335,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_or_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_ori(s, a0, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RR, OR, a0, a2); - } else { - tcg_out_insn(s, RRFa, ORK, a0, a1, a2); - } - break; case INDEX_op_xor_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { @@ -2561,15 +2575,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_or_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_ori(s, a0, a2); - } else { - tcg_out_insn(s, RRFa, OGRK, a0, a1, a2); - } - break; case INDEX_op_xor_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { @@ -3282,10 +3287,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_or_i32: case INDEX_op_xor_i32: return C_O1_I2(r, r, ri); - case INDEX_op_or_i64: case INDEX_op_xor_i64: return C_O1_I2(r, r, rK); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index fe9175aa1a..b01d55c80b 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1333,6 +1333,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_OR); +} + +static void tgen_ori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_OR); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_or, + .out_rri = tgen_ori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1390,9 +1408,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(or): - c = ARITH_OR; - goto gen_arith; OP_32_64(orc): c = ARITH_ORN; goto gen_arith; @@ -1612,8 +1627,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: case INDEX_op_xor_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 38b2dd1c44..7357b5c127 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1007,6 +1007,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_or_i32, TCGOutOpBinary, outop_or), + OUTOP(INDEX_op_or_i64, TCGOutOpBinary, outop_or), }; #undef OUTOP @@ -5441,6 +5443,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_or_i32: + case INDEX_op_or_i64: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 92c588305a..6fdfcab061 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -101,8 +101,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_orc_i32: case INDEX_op_orc_i64: case INDEX_op_xor_i32: @@ -668,6 +666,17 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_or(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_or_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_or = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_or, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -712,7 +721,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(or) CASE_32_64(xor) CASE_32_64(orc) /* Optional (TCG_TARGET_HAS_orc_*). */ CASE_32_64(eqv) /* Optional (TCG_TARGET_HAS_eqv_*). */ From 49bd751497f3b71550b152ef9da0e265a94a64c1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 14:00:40 -0800 Subject: [PATCH 0373/2760] tcg: Merge INDEX_op_or_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- target/sh4/translate.c | 4 ++-- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 9 +++------ tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 8 files changed, 16 insertions(+), 19 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 116a0438b1..8d67b0cdeb 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -307,7 +307,7 @@ Logical - | *t0* = *t1* & *t2* - * - or_i32/i64 *t0*, *t1*, *t2* + * - or *t0*, *t1*, *t2* - | *t0* = *t1* | *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 9bc511992d..95608d6d31 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -42,6 +42,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) +DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) @@ -64,7 +65,6 @@ DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) DEF(div2_i32, 2, 3, 0, 0) DEF(divu2_i32, 2, 3, 0, 0) -DEF(or_i32, 1, 2, 0, 0) DEF(xor_i32, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) @@ -124,7 +124,6 @@ DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) DEF(div2_i64, 2, 3, 0, 0) DEF(divu2_i64, 2, 3, 0, 0) -DEF(or_i64, 1, 2, 0, 0) DEF(xor_i64, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 3d0eda2128..094613d312 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1949,7 +1949,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) op_opc = INDEX_op_xor_i32; goto do_reg_op; case 0x200b: /* or Rm,Rn */ - op_opc = INDEX_op_or_i32; + op_opc = INDEX_op_or; do_reg_op: /* The operation register should be as expected, and the other input cannot depend on the load. */ @@ -2119,7 +2119,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) } break; - case INDEX_op_or_i32: + case INDEX_op_or: if (op_dst != st_src) { goto fail; } diff --git a/tcg/optimize.c b/tcg/optimize.c index 875d80c254..7d5f7af223 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -437,7 +437,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_and_vec: return x & y; - CASE_OP_32_64_VEC(or): + case INDEX_op_or: + case INDEX_op_or_vec: return x | y; CASE_OP_32_64_VEC(xor): @@ -2961,7 +2962,8 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64_VEC(not): done = fold_not(&ctx, op); break; - CASE_OP_32_64_VEC(or): + case INDEX_op_or: + case INDEX_op_or_vec: done = fold_or(&ctx, op); break; CASE_OP_32_64_VEC(orc): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index d87bd13375..6807f4eebd 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -436,7 +436,7 @@ void tcg_gen_andi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_or_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_or_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_or, ret, arg1, arg2); } void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1585,7 +1585,7 @@ void tcg_gen_and_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_or_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_or, ret, arg1, arg2); } else { tcg_gen_or_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_or_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); diff --git a/tcg/tcg.c b/tcg/tcg.c index 7357b5c127..f31ae4e56b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1007,8 +1007,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_or_i32, TCGOutOpBinary, outop_or), - OUTOP(INDEX_op_or_i64, TCGOutOpBinary, outop_or), + OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), }; #undef OUTOP @@ -2212,6 +2211,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add: case INDEX_op_and: case INDEX_op_mov: + case INDEX_op_or: return has_type; case INDEX_op_setcond_i32: @@ -2228,7 +2228,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_neg_i32: case INDEX_op_mul_i32: - case INDEX_op_or_i32: case INDEX_op_xor_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: @@ -2308,7 +2307,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_neg_i64: case INDEX_op_mul_i64: - case INDEX_op_or_i64: case INDEX_op_xor_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: @@ -5443,8 +5441,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: - case INDEX_op_or_i32: - case INDEX_op_or_i64: + case INDEX_op_or: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index e4a0408fec..3e361be6bd 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -539,7 +539,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & regs[r2]; break; - CASE_32_64(or) + case INDEX_op_or: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | regs[r2]; break; @@ -1083,12 +1083,11 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_or: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_or_i32: - case INDEX_op_or_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: case INDEX_op_orc_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 6fdfcab061..4214b76b34 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -669,7 +669,7 @@ static const TCGOutOpBinary outop_andc = { static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_or_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_or, a0, a1, a2); } static const TCGOutOpBinary outop_or = { From 50e40ecd7a5eb803a67d02aa586b5671968ac58b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 10 Dec 2024 08:13:10 -0600 Subject: [PATCH 0374/2760] tcg/optimize: Fold orc with immediate to or MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 7d5f7af223..684b1099d0 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2143,6 +2143,7 @@ static bool fold_or(OptContext *ctx, TCGOp *op) static bool fold_orc(OptContext *ctx, TCGOp *op) { uint64_t s_mask; + TempOptInfo *t1, *t2; if (fold_const2(ctx, op) || fold_xx_to_i(ctx, op, -1) || @@ -2151,8 +2152,28 @@ static bool fold_orc(OptContext *ctx, TCGOp *op) return true; } - s_mask = arg_info(op->args[1])->s_mask - & arg_info(op->args[2])->s_mask; + t2 = arg_info(op->args[2]); + if (ti_is_const(t2)) { + /* Fold orc r,x,i to or r,x,~i. */ + switch (ctx->type) { + case TCG_TYPE_I32: + case TCG_TYPE_I64: + op->opc = INDEX_op_or; + break; + case TCG_TYPE_V64: + case TCG_TYPE_V128: + case TCG_TYPE_V256: + op->opc = INDEX_op_or_vec; + break; + default: + g_assert_not_reached(); + } + op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2)); + return fold_or(ctx, op); + } + + t1 = arg_info(op->args[1]); + s_mask = t1->s_mask & t2->s_mask; return fold_masks_s(ctx, op, s_mask); } From d262ae608115d2e6fc61ba6998d9813a5208b0e5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 14:30:50 -0800 Subject: [PATCH 0375/2760] tcg: Convert orc to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, drop all backend support for immediate operands, as we now transform orc to or during optimize. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 24 ++++++++--------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 +++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 +++ tcg/loongarch64/tcg-target-con-set.h | 1 - tcg/loongarch64/tcg-target-con-str.h | 1 - tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 40 ++++++++++------------------ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 4 +++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 22 +++++++-------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 22 ++++++++------- tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 36 +++++++++++-------------- tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 16 +++++++---- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 +-- tcg/tcg.c | 8 +++--- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 14 +++++++--- 26 files changed, 104 insertions(+), 118 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 851f6b01b4..8469a9446f 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 4b62e4e382..13592303a8 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2175,6 +2175,17 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, ORN, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2256,17 +2267,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_orc_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_orc_i64: - if (c2) { - tcg_out_logicali(s, I3404_ORRI, ext, a0, a1, ~a2); - } else { - tcg_out_insn(s, 3510, ORN, ext, a0, a1, a2); - } - break; - case INDEX_op_xor_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3025,8 +3025,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor_i32: case INDEX_op_xor_i64: - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: return C_O1_I2(r, r, rL); diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 0268858a3b..39dcc87fe8 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0575d397c9..48cbcd67b9 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1899,6 +1899,10 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index b29b70357a..e525f23c05 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -31,7 +31,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 @@ -56,7 +55,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 813092622c..3fe1d9d9cc 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2653,6 +2653,10 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index b7c9b89e9e..b4af4f5423 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -23,7 +23,6 @@ C_O1_I1(r, r) C_O1_I1(w, r) C_O1_I1(w, w) C_O1_I2(r, r, r) -C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) C_O1_I2(r, r, rJ) diff --git a/tcg/loongarch64/tcg-target-con-str.h b/tcg/loongarch64/tcg-target-con-str.h index 99759120b4..e5e57452d6 100644 --- a/tcg/loongarch64/tcg-target-con-str.h +++ b/tcg/loongarch64/tcg-target-con-str.h @@ -23,7 +23,6 @@ REGS('w', ALL_VECTOR_REGS) CONST('I', TCG_CT_CONST_S12) CONST('J', TCG_CT_CONST_S32) CONST('U', TCG_CT_CONST_U12) -CONST('C', TCG_CT_CONST_C12) CONST('W', TCG_CT_CONST_WSZ) CONST('M', TCG_CT_CONST_VCMP) CONST('A', TCG_CT_CONST_VADD) diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 71d91fec19..fb1142958c 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 1 @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index a7ead51263..b6f13090b9 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -176,10 +176,9 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define TCG_CT_CONST_S12 0x100 #define TCG_CT_CONST_S32 0x200 #define TCG_CT_CONST_U12 0x400 -#define TCG_CT_CONST_C12 0x800 -#define TCG_CT_CONST_WSZ 0x1000 -#define TCG_CT_CONST_VCMP 0x2000 -#define TCG_CT_CONST_VADD 0x4000 +#define TCG_CT_CONST_WSZ 0x800 +#define TCG_CT_CONST_VCMP 0x1000 +#define TCG_CT_CONST_VADD 0x2000 #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) #define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32) @@ -205,9 +204,6 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_U12) && val >= 0 && val <= 0xfff) { return true; } - if ((ct & TCG_CT_CONST_C12) && ~val >= 0 && ~val <= 0xfff) { - return true; - } if ((ct & TCG_CT_CONST_WSZ) && val == (type == TCG_TYPE_I32 ? 32 : 64)) { return true; } @@ -1350,6 +1346,17 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_orn(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1400,16 +1407,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: - if (c2) { - /* guaranteed to fit due to constraint */ - tcg_out_opc_ori(s, a0, a1, ~a2); - } else { - tcg_out_opc_orn(s, a0, a1, a2); - } - break; - case INDEX_op_xor_i32: case INDEX_op_xor_i64: if (c2) { @@ -2286,15 +2283,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: - /* - * LoongArch insns for these ops don't have reg-imm forms, but we - * can express using andi/ori if ~constant satisfies - * TCG_CT_CONST_U12. - */ - return C_O1_I2(r, r, rC); - case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 6a6d4377e7..b3dfa390f9 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_nor_i32 1 -#define TCG_TARGET_HAS_orc_i32 0 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) @@ -62,7 +61,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_nor_i64 1 -#define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_add2_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 74eef1d3b3..f6987963ec 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1730,6 +1730,10 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 63bb66f446..6f3ab41ebb 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -23,7 +23,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 1 #define TCG_TARGET_HAS_nor_i32 1 @@ -49,7 +48,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index b638a5f813..ccd7812016 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2972,6 +2972,17 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, ORC | SAB(a1, a0, a2)); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3066,15 +3077,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, XOR | SAB(a1, a0, a2)); } break; - case INDEX_op_orc_i32: - if (const_args[2]) { - tcg_out_ori32(s, args[0], args[1], ~args[2]); - break; - } - /* FALLTHRU */ - case INDEX_op_orc_i64: - tcg_out32(s, ORC | SAB(args[1], args[0], args[2])); - break; case INDEX_op_eqv_i32: if (const_args[2]) { tcg_out_xori32(s, args[0], args[1], ~args[2]); @@ -4140,7 +4142,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O0_I2(r, r); case INDEX_op_xor_i32: - case INDEX_op_orc_i32: case INDEX_op_eqv_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: @@ -4166,7 +4167,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nor_i32: case INDEX_op_muluh_i32: case INDEX_op_mulsh_i32: - case INDEX_op_orc_i64: case INDEX_op_eqv_i64: case INDEX_op_nand_i64: case INDEX_op_nor_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index a3918bf7f5..7b8f4386c9 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_eqv_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 @@ -45,7 +44,6 @@ #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_eqv_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 9bacd109d4..14216e9dff 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2031,6 +2031,18 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_ORN, a0, a1, a2); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2118,14 +2130,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ORI, a0, a1, ~a2); - } else { - tcg_out_opc_reg(s, OPC_ORN, a0, a1, a2); - } - break; case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: if (c2) { @@ -2699,8 +2703,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: return C_O1_I2(r, r, rJ); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 15ec0dc2ff..850c16a164 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -34,7 +34,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_orc_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_eqv_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3) @@ -58,7 +57,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_orc_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_eqv_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 9267aef544..97587939bd 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2267,6 +2267,22 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori_3, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, OCRK, a0, a1, a2); + } else { + tcg_out_insn(s, RRFa, OCGRK, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_misc3_rrr, + .out_rrr = tgen_orc, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2347,15 +2363,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_orc_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tgen_ori(s, a0, (uint32_t)~a2); - } else { - tcg_out_insn(s, RRFa, OCRK, a0, a1, a2); - } - break; case INDEX_op_eqv_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { @@ -2585,15 +2592,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_orc_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_ori(s, a0, ~a2); - } else { - tcg_out_insn(s, RRFa, OCGRK, a0, a1, a2); - } - break; case INDEX_op_eqv_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { @@ -3292,10 +3290,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor_i64: return C_O1_I2(r, r, rK); - case INDEX_op_orc_i32: case INDEX_op_eqv_i32: return C_O1_I2(r, r, ri); - case INDEX_op_orc_i64: case INDEX_op_eqv_i64: return C_O1_I2(r, r, rNK); diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 510b9e64a4..8e20e4cdeb 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 @@ -45,7 +44,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index b01d55c80b..38b325e8a9 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1351,6 +1351,17 @@ static const TCGOutOpBinary outop_or = { .out_rri = tgen_ori, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_ORN); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1408,9 +1419,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(orc): - c = ARITH_ORN; - goto gen_arith; OP_32_64(xor): c = ARITH_XOR; goto gen_arith; @@ -1627,8 +1635,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: case INDEX_op_shl_i32: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 7e4301521e..df9c951262 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 0 -#define TCG_TARGET_HAS_orc_i64 0 #define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 6807f4eebd..503d395ac8 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -710,7 +710,7 @@ void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_orc_i32) { + if (tcg_op_supported(INDEX_op_orc_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2318,7 +2318,7 @@ void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (TCG_TARGET_HAS_orc_i64) { + } else if (tcg_op_supported(INDEX_op_orc_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index f31ae4e56b..4737a6b2cc 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1008,6 +1008,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), + OUTOP(INDEX_op_orc_i32, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_orc_i64, TCGOutOpBinary, outop_orc), }; #undef OUTOP @@ -2271,8 +2273,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_not_i32: return TCG_TARGET_HAS_not_i32; - case INDEX_op_orc_i32: - return TCG_TARGET_HAS_orc_i32; case INDEX_op_eqv_i32: return TCG_TARGET_HAS_eqv_i32; case INDEX_op_nand_i32: @@ -2345,8 +2345,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_not_i64: return TCG_TARGET_HAS_not_i64; - case INDEX_op_orc_i64: - return TCG_TARGET_HAS_orc_i64; case INDEX_op_eqv_i64: return TCG_TARGET_HAS_eqv_i64; case INDEX_op_nand_i64: @@ -5442,6 +5440,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_or: + case INDEX_op_orc_i32: + case INDEX_op_orc_i64: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 3e361be6bd..7a926b30db 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -551,12 +551,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & ~regs[r2]; break; -#if TCG_TARGET_HAS_orc_i32 || TCG_TARGET_HAS_orc_i64 CASE_32_64(orc) tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | ~regs[r2]; break; -#endif #if TCG_TARGET_HAS_eqv_i32 || TCG_TARGET_HAS_eqv_i64 CASE_32_64(eqv) tci_args_rrr(insn, &r0, &r1, &r2); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index e09d366517..d247774e52 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_orc_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 @@ -42,7 +41,6 @@ #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_orc_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4214b76b34..2e45cc4768 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -101,8 +101,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: case INDEX_op_shl_i32: @@ -677,6 +675,17 @@ static const TCGOutOpBinary outop_or = { .out_rrr = tgen_or, }; +static void tgen_orc(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_orc_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_orc = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_orc, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -722,7 +731,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) CASE_32_64(xor) - CASE_32_64(orc) /* Optional (TCG_TARGET_HAS_orc_*). */ CASE_32_64(eqv) /* Optional (TCG_TARGET_HAS_eqv_*). */ CASE_32_64(nand) /* Optional (TCG_TARGET_HAS_nand_*). */ CASE_32_64(nor) /* Optional (TCG_TARGET_HAS_nor_*). */ From 6aba25ebb9eb6e1e86398294694aa0ab1f12076f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 14:46:26 -0800 Subject: [PATCH 0376/2760] tcg: Merge INDEX_op_orc_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- target/arm/tcg/translate-sve.c | 2 +- target/tricore/translate.c | 2 +- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 9 files changed, 17 insertions(+), 19 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 8d67b0cdeb..c5c5a4d19e 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -335,7 +335,7 @@ Logical - | *t0* = ~(*t1* | *t2*) - * - orc_i32/i64 *t0*, *t1*, *t2* + * - orc *t0*, *t1*, *t2* - | *t0* = *t1* | ~\ *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 95608d6d31..caf0f01042 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) +DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) @@ -92,7 +93,6 @@ DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) DEF(neg_i32, 1, 1, 0, 0) -DEF(orc_i32, 1, 2, 0, 0) DEF(eqv_i32, 1, 2, 0, 0) DEF(nand_i32, 1, 2, 0, 0) DEF(nor_i32, 1, 2, 0, 0) @@ -148,7 +148,6 @@ DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) DEF(neg_i64, 1, 1, 0, 0) -DEF(orc_i64, 1, 2, 0, 0) DEF(eqv_i64, 1, 2, 0, 0) DEF(nand_i64, 1, 2, 0, 0) DEF(nor_i64, 1, 2, 0, 0) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index d23be477b4..f3cf028cb9 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -629,7 +629,7 @@ static void gen_bsl2n_i64(TCGv_i64 d, TCGv_i64 n, TCGv_i64 m, TCGv_i64 k) * = | ~(m | k) */ tcg_gen_and_i64(n, n, k); - if (tcg_op_supported(INDEX_op_orc_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_orc, TCG_TYPE_I64, 0)) { tcg_gen_or_i64(m, m, k); tcg_gen_orc_i64(d, n, m); } else { diff --git a/target/tricore/translate.c b/target/tricore/translate.c index 2d0cde0268..ede0c92c1e 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -4114,7 +4114,7 @@ static void decode_bit_orand(DisasContext *ctx) pos1, pos2, &tcg_gen_andc_tl, &tcg_gen_or_tl); break; case OPC2_32_BIT_OR_NOR_T: - if (tcg_op_supported(INDEX_op_orc_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_orc, TCG_TYPE_I32, 0)) { gen_bit_2op(cpu_gpr_d[r3], cpu_gpr_d[r1], cpu_gpr_d[r2], pos1, pos2, &tcg_gen_or_tl, &tcg_gen_orc_tl); } else { diff --git a/tcg/optimize.c b/tcg/optimize.c index 684b1099d0..5f0ab354d6 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -484,7 +484,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_andc_vec: return x & ~y; - CASE_OP_32_64_VEC(orc): + case INDEX_op_orc: + case INDEX_op_orc_vec: return x | ~y; CASE_OP_32_64_VEC(eqv): @@ -2987,7 +2988,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_or_vec: done = fold_or(&ctx, op); break; - CASE_OP_32_64_VEC(orc): + case INDEX_op_orc: + case INDEX_op_orc_vec: done = fold_orc(&ctx, op); break; case INDEX_op_qemu_ld_i32: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 503d395ac8..bf481060fa 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -710,8 +710,8 @@ void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_orc_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_orc_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_orc, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_orc, ret, arg1, arg2); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_not_i32(t0, arg2); @@ -2318,8 +2318,8 @@ void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_orc_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_orc_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (tcg_op_supported(INDEX_op_orc_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_orc_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_orc, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_orc, ret, arg1, arg2); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_not_i64(t0, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 4737a6b2cc..1b7e230219 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1008,8 +1008,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), - OUTOP(INDEX_op_orc_i32, TCGOutOpBinary, outop_orc), - OUTOP(INDEX_op_orc_i64, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), }; #undef OUTOP @@ -5440,8 +5439,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_or: - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: + case INDEX_op_orc: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 7a926b30db..68636e70da 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -551,7 +551,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] & ~regs[r2]; break; - CASE_32_64(orc) + case INDEX_op_orc: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | ~regs[r2]; break; @@ -1082,14 +1082,13 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_or: + case INDEX_op_orc: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: case INDEX_op_xor_i32: case INDEX_op_xor_i64: - case INDEX_op_orc_i32: - case INDEX_op_orc_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: case INDEX_op_nand_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2e45cc4768..b9309e2fb9 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -678,7 +678,7 @@ static const TCGOutOpBinary outop_or = { static void tgen_orc(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_orc_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_orc, a0, a1, a2); } static const TCGOutOpBinary outop_orc = { From d3e56f382493540b3a46a432a7e09261f4f5dbe7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 15:11:22 -0800 Subject: [PATCH 0377/2760] tcg: Convert xor to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 31 +++++++++++--------- tcg/arm/tcg-target.c.inc | 25 +++++++++++----- tcg/i386/tcg-target.c.inc | 27 ++++++++++++----- tcg/loongarch64/tcg-target.c.inc | 29 +++++++++++------- tcg/mips/tcg-target.c.inc | 28 +++++++++++------- tcg/ppc/tcg-target.c.inc | 30 +++++++++++-------- tcg/riscv/tcg-target.c.inc | 29 +++++++++++------- tcg/s390x/tcg-target.c.inc | 50 ++++++++++++++++---------------- tcg/sparc64/tcg-target.c.inc | 23 +++++++++++---- tcg/tcg.c | 4 +++ tcg/tci/tcg-target.c.inc | 14 +++++++-- 11 files changed, 186 insertions(+), 104 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 13592303a8..d575635fe0 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2186,6 +2186,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, EOR, type, a0, a1, a2); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_logicali(s, I3404_EORI, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rL), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2267,17 +2285,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_xor_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_xor_i64: - if (c2) { - tcg_out_logicali(s, I3404_EORI, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3510, EOR, ext, a0, a1, a2); - } - break; - case INDEX_op_eqv_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3023,8 +3030,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: return C_O1_I2(r, r, rL); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 48cbcd67b9..98cb3cf5e2 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1903,6 +1903,24 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_EOR, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_EOR, a0, a1, encode_imm_nofail(a2)); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1965,10 +1983,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[0], args[1], args[2], const_args[2]); } break; - case INDEX_op_xor_i32: - c = ARITH_EOR; - tcg_out_dat_rI(s, COND_AL, c, args[0], args[1], args[2], const_args[2]); - break; case INDEX_op_add2_i32: a0 = args[0], a1 = args[1], a2 = args[2]; a3 = args[3], a4 = args[4], a5 = args[5]; @@ -2226,9 +2240,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_xor_i32: - return C_O1_I2(r, r, rI); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 3fe1d9d9cc..9126f9aeff 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2657,6 +2657,26 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_XOR + rexw, a0, a2); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_XOR + rexw, a0, a2, false); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2740,11 +2760,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; - goto gen_arith; - OP_32_64(xor): - c = ARITH_XOR; - goto gen_arith; - gen_arith: if (const_a2) { tgen_arithi(s, c + rexw, a0, a2, 0); } else { @@ -3666,8 +3681,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: return C_O1_I2(r, 0, re); case INDEX_op_shl_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index b6f13090b9..296a84af79 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1357,6 +1357,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_xor(s, a0, a1, a2); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_xori(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rU), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1407,15 +1425,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: - if (c2) { - tcg_out_opc_xori(s, a0, a1, a2); - } else { - tcg_out_opc_xor(s, a0, a1, a2); - } - break; - case INDEX_op_extract_i32: if (a2 == 0 && args[3] <= 12) { tcg_out_opc_andi(s, a0, a1, (1 << args[3]) - 1); @@ -2297,8 +2306,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nor_i32: case INDEX_op_nor_i64: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: /* LoongArch reg-imm bitops have their imms ZERO-extended */ return C_O1_I2(r, r, rU); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index f6987963ec..30fb01cb0a 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1734,6 +1734,24 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_XOR, a0, a1, a2); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_imm(s, OPC_XORI, a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1807,13 +1825,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: - i1 = OPC_XOR, i2 = OPC_XORI; - if (c2) { - tcg_out_opc_imm(s, i2, a0, a1, a2); - break; - } do_binaryv: tcg_out_opc_reg(s, i1, a0, a1, a2); break; @@ -2235,9 +2246,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: - return C_O1_I2(r, r, rI); case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index ccd7812016..16d3dbd841 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2983,6 +2983,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, XOR | SAB(a1, a0, a2)); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_xori32(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rU), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3068,15 +3086,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_xor_i64: - case INDEX_op_xor_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_xori32(s, a0, a1, a2); - } else { - tcg_out32(s, XOR | SAB(a1, a0, a2)); - } - break; case INDEX_op_eqv_i32: if (const_args[2]) { tcg_out_xori32(s, args[0], args[1], ~args[2]); @@ -4141,7 +4150,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_xor_i32: case INDEX_op_eqv_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: @@ -4180,8 +4188,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: return C_O1_I2(r, rI, ri); - case INDEX_op_xor_i64: - return C_O1_I2(r, r, rU); case INDEX_op_sub_i64: return C_O1_I2(r, rI, rT); case INDEX_op_clz_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 14216e9dff..c981ea389a 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2043,6 +2043,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_XOR, a0, a1, a2); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_opc_imm(s, OPC_XORI, a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2121,15 +2139,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_XORI, a0, a1, a2); - } else { - tcg_out_opc_reg(s, OPC_XOR, a0, a1, a2); - } - break; - case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: if (c2) { @@ -2695,8 +2704,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: case INDEX_op_negsetcond_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 97587939bd..bedad7137b 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2283,6 +2283,31 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, XGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, XR, a0, a2); + } else { + tcg_out_insn(s, RRFa, XRK, a0, a1, a2); + } +} + +static void tgen_xori_3(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + tgen_xori(s, a0, type == TCG_TYPE_I32 ? (uint32_t)a2 : a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rK), + .out_rrr = tgen_xor, + .out_rri = tgen_xori_3, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2351,18 +2376,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_xor_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tcg_out_insn(s, RIL, XILF, a0, a2); - } else if (a0 == a1) { - tcg_out_insn(s, RR, XR, args[0], args[2]); - } else { - tcg_out_insn(s, RRFa, XRK, a0, a1, a2); - } - break; - case INDEX_op_eqv_i32: a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; if (const_args[2]) { @@ -2582,16 +2595,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_xor_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_xori(s, a0, a2); - } else { - tcg_out_insn(s, RRFa, XGRK, a0, a1, a2); - } - break; - case INDEX_op_eqv_i64: a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[2]) { @@ -3285,10 +3288,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_xor_i32: return C_O1_I2(r, r, ri); - case INDEX_op_xor_i64: - return C_O1_I2(r, r, rK); case INDEX_op_eqv_i32: return C_O1_I2(r, r, ri); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 38b325e8a9..8a6c9852d2 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1362,6 +1362,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_XOR); +} + +static void tgen_xori(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_XOR); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_xor, + .out_rri = tgen_xori, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1419,9 +1437,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(sub): c = ARITH_SUB; goto gen_arith; - OP_32_64(xor): - c = ARITH_XOR; - goto gen_arith; case INDEX_op_shl_i32: c = SHIFT_SLL; do_shift32: @@ -1635,8 +1650,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_sub_i32: case INDEX_op_sub_i64: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 1b7e230219..042f177966 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1009,6 +1009,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_xor_i32, TCGOutOpBinary, outop_xor), + OUTOP(INDEX_op_xor_i64, TCGOutOpBinary, outop_xor), }; #undef OUTOP @@ -5440,6 +5442,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_or: case INDEX_op_orc: + case INDEX_op_xor_i32: + case INDEX_op_xor_i64: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index b9309e2fb9..85caff300f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -101,8 +101,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: @@ -686,6 +684,17 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_xor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_xor_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_xor = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_xor, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -730,7 +739,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(xor) CASE_32_64(eqv) /* Optional (TCG_TARGET_HAS_eqv_*). */ CASE_32_64(nand) /* Optional (TCG_TARGET_HAS_nand_*). */ CASE_32_64(nor) /* Optional (TCG_TARGET_HAS_nor_*). */ From fffd3dc9022efe89b9196d738127c294cf43a4d6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 15:18:35 -0800 Subject: [PATCH 0378/2760] tcg: Merge INDEX_op_xor_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- target/sh4/translate.c | 6 +++--- tcg/optimize.c | 18 ++++++++---------- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 9 +++------ tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 8 files changed, 21 insertions(+), 28 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index c5c5a4d19e..a4aa4f8824 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -311,7 +311,7 @@ Logical - | *t0* = *t1* | *t2* - * - xor_i32/i64 *t0*, *t1*, *t2* + * - xor *t0*, *t1*, *t2* - | *t0* = *t1* ^ *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index caf0f01042..8f6115bedb 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) +DEF(xor, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) DEF(negsetcond_i32, 1, 2, 1, 0) @@ -66,7 +67,6 @@ DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) DEF(div2_i32, 2, 3, 0, 0) DEF(divu2_i32, 2, 3, 0, 0) -DEF(xor_i32, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) DEF(shr_i32, 1, 2, 0, 0) @@ -124,7 +124,6 @@ DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) DEF(div2_i64, 2, 3, 0, 0) DEF(divu2_i64, 2, 3, 0, 0) -DEF(xor_i64, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) DEF(shr_i64, 1, 2, 0, 0) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 094613d312..8248648c0c 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1946,7 +1946,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) op_opc = INDEX_op_and; goto do_reg_op; case 0x200a: /* xor Rm,Rn */ - op_opc = INDEX_op_xor_i32; + op_opc = INDEX_op_xor; goto do_reg_op; case 0x200b: /* or Rm,Rn */ op_opc = INDEX_op_or; @@ -1976,7 +1976,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) goto fail; } op_dst = B11_8; - op_opc = INDEX_op_xor_i32; + op_opc = INDEX_op_xor; op_arg = tcg_constant_i32(-1); break; @@ -2133,7 +2133,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) } break; - case INDEX_op_xor_i32: + case INDEX_op_xor: if (op_dst != st_src) { goto fail; } diff --git a/tcg/optimize.c b/tcg/optimize.c index 5f0ab354d6..9303bb5b64 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -441,7 +441,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_or_vec: return x | y; - CASE_OP_32_64_VEC(xor): + case INDEX_op_xor: + case INDEX_op_xor_vec: return x ^ y; case INDEX_op_shl_i32: @@ -2289,7 +2290,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) break; } if (convert) { - TCGOpcode xor_opc, neg_opc; + TCGOpcode neg_opc; if (!inv && !neg) { return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]); @@ -2298,11 +2299,9 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: neg_opc = INDEX_op_neg_i32; - xor_opc = INDEX_op_xor_i32; break; case TCG_TYPE_I64: neg_opc = INDEX_op_neg_i64; - xor_opc = INDEX_op_xor_i64; break; default: g_assert_not_reached(); @@ -2314,7 +2313,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) op->opc = INDEX_op_add; op->args[2] = arg_new_constant(ctx, -1); } else { - op->opc = xor_opc; + op->opc = INDEX_op_xor; op->args[2] = arg_new_constant(ctx, 1); } return -1; @@ -2325,7 +2324,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode xor_opc, neg_opc, shr_opc; + TCGOpcode neg_opc, shr_opc; TCGOpcode uext_opc = 0, sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; @@ -2347,7 +2346,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - xor_opc = INDEX_op_xor_i32; shr_opc = INDEX_op_shr_i32; neg_opc = INDEX_op_neg_i32; if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) { @@ -2358,7 +2356,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } break; case TCG_TYPE_I64: - xor_opc = INDEX_op_xor_i64; shr_opc = INDEX_op_shr_i64; neg_opc = INDEX_op_neg_i64; if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) { @@ -2406,7 +2403,7 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op2->args[1] = ret; op2->args[2] = arg_new_constant(ctx, -1); } else if (inv) { - op2 = opt_insert_after(ctx, op, xor_opc, 3); + op2 = opt_insert_after(ctx, op, INDEX_op_xor, 3); op2->args[0] = ret; op2->args[1] = ret; op2->args[2] = arg_new_constant(ctx, 1); @@ -3051,7 +3048,8 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(sub2): done = fold_sub2(&ctx, op); break; - CASE_OP_32_64_VEC(xor): + case INDEX_op_xor: + case INDEX_op_xor_vec: done = fold_xor(&ctx, op); break; case INDEX_op_set_label: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index bf481060fa..b10f61435c 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -453,7 +453,7 @@ void tcg_gen_ori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_xor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_xor_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_xor, ret, arg1, arg2); } void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1595,7 +1595,7 @@ void tcg_gen_or_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_xor_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_xor, ret, arg1, arg2); } else { tcg_gen_xor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_xor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); diff --git a/tcg/tcg.c b/tcg/tcg.c index 042f177966..3c4905aa68 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1009,8 +1009,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), - OUTOP(INDEX_op_xor_i32, TCGOutOpBinary, outop_xor), - OUTOP(INDEX_op_xor_i64, TCGOutOpBinary, outop_xor), + OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; #undef OUTOP @@ -2215,6 +2214,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_and: case INDEX_op_mov: case INDEX_op_or: + case INDEX_op_xor: return has_type; case INDEX_op_setcond_i32: @@ -2231,7 +2231,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i32: case INDEX_op_neg_i32: case INDEX_op_mul_i32: - case INDEX_op_xor_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: @@ -2308,7 +2307,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_neg_i64: case INDEX_op_mul_i64: - case INDEX_op_xor_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: @@ -5442,8 +5440,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_or: case INDEX_op_orc: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: + case INDEX_op_xor: { const TCGOutOpBinary *out = container_of(all_outop[op->opc], TCGOutOpBinary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 68636e70da..cb300c4846 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -543,7 +543,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | regs[r2]; break; - CASE_32_64(xor) + case INDEX_op_xor: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ^ regs[r2]; break; @@ -1083,12 +1083,11 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_andc: case INDEX_op_or: case INDEX_op_orc: + case INDEX_op_xor: case INDEX_op_sub_i32: case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_xor_i32: - case INDEX_op_xor_i64: case INDEX_op_eqv_i32: case INDEX_op_eqv_i64: case INDEX_op_nand_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 85caff300f..0a912744b3 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -687,7 +687,7 @@ static const TCGOutOpBinary outop_orc = { static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_xor_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_xor, a0, a1, a2); } static const TCGOutOpBinary outop_xor = { From 46c68d75063d2d1119d5907e24e64e068ff64ba4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Nov 2023 11:51:28 -0800 Subject: [PATCH 0379/2760] tcg/optimize: Fold eqv with immediate to xor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/optimize.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 9303bb5b64..e18fe37ad2 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1807,6 +1807,7 @@ static bool fold_dup2(OptContext *ctx, TCGOp *op) static bool fold_eqv(OptContext *ctx, TCGOp *op) { uint64_t s_mask; + TempOptInfo *t1, *t2; if (fold_const2_commutative(ctx, op) || fold_xi_to_x(ctx, op, -1) || @@ -1814,8 +1815,28 @@ static bool fold_eqv(OptContext *ctx, TCGOp *op) return true; } - s_mask = arg_info(op->args[1])->s_mask - & arg_info(op->args[2])->s_mask; + t2 = arg_info(op->args[2]); + if (ti_is_const(t2)) { + /* Fold eqv r,x,i to xor r,x,~i. */ + switch (ctx->type) { + case TCG_TYPE_I32: + case TCG_TYPE_I64: + op->opc = INDEX_op_xor; + break; + case TCG_TYPE_V64: + case TCG_TYPE_V128: + case TCG_TYPE_V256: + op->opc = INDEX_op_xor_vec; + break; + default: + g_assert_not_reached(); + } + op->args[2] = arg_new_constant(ctx, ~ti_const_val(t2)); + return fold_xor(ctx, op); + } + + t1 = arg_info(op->args[1]); + s_mask = t1->s_mask & t2->s_mask; return fold_masks_s(ctx, op, s_mask); } From 18bc92091641880121d43584093ff207b0c44cfb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 15:37:43 -0800 Subject: [PATCH 0380/2760] tcg: Convert eqv to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 26 +++++++++------------ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 4 ++++ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 4 ++++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 22 +++++++++--------- tcg/riscv/tcg-target-con-set.h | 1 - tcg/riscv/tcg-target-con-str.h | 1 - tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 37 ++++++++++++------------------ tcg/s390x/tcg-target-con-set.h | 1 - tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 39 +++++++++++++------------------- tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 8 +++---- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 14 +++++++++--- 27 files changed, 89 insertions(+), 106 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 8469a9446f..c17aafc3bb 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 @@ -43,7 +42,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index d575635fe0..83813af63e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2157,6 +2157,17 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_eqv(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3510, EON, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_eqv, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2285,17 +2296,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); break; - case INDEX_op_eqv_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_eqv_i64: - if (c2) { - tcg_out_logicali(s, I3404_EORI, ext, a0, a1, ~a2); - } else { - tcg_out_insn(s, 3510, EON, ext, a0, a1, a2); - } - break; - case INDEX_op_not_i64: case INDEX_op_not_i32: tcg_out_insn(s, 3510, ORN, ext, a0, TCG_REG_XZR, a1); @@ -3030,10 +3030,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: - return C_O1_I2(r, r, rL); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 39dcc87fe8..9ed85798e7 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 98cb3cf5e2..57acb44c7a 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1881,6 +1881,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index e525f23c05..0183cafe61 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -31,7 +31,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 @@ -55,7 +54,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 9126f9aeff..1fd53cb94f 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2633,6 +2633,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index fb1142958c..d3697ee0f2 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -45,7 +44,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 296a84af79..6bd1826ef9 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1328,6 +1328,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index b3dfa390f9..9745c64db1 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_nor_i32 1 -#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) @@ -61,7 +60,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_nor_i64 1 -#define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 30fb01cb0a..3a3c72cb11 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1712,6 +1712,10 @@ static const TCGOutOpBinary outop_andc = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 6f3ab41ebb..8ede19bfad 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -23,7 +23,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 1 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -48,7 +47,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 16d3dbd841..203f089cd7 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2954,6 +2954,17 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_eqv(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, EQV | SAB(a1, a0, a2)); +} + +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_eqv, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3086,15 +3097,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_eqv_i32: - if (const_args[2]) { - tcg_out_xori32(s, args[0], args[1], ~args[2]); - break; - } - /* FALLTHRU */ - case INDEX_op_eqv_i64: - tcg_out32(s, EQV | SAB(args[1], args[0], args[2])); - break; case INDEX_op_nand_i32: case INDEX_op_nand_i64: tcg_out32(s, NAND | SAB(args[1], args[0], args[2])); @@ -4150,7 +4152,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_eqv_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: @@ -4175,7 +4176,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nor_i32: case INDEX_op_muluh_i32: case INDEX_op_mulsh_i32: - case INDEX_op_eqv_i64: case INDEX_op_nand_i64: case INDEX_op_nor_i64: case INDEX_op_div_i64: diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index f1f5d415f7..21f8833b3b 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -16,7 +16,6 @@ C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) -C_O1_I2(r, r, rJ) C_O1_I2(r, rz, rN) C_O1_I2(r, rz, rz) C_N1_I2(r, r, rM) diff --git a/tcg/riscv/tcg-target-con-str.h b/tcg/riscv/tcg-target-con-str.h index 2f9700638c..1956f75f9a 100644 --- a/tcg/riscv/tcg-target-con-str.h +++ b/tcg/riscv/tcg-target-con-str.h @@ -16,7 +16,6 @@ REGS('v', ALL_VECTOR_REGS) * CONST(letter, TCG_CT_CONST_* bit set) */ CONST('I', TCG_CT_CONST_S12) -CONST('J', TCG_CT_CONST_J12) CONST('K', TCG_CT_CONST_S5) CONST('L', TCG_CT_CONST_CMP_VI) CONST('N', TCG_CT_CONST_N12) diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 7b8f4386c9..2faa2895e3 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_eqv_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_eqv_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index c981ea389a..ff2a412821 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -115,9 +115,8 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define TCG_CT_CONST_S12 0x100 #define TCG_CT_CONST_N12 0x200 #define TCG_CT_CONST_M12 0x400 -#define TCG_CT_CONST_J12 0x800 -#define TCG_CT_CONST_S5 0x1000 -#define TCG_CT_CONST_CMP_VI 0x2000 +#define TCG_CT_CONST_S5 0x800 +#define TCG_CT_CONST_CMP_VI 0x1000 #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) #define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32) @@ -416,13 +415,6 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) { return 1; } - /* - * Inverse of sign extended from 12 bits: ~[-0x800, 0x7ff]. - * Used to map ANDN back to ANDI, etc. - */ - if ((ct & TCG_CT_CONST_J12) && ~val >= -0x800 && ~val <= 0x7ff) { - return 1; - } /* * Sign extended from 5 bits: [-0x10, 0x0f]. * Used for vector-immediate. @@ -2013,6 +2005,18 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_eqv(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_XNOR, a0, a1, a2); +} + +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_zbb_rrr, + .out_rrr = tgen_eqv, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2139,15 +2143,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_XORI, a0, a1, ~a2); - } else { - tcg_out_opc_reg(s, OPC_XNOR, a0, a1, a2); - } - break; - case INDEX_op_not_i32: case INDEX_op_not_i64: tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1); @@ -2710,10 +2705,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: - return C_O1_I2(r, r, rJ); - case INDEX_op_sub_i32: case INDEX_op_sub_i64: return C_O1_I2(r, rz, rN); diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index 39903a60ad..86af067965 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -31,7 +31,6 @@ C_O1_I2(r, r, rC) C_O1_I2(r, r, rI) C_O1_I2(r, r, rJ) C_O1_I2(r, r, rK) -C_O1_I2(r, r, rNK) C_O1_I2(r, r, rNKR) C_O1_I2(r, rZ, r) C_O1_I2(v, v, r) diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 850c16a164..722a2ede1c 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -34,7 +34,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_eqv_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i32 0 @@ -57,7 +56,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_eqv_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index bedad7137b..6c32aa286d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2242,6 +2242,22 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_eqv(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, NXRK, a0, a1, a2); + } else { + tcg_out_insn(s, RRFa, NXGRK, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_misc3_rrr, + .out_rrr = tgen_eqv, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2376,15 +2392,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_eqv_i32: - a0 = args[0], a1 = args[1], a2 = (uint32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tcg_out_insn(s, RIL, XILF, a0, ~a2); - } else { - tcg_out_insn(s, RRFa, NXRK, a0, a1, a2); - } - break; case INDEX_op_nand_i32: tcg_out_insn(s, RRFa, NNRK, args[0], args[1], args[2]); break; @@ -2595,15 +2602,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_eqv_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - tgen_xori(s, a0, ~a2); - } else { - tcg_out_insn(s, RRFa, NXGRK, a0, a1, a2); - } - break; case INDEX_op_nand_i64: tcg_out_insn(s, RRFa, NNGRK, args[0], args[1], args[2]); break; @@ -3290,11 +3288,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: return C_O1_I2(r, r, ri); - case INDEX_op_eqv_i32: - return C_O1_I2(r, r, ri); - case INDEX_op_eqv_i64: - return C_O1_I2(r, r, rNK); - case INDEX_op_nand_i32: case INDEX_op_nand_i64: case INDEX_op_nor_i32: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 8e20e4cdeb..2ec5f5657c 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_eqv_i32 0 #define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 0 @@ -44,7 +43,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 8a6c9852d2..6d7ee19db1 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1333,6 +1333,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index df9c951262..a5808dcc0a 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 0 -#define TCG_TARGET_HAS_eqv_i64 0 #define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b10f61435c..8008b0d3e0 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -680,7 +680,7 @@ void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_eqv_i32) { + if (tcg_op_supported(INDEX_op_eqv_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2); } else { tcg_gen_xor_i32(ret, arg1, arg2); @@ -2279,7 +2279,7 @@ void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (TCG_TARGET_HAS_eqv_i64) { + } else if (tcg_op_supported(INDEX_op_eqv_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2); } else { tcg_gen_xor_i64(ret, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 3c4905aa68..53158a292b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1007,6 +1007,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_eqv_i32, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_eqv_i64, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -2273,8 +2275,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_not_i32: return TCG_TARGET_HAS_not_i32; - case INDEX_op_eqv_i32: - return TCG_TARGET_HAS_eqv_i32; case INDEX_op_nand_i32: return TCG_TARGET_HAS_nand_i32; case INDEX_op_nor_i32: @@ -2344,8 +2344,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_not_i64: return TCG_TARGET_HAS_not_i64; - case INDEX_op_eqv_i64: - return TCG_TARGET_HAS_eqv_i64; case INDEX_op_nand_i64: return TCG_TARGET_HAS_nand_i64; case INDEX_op_nor_i64: @@ -5438,6 +5436,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_eqv_i32: + case INDEX_op_eqv_i64: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index cb300c4846..26a271e71f 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -555,12 +555,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | ~regs[r2]; break; -#if TCG_TARGET_HAS_eqv_i32 || TCG_TARGET_HAS_eqv_i64 CASE_32_64(eqv) tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] ^ regs[r2]); break; -#endif #if TCG_TARGET_HAS_nand_i32 || TCG_TARGET_HAS_nand_i64 CASE_32_64(nand) tci_args_rrr(insn, &r0, &r1, &r2); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index d247774e52..2c0876a0fd 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -12,7 +12,6 @@ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_eqv_i32 1 #define TCG_TARGET_HAS_nand_i32 1 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -34,7 +33,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_eqv_i64 1 #define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 0a912744b3..4c9e055614 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -95,8 +95,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: case INDEX_op_nand_i32: case INDEX_op_nand_i64: case INDEX_op_nor_i32: @@ -662,6 +660,17 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_eqv(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_eqv_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_eqv = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_eqv, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -739,7 +748,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(eqv) /* Optional (TCG_TARGET_HAS_eqv_*). */ CASE_32_64(nand) /* Optional (TCG_TARGET_HAS_nand_*). */ CASE_32_64(nor) /* Optional (TCG_TARGET_HAS_nor_*). */ CASE_32_64(shl) From 5c0968a7e1da73f91f148d563a29af529427c5a5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 15:47:53 -0800 Subject: [PATCH 0381/2760] tcg: Merge INDEX_op_eqv_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index a4aa4f8824..fe149e012d 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -323,7 +323,7 @@ Logical - | *t0* = *t1* & ~\ *t2* - * - eqv_i32/i64 *t0*, *t1*, *t2* + * - eqv *t0*, *t1*, *t2* - | *t0* = ~(*t1* ^ *t2*), or equivalently, *t0* = *t1* ^ ~\ *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 8f6115bedb..c6869de244 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -42,6 +42,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) +DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -93,7 +94,6 @@ DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) DEF(neg_i32, 1, 1, 0, 0) -DEF(eqv_i32, 1, 2, 0, 0) DEF(nand_i32, 1, 2, 0, 0) DEF(nor_i32, 1, 2, 0, 0) DEF(clz_i32, 1, 2, 0, 0) @@ -147,7 +147,6 @@ DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) DEF(neg_i64, 1, 1, 0, 0) -DEF(eqv_i64, 1, 2, 0, 0) DEF(nand_i64, 1, 2, 0, 0) DEF(nor_i64, 1, 2, 0, 0) DEF(clz_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index e18fe37ad2..47898b7086 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -489,7 +489,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_orc_vec: return x | ~y; - CASE_OP_32_64_VEC(eqv): + case INDEX_op_eqv: + case INDEX_op_eqv_vec: return ~(x ^ y); CASE_OP_32_64_VEC(nand): @@ -2929,7 +2930,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_dup2_vec: done = fold_dup2(&ctx, op); break; - CASE_OP_32_64_VEC(eqv): + case INDEX_op_eqv: + case INDEX_op_eqv_vec: done = fold_eqv(&ctx, op); break; CASE_OP_32_64(extract): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 8008b0d3e0..2520a60cee 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -680,8 +680,8 @@ void tcg_gen_andc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_eqv_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_eqv_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_eqv, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_eqv, ret, arg1, arg2); } else { tcg_gen_xor_i32(ret, arg1, arg2); tcg_gen_not_i32(ret, ret); @@ -2279,8 +2279,8 @@ void tcg_gen_eqv_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_eqv_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_eqv_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (tcg_op_supported(INDEX_op_eqv_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_eqv_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_eqv, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_eqv, ret, arg1, arg2); } else { tcg_gen_xor_i64(ret, arg1, arg2); tcg_gen_not_i64(ret, ret); diff --git a/tcg/tcg.c b/tcg/tcg.c index 53158a292b..6642429df6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1007,8 +1007,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_eqv_i32, TCGOutOpBinary, outop_eqv), - OUTOP(INDEX_op_eqv_i64, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -5436,8 +5435,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: + case INDEX_op_eqv: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index 26a271e71f..d2baa8d3fc 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -555,7 +555,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] | ~regs[r2]; break; - CASE_32_64(eqv) + case INDEX_op_eqv: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] ^ regs[r2]); break; @@ -1079,6 +1079,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_eqv: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: @@ -1086,8 +1087,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_eqv_i32: - case INDEX_op_eqv_i64: case INDEX_op_nand_i32: case INDEX_op_nand_i64: case INDEX_op_nor_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4c9e055614..fe3450373e 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -663,7 +663,7 @@ static const TCGOutOpBinary outop_andc = { static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_eqv_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_eqv, a0, a1, a2); } static const TCGOutOpBinary outop_eqv = { From e5a3162cb6c1aec4f47c6b51671e989b5975f345 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 16:18:19 -0800 Subject: [PATCH 0382/2760] tcg: Convert nand to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 4 ++++ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 4 ++++ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 4 ++++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 17 +++++++++++------ tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 4 ++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 24 ++++++++++++++++-------- tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 8 ++++---- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 14 +++++++++++--- 24 files changed, 72 insertions(+), 45 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index c17aafc3bb..2acc9bd3b7 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -42,7 +41,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 83813af63e..093bb0afb7 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2168,6 +2168,10 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 9ed85798e7..8d7b176993 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 57acb44c7a..55d28be15b 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1885,6 +1885,10 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 0183cafe61..93552f2337 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -31,7 +31,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -54,7 +53,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1fd53cb94f..51c3711ee5 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2637,6 +2637,10 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index d3697ee0f2..55249de465 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 6bd1826ef9..814596608a 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1332,6 +1332,10 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 9745c64db1..2f8325d56f 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_nor_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muluh_i32 1 @@ -60,7 +59,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_nor_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 3a3c72cb11..46cf393041 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1716,6 +1716,10 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 8ede19bfad..810f20d120 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -23,7 +23,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nand_i32 1 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 have_isa_3_00 @@ -47,7 +46,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 have_isa_3_00 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 203f089cd7..29341aff2c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2965,6 +2965,17 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_nand(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, NAND | SAB(a1, a0, a2)); +} + +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nand, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3097,10 +3108,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nand_i32: - case INDEX_op_nand_i64: - tcg_out32(s, NAND | SAB(args[1], args[0], args[2])); - break; case INDEX_op_nor_i32: case INDEX_op_nor_i64: tcg_out32(s, NOR | SAB(args[1], args[0], args[2])); @@ -4172,11 +4179,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_nand_i32: case INDEX_op_nor_i32: case INDEX_op_muluh_i32: case INDEX_op_mulsh_i32: - case INDEX_op_nand_i64: case INDEX_op_nor_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 2faa2895e3..3736a52d56 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i32 (cpuinfo & CPUINFO_ZBB) @@ -43,7 +42,6 @@ #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index ff2a412821..cb2b58e495 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2017,6 +2017,10 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 722a2ede1c..d8afd73814 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -34,7 +34,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_nand_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 @@ -56,7 +55,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_nand_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 0 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 6c32aa286d..33eece6e5d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2258,6 +2258,22 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_nand(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, NNRK, a0, a1, a2); + } else { + tcg_out_insn(s, RRFa, NNGRK, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_misc3_rrr, + .out_rrr = tgen_nand, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2392,9 +2408,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nand_i32: - tcg_out_insn(s, RRFa, NNRK, args[0], args[1], args[2]); - break; case INDEX_op_nor_i32: tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[2]); break; @@ -2602,9 +2615,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nand_i64: - tcg_out_insn(s, RRFa, NNGRK, args[0], args[1], args[2]); - break; case INDEX_op_nor_i64: tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[2]); break; @@ -3288,8 +3298,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: return C_O1_I2(r, r, ri); - case INDEX_op_nand_i32: - case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: return C_O1_I2(r, r, r); diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 2ec5f5657c..9bc0474107 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nand_i32 0 #define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 @@ -43,7 +42,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 6d7ee19db1..02c443efb9 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1337,6 +1337,10 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index a5808dcc0a..e2a99067ac 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 0 -#define TCG_TARGET_HAS_nand_i64 0 #define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 2520a60cee..3921bac48d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -690,7 +690,7 @@ void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_nand_i32) { + if (tcg_op_supported(INDEX_op_nand_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2); } else { tcg_gen_and_i32(ret, arg1, arg2); @@ -2292,7 +2292,7 @@ void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (TCG_TARGET_HAS_nand_i64) { + } else if (tcg_op_supported(INDEX_op_nand_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2); } else { tcg_gen_and_i64(ret, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 6642429df6..50361864aa 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1008,6 +1008,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_nand_i32, TCGOutOpBinary, outop_nand), + OUTOP(INDEX_op_nand_i64, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -2274,8 +2276,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_not_i32: return TCG_TARGET_HAS_not_i32; - case INDEX_op_nand_i32: - return TCG_TARGET_HAS_nand_i32; case INDEX_op_nor_i32: return TCG_TARGET_HAS_nor_i32; case INDEX_op_clz_i32: @@ -2343,8 +2343,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_not_i64: return TCG_TARGET_HAS_not_i64; - case INDEX_op_nand_i64: - return TCG_TARGET_HAS_nand_i64; case INDEX_op_nor_i64: return TCG_TARGET_HAS_nor_i64; case INDEX_op_clz_i64: @@ -5436,6 +5434,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: + case INDEX_op_nand_i32: + case INDEX_op_nand_i64: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index d2baa8d3fc..8be59a0193 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -559,12 +559,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] ^ regs[r2]); break; -#if TCG_TARGET_HAS_nand_i32 || TCG_TARGET_HAS_nand_i64 CASE_32_64(nand) tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] & regs[r2]); break; -#endif #if TCG_TARGET_HAS_nor_i32 || TCG_TARGET_HAS_nor_i64 CASE_32_64(nor) tci_args_rrr(insn, &r0, &r1, &r2); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 2c0876a0fd..8be70297f5 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -12,7 +12,6 @@ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_nand_i32 1 #define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -33,7 +32,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_nand_i64 1 #define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index fe3450373e..2a5c72705d 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -95,8 +95,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_nand_i32: - case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: case INDEX_op_shl_i32: @@ -671,6 +669,17 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_nand(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_nand_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_nand = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nand, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -748,7 +757,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(nand) /* Optional (TCG_TARGET_HAS_nand_*). */ CASE_32_64(nor) /* Optional (TCG_TARGET_HAS_nor_*). */ CASE_32_64(shl) CASE_32_64(shr) From 59379a45af1f4d62fc8c1ae0ddee988f47075787 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 20:32:54 -0800 Subject: [PATCH 0383/2760] tcg: Merge INDEX_op_nand_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index fe149e012d..7703dfbc51 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -327,7 +327,7 @@ Logical - | *t0* = ~(*t1* ^ *t2*), or equivalently, *t0* = *t1* ^ ~\ *t2* - * - nand_i32/i64 *t0*, *t1*, *t2* + * - nand *t0*, *t1*, *t2* - | *t0* = ~(*t1* & *t2*) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index c6869de244..1acdd7cfda 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) +DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -94,7 +95,6 @@ DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) DEF(neg_i32, 1, 1, 0, 0) -DEF(nand_i32, 1, 2, 0, 0) DEF(nor_i32, 1, 2, 0, 0) DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) @@ -147,7 +147,6 @@ DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) DEF(neg_i64, 1, 1, 0, 0) -DEF(nand_i64, 1, 2, 0, 0) DEF(nor_i64, 1, 2, 0, 0) DEF(clz_i64, 1, 2, 0, 0) DEF(ctz_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 47898b7086..e8e6a0c2ce 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -493,7 +493,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_eqv_vec: return ~(x ^ y); - CASE_OP_32_64_VEC(nand): + case INDEX_op_nand: + case INDEX_op_nand_vec: return ~(x & y); CASE_OP_32_64_VEC(nor): @@ -2992,7 +2993,8 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(mulu2): done = fold_multiply2(&ctx, op); break; - CASE_OP_32_64_VEC(nand): + case INDEX_op_nand: + case INDEX_op_nand_vec: done = fold_nand(&ctx, op); break; CASE_OP_32_64(neg): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 3921bac48d..57782864fa 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -690,8 +690,8 @@ void tcg_gen_eqv_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_nand_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_nand_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_nand, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_nand, ret, arg1, arg2); } else { tcg_gen_and_i32(ret, arg1, arg2); tcg_gen_not_i32(ret, ret); @@ -2292,8 +2292,8 @@ void tcg_gen_nand_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_nand_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_nand_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (tcg_op_supported(INDEX_op_nand_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_nand_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_nand, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_nand, ret, arg1, arg2); } else { tcg_gen_and_i64(ret, arg1, arg2); tcg_gen_not_i64(ret, ret); diff --git a/tcg/tcg.c b/tcg/tcg.c index 50361864aa..72e9175d06 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1008,8 +1008,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), - OUTOP(INDEX_op_nand_i32, TCGOutOpBinary, outop_nand), - OUTOP(INDEX_op_nand_i64, TCGOutOpBinary, outop_nand), + OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -5434,8 +5433,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: - case INDEX_op_nand_i32: - case INDEX_op_nand_i64: + case INDEX_op_nand: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index 8be59a0193..9886ddf001 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -559,7 +559,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] ^ regs[r2]); break; - CASE_32_64(nand) + case INDEX_op_nand: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] & regs[r2]); break; @@ -1078,6 +1078,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: + case INDEX_op_nand: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: @@ -1085,8 +1086,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_nand_i32: - case INDEX_op_nand_i64: case INDEX_op_nor_i32: case INDEX_op_nor_i64: case INDEX_op_div_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2a5c72705d..34a44a7674 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -672,7 +672,7 @@ static const TCGOutOpBinary outop_eqv = { static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_nand_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_nand, a0, a1, a2); } static const TCGOutOpBinary outop_nand = { From 8fb04b8295994e7416a222906939696d496638f3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 20:37:25 -0800 Subject: [PATCH 0384/2760] tcg/loongarch64: Do not accept constant argument to nor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The instruction set does not implement nor with immediate. There is no reason to pretend that we do. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target.c.inc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 814596608a..e74c7d8a87 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1425,12 +1425,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_nor_i32: case INDEX_op_nor_i64: - if (c2) { - tcg_out_opc_ori(s, a0, a1, a2); - tcg_out_opc_nor(s, a0, a0, TCG_REG_ZERO); - } else { - tcg_out_opc_nor(s, a0, a1, a2); - } + tcg_out_opc_nor(s, a0, a1, a2); break; case INDEX_op_extract_i32: @@ -2314,8 +2309,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_nor_i32: case INDEX_op_nor_i64: - /* LoongArch reg-imm bitops have their imms ZERO-extended */ - return C_O1_I2(r, r, rU); + return C_O1_I2(r, r, r); case INDEX_op_clz_i32: case INDEX_op_clz_i64: From 3f6b223012f62bb3f73552bea4489383f08cdc23 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 20:57:21 -0800 Subject: [PATCH 0385/2760] tcg: Convert nor to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 4 ++++ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 20 +++++++++++--------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 17 +++++++++++------ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 18 +++++++++++------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 4 ++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 28 ++++++++++++++++------------ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 8 ++++---- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 14 +++++++++++--- 24 files changed, 86 insertions(+), 65 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 2acc9bd3b7..240fcac2cc 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -41,7 +40,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 -#define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 093bb0afb7..30cad937b7 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2172,6 +2172,10 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 8d7b176993..e80711ee40 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 -#define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions #define TCG_TARGET_HAS_ctpop_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 55d28be15b..8e9edeb7c6 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1889,6 +1889,10 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 93552f2337..b27f853dcd 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -31,7 +31,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 have_popcnt @@ -53,7 +52,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 have_popcnt diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 51c3711ee5..9185f6879c 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2641,6 +2641,10 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 55249de465..7860432489 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -43,7 +42,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e74c7d8a87..dc4ed0e8b0 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1336,6 +1336,17 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static void tgen_nor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_nor(s, a0, a1, a2); +} + +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nor, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1423,11 +1434,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_nor(s, a0, a1, TCG_REG_ZERO); break; - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: - tcg_out_opc_nor(s, a0, a1, a2); - break; - case INDEX_op_extract_i32: if (a2 == 0 && args[3] <= 12) { tcg_out_opc_andi(s, a0, a1, (1 << args[3]) - 1); @@ -2307,10 +2313,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: - return C_O1_I2(r, r, r); - case INDEX_op_clz_i32: case INDEX_op_clz_i64: case INDEX_op_ctz_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 2f8325d56f..987f83f761 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -42,7 +42,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muluh_i32 1 @@ -58,7 +57,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 46cf393041..bfe329b3ef 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1720,6 +1720,17 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static void tgen_nor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_NOR, a0, a1, a2); +} + +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nor, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1848,10 +1859,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; } goto do_binaryv; - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: - i1 = OPC_NOR; - goto do_binaryv; case INDEX_op_mul_i32: if (use_mips32_instructions) { @@ -2237,7 +2244,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_nor_i32: case INDEX_op_setcond_i32: case INDEX_op_mul_i64: case INDEX_op_mulsh_i64: @@ -2246,7 +2252,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: - case INDEX_op_nor_i64: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rz); case INDEX_op_muls2_i32: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 810f20d120..6be6d7f994 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -23,7 +23,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06 @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 29341aff2c..c3366e4316 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2976,6 +2976,17 @@ static const TCGOutOpBinary outop_nand = { .out_rrr = tgen_nand, }; +static void tgen_nor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, NOR | SAB(a1, a0, a2)); +} + +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nor, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3108,11 +3119,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: - tcg_out32(s, NOR | SAB(args[1], args[0], args[2])); - break; - case INDEX_op_clz_i32: tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1], args[2], const_args[2]); @@ -4179,10 +4185,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_nor_i32: case INDEX_op_muluh_i32: case INDEX_op_mulsh_i32: - case INDEX_op_nor_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 3736a52d56..0fcf940a8a 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -25,7 +25,6 @@ #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i32 (cpuinfo & CPUINFO_ZBB) @@ -42,7 +41,6 @@ #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index cb2b58e495..887f20d4cb 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2021,6 +2021,10 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index d8afd73814..374db3cf9d 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -34,7 +34,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_nor_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 1 @@ -55,7 +54,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) -#define TCG_TARGET_HAS_nor_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 33eece6e5d..29570d3be1 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2274,6 +2274,22 @@ static const TCGOutOpBinary outop_nand = { .out_rrr = tgen_nand, }; +static void tgen_nor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, NORK, a0, a1, a2); + } else { + tcg_out_insn(s, RRFa, NOGRK, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_misc3_rrr, + .out_rrr = tgen_nor, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2408,10 +2424,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nor_i32: - tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[2]); - break; - case INDEX_op_neg_i32: tcg_out_insn(s, RR, LCR, args[0], args[1]); break; @@ -2615,10 +2627,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_nor_i64: - tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[2]); - break; - case INDEX_op_neg_i64: tcg_out_insn(s, RRE, LCGR, args[0], args[1]); break; @@ -3298,10 +3306,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: return C_O1_I2(r, r, ri); - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: - return C_O1_I2(r, r, r); - case INDEX_op_mul_i32: return (HAVE_FACILITY(MISC_INSN_EXT2) ? C_O1_I2(r, r, ri) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 9bc0474107..35ae536879 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_not_i32 1 -#define TCG_TARGET_HAS_nor_i32 0 #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -42,7 +41,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 1 -#define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 02c443efb9..1ebff04af4 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1341,6 +1341,10 @@ static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index e2a99067ac..7de13ef383 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_not_i64 0 -#define TCG_TARGET_HAS_nor_i64 0 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 57782864fa..ac939bb4ea 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -700,7 +700,7 @@ void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_nor_i32) { + if (tcg_op_supported(INDEX_op_nor_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2); } else { tcg_gen_or_i32(ret, arg1, arg2); @@ -2305,7 +2305,7 @@ void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (TCG_TARGET_HAS_nor_i64) { + } else if (tcg_op_supported(INDEX_op_nor_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2); } else { tcg_gen_or_i64(ret, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 72e9175d06..d9807b77dc 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1009,6 +1009,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), + OUTOP(INDEX_op_nor_i32, TCGOutOpBinary, outop_nor), + OUTOP(INDEX_op_nor_i64, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -2275,8 +2277,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_not_i32: return TCG_TARGET_HAS_not_i32; - case INDEX_op_nor_i32: - return TCG_TARGET_HAS_nor_i32; case INDEX_op_clz_i32: return TCG_TARGET_HAS_clz_i32; case INDEX_op_ctz_i32: @@ -2342,8 +2342,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_not_i64: return TCG_TARGET_HAS_not_i64; - case INDEX_op_nor_i64: - return TCG_TARGET_HAS_nor_i64; case INDEX_op_clz_i64: return TCG_TARGET_HAS_clz_i64; case INDEX_op_ctz_i64: @@ -5434,6 +5432,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_nand: + case INDEX_op_nor_i32: + case INDEX_op_nor_i64: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index 9886ddf001..3ea93fa5a6 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -563,12 +563,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] & regs[r2]); break; -#if TCG_TARGET_HAS_nor_i32 || TCG_TARGET_HAS_nor_i64 CASE_32_64(nor) tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] | regs[r2]); break; -#endif /* Arithmetic operations (32 bit). */ diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 8be70297f5..13c9dc3dfa 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -12,7 +12,6 @@ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_nor_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 @@ -32,7 +31,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_nor_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 34a44a7674..a0f4c58be8 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -95,8 +95,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: @@ -680,6 +678,17 @@ static const TCGOutOpBinary outop_nand = { .out_rrr = tgen_nand, }; +static void tgen_nor(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_nor_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_nor = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_nor, +}; + static void tgen_or(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -757,7 +766,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sub) CASE_32_64(mul) - CASE_32_64(nor) /* Optional (TCG_TARGET_HAS_nor_*). */ CASE_32_64(shl) CASE_32_64(shr) CASE_32_64(sar) From 3a8c4e9e53c6f4aa7c590971950000b174e74fa1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 21:02:17 -0800 Subject: [PATCH 0386/2760] tcg: Merge INDEX_op_nor_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 6 ++++-- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 15 insertions(+), 17 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 7703dfbc51..26d464fa38 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -331,7 +331,7 @@ Logical - | *t0* = ~(*t1* & *t2*) - * - nor_i32/i64 *t0*, *t1*, *t2* + * - nor *t0*, *t1*, *t2* - | *t0* = ~(*t1* | *t2*) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 1acdd7cfda..aa9ed393c9 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) +DEF(nor, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -95,7 +96,6 @@ DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) DEF(neg_i32, 1, 1, 0, 0) -DEF(nor_i32, 1, 2, 0, 0) DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) @@ -147,7 +147,6 @@ DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) DEF(neg_i64, 1, 1, 0, 0) -DEF(nor_i64, 1, 2, 0, 0) DEF(clz_i64, 1, 2, 0, 0) DEF(ctz_i64, 1, 2, 0, 0) DEF(ctpop_i64, 1, 1, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index e8e6a0c2ce..e4c319fe45 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -497,7 +497,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_nand_vec: return ~(x & y); - CASE_OP_32_64_VEC(nor): + case INDEX_op_nor: + case INDEX_op_nor_vec: return ~(x | y); case INDEX_op_clz_i32: @@ -3000,7 +3001,8 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(neg): done = fold_neg(&ctx, op); break; - CASE_OP_32_64_VEC(nor): + case INDEX_op_nor: + case INDEX_op_nor_vec: done = fold_nor(&ctx, op); break; CASE_OP_32_64_VEC(not): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ac939bb4ea..228aa8f088 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -700,8 +700,8 @@ void tcg_gen_nand_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_nor_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_nor_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_nor_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_nor, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_nor, ret, arg1, arg2); } else { tcg_gen_or_i32(ret, arg1, arg2); tcg_gen_not_i32(ret, ret); @@ -2305,8 +2305,8 @@ void tcg_gen_nor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_nor_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_LOW(arg2)); tcg_gen_nor_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), TCGV_HIGH(arg2)); - } else if (tcg_op_supported(INDEX_op_nor_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_nor_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_nor, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_nor, ret, arg1, arg2); } else { tcg_gen_or_i64(ret, arg1, arg2); tcg_gen_not_i64(ret, ret); diff --git a/tcg/tcg.c b/tcg/tcg.c index d9807b77dc..c0178030ce 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1009,8 +1009,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), - OUTOP(INDEX_op_nor_i32, TCGOutOpBinary, outop_nor), - OUTOP(INDEX_op_nor_i64, TCGOutOpBinary, outop_nor), + OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), @@ -5432,8 +5431,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_nand: - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: + case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index 3ea93fa5a6..ff129266c2 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -563,7 +563,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] & regs[r2]); break; - CASE_32_64(nor) + case INDEX_op_nor: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] | regs[r2]); break; @@ -1077,6 +1077,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_nand: + case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_xor: @@ -1084,8 +1085,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: - case INDEX_op_nor_i32: - case INDEX_op_nor_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_rem_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index a0f4c58be8..dec51692f0 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -681,7 +681,7 @@ static const TCGOutOpBinary outop_nand = { static void tgen_nor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_nor_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_nor, a0, a1, a2); } static const TCGOutOpBinary outop_nor = { From a3b37bc6faafe5932739c997b2b34a8f6dd57bfd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 2 Jan 2025 13:25:15 -0800 Subject: [PATCH 0387/2760] tcg/arm: Fix constraints for sub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 7536b82d288 we lost the rI constraint that allowed the use of RSB to perform reg = imm - reg. At the same time, drop support for reg = reg - imm, which is now transformed generically to addition, and need not be handled by the backend. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/arm/tcg-target-con-set.h | 1 + tcg/arm/tcg-target.c.inc | 11 ++++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tcg/arm/tcg-target-con-set.h b/tcg/arm/tcg-target-con-set.h index 229ae258ac..f46a8444fb 100644 --- a/tcg/arm/tcg-target-con-set.h +++ b/tcg/arm/tcg-target-con-set.h @@ -30,6 +30,7 @@ C_O1_I2(r, r, rI) C_O1_I2(r, r, rIK) C_O1_I2(r, r, rIN) C_O1_I2(r, r, ri) +C_O1_I2(r, rI, r) C_O1_I2(r, rZ, rZ) C_O1_I2(w, 0, w) C_O1_I2(w, w, w) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 8e9edeb7c6..47c09ff2b1 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1984,12 +1984,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; case INDEX_op_sub_i32: if (const_args[1]) { - if (const_args[2]) { - tcg_out_movi32(s, COND_AL, args[0], args[1] - args[2]); - } else { - tcg_out_dat_rI(s, COND_AL, ARITH_RSB, - args[0], args[2], args[1], 1); - } + tcg_out_dat_imm(s, COND_AL, ARITH_RSB, + args[0], args[2], encode_imm_nofail(args[1])); } else { tcg_out_dat_rIN(s, COND_AL, ARITH_SUB, ARITH_ADD, args[0], args[1], args[2], const_args[2]); @@ -2234,10 +2230,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_sub_i32: case INDEX_op_setcond_i32: case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); + case INDEX_op_sub_i32: + return C_O1_I2(r, rI, r); case INDEX_op_clz_i32: case INDEX_op_ctz_i32: From 3f057e24006fbc5eaf42278ba9368d383a1c7bed Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 21:57:43 -0800 Subject: [PATCH 0388/2760] tcg: Convert sub to TCGOutOpSubtract Create a special subclass for sub, because two backends can support "subtract from immediate". Drop all backend support for an immediate as the second operand, as we transform sub to add during optimize. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 24 +++++++-------- tcg/arm/tcg-target.c.inc | 29 +++++++++++------- tcg/i386/tcg-target.c.inc | 23 +++++++------- tcg/loongarch64/tcg-target.c.inc | 32 +++++++++----------- tcg/mips/tcg-target-con-set.h | 1 - tcg/mips/tcg-target.c.inc | 31 ++++++++----------- tcg/ppc/tcg-target-con-set.h | 3 +- tcg/ppc/tcg-target.c.inc | 52 +++++++++++--------------------- tcg/riscv/tcg-target-con-set.h | 1 - tcg/riscv/tcg-target-con-str.h | 1 - tcg/riscv/tcg-target.c.inc | 45 +++++++++------------------ tcg/s390x/tcg-target.c.inc | 41 +++++++++++-------------- tcg/sparc64/tcg-target.c.inc | 16 +++++++--- tcg/tcg.c | 30 ++++++++++++++++-- tcg/tci/tcg-target.c.inc | 14 +++++++-- 15 files changed, 169 insertions(+), 174 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 30cad937b7..dfe67c1261 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2205,6 +2205,17 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3502, SUB, type, a0, a1, a2); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2290,15 +2301,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: - if (c2) { - tgen_addi(s, ext, a0, a1, -a2); - } else { - tcg_out_insn(s, 3502, SUB, ext, a0, a1, a2); - } - break; - case INDEX_op_neg_i64: case INDEX_op_neg_i32: tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); @@ -3014,10 +3016,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: - return C_O1_I2(r, r, rA); - case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: case INDEX_op_negsetcond_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 47c09ff2b1..13b78f0ada 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1915,6 +1915,24 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_SUB, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_subfi(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_RSB, a0, a2, encode_imm_nofail(a1)); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, rI, r), + .out_rrr = tgen_sub, + .out_rir = tgen_subfi, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1982,15 +2000,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[c], ARITH_MOV, ARITH_MVN, args[0], 0, args[3], const_args[3]); break; - case INDEX_op_sub_i32: - if (const_args[1]) { - tcg_out_dat_imm(s, COND_AL, ARITH_RSB, - args[0], args[2], encode_imm_nofail(args[1])); - } else { - tcg_out_dat_rIN(s, COND_AL, ARITH_SUB, ARITH_ADD, - args[0], args[1], args[2], const_args[2]); - } - break; case INDEX_op_add2_i32: a0 = args[0], a1 = args[1], a2 = args[2]; a3 = args[3], a4 = args[4], a5 = args[5]; @@ -2233,8 +2242,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i32: case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); - case INDEX_op_sub_i32: - return C_O1_I2(r, rI, r); case INDEX_op_clz_i32: case INDEX_op_ctz_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 9185f6879c..104f1b010a 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2669,6 +2669,18 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_SUB + rexw, a0, a2); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, 0, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2770,15 +2782,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(sub): - c = ARITH_SUB; - if (const_a2) { - tgen_arithi(s, c + rexw, a0, a2, 0); - } else { - tgen_arithr(s, c + rexw, a0, a2); - } - break; - OP_32_64(mul): if (const_a2) { int32_t val; @@ -3689,8 +3692,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: return C_O1_I2(r, 0, re); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index dc4ed0e8b0..f01b19463b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1376,6 +1376,21 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sub_w(s, a0, a1, a2); + } else { + tcg_out_opc_sub_d(s, a0, a1, a2); + } +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1596,21 +1611,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_sub_i32: - if (c2) { - tcg_out_addi(s, TCG_TYPE_I32, a0, a1, -a2); - } else { - tcg_out_opc_sub_w(s, a0, a1, a2); - } - break; - case INDEX_op_sub_i64: - if (c2) { - tcg_out_addi(s, TCG_TYPE_I64, a0, a1, -a2); - } else { - tcg_out_opc_sub_d(s, a0, a1, a2); - } - break; - case INDEX_op_neg_i32: tcg_out_opc_sub_w(s, a0, TCG_REG_ZERO, a1); break; @@ -2324,10 +2324,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) /* Must deposit into the same register as input */ return C_O1_I2(r, 0, rz); - case INDEX_op_sub_i32: case INDEX_op_setcond_i32: return C_O1_I2(r, rz, ri); - case INDEX_op_sub_i64: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index 06ab04cc4d..248bc95d9b 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -24,7 +24,6 @@ C_O1_I2(r, r, rI) C_O1_I2(r, r, rIK) C_O1_I2(r, r, rJ) C_O1_I2(r, r, rzW) -C_O1_I2(r, rz, rN) C_O1_I2(r, rz, rz) C_O1_I4(r, rz, rz, rz, 0) C_O1_I4(r, rz, rz, rz, rz) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index bfe329b3ef..15c5661fb8 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1753,6 +1753,18 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_SUBU : OPC_DSUBU; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1844,22 +1856,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - do_binaryv: - tcg_out_opc_reg(s, i1, a0, a1, a2); - break; - - case INDEX_op_sub_i32: - i1 = OPC_SUBU, i2 = OPC_ADDIU; - goto do_subtract; - case INDEX_op_sub_i64: - i1 = OPC_DSUBU, i2 = OPC_DADDIU; - do_subtract: - if (c2) { - tcg_out_opc_imm(s, i2, a0, a1, -a2); - break; - } - goto do_binaryv; - case INDEX_op_mul_i32: if (use_mips32_instructions) { tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2); @@ -2234,9 +2230,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: - return C_O1_I2(r, rz, rN); case INDEX_op_mul_i32: case INDEX_op_mulsh_i32: case INDEX_op_muluh_i32: diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h index 453abde6c1..77a1038d51 100644 --- a/tcg/ppc/tcg-target-con-set.h +++ b/tcg/ppc/tcg-target-con-set.h @@ -22,8 +22,7 @@ C_O1_I1(v, r) C_O1_I1(v, v) C_O1_I1(v, vr) C_O1_I2(r, 0, rZ) -C_O1_I2(r, rI, ri) -C_O1_I2(r, rI, rT) +C_O1_I2(r, rI, r) C_O1_I2(r, r, r) C_O1_I2(r, r, ri) C_O1_I2(r, r, rC) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index c3366e4316..bfbfdc2dfa 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3016,6 +3016,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, SUBF | TAB(a0, a2, a1)); +} + +static void tgen_subfi(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_out32(s, SUBFIC | TAI(a0, a2, a1)); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, rI, r), + .out_rrr = tgen_sub, + .out_rir = tgen_subfi, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3104,21 +3122,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_sub_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[1]) { - if (const_args[2]) { - tcg_out_movi(s, TCG_TYPE_I32, a0, a1 - a2); - } else { - tcg_out32(s, SUBFIC | TAI(a0, a2, a1)); - } - } else if (const_args[2]) { - tgen_addi(s, type, a0, a1, (int32_t)-a2); - } else { - tcg_out32(s, SUBF | TAB(a0, a2, a1)); - } - break; - case INDEX_op_clz_i32: tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1], args[2], const_args[2]); @@ -3231,21 +3234,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, NOR | SAB(args[1], args[0], args[1])); break; - case INDEX_op_sub_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[1]) { - if (const_args[2]) { - tcg_out_movi(s, TCG_TYPE_I64, a0, a1 - a2); - } else { - tcg_out32(s, SUBFIC | TAI(a0, a2, a1)); - } - } else if (const_args[2]) { - tgen_addi(s, type, a0, a1, -a2); - } else { - tcg_out32(s, SUBF | TAB(a0, a2, a1)); - } - break; - case INDEX_op_shl_i64: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -4195,10 +4183,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muluh_i64: return C_O1_I2(r, r, r); - case INDEX_op_sub_i32: - return C_O1_I2(r, rI, ri); - case INDEX_op_sub_i64: - return C_O1_I2(r, rI, rT); case INDEX_op_clz_i32: case INDEX_op_ctz_i32: case INDEX_op_clz_i64: diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index 21f8833b3b..f3a6f7a7ed 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -16,7 +16,6 @@ C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) -C_O1_I2(r, rz, rN) C_O1_I2(r, rz, rz) C_N1_I2(r, r, rM) C_O1_I4(r, r, rI, rM, rM) diff --git a/tcg/riscv/tcg-target-con-str.h b/tcg/riscv/tcg-target-con-str.h index 1956f75f9a..c04e15ddfa 100644 --- a/tcg/riscv/tcg-target-con-str.h +++ b/tcg/riscv/tcg-target-con-str.h @@ -18,5 +18,4 @@ REGS('v', ALL_VECTOR_REGS) CONST('I', TCG_CT_CONST_S12) CONST('K', TCG_CT_CONST_S5) CONST('L', TCG_CT_CONST_CMP_VI) -CONST('N', TCG_CT_CONST_N12) CONST('M', TCG_CT_CONST_M12) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 887f20d4cb..54da432ab1 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -113,10 +113,9 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) } #define TCG_CT_CONST_S12 0x100 -#define TCG_CT_CONST_N12 0x200 -#define TCG_CT_CONST_M12 0x400 -#define TCG_CT_CONST_S5 0x800 -#define TCG_CT_CONST_CMP_VI 0x1000 +#define TCG_CT_CONST_M12 0x200 +#define TCG_CT_CONST_S5 0x400 +#define TCG_CT_CONST_CMP_VI 0x800 #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 32) #define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32) @@ -400,13 +399,6 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_S12) && val >= -0x800 && val <= 0x7ff) { return 1; } - /* - * Sign extended from 12 bits, negated: [-0x7ff, 0x800]. - * Used for subtraction, where a constant must be handled by ADDI. - */ - if ((ct & TCG_CT_CONST_N12) && val >= -0x7ff && val <= 0x800) { - return 1; - } /* * Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff]. * Used by addsub2 and movcond, which may need the negative value, @@ -2055,6 +2047,18 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SUBW : OPC_SUB; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2136,21 +2140,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_sub_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_ADDIW, a0, a1, -a2); - } else { - tcg_out_opc_reg(s, OPC_SUBW, a0, a1, a2); - } - break; - case INDEX_op_sub_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_ADDI, a0, a1, -a2); - } else { - tcg_out_opc_reg(s, OPC_SUB, a0, a1, a2); - } - break; - case INDEX_op_not_i32: case INDEX_op_not_i64: tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1); @@ -2713,10 +2702,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: - return C_O1_I2(r, rz, rN); - case INDEX_op_mul_i32: case INDEX_op_mulsh_i32: case INDEX_op_muluh_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 29570d3be1..662984f733 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2331,6 +2331,23 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, SGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, SR, a0, a2); + } else { + tcg_out_insn(s, RRFa, SRK, a0, a1, a2); + } +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2413,17 +2430,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_sub_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tgen_addi(s, type, a0, a1, (int32_t)-a2); - } else if (a0 == a1) { - tcg_out_insn(s, RR, SR, a0, a2); - } else { - tcg_out_insn(s, RRFa, SRK, a0, a1, a2); - } - break; - case INDEX_op_neg_i32: tcg_out_insn(s, RR, LCR, args[0], args[1]); break; @@ -2618,15 +2624,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_sub_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tgen_addi(s, type, a0, a1, -a2); - } else { - tcg_out_insn(s, RRFa, SGRK, a0, a1, a2); - } - break; - case INDEX_op_neg_i64: tcg_out_insn(s, RRE, LCGR, args[0], args[1]); break; @@ -3302,10 +3299,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_clz_i64: return C_O1_I2(r, r, rI); - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: - return C_O1_I2(r, r, ri); - case INDEX_op_mul_i32: return (HAVE_FACILITY(MISC_INSN_EXT2) ? C_O1_I2(r, r, ri) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 1ebff04af4..04b2b3b195 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1374,6 +1374,17 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_SUB); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1446,9 +1457,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st32_i64: tcg_out_ldst(s, a0, a1, a2, STW); break; - OP_32_64(sub): - c = ARITH_SUB; - goto gen_arith; case INDEX_op_shl_i32: c = SHIFT_SLL; do_shift32: @@ -1660,8 +1668,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_div_i64: case INDEX_op_divu_i32: case INDEX_op_divu_i64: - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index c0178030ce..d7a44ac1b1 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -986,6 +986,14 @@ typedef struct TCGOutOpBinary { TCGReg a0, TCGReg a1, tcg_target_long a2); } TCGOutOpBinary; +typedef struct TCGOutOpSubtract { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2); + void (*out_rir)(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2); +} TCGOutOpSubtract; + #include "tcg-target.c.inc" #ifndef CONFIG_TCG_INTERPRETER @@ -1012,6 +1020,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_sub_i32, TCGOutOpSubtract, outop_sub), + OUTOP(INDEX_op_sub_i64, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -2231,7 +2241,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_sub_i32: case INDEX_op_neg_i32: case INDEX_op_mul_i32: case INDEX_op_shl_i32: @@ -2301,7 +2310,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_sub_i64: case INDEX_op_neg_i64: case INDEX_op_mul_i64: case INDEX_op_shl_i64: @@ -5449,6 +5457,24 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_sub_i32: + case INDEX_op_sub_i64: + { + const TCGOutOpSubtract *out = &outop_sub; + + /* + * Constants should never appear in the second source operand. + * These are folded to add with negative constant. + */ + tcg_debug_assert(!const_args[2]); + if (const_args[1]) { + out->out_rir(s, type, new_args[0], new_args[1], new_args[2]); + } else { + out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); + } + } + break; + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index dec51692f0..353994e83f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -91,8 +91,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: case INDEX_op_shl_i32: @@ -711,6 +709,17 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_sub(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_sub_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpSubtract outop_sub = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sub, +}; + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -764,7 +773,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(sub) CASE_32_64(mul) CASE_32_64(shl) CASE_32_64(shr) From 60f34f55f1a708c071774bd7f837163d6b686867 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 22:06:32 -0800 Subject: [PATCH 0389/2760] tcg: Merge INDEX_op_sub_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 4 ++-- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 10 +++------- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 12 insertions(+), 18 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 26d464fa38..96b7f05919 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -265,7 +265,7 @@ Arithmetic - | *t0* = *t1* + *t2* - * - sub_i32/i64 *t0*, *t1*, *t2* + * - sub *t0*, *t1*, *t2* - | *t0* = *t1* - *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index aa9ed393c9..1be9b01caf 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -47,6 +47,7 @@ DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) +DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) DEF(setcond_i32, 1, 2, 1, 0) @@ -62,7 +63,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(sub_i32, 1, 2, 0, 0) DEF(mul_i32, 1, 2, 0, 0) DEF(div_i32, 1, 2, 0, 0) DEF(divu_i32, 1, 2, 0, 0) @@ -116,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(sub_i64, 1, 2, 0, 0) DEF(mul_i64, 1, 2, 0, 0) DEF(div_i64, 1, 2, 0, 0) DEF(divu_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index e4c319fe45..718809ab8d 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -427,7 +427,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_add: return x + y; - CASE_OP_32_64(sub): + case INDEX_op_sub: return x - y; CASE_OP_32_64(mul): @@ -3066,7 +3066,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(sextract): done = fold_sextract(&ctx, op); break; - CASE_OP_32_64(sub): + case INDEX_op_sub: done = fold_sub(&ctx, op); break; case INDEX_op_sub_vec: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 228aa8f088..15faf4dc57 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -377,7 +377,7 @@ void tcg_gen_addi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_sub_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_sub_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_sub, ret, arg1, arg2); } void tcg_gen_subfi_i32(TCGv_i32 ret, int32_t arg1, TCGv_i32 arg2) @@ -1565,7 +1565,7 @@ void tcg_gen_add_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_sub_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_sub_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_sub, ret, arg1, arg2); } else { tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2)); diff --git a/tcg/tcg.c b/tcg/tcg.c index d7a44ac1b1..b31e9798c5 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1020,8 +1020,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), - OUTOP(INDEX_op_sub_i32, TCGOutOpSubtract, outop_sub), - OUTOP(INDEX_op_sub_i64, TCGOutOpSubtract, outop_sub), + OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -4010,10 +4009,8 @@ liveness_pass_1(TCGContext *s) opc_new = INDEX_op_add; goto do_addsub2; case INDEX_op_sub2_i32: - opc_new = INDEX_op_sub_i32; - goto do_addsub2; case INDEX_op_sub2_i64: - opc_new = INDEX_op_sub_i64; + opc_new = INDEX_op_sub; do_addsub2: nb_iargs = 4; nb_oargs = 2; @@ -5457,8 +5454,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: + case INDEX_op_sub: { const TCGOutOpSubtract *out = &outop_sub; diff --git a/tcg/tci.c b/tcg/tci.c index ff129266c2..508d1405cd 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -527,7 +527,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] + regs[r2]; break; - CASE_32_64(sub) + case INDEX_op_sub: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] - regs[r2]; break; @@ -1080,9 +1080,8 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: + case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_sub_i32: - case INDEX_op_sub_i64: case INDEX_op_mul_i32: case INDEX_op_mul_i64: case INDEX_op_div_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 353994e83f..67a46c6321 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -712,7 +712,7 @@ static const TCGOutOpBinary outop_orc = { static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_sub_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_sub, a0, a1, a2); } static const TCGOutOpSubtract outop_sub = { From e126a91c38f85750d84cabf27f44c055e17ef6df Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 22:37:07 -0800 Subject: [PATCH 0390/2760] tcg: Convert neg to TCGOutOpUnary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 18 +++++++++++------- tcg/arm/tcg-target.c.inc | 14 ++++++++++---- tcg/i386/tcg-target.c.inc | 16 +++++++++++----- tcg/loongarch64/tcg-target.c.inc | 19 ++++++++++--------- tcg/mips/tcg-target.c.inc | 18 ++++++++++-------- tcg/ppc/tcg-target.c.inc | 17 ++++++++++------- tcg/riscv/tcg-target.c.inc | 19 ++++++++++--------- tcg/s390x/tcg-target.c.inc | 22 ++++++++++++++-------- tcg/sparc64/tcg-target.c.inc | 15 ++++++++++----- tcg/tcg.c | 21 +++++++++++++++++++-- tcg/tci/tcg-target.c.inc | 13 ++++++++++--- 11 files changed, 125 insertions(+), 67 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index dfe67c1261..cf7a3f2632 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2235,6 +2235,17 @@ static const TCGOutOpBinary outop_xor = { }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_sub(s, type, a0, TCG_REG_XZR, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2301,11 +2312,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_neg_i64: - case INDEX_op_neg_i32: - tcg_out_insn(s, 3502, SUB, ext, a0, TCG_REG_XZR, a1); - break; - case INDEX_op_not_i64: case INDEX_op_not_i32: tcg_out_insn(s, 3510, ORN, ext, a0, TCG_REG_XZR, a1); @@ -2990,8 +2996,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: case INDEX_op_bswap16_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 13b78f0ada..5ea4488606 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1951,6 +1951,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_subfi(s, type, a0, 0, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2040,9 +2050,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_neg_i32: - tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0); - break; case INDEX_op_not_i32: tcg_out_dat_reg(s, COND_AL, ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0)); @@ -2226,7 +2233,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_neg_i32: case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 104f1b010a..082aa982fb 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2701,6 +2701,17 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, a0); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2900,9 +2911,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(neg): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NEG, a0); - break; OP_32_64(not): tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, a0); break; @@ -3719,8 +3727,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: case INDEX_op_extrh_i64_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index f01b19463b..31ec7262e0 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1409,6 +1409,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_sub(s, type, a0, TCG_REG_ZERO, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1611,13 +1621,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_neg_i32: - tcg_out_opc_sub_w(s, a0, TCG_REG_ZERO, a1); - break; - case INDEX_op_neg_i64: - tcg_out_opc_sub_d(s, a0, TCG_REG_ZERO, a1); - break; - case INDEX_op_mul_i32: tcg_out_opc_mul_w(s, a0, a1, a2); break; @@ -2272,8 +2275,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: case INDEX_op_extract_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 15c5661fb8..0fda255a7b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1783,6 +1783,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_sub(s, type, a0, TCG_REG_ZERO, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1975,12 +1985,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0); break; - case INDEX_op_neg_i32: - i1 = OPC_SUBU; - goto do_unary; - case INDEX_op_neg_i64: - i1 = OPC_DSUBU; - goto do_unary; case INDEX_op_not_i32: case INDEX_op_not_i64: i1 = OPC_NOR; @@ -2195,7 +2199,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_neg_i32: case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: @@ -2208,7 +2211,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_neg_i64: case INDEX_op_not_i64: case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index bfbfdc2dfa..da45436a5a 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3052,6 +3052,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out32(s, NEG | RT(a0) | RA(a1)); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3224,11 +3234,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: - tcg_out32(s, NEG | RT(args[0]) | RA(args[1])); - break; - case INDEX_op_not_i32: case INDEX_op_not_i64: tcg_out32(s, NOR | SAB(args[1], args[0], args[1])); @@ -4119,7 +4124,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: case INDEX_op_ctpop_i32: - case INDEX_op_neg_i32: case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: @@ -4133,7 +4137,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: case INDEX_op_ctpop_i64: - case INDEX_op_neg_i64: case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 54da432ab1..4e16c44aa5 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2077,6 +2077,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_sub(s, type, a0, TCG_REG_ZERO, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2145,13 +2155,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1); break; - case INDEX_op_neg_i32: - tcg_out_opc_reg(s, OPC_SUBW, a0, TCG_REG_ZERO, a1); - break; - case INDEX_op_neg_i64: - tcg_out_opc_reg(s, OPC_SUB, a0, TCG_REG_ZERO, a1); - break; - case INDEX_op_mul_i32: tcg_out_opc_reg(s, OPC_MULW, a0, a1, a2); break; @@ -2660,7 +2663,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: case INDEX_op_not_i32: - case INDEX_op_neg_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i64: @@ -2669,7 +2671,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: case INDEX_op_not_i64: - case INDEX_op_neg_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 662984f733..08e65834d7 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2373,6 +2373,20 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori_3, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, LCR, a0, a1); + } else { + tcg_out_insn(s, RRE, LCGR, a0, a1); + } +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2430,9 +2444,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_neg_i32: - tcg_out_insn(s, RR, LCR, args[0], args[1]); - break; case INDEX_op_not_i32: tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[1]); break; @@ -2624,9 +2635,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_neg_i64: - tcg_out_insn(s, RRE, LCGR, args[0], args[1]); - break; case INDEX_op_not_i64: tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[1]); break; @@ -3323,8 +3331,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 04b2b3b195..a3926ea1c3 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1403,6 +1403,16 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_sub(s, type, a0, TCG_REG_G0, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1473,9 +1483,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, c = ARITH_UMUL; goto gen_arith; - OP_32_64(neg): - c = ARITH_SUB; - goto gen_arith1; OP_32_64(not): c = ARITH_ORN; goto gen_arith1; @@ -1639,8 +1646,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: diff --git a/tcg/tcg.c b/tcg/tcg.c index b31e9798c5..b5de69e4a9 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -986,6 +986,11 @@ typedef struct TCGOutOpBinary { TCGReg a0, TCGReg a1, tcg_target_long a2); } TCGOutOpBinary; +typedef struct TCGOutOpUnary { + TCGOutOp base; + void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); +} TCGOutOpUnary; + typedef struct TCGOutOpSubtract { TCGOutOp base; void (*out_rrr)(TCGContext *s, TCGType type, @@ -1017,6 +1022,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), + OUTOP(INDEX_op_neg_i32, TCGOutOpUnary, outop_neg), + OUTOP(INDEX_op_neg_i64, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), @@ -2240,7 +2247,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_neg_i32: case INDEX_op_mul_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: @@ -2309,7 +2315,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_neg_i64: case INDEX_op_mul_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: @@ -5471,6 +5476,18 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_neg_i32: + case INDEX_op_neg_i64: + { + const TCGOutOpUnary *out = + container_of(all_outop[op->opc], TCGOutOpUnary, base); + + /* Constants should have been folded. */ + tcg_debug_assert(!const_args[1]); + out->out_rr(s, type, new_args[0], new_args[1]); + } + break; + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 67a46c6321..200b256e73 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,8 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: @@ -731,6 +729,16 @@ static const TCGOutOpBinary outop_xor = { .out_rrr = tgen_xor, }; +static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_op_rr(s, glue(INDEX_op_neg_i,TCG_TARGET_REG_BITS), a0, a1); +} + +static const TCGOutOpUnary outop_neg = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_neg, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -804,7 +812,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rl(s, opc, TCG_REG_TMP, arg_label(args[3])); break; - CASE_32_64(neg) /* Optional (TCG_TARGET_HAS_neg_*). */ CASE_32_64(not) /* Optional (TCG_TARGET_HAS_not_*). */ CASE_32_64(ctpop) /* Optional (TCG_TARGET_HAS_ctpop_*). */ case INDEX_op_bswap32_i32: /* Optional (TCG_TARGET_HAS_bswap32_i32). */ From 6971358747d8998a5770d1bf997495d3061d6c6a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 22:48:57 -0800 Subject: [PATCH 0391/2760] tcg: Merge INDEX_op_neg_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 30 ++++++------------------------ tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 6 ++---- tcg/tci.c | 11 +++++------ tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 18 insertions(+), 40 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 96b7f05919..fb51691538 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -269,7 +269,7 @@ Arithmetic - | *t0* = *t1* - *t2* - * - neg_i32/i64 *t0*, *t1* + * - neg *t0*, *t1* - | *t0* = -*t1* (two's complement) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 1be9b01caf..13b7650cec 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) +DEF(neg, 1, 1, 0, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) @@ -95,7 +96,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) DEF(not_i32, 1, 1, 0, 0) -DEF(neg_i32, 1, 1, 0, 0) DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) @@ -145,7 +145,6 @@ DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(not_i64, 1, 1, 0, 0) -DEF(neg_i64, 1, 1, 0, 0) DEF(clz_i64, 1, 2, 0, 0) DEF(ctz_i64, 1, 2, 0, 0) DEF(ctpop_i64, 1, 1, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 718809ab8d..eb360e2b63 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -478,7 +478,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) CASE_OP_32_64_VEC(not): return ~x; - CASE_OP_32_64(neg): + case INDEX_op_neg: return -x; case INDEX_op_andc: @@ -2314,25 +2314,12 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) break; } if (convert) { - TCGOpcode neg_opc; - if (!inv && !neg) { return tcg_opt_gen_mov(ctx, op, op->args[0], op->args[1]); } - switch (ctx->type) { - case TCG_TYPE_I32: - neg_opc = INDEX_op_neg_i32; - break; - case TCG_TYPE_I64: - neg_opc = INDEX_op_neg_i64; - break; - default: - g_assert_not_reached(); - } - if (!inv) { - op->opc = neg_opc; + op->opc = INDEX_op_neg; } else if (neg) { op->opc = INDEX_op_add; op->args[2] = arg_new_constant(ctx, -1); @@ -2348,7 +2335,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode neg_opc, shr_opc; + TCGOpcode shr_opc; TCGOpcode uext_opc = 0, sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; @@ -2371,7 +2358,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: shr_opc = INDEX_op_shr_i32; - neg_opc = INDEX_op_neg_i32; if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) { uext_opc = INDEX_op_extract_i32; } @@ -2381,7 +2367,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) break; case TCG_TYPE_I64: shr_opc = INDEX_op_shr_i64; - neg_opc = INDEX_op_neg_i64; if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) { uext_opc = INDEX_op_extract_i64; } @@ -2432,7 +2417,7 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op2->args[1] = ret; op2->args[2] = arg_new_constant(ctx, 1); } else if (neg) { - op2 = opt_insert_after(ctx, op, neg_opc, 2); + op2 = opt_insert_after(ctx, op, INDEX_op_neg, 2); op2->args[0] = ret; op2->args[1] = ret; } @@ -2644,11 +2629,8 @@ static bool fold_sub_to_neg(OptContext *ctx, TCGOp *op) switch (ctx->type) { case TCG_TYPE_I32: - neg_op = INDEX_op_neg_i32; - have_neg = true; - break; case TCG_TYPE_I64: - neg_op = INDEX_op_neg_i64; + neg_op = INDEX_op_neg; have_neg = true; break; case TCG_TYPE_V64: @@ -2998,7 +2980,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_nand_vec: done = fold_nand(&ctx, op); break; - CASE_OP_32_64(neg): + case INDEX_op_neg: done = fold_neg(&ctx, op); break; case INDEX_op_nor: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 15faf4dc57..cb2eb9ae52 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -396,7 +396,7 @@ void tcg_gen_subi_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_neg_i32(TCGv_i32 ret, TCGv_i32 arg) { - tcg_gen_op2_i32(INDEX_op_neg_i32, ret, arg); + tcg_gen_op2_i32(INDEX_op_neg, ret, arg); } void tcg_gen_and_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) @@ -1691,7 +1691,7 @@ void tcg_gen_subi_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) void tcg_gen_neg_i64(TCGv_i64 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op2_i64(INDEX_op_neg_i64, ret, arg); + tcg_gen_op2_i64(INDEX_op_neg, ret, arg); } else { TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_sub2_i32(TCGV_LOW(ret), TCGV_HIGH(ret), diff --git a/tcg/tcg.c b/tcg/tcg.c index b5de69e4a9..92d185558f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1022,8 +1022,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), - OUTOP(INDEX_op_neg_i32, TCGOutOpUnary, outop_neg), - OUTOP(INDEX_op_neg_i64, TCGOutOpUnary, outop_neg), + OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), @@ -5476,8 +5475,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: + case INDEX_op_neg: { const TCGOutOpUnary *out = container_of(all_outop[op->opc], TCGOutOpUnary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 508d1405cd..c736691e9f 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -567,6 +567,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ~(regs[r1] | regs[r2]); break; + case INDEX_op_neg: + tci_args_rr(insn, &r0, &r1); + regs[r0] = -regs[r1]; + break; /* Arithmetic operations (32 bit). */ @@ -697,10 +701,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = ~regs[r1]; break; #endif - CASE_32_64(neg) - tci_args_rr(insn, &r0, &r1); - regs[r0] = -regs[r1]; - break; #if TCG_TARGET_REG_BITS == 64 /* Load/store operations (64 bit). */ @@ -1054,6 +1054,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_mov: + case INDEX_op_neg: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: @@ -1063,8 +1064,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_bswap64_i64: case INDEX_op_not_i32: case INDEX_op_not_i64: - case INDEX_op_neg_i32: - case INDEX_op_neg_i64: case INDEX_op_ctpop_i32: case INDEX_op_ctpop_i64: tci_args_rr(insn, &r0, &r1); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 200b256e73..c42f9dff11 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -731,7 +731,7 @@ static const TCGOutOpBinary outop_xor = { static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { - tcg_out_op_rr(s, glue(INDEX_op_neg_i,TCG_TARGET_REG_BITS), a0, a1); + tcg_out_op_rr(s, INDEX_op_neg, a0, a1); } static const TCGOutOpUnary outop_neg = { From 592982bf04cfa92dc4c992056c7330ac46f4882f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 23:37:54 -0800 Subject: [PATCH 0392/2760] tcg: Convert not to TCGOutOpUnary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 17 ++++++++++------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 15 ++++++++++----- tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 17 +++++++++++------ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 17 ++++++++++------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 20 ++++++++++---------- tcg/optimize.c | 4 ++-- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 17 ++++++++++------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 17 ++++++++++------- tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 25 ++++++++++++++++--------- tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 20 ++++++++++---------- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 10 ++++++---- tcg/tcg.c | 8 ++++---- tcg/tci.c | 2 -- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 13 ++++++++++--- 25 files changed, 119 insertions(+), 103 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 240fcac2cc..7f18727686 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -17,7 +17,6 @@ #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -38,7 +37,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index cf7a3f2632..97b444bc17 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2245,6 +2245,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_orc(s, type, a0, TCG_REG_XZR, a1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2312,11 +2322,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_not_i64: - case INDEX_op_not_i32: - tcg_out_insn(s, 3510, ORN, ext, a0, TCG_REG_XZR, a1); - break; - case INDEX_op_mul_i64: case INDEX_op_mul_i32: tcg_out_insn(s, 3509, MADD, ext, a0, a1, a2, TCG_REG_XZR); @@ -2996,8 +3001,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_bswap16_i64: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index e80711ee40..e766c6d628 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -26,7 +26,6 @@ extern bool use_neon_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 5ea4488606..2477b1c4ab 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1961,6 +1961,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MVN, a0, 0, a1, SHIFT_IMM_LSL(0)); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2050,10 +2060,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_not_i32: - tcg_out_dat_reg(s, COND_AL, - ARITH_MVN, args[0], 0, args[1], SHIFT_IMM_LSL(0)); - break; case INDEX_op_mul_i32: tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); break; @@ -2233,7 +2239,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index b27f853dcd..3d36fe58f2 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -30,7 +30,6 @@ #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 have_popcnt @@ -51,7 +50,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 have_popcnt diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 082aa982fb..24fef09c9e 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2712,6 +2712,17 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, a0); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2911,10 +2922,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(not): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, a0); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I32); break; @@ -3727,8 +3734,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 7860432489..ffacb41e80 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -24,7 +24,6 @@ #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -41,7 +40,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 31ec7262e0..c24882b6ba 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1419,6 +1419,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_nor(s, type, a0, a1, TCG_REG_ZERO); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1454,11 +1464,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_srai_d(s, a0, a1, 32); break; - case INDEX_op_not_i32: - case INDEX_op_not_i64: - tcg_out_opc_nor(s, a0, a1, TCG_REG_ZERO); - break; - case INDEX_op_extract_i32: if (a2 == 0 && args[3] <= 12) { tcg_out_opc_andi(s, a0, a1, (1 << args[3]) - 1); @@ -2275,8 +2280,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_extract_i32: case INDEX_op_extract_i64: case INDEX_op_sextract_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 987f83f761..9d8e0fb8df 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -41,7 +41,6 @@ extern bool use_mips32r2_instructions; /* optional instructions */ #define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muluh_i32 1 @@ -56,7 +55,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 0fda255a7b..4942855189 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1793,6 +1793,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_nor(s, type, a0, TCG_REG_ZERO, a1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1985,14 +1995,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0); break; - case INDEX_op_not_i32: - case INDEX_op_not_i64: - i1 = OPC_NOR; - goto do_unary; - do_unary: - tcg_out_opc_reg(s, i1, a0, TCG_REG_ZERO, a1); - break; - case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: tcg_out_bswap16(s, a0, a1, a2); @@ -2199,7 +2201,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: @@ -2211,7 +2212,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_not_i64: case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: diff --git a/tcg/optimize.c b/tcg/optimize.c index eb360e2b63..b4a675ea37 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1104,11 +1104,11 @@ static bool fold_to_not(OptContext *ctx, TCGOp *op, int idx) switch (ctx->type) { case TCG_TYPE_I32: not_op = INDEX_op_not_i32; - have_not = TCG_TARGET_HAS_not_i32; + have_not = tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0); break; case TCG_TYPE_I64: not_op = INDEX_op_not_i64; - have_not = TCG_TARGET_HAS_not_i64; + have_not = tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0); break; case TCG_TYPE_V64: case TCG_TYPE_V128: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 6be6d7f994..7ebcb49a19 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -22,7 +22,6 @@ #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06 @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index da45436a5a..38cbe5223b 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3062,6 +3062,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_nor(s, type, a0, a1, a1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3234,11 +3244,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_not_i32: - case INDEX_op_not_i64: - tcg_out32(s, NOR | SAB(args[1], args[0], args[1])); - break; - case INDEX_op_shl_i64: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -4124,7 +4129,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: case INDEX_op_ctpop_i32: - case INDEX_op_not_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: @@ -4137,7 +4141,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: case INDEX_op_ctpop_i64: - case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 0fcf940a8a..e3018717ea 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -24,7 +24,6 @@ #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i32 (cpuinfo & CPUINFO_ZBB) @@ -40,7 +39,6 @@ #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_clz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 4e16c44aa5..5e9e14815d 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2087,6 +2087,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_xori(s, type, a0, a1, -1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2150,11 +2160,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_not_i32: - case INDEX_op_not_i64: - tcg_out_opc_imm(s, OPC_XORI, a0, a1, -1); - break; - case INDEX_op_mul_i32: tcg_out_opc_reg(s, OPC_MULW, a0, a1, a2); break; @@ -2662,7 +2667,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_not_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i64: @@ -2670,7 +2674,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_not_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 374db3cf9d..e5c132cf12 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -33,7 +33,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_not_i32 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 1 @@ -53,7 +52,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_not_i64 HAVE_FACILITY(MISC_INSN_EXT3) #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 08e65834d7..98bf3ee19e 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2387,6 +2387,22 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_nor(s, type, a0, a1, a1); +} + +static TCGConstraintSetIndex cset_not(TCGType type, unsigned flags) +{ + return HAVE_FACILITY(MISC_INSN_EXT3) ? C_O1_I1(r, r) : C_NotImplemented; +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_not, + .out_rr = tgen_not, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -2444,10 +2460,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_not_i32: - tcg_out_insn(s, RRFa, NORK, args[0], args[1], args[1]); - break; - case INDEX_op_mul_i32: a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; if (const_args[2]) { @@ -2635,9 +2647,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_not_i64: - tcg_out_insn(s, RRFa, NOGRK, args[0], args[1], args[1]); - break; case INDEX_op_bswap64_i64: tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; @@ -3331,8 +3340,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 35ae536879..df87249df2 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -19,7 +19,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_rot_i32 0 #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -40,7 +39,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index a3926ea1c3..5819dc44fe 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1413,6 +1413,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tgen_orc(s, type, a0, TCG_REG_G0, a1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1483,10 +1493,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, c = ARITH_UMUL; goto gen_arith; - OP_32_64(not): - c = ARITH_ORN; - goto gen_arith1; - case INDEX_op_div_i32: tcg_out_div32(s, a0, a1, a2, c2, 0); break; @@ -1600,10 +1606,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_arithc(s, a0, a1, a2, c2, c); break; - gen_arith1: - tcg_out_arithc(s, a0, TCG_REG_G0, a1, const_args[1], c); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -1646,8 +1648,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i64: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 7de13ef383..a84ed1313a 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_not_i64 0 #define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index cb2eb9ae52..e0f8ab28b8 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -461,7 +461,8 @@ void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) /* Some cases can be optimized here. */ if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); - } else if (arg2 == -1 && TCG_TARGET_HAS_not_i32) { + } else if (arg2 == -1 && + tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0)) { /* Don't recurse with tcg_gen_not_i32. */ tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1); } else { @@ -471,7 +472,7 @@ void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_not_i32) { + if (tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0)) { tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg); } else { tcg_gen_xori_i32(ret, arg, -1); @@ -1762,7 +1763,8 @@ void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) /* Some cases can be optimized here. */ if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); - } else if (arg2 == -1 && TCG_TARGET_HAS_not_i64) { + } else if (arg2 == -1 && + tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0)) { /* Don't recurse with tcg_gen_not_i64. */ tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1); } else { @@ -2252,7 +2254,7 @@ void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg)); tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); - } else if (TCG_TARGET_HAS_not_i64) { + } else if (tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0)) { tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); } else { tcg_gen_xori_i64(ret, arg, -1); diff --git a/tcg/tcg.c b/tcg/tcg.c index 92d185558f..acd666d30b 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1024,6 +1024,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), + OUTOP(INDEX_op_not_i32, TCGOutOpUnary, outop_not), + OUTOP(INDEX_op_not_i64, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -2287,8 +2289,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: return TCG_TARGET_HAS_bswap32_i32; - case INDEX_op_not_i32: - return TCG_TARGET_HAS_not_i32; case INDEX_op_clz_i32: return TCG_TARGET_HAS_clz_i32; case INDEX_op_ctz_i32: @@ -2350,8 +2350,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: return TCG_TARGET_HAS_bswap64_i64; - case INDEX_op_not_i64: - return TCG_TARGET_HAS_not_i64; case INDEX_op_clz_i64: return TCG_TARGET_HAS_clz_i64; case INDEX_op_ctz_i64: @@ -5476,6 +5474,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_neg: + case INDEX_op_not_i32: + case INDEX_op_not_i64: { const TCGOutOpUnary *out = container_of(all_outop[op->opc], TCGOutOpUnary, base); diff --git a/tcg/tci.c b/tcg/tci.c index c736691e9f..25ad37fcd5 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -695,12 +695,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = bswap32(regs[r1]); break; #endif -#if TCG_TARGET_HAS_not_i32 || TCG_TARGET_HAS_not_i64 CASE_32_64(not) tci_args_rr(insn, &r0, &r1); regs[r0] = ~regs[r1]; break; -#endif #if TCG_TARGET_REG_BITS == 64 /* Load/store operations (64 bit). */ diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 13c9dc3dfa..f147da5c0e 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 -#define TCG_TARGET_HAS_not_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 @@ -34,7 +33,6 @@ #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 -#define TCG_TARGET_HAS_not_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index c42f9dff11..d3da498098 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -55,8 +55,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: @@ -739,6 +737,16 @@ static const TCGOutOpUnary outop_neg = { .out_rr = tgen_neg, }; +static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_op_rr(s, glue(INDEX_op_not_i,TCG_TARGET_REG_BITS), a0, a1); +} + +static const TCGOutOpUnary outop_not = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_not, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -812,7 +820,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rl(s, opc, TCG_REG_TMP, arg_label(args[3])); break; - CASE_32_64(not) /* Optional (TCG_TARGET_HAS_not_*). */ CASE_32_64(ctpop) /* Optional (TCG_TARGET_HAS_ctpop_*). */ case INDEX_op_bswap32_i32: /* Optional (TCG_TARGET_HAS_bswap32_i32). */ case INDEX_op_bswap64_i64: /* Optional (TCG_TARGET_HAS_bswap64_i64). */ From 5c62d3779b8b1075782672751165c0e4f716762f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 6 Jan 2025 23:46:47 -0800 Subject: [PATCH 0393/2760] tcg: Merge INDEX_op_not_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 13 ++++++------- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- tcg/tci.c | 11 +++++------ tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 24 insertions(+), 29 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index fb51691538..96dddc5fd3 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -315,7 +315,7 @@ Logical - | *t0* = *t1* ^ *t2* - * - not_i32/i64 *t0*, *t1* + * - not *t0*, *t1* - | *t0* = ~\ *t1* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 13b7650cec..d0fcdfd241 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -46,6 +46,7 @@ DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) +DEF(not, 1, 1, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) @@ -95,7 +96,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(not_i32, 1, 1, 0, 0) DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) @@ -144,7 +144,6 @@ DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) -DEF(not_i64, 1, 1, 0, 0) DEF(clz_i64, 1, 2, 0, 0) DEF(ctz_i64, 1, 2, 0, 0) DEF(ctpop_i64, 1, 1, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index b4a675ea37..315ee0a8bc 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -475,7 +475,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_rotl_i64: return rol64(x, y & 63); - CASE_OP_32_64_VEC(not): + case INDEX_op_not: + case INDEX_op_not_vec: return ~x; case INDEX_op_neg: @@ -1103,12 +1104,9 @@ static bool fold_to_not(OptContext *ctx, TCGOp *op, int idx) switch (ctx->type) { case TCG_TYPE_I32: - not_op = INDEX_op_not_i32; - have_not = tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0); - break; case TCG_TYPE_I64: - not_op = INDEX_op_not_i64; - have_not = tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0); + not_op = INDEX_op_not; + have_not = tcg_op_supported(INDEX_op_not, ctx->type, 0); break; case TCG_TYPE_V64: case TCG_TYPE_V128: @@ -2987,7 +2985,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_nor_vec: done = fold_nor(&ctx, op); break; - CASE_OP_32_64_VEC(not): + case INDEX_op_not: + case INDEX_op_not_vec: done = fold_not(&ctx, op); break; case INDEX_op_or: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index e0f8ab28b8..ddc1f465a4 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -462,9 +462,9 @@ void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); } else if (arg2 == -1 && - tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0)) { + tcg_op_supported(INDEX_op_not, TCG_TYPE_I32, 0)) { /* Don't recurse with tcg_gen_not_i32. */ - tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg1); + tcg_gen_op2_i32(INDEX_op_not, ret, arg1); } else { tcg_gen_xor_i32(ret, arg1, tcg_constant_i32(arg2)); } @@ -472,8 +472,8 @@ void tcg_gen_xori_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (tcg_op_supported(INDEX_op_not_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op2_i32(INDEX_op_not_i32, ret, arg); + if (tcg_op_supported(INDEX_op_not, TCG_TYPE_I32, 0)) { + tcg_gen_op2_i32(INDEX_op_not, ret, arg); } else { tcg_gen_xori_i32(ret, arg, -1); } @@ -1764,9 +1764,9 @@ void tcg_gen_xori_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); } else if (arg2 == -1 && - tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0)) { + tcg_op_supported(INDEX_op_not, TCG_TYPE_I64, 0)) { /* Don't recurse with tcg_gen_not_i64. */ - tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg1); + tcg_gen_op2_i64(INDEX_op_not, ret, arg1); } else { tcg_gen_xor_i64(ret, arg1, tcg_constant_i64(arg2)); } @@ -2254,8 +2254,8 @@ void tcg_gen_not_i64(TCGv_i64 ret, TCGv_i64 arg) if (TCG_TARGET_REG_BITS == 32) { tcg_gen_not_i32(TCGV_LOW(ret), TCGV_LOW(arg)); tcg_gen_not_i32(TCGV_HIGH(ret), TCGV_HIGH(arg)); - } else if (tcg_op_supported(INDEX_op_not_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op2_i64(INDEX_op_not_i64, ret, arg); + } else if (tcg_op_supported(INDEX_op_not, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_not, ret, arg); } else { tcg_gen_xori_i64(ret, arg, -1); } diff --git a/tcg/tcg.c b/tcg/tcg.c index acd666d30b..5e43a304c0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1024,8 +1024,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), - OUTOP(INDEX_op_not_i32, TCGOutOpUnary, outop_not), - OUTOP(INDEX_op_not_i64, TCGOutOpUnary, outop_not), + OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -5474,8 +5473,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_neg: - case INDEX_op_not_i32: - case INDEX_op_not_i64: + case INDEX_op_not: { const TCGOutOpUnary *out = container_of(all_outop[op->opc], TCGOutOpUnary, base); diff --git a/tcg/tci.c b/tcg/tci.c index 25ad37fcd5..96e3667ab2 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -571,6 +571,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = -regs[r1]; break; + case INDEX_op_not: + tci_args_rr(insn, &r0, &r1); + regs[r0] = ~regs[r1]; + break; /* Arithmetic operations (32 bit). */ @@ -695,10 +699,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = bswap32(regs[r1]); break; #endif - CASE_32_64(not) - tci_args_rr(insn, &r0, &r1); - regs[r0] = ~regs[r1]; - break; #if TCG_TARGET_REG_BITS == 64 /* Load/store operations (64 bit). */ @@ -1053,6 +1053,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_mov: case INDEX_op_neg: + case INDEX_op_not: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i32: @@ -1060,8 +1061,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_not_i32: - case INDEX_op_not_i64: case INDEX_op_ctpop_i32: case INDEX_op_ctpop_i64: tci_args_rr(insn, &r0, &r1); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d3da498098..a1f9a3a2f0 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -739,7 +739,7 @@ static const TCGOutOpUnary outop_neg = { static void tgen_not(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { - tcg_out_op_rr(s, glue(INDEX_op_not_i,TCG_TARGET_REG_BITS), a0, a1); + tcg_out_op_rr(s, INDEX_op_not, a0, a1); } static const TCGOutOpUnary outop_not = { From 1e4ac0ea5dc86c54e97bbc4db9638f2febdfde8b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 09:15:09 -0800 Subject: [PATCH 0394/2760] tcg: Convert mul to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 18 ++++--- tcg/arm/tcg-target.c.inc | 23 ++++---- tcg/i386/tcg-target.c.inc | 47 +++++++++------- tcg/loongarch64/tcg-target.c.inc | 24 +++++---- tcg/mips/tcg-target.c.inc | 43 +++++++++------ tcg/ppc/tcg-target.c.inc | 42 +++++++-------- tcg/riscv/tcg-target.c.inc | 21 ++++---- tcg/s390x/tcg-target.c.inc | 92 ++++++++++++++++++-------------- tcg/sparc64/tcg-target.c.inc | 28 +++++++--- tcg/tcg.c | 6 ++- tcg/tci/tcg-target.c.inc | 14 +++-- 11 files changed, 210 insertions(+), 148 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 97b444bc17..4513140f58 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2168,6 +2168,17 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3509, MADD, type, a0, a1, a2, TCG_REG_XZR); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2322,11 +2333,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_mul_i64: - case INDEX_op_mul_i32: - tcg_out_insn(s, 3509, MADD, ext, a0, a1, a2, TCG_REG_XZR); - break; - case INDEX_op_div_i64: case INDEX_op_div_i32: tcg_out_insn(s, 3508, SDIV, ext, a0, a1, a2); @@ -3029,8 +3035,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_divu_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 2477b1c4ab..93e5c70ae3 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -921,13 +921,6 @@ static void tcg_out_dat_rIN(TCGContext *s, ARMCond cond, ARMInsn opc, } } -static void tcg_out_mul32(TCGContext *s, ARMCond cond, TCGReg rd, - TCGReg rn, TCGReg rm) -{ - /* mul */ - tcg_out32(s, (cond << 28) | 0x90 | (rd << 16) | (rm << 8) | rn); -} - static void tcg_out_umull32(TCGContext *s, ARMCond cond, TCGReg rd0, TCGReg rd1, TCGReg rn, TCGReg rm) { @@ -1885,6 +1878,18 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + /* mul */ + tcg_out32(s, (COND_AL << 28) | 0x90 | (a0 << 16) | (a1 << 8) | a2); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2060,9 +2065,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_mul_i32: - tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]); - break; case INDEX_op_mulu2_i32: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; @@ -2258,7 +2260,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctz_i32: return C_O1_I2(r, r, rIK); - case INDEX_op_mul_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: return C_O1_I2(r, r, r); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 24fef09c9e..4abe89d06e 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2637,6 +2637,33 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, a0, a2); +} + +static void tgen_muli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + if (a2 == (int8_t)a2) { + tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, a0, a0); + tcg_out8(s, a2); + } else { + tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, a0, a0); + tcg_out32(s, a2); + } +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_mul, + .out_rri = tgen_muli, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2804,22 +2831,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(mul): - if (const_a2) { - int32_t val; - val = a2; - if (val == (int8_t)val) { - tcg_out_modrm(s, OPC_IMUL_GvEvIb + rexw, a0, a0); - tcg_out8(s, val); - } else { - tcg_out_modrm(s, OPC_IMUL_GvEvIz + rexw, a0, a0); - tcg_out32(s, val); - } - } else { - tcg_out_modrm(s, OPC_IMUL_GvEv + rexw, a0, a2); - } - break; - OP_32_64(div2): tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]); break; @@ -3707,10 +3718,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: - return C_O1_I2(r, 0, re); - case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index c24882b6ba..448896ac0d 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1332,6 +1332,21 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_mul_w(s, a0, a1, a2); + } else { + tcg_out_opc_mul_d(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1626,13 +1641,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mul_i32: - tcg_out_opc_mul_w(s, a0, a1, a2); - break; - case INDEX_op_mul_i64: - tcg_out_opc_mul_d(s, a0, a1, a2); - break; - case INDEX_op_mulsh_i32: tcg_out_opc_mulh_w(s, a0, a1, a2); break; @@ -2333,8 +2341,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: case INDEX_op_mulsh_i32: case INDEX_op_mulsh_i64: case INDEX_op_muluh_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 4942855189..95c2645226 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1716,6 +1716,33 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn; + + if (type == TCG_TYPE_I32) { + if (use_mips32_instructions) { + tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2); + return; + } + insn = OPC_MULT; + } else { + if (use_mips32r6_instructions) { + tcg_out_opc_reg(s, OPC_DMUL, a0, a1, a2); + return; + } + insn = OPC_DMULT; + } + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1876,13 +1903,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_mul_i32: - if (use_mips32_instructions) { - tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2); - break; - } - i1 = OPC_MULT, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_mulsh_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_MUH, a0, a1, a2); @@ -1925,13 +1945,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DIVU, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_mul_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DMUL, a0, a1, a2); - break; - } - i1 = OPC_DMULT, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_mulsh_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DMUH, a0, a1, a2); @@ -2232,7 +2245,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_mul_i32: case INDEX_op_mulsh_i32: case INDEX_op_muluh_i32: case INDEX_op_div_i32: @@ -2240,7 +2252,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_mul_i64: case INDEX_op_mulsh_i64: case INDEX_op_muluh_i64: case INDEX_op_div_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 38cbe5223b..a7cc9d0bc7 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2965,6 +2965,25 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? MULLW : MULLD; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static void tgen_muli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out32(s, MULLI | TAI(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_mul, + .out_rri = tgen_muli, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3077,7 +3096,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2; + TCGArg a0, a1; switch (opc) { case INDEX_op_goto_ptr: @@ -3166,15 +3185,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_mul_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out32(s, MULLI | TAI(a0, a1, a2)); - } else { - tcg_out32(s, MULLW | TAB(a0, a1, a2)); - } - break; - case INDEX_op_div_i32: tcg_out32(s, DIVW | TAB(args[0], args[1], args[2])); break; @@ -3283,14 +3293,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mul_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out32(s, MULLI | TAI(a0, a1, a2)); - } else { - tcg_out32(s, MULLD | TAB(a0, a1, a2)); - } - break; case INDEX_op_div_i64: tcg_out32(s, DIVD | TAB(args[0], args[1], args[2])); break; @@ -4171,10 +4173,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: - return C_O1_I2(r, r, rI); - case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 5e9e14815d..ff685037d7 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2009,6 +2009,18 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_MULW : OPC_MUL; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2160,13 +2172,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_mul_i32: - tcg_out_opc_reg(s, OPC_MULW, a0, a1, a2); - break; - case INDEX_op_mul_i64: - tcg_out_opc_reg(s, OPC_MUL, a0, a1, a2); - break; - case INDEX_op_div_i32: tcg_out_opc_reg(s, OPC_DIVW, a0, a1, a2); break; @@ -2706,14 +2711,12 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_mul_i32: case INDEX_op_mulsh_i32: case INDEX_op_muluh_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_mul_i64: case INDEX_op_mulsh_i64: case INDEX_op_muluh_i64: case INDEX_op_div_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 98bf3ee19e..1ba9741fdd 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2258,6 +2258,57 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + if (a0 == a1) { + tcg_out_insn(s, RRE, MSR, a0, a2); + } else { + tcg_out_insn(s, RRFa, MSRKC, a0, a1, a2); + } + } else { + if (a0 == a1) { + tcg_out_insn(s, RRE, MSGR, a0, a2); + } else { + tcg_out_insn(s, RRFa, MSGRKC, a0, a1, a2); + } + } +} + +static void tgen_muli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + if (type == TCG_TYPE_I32) { + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, MHI, a0, a2); + } else { + tcg_out_insn(s, RIL, MSFI, a0, a2); + } + } else { + if (a2 == (int16_t)a2) { + tcg_out_insn(s, RI, MGHI, a0, a2); + } else { + tcg_out_insn(s, RIL, MSGFI, a0, a2); + } + } +} + +static TCGConstraintSetIndex cset_mul(TCGType type, unsigned flags) +{ + return (HAVE_FACILITY(MISC_INSN_EXT2) + ? C_O1_I2(r, r, rJ) + : C_O1_I2(r, 0, rJ)); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul, + .out_rrr = tgen_mul, + .out_rri = tgen_muli, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2460,22 +2511,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_mul_i32: - a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - if (a2 == (int16_t)a2) { - tcg_out_insn(s, RI, MHI, a0, a2); - } else { - tcg_out_insn(s, RIL, MSFI, a0, a2); - } - } else if (a0 == a1) { - tcg_out_insn(s, RRE, MSR, a0, a2); - } else { - tcg_out_insn(s, RRFa, MSRKC, a0, a1, a2); - } - break; - case INDEX_op_div2_i32: tcg_debug_assert(args[0] == args[2]); tcg_debug_assert(args[1] == args[3]); @@ -2651,22 +2686,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; - case INDEX_op_mul_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[2]) { - tcg_out_mov(s, TCG_TYPE_I64, a0, a1); - if (a2 == (int16_t)a2) { - tcg_out_insn(s, RI, MGHI, a0, a2); - } else { - tcg_out_insn(s, RIL, MSGFI, a0, a2); - } - } else if (a0 == a1) { - tcg_out_insn(s, RRE, MSGR, a0, a2); - } else { - tcg_out_insn(s, RRFa, MSGRKC, a0, a1, a2); - } - break; - case INDEX_op_div2_i64: /* * ??? We get an unnecessary sign-extension of the dividend @@ -3316,15 +3335,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_clz_i64: return C_O1_I2(r, r, rI); - case INDEX_op_mul_i32: - return (HAVE_FACILITY(MISC_INSN_EXT2) - ? C_O1_I2(r, r, ri) - : C_O1_I2(r, 0, ri)); - case INDEX_op_mul_i64: - return (HAVE_FACILITY(MISC_INSN_EXT2) - ? C_O1_I2(r, r, rJ) - : C_O1_I2(r, 0, rJ)); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 5819dc44fe..0a13a91166 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1337,6 +1337,26 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? ARITH_UMUL : ARITH_MULX; + tcg_out_arith(s, a0, a1, a2, insn); +} + +static void tgen_muli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? ARITH_UMUL : ARITH_MULX; + tcg_out_arithi(s, a0, a1, a2, insn); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_mul, + .out_rri = tgen_muli, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1489,9 +1509,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i32: c = SHIFT_SRA; goto do_shift32; - case INDEX_op_mul_i32: - c = ARITH_UMUL; - goto gen_arith; case INDEX_op_div_i32: tcg_out_div32(s, a0, a1, a2, c2, 0); @@ -1568,9 +1585,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i64: c = SHIFT_SRAX; goto do_shift64; - case INDEX_op_mul_i64: - c = ARITH_MULX; - goto gen_arith; case INDEX_op_div_i64: c = ARITH_SDIVX; goto gen_arith; @@ -1667,8 +1681,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_divu_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 5e43a304c0..4d221cea6f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1021,6 +1021,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_mul_i32, TCGOutOpBinary, outop_mul), + OUTOP(INDEX_op_mul_i64, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), @@ -2247,7 +2249,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_mul_i32: case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: @@ -2313,7 +2314,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_mul_i64: case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: @@ -5436,6 +5436,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: + case INDEX_op_mul_i32: + case INDEX_op_mul_i64: case INDEX_op_nand: case INDEX_op_nor: case INDEX_op_or: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index a1f9a3a2f0..ce17079ffc 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -87,8 +87,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: @@ -661,6 +659,17 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_mul(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_mul_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_mul = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mul, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -789,7 +798,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(mul) CASE_32_64(shl) CASE_32_64(shr) CASE_32_64(sar) From d2c3ecadea89832ab82566e881bc3a288b020473 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 09:32:18 -0800 Subject: [PATCH 0395/2760] tcg: Merge INDEX_op_mul_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 4 ++-- tcg/tcg-op.c | 12 ++++++------ tcg/tcg.c | 14 ++++++-------- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 96dddc5fd3..6c36e72242 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -273,7 +273,7 @@ Arithmetic - | *t0* = -*t1* (two's complement) - * - mul_i32/i64 *t0*, *t1*, *t2* + * - mul *t0*, *t1*, *t2* - | *t0* = *t1* * *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index d0fcdfd241..4ecba62fda 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) +DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) @@ -65,7 +66,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(mul_i32, 1, 2, 0, 0) DEF(div_i32, 1, 2, 0, 0) DEF(divu_i32, 1, 2, 0, 0) DEF(rem_i32, 1, 2, 0, 0) @@ -116,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(mul_i64, 1, 2, 0, 0) DEF(div_i64, 1, 2, 0, 0) DEF(divu_i64, 1, 2, 0, 0) DEF(rem_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 315ee0a8bc..653246f3d2 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -430,7 +430,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_sub: return x - y; - CASE_OP_32_64(mul): + case INDEX_op_mul: return x * y; case INDEX_op_and: @@ -2963,7 +2963,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(movcond): done = fold_movcond(&ctx, op); break; - CASE_OP_32_64(mul): + case INDEX_op_mul: done = fold_mul(&ctx, op); break; CASE_OP_32_64(mulsh): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ddc1f465a4..76d5b67fba 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -585,7 +585,7 @@ void tcg_gen_negsetcondi_i32(TCGCond cond, TCGv_i32 ret, void tcg_gen_mul_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_mul_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_mul, ret, arg1, arg2); } void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1134,7 +1134,7 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); } else if (TCG_TARGET_HAS_muluh_i32) { TCGv_i32 t = tcg_temp_ebb_new_i32(); - tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); tcg_gen_mov_i32(rl, t); tcg_temp_free_i32(t); @@ -1158,7 +1158,7 @@ void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); } else if (TCG_TARGET_HAS_mulsh_i32) { TCGv_i32 t = tcg_temp_ebb_new_i32(); - tcg_gen_op3_i32(INDEX_op_mul_i32, t, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); tcg_gen_mov_i32(rl, t); tcg_temp_free_i32(t); @@ -1636,7 +1636,7 @@ void tcg_gen_mul_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) TCGv_i32 t1; if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_mul_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_mul, ret, arg1, arg2); return; } @@ -2844,7 +2844,7 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); } else if (TCG_TARGET_HAS_muluh_i64) { TCGv_i64 t = tcg_temp_ebb_new_i64(); - tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); @@ -2863,7 +2863,7 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); } else if (TCG_TARGET_HAS_mulsh_i64) { TCGv_i64 t = tcg_temp_ebb_new_i64(); - tcg_gen_op3_i64(INDEX_op_mul_i64, t, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); diff --git a/tcg/tcg.c b/tcg/tcg.c index 4d221cea6f..d16ed332c8 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1021,8 +1021,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), - OUTOP(INDEX_op_mul_i32, TCGOutOpBinary, outop_mul), - OUTOP(INDEX_op_mul_i64, TCGOutOpBinary, outop_mul), + OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), @@ -4035,22 +4034,22 @@ liveness_pass_1(TCGContext *s) goto do_not_remove; case INDEX_op_mulu2_i32: - opc_new = INDEX_op_mul_i32; + opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh_i32; have_opc_new2 = TCG_TARGET_HAS_muluh_i32; goto do_mul2; case INDEX_op_muls2_i32: - opc_new = INDEX_op_mul_i32; + opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh_i32; have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; goto do_mul2; case INDEX_op_mulu2_i64: - opc_new = INDEX_op_mul_i64; + opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh_i64; have_opc_new2 = TCG_TARGET_HAS_muluh_i64; goto do_mul2; case INDEX_op_muls2_i64: - opc_new = INDEX_op_mul_i64; + opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh_i64; have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; goto do_mul2; @@ -5436,8 +5435,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: + case INDEX_op_mul: case INDEX_op_nand: case INDEX_op_nor: case INDEX_op_or: diff --git a/tcg/tci.c b/tcg/tci.c index 96e3667ab2..61c0ccf21e 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -531,7 +531,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] - regs[r2]; break; - CASE_32_64(mul) + case INDEX_op_mul: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] * regs[r2]; break; @@ -1072,14 +1072,13 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_eqv: + case INDEX_op_mul: case INDEX_op_nand: case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_mul_i32: - case INDEX_op_mul_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_rem_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ce17079ffc..ffc8654427 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -662,7 +662,7 @@ static const TCGOutOpBinary outop_eqv = { static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_mul_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_mul, a0, a1, a2); } static const TCGOutOpBinary outop_mul = { From 937246f2ee87d01062bac7c356c1766b8c5038a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 10:16:03 -0800 Subject: [PATCH 0396/2760] tcg: Convert muluh to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unreachable mul[su]h_i32 leftovers from commit aeb6326ec5e ("tcg/riscv: Require TCG_TARGET_REG_BITS == 64"). Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 21 ++++++++++++++++---- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 24 +++++++++++++--------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 34 +++++++++++++++++--------------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 20 +++++++++++-------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 24 +++++++++++++++------- tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 4 ++++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 23 ++++++++++++++++----- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 7 ++++--- tcg/tcg.c | 16 ++++++--------- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 4 ++++ 23 files changed, 123 insertions(+), 82 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 7f18727686..207a85ed61 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -27,7 +27,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -47,7 +46,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 /* diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 4513140f58..bd0b7938c8 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2179,6 +2179,23 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_I64 ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, UMULH, TCG_TYPE_I64, a0, a1, a2); +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mulh, + .out_rrr = tgen_muluh, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2526,9 +2543,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, args[5], const_args[4], const_args[5], true); break; - case INDEX_op_muluh_i64: - tcg_out_insn(s, 3508, UMULH, TCG_TYPE_I64, a0, a1, a2); - break; case INDEX_op_mulsh_i64: tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2); break; @@ -3043,7 +3057,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: - case INDEX_op_muluh_i64: case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index e766c6d628..d6b06e96bf 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -34,7 +34,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_div_i32 use_idiv_instructions #define TCG_TARGET_HAS_rem_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 93e5c70ae3..b08e23d0dc 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1890,6 +1890,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 3d36fe58f2..f4487ac1fc 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -39,7 +39,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -59,7 +58,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_muls2_i64 1 -#define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 4abe89d06e..5fdca05c9d 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2664,6 +2664,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index ffacb41e80..53335b2cdb 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -47,7 +46,6 @@ #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 448896ac0d..738fdd1a9e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1347,6 +1347,21 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_mulh_wu(s, a0, a1, a2); + } else { + tcg_out_opc_mulh_du(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_muluh, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1648,13 +1663,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_mulh_d(s, a0, a1, a2); break; - case INDEX_op_muluh_i32: - tcg_out_opc_mulh_wu(s, a0, a1, a2); - break; - case INDEX_op_muluh_i64: - tcg_out_opc_mulh_du(s, a0, a1, a2); - break; - case INDEX_op_div_i32: tcg_out_opc_div_w(s, a0, a1, a2); break; @@ -2343,8 +2351,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulsh_i32: case INDEX_op_mulsh_i64: - case INDEX_op_muluh_i32: - case INDEX_op_muluh_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_divu_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 9d8e0fb8df..b559ab3846 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -59,7 +58,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i64 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 95c2645226..24f8184c33 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1743,6 +1743,24 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MUHU : OPC_DMUHU; + tcg_out_opc_reg(s, insn, a0, a1, a2); + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MULTU : OPC_DMULTU; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFHI, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_muluh, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1910,13 +1928,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_MULT, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_muluh_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_MUHU, a0, a1, a2); - break; - } - i1 = OPC_MULTU, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_div_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2); @@ -1952,13 +1963,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DMULT, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_muluh_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DMUHU, a0, a1, a2); - break; - } - i1 = OPC_DMULTU, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_div_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DDIV_R6, a0, a1, a2); @@ -2246,14 +2250,12 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O0_I2(rz, r); case INDEX_op_mulsh_i32: - case INDEX_op_muluh_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: case INDEX_op_mulsh_i64: - case INDEX_op_muluh_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 7ebcb49a19..18ec573f7e 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -29,7 +29,6 @@ #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_muluh_i32 1 #define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -52,7 +51,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 #endif diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index a7cc9d0bc7..06a7abf2ba 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2984,6 +2984,18 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? MULHWU : MULHDU; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_muluh, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3487,15 +3499,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_muluh_i32: - tcg_out32(s, MULHWU | TAB(args[0], args[1], args[2])); - break; case INDEX_op_mulsh_i32: tcg_out32(s, MULHW | TAB(args[0], args[1], args[2])); break; - case INDEX_op_muluh_i64: - tcg_out32(s, MULHDU | TAB(args[0], args[1], args[2])); - break; case INDEX_op_mulsh_i64: tcg_out32(s, MULHD | TAB(args[0], args[1], args[2])); break; @@ -4177,14 +4183,12 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_muluh_i32: case INDEX_op_mulsh_i32: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: case INDEX_op_mulsh_i64: - case INDEX_op_muluh_i64: return C_O1_I2(r, r, r); case INDEX_op_clz_i32: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index e3018717ea..453942a6a5 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 1 #define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index ff685037d7..65246cc450 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2021,6 +2021,23 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_I32 ? C_NotImplemented : C_O1_I2(r, r, r); +} + +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MULHU, a0, a1, a2); +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mulh, + .out_rrr = tgen_muluh, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -2379,11 +2396,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_reg(s, OPC_MULH, a0, a1, a2); break; - case INDEX_op_muluh_i32: - case INDEX_op_muluh_i64: - tcg_out_opc_reg(s, OPC_MULHU, a0, a1, a2); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -2712,13 +2724,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O1_I2(r, r, rI); case INDEX_op_mulsh_i32: - case INDEX_op_muluh_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_mulsh_i64: - case INDEX_op_muluh_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index e5c132cf12..ac808e21e5 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -42,7 +42,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -61,7 +60,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_muls2_i64 HAVE_FACILITY(MISC_INSN_EXT2) -#define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 1ba9741fdd..e3d70ca236 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2309,6 +2309,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index df87249df2..093de87a1d 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -48,7 +47,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 use_vis3_instructions #define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 0a13a91166..31bdaecafa 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1357,6 +1357,24 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static void tgen_muluh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_UMULXHI); +} + +static TCGConstraintSetIndex cset_muluh(TCGType type, unsigned flags) +{ + return (type == TCG_TYPE_I64 && use_vis3_instructions + ? C_O1_I2(r, r, r) : C_NotImplemented); +} + +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_muluh, + .out_rrr = tgen_muluh, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -1612,9 +1630,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_addsub2_i64(s, args[0], args[1], args[2], args[3], args[4], const_args[4], args[5], const_args[5], true); break; - case INDEX_op_muluh_i64: - tcg_out_arith(s, args[0], args[1], args[2], ARITH_UMULXHI); - break; gen_arith: tcg_out_arithc(s, a0, a1, a2, c2, c); @@ -1711,8 +1726,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulu2_i32: case INDEX_op_muls2_i32: return C_O2_I2(r, r, rz, rJ); - case INDEX_op_muluh_i64: - return C_O1_I2(r, r, r); default: return C_NotImplemented; diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index a84ed1313a..7f3ef73f2e 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -28,7 +28,6 @@ #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 76d5b67fba..39581465f2 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1132,7 +1132,7 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_mulu2_i32) { tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); - } else if (TCG_TARGET_HAS_muluh_i32) { + } else if (tcg_op_supported(INDEX_op_muluh_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); @@ -2842,7 +2842,7 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_mulu2_i64) { tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); - } else if (TCG_TARGET_HAS_muluh_i64) { + } else if (tcg_op_supported(INDEX_op_muluh_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); @@ -2867,7 +2867,8 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); - } else if (TCG_TARGET_HAS_mulu2_i64 || TCG_TARGET_HAS_muluh_i64) { + } else if (TCG_TARGET_HAS_mulu2_i64 || + tcg_op_supported(INDEX_op_muluh_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index d16ed332c8..cd85967229 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1022,6 +1022,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), + OUTOP(INDEX_op_muluh_i32, TCGOutOpBinary, outop_muluh), + OUTOP(INDEX_op_muluh_i64, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), @@ -2280,8 +2282,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_mulu2_i32; case INDEX_op_muls2_i32: return TCG_TARGET_HAS_muls2_i32; - case INDEX_op_muluh_i32: - return TCG_TARGET_HAS_muluh_i32; case INDEX_op_mulsh_i32: return TCG_TARGET_HAS_mulsh_i32; case INDEX_op_bswap16_i32: @@ -2362,8 +2362,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_mulu2_i64; case INDEX_op_muls2_i64: return TCG_TARGET_HAS_muls2_i64; - case INDEX_op_muluh_i64: - return TCG_TARGET_HAS_muluh_i64; case INDEX_op_mulsh_i64: return TCG_TARGET_HAS_mulsh_i64; @@ -3876,7 +3874,6 @@ liveness_pass_1(TCGContext *s) QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { int nb_iargs, nb_oargs; TCGOpcode opc_new, opc_new2; - bool have_opc_new2; TCGLifeData arg_life = 0; TCGTemp *ts; TCGOpcode opc = op->opc; @@ -4036,22 +4033,18 @@ liveness_pass_1(TCGContext *s) case INDEX_op_mulu2_i32: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh_i32; - have_opc_new2 = TCG_TARGET_HAS_muluh_i32; goto do_mul2; case INDEX_op_muls2_i32: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh_i32; - have_opc_new2 = TCG_TARGET_HAS_mulsh_i32; goto do_mul2; case INDEX_op_mulu2_i64: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh_i64; - have_opc_new2 = TCG_TARGET_HAS_muluh_i64; goto do_mul2; case INDEX_op_muls2_i64: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh_i64; - have_opc_new2 = TCG_TARGET_HAS_mulsh_i64; goto do_mul2; do_mul2: nb_iargs = 2; @@ -4065,7 +4058,8 @@ liveness_pass_1(TCGContext *s) op->opc = opc = opc_new; op->args[1] = op->args[2]; op->args[2] = op->args[3]; - } else if (arg_temp(op->args[0])->state == TS_DEAD && have_opc_new2) { + } else if (arg_temp(op->args[0])->state == TS_DEAD && + tcg_op_supported(opc_new2, TCGOP_TYPE(op), 0)) { /* The low part of the operation is dead; generate the high. */ op->opc = opc = opc_new2; op->args[0] = op->args[1]; @@ -5436,6 +5430,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_mul: + case INDEX_op_muluh_i32: + case INDEX_op_muluh_i64: case INDEX_op_nand: case INDEX_op_nor: case INDEX_op_or: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index f147da5c0e..b99b12c24c 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_muluh_i32 0 #define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -42,7 +41,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 -#define TCG_TARGET_HAS_muluh_i64 0 #define TCG_TARGET_HAS_mulsh_i64 0 #else #define TCG_TARGET_HAS_mulu2_i32 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ffc8654427..e4a2b171df 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -670,6 +670,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpBinary outop_muluh = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_nand(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From aa28c9ef8e109db40d4781d82452805486f2a2bf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 10:36:24 -0800 Subject: [PATCH 0397/2760] tcg: Merge INDEX_op_muluh_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 19 +++++++++++-------- tcg/tcg-op.c | 10 +++++----- tcg/tcg.c | 13 ++++--------- 5 files changed, 22 insertions(+), 25 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 6c36e72242..4fed5a77c6 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -591,7 +591,7 @@ Multiword arithmetic support * - mulsh_i32/i64 *t0*, *t1*, *t2* - muluh_i32/i64 *t0*, *t1*, *t2* + muluh *t0*, *t1*, *t2* - | Provide the high part of a signed or unsigned multiply, respectively. | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 4ecba62fda..28a5128537 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) +DEF(muluh, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) @@ -89,7 +90,6 @@ DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) DEF(mulu2_i32, 2, 2, 0, 0) DEF(muls2_i32, 2, 2, 0, 0) -DEF(muluh_i32, 1, 2, 0, 0) DEF(mulsh_i32, 1, 2, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) @@ -151,7 +151,6 @@ DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) DEF(mulu2_i64, 2, 2, 0, 0) DEF(muls2_i64, 2, 2, 0, 0) -DEF(muluh_i64, 1, 2, 0, 0) DEF(mulsh_i64, 1, 2, 0, 0) #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) diff --git a/tcg/optimize.c b/tcg/optimize.c index 653246f3d2..e19bccf906 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -419,7 +419,8 @@ static bool tcg_opt_gen_movi(OptContext *ctx, TCGOp *op, return tcg_opt_gen_mov(ctx, op, dst, arg_new_constant(ctx, val)); } -static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) +static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, + uint64_t x, uint64_t y) { uint64_t l64, h64; @@ -541,14 +542,16 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) case INDEX_op_extrh_i64_i32: return (uint64_t)x >> 32; - case INDEX_op_muluh_i32: - return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32; + case INDEX_op_muluh: + if (type == TCG_TYPE_I32) { + return ((uint64_t)(uint32_t)x * (uint32_t)y) >> 32; + } + mulu64(&l64, &h64, x, y); + return h64; + case INDEX_op_mulsh_i32: return ((int64_t)(int32_t)x * (int32_t)y) >> 32; - case INDEX_op_muluh_i64: - mulu64(&l64, &h64, x, y); - return h64; case INDEX_op_mulsh_i64: muls64(&l64, &h64, x, y); return h64; @@ -580,7 +583,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, uint64_t x, uint64_t y) static uint64_t do_constant_folding(TCGOpcode op, TCGType type, uint64_t x, uint64_t y) { - uint64_t res = do_constant_folding_2(op, x, y); + uint64_t res = do_constant_folding_2(op, type, x, y); if (type == TCG_TYPE_I32) { res = (int32_t)res; } @@ -2967,7 +2970,7 @@ void tcg_optimize(TCGContext *s) done = fold_mul(&ctx, op); break; CASE_OP_32_64(mulsh): - CASE_OP_32_64(muluh): + case INDEX_op_muluh: done = fold_mul_highpart(&ctx, op); break; CASE_OP_32_64(muls2): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 39581465f2..7a37b21c56 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1132,10 +1132,10 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_mulu2_i32) { tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_muluh_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); - tcg_gen_op3_i32(INDEX_op_muluh_i32, rh, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_muluh, rh, arg1, arg2); tcg_gen_mov_i32(rl, t); tcg_temp_free_i32(t); } else if (TCG_TARGET_REG_BITS == 64) { @@ -2842,10 +2842,10 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_mulu2_i64) { tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_muluh_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); - tcg_gen_op3_i64(INDEX_op_muluh_i64, rh, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_muluh, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); } else { @@ -2868,7 +2868,7 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); } else if (TCG_TARGET_HAS_mulu2_i64 || - tcg_op_supported(INDEX_op_muluh_i64, TCG_TYPE_I64, 0)) { + tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index cd85967229..808ac8c431 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1022,8 +1022,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), - OUTOP(INDEX_op_muluh_i32, TCGOutOpBinary, outop_muluh), - OUTOP(INDEX_op_muluh_i64, TCGOutOpBinary, outop_muluh), + OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), @@ -4030,17 +4029,14 @@ liveness_pass_1(TCGContext *s) } goto do_not_remove; - case INDEX_op_mulu2_i32: - opc_new = INDEX_op_mul; - opc_new2 = INDEX_op_muluh_i32; - goto do_mul2; case INDEX_op_muls2_i32: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh_i32; goto do_mul2; + case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: opc_new = INDEX_op_mul; - opc_new2 = INDEX_op_muluh_i64; + opc_new2 = INDEX_op_muluh; goto do_mul2; case INDEX_op_muls2_i64: opc_new = INDEX_op_mul; @@ -5430,8 +5426,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_mul: - case INDEX_op_muluh_i32: - case INDEX_op_muluh_i64: + case INDEX_op_muluh: case INDEX_op_nand: case INDEX_op_nor: case INDEX_op_or: From a9983f81290d41ed614a193a33d03be936f6435c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 11:13:05 -0800 Subject: [PATCH 0398/2760] tcg: Convert mulsh to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 17 +++++++++++----- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 24 +++++++++++++--------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 34 +++++++++++++++++--------------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 21 +++++++++++--------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 19 +++++++++++------- tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 4 ++++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 8 ++++---- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 4 ++++ 23 files changed, 95 insertions(+), 72 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 207a85ed61..bde6db8f2a 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -27,7 +27,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 1 /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index bd0b7938c8..493c504682 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2184,6 +2184,18 @@ static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) return type == TCG_TYPE_I64 ? C_O1_I2(r, r, r) : C_NotImplemented; } +static void tgen_mulsh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2); +} + +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mulh, + .out_rrr = tgen_mulsh, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2543,10 +2555,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, args[5], const_args[4], const_args[5], true); break; - case INDEX_op_mulsh_i64: - tcg_out_insn(s, 3508, SMULH, TCG_TYPE_I64, a0, a1, a2); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -3057,7 +3065,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: - case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); case INDEX_op_shl_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index d6b06e96bf..ab9b7b6162 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -34,7 +34,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_div_i32 use_idiv_instructions #define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index b08e23d0dc..1c19004e6e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1890,6 +1890,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index f4487ac1fc..121fb95ee0 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -39,7 +39,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_mulsh_i32 0 #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ @@ -58,7 +57,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_muls2_i64 1 -#define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else #define TCG_TARGET_HAS_qemu_st8_i32 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 5fdca05c9d..d0391157a4 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2664,6 +2664,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 53335b2cdb..e29c892756 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 738fdd1a9e..7503270ca3 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1347,6 +1347,21 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_mulsh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_mulh_w(s, a0, a1, a2); + } else { + tcg_out_opc_mulh_d(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mulsh, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1656,13 +1671,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mulsh_i32: - tcg_out_opc_mulh_w(s, a0, a1, a2); - break; - case INDEX_op_mulsh_i64: - tcg_out_opc_mulh_d(s, a0, a1, a2); - break; - case INDEX_op_div_i32: tcg_out_opc_div_w(s, a0, a1, a2); break; @@ -2349,8 +2357,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_mulsh_i32: - case INDEX_op_mulsh_i64: case INDEX_op_div_i32: case INDEX_op_div_i64: case INDEX_op_divu_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index b559ab3846..ebaaa49cdd 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -43,7 +43,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 @@ -58,7 +57,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i64 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 24f8184c33..a1c215c25d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1743,6 +1743,24 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_mulsh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MUH : OPC_DMUH; + tcg_out_opc_reg(s, insn, a0, a1, a2); + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MULT : OPC_DMULT; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFHI, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mulsh, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1921,13 +1939,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_mulsh_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_MUH, a0, a1, a2); - break; - } - i1 = OPC_MULT, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_div_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2); @@ -1956,13 +1967,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DIVU, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_mulsh_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DMUH, a0, a1, a2); - break; - } - i1 = OPC_DMULT, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_div_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DDIV_R6, a0, a1, a2); @@ -2249,13 +2253,11 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_mulsh_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_mulsh_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 18ec573f7e..bbbd8de2c7 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -29,7 +29,6 @@ #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_mulsh_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -51,7 +50,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 1 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 06a7abf2ba..7ebadf396a 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2984,6 +2984,18 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static void tgen_mulsh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? MULHW : MULHD; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_mulsh, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3499,13 +3511,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mulsh_i32: - tcg_out32(s, MULHW | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_mulsh_i64: - tcg_out32(s, MULHD | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_mb: tcg_out_mb(s, args[0]); break; @@ -4183,12 +4188,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_mulsh_i32: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: - case INDEX_op_mulsh_i64: return C_O1_I2(r, r, r); case INDEX_op_clz_i32: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 453942a6a5..f7e1ef82fc 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) @@ -45,7 +44,6 @@ #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 1 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 65246cc450..82f76b8e0c 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2026,6 +2026,18 @@ static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) return type == TCG_TYPE_I32 ? C_NotImplemented : C_O1_I2(r, r, r); } +static void tgen_mulsh(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_opc_reg(s, OPC_MULH, a0, a1, a2); +} + +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mulh, + .out_rrr = tgen_mulsh, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2391,11 +2403,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_SRAI, a0, a1, 32); break; - case INDEX_op_mulsh_i32: - case INDEX_op_mulsh_i64: - tcg_out_opc_reg(s, OPC_MULH, a0, a1, a2); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -2723,12 +2730,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_mulsh_i32: case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_mulsh_i64: case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index ac808e21e5..64f1805641 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -42,7 +42,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_muls2_i32 0 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -60,7 +59,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_muls2_i64 HAVE_FACILITY(MISC_INSN_EXT2) -#define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e3d70ca236..2685e6ffa1 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2309,6 +2309,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 093de87a1d..5a517b6835 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 @@ -47,7 +46,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 31bdaecafa..95a138ef56 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1357,6 +1357,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 7f3ef73f2e..3d4c67698f 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -28,7 +28,6 @@ #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_muls2_i64 0 -#define TCG_TARGET_HAS_mulsh_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7a37b21c56..a043c4554b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1156,7 +1156,7 @@ void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_muls2_i32) { tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); - } else if (TCG_TARGET_HAS_mulsh_i32) { + } else if (tcg_op_supported(INDEX_op_mulsh_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); @@ -2861,7 +2861,7 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_muls2_i64) { tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); - } else if (TCG_TARGET_HAS_mulsh_i64) { + } else if (tcg_op_supported(INDEX_op_mulsh_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 808ac8c431..4bfda0a38f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1022,6 +1022,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), + OUTOP(INDEX_op_mulsh_i32, TCGOutOpBinary, outop_mulsh), + OUTOP(INDEX_op_mulsh_i64, TCGOutOpBinary, outop_mulsh), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), @@ -2281,8 +2283,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_mulu2_i32; case INDEX_op_muls2_i32: return TCG_TARGET_HAS_muls2_i32; - case INDEX_op_mulsh_i32: - return TCG_TARGET_HAS_mulsh_i32; case INDEX_op_bswap16_i32: return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: @@ -2361,8 +2361,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_mulu2_i64; case INDEX_op_muls2_i64: return TCG_TARGET_HAS_muls2_i64; - case INDEX_op_mulsh_i64: - return TCG_TARGET_HAS_mulsh_i64; case INDEX_op_mov_vec: case INDEX_op_dup_vec: @@ -5426,6 +5424,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_mul: + case INDEX_op_mulsh_i32: + case INDEX_op_mulsh_i64: case INDEX_op_muluh: case INDEX_op_nand: case INDEX_op_nor: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index b99b12c24c..0627585097 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_mulsh_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -41,7 +40,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 -#define TCG_TARGET_HAS_mulsh_i64 0 #else #define TCG_TARGET_HAS_mulu2_i32 1 #endif /* TCG_TARGET_REG_BITS == 64 */ diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index e4a2b171df..1dcce543ec 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -670,6 +670,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpBinary outop_mulsh = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; From c742824dd8df3283098d5339291d49e65e515751 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 11:19:29 -0800 Subject: [PATCH 0399/2760] tcg: Merge INDEX_op_mulsh_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 10 +++++----- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 14 ++++---------- 5 files changed, 15 insertions(+), 22 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 4fed5a77c6..fe922d1dac 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -589,7 +589,7 @@ Multiword arithmetic support - | Similar to mulu2, except the two inputs *t1* and *t2* are signed. - * - mulsh_i32/i64 *t0*, *t1*, *t2* + * - mulsh *t0*, *t1*, *t2* muluh *t0*, *t1*, *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 28a5128537..a9d7938a52 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) +DEF(mulsh, 1, 2, 0, TCG_OPF_INT) DEF(muluh, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) @@ -90,7 +91,6 @@ DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) DEF(mulu2_i32, 2, 2, 0, 0) DEF(muls2_i32, 2, 2, 0, 0) -DEF(mulsh_i32, 1, 2, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) @@ -151,7 +151,6 @@ DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) DEF(mulu2_i64, 2, 2, 0, 0) DEF(muls2_i64, 2, 2, 0, 0) -DEF(mulsh_i64, 1, 2, 0, 0) #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) diff --git a/tcg/optimize.c b/tcg/optimize.c index e19bccf906..fd446fc47d 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -549,10 +549,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, mulu64(&l64, &h64, x, y); return h64; - case INDEX_op_mulsh_i32: - return ((int64_t)(int32_t)x * (int32_t)y) >> 32; - - case INDEX_op_mulsh_i64: + case INDEX_op_mulsh: + if (type == TCG_TYPE_I32) { + return ((int64_t)(int32_t)x * (int32_t)y) >> 32; + } muls64(&l64, &h64, x, y); return h64; @@ -2969,7 +2969,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_mul: done = fold_mul(&ctx, op); break; - CASE_OP_32_64(mulsh): + case INDEX_op_mulsh: case INDEX_op_muluh: done = fold_mul_highpart(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index a043c4554b..664c698187 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1156,10 +1156,10 @@ void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_muls2_i32) { tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_mulsh_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); - tcg_gen_op3_i32(INDEX_op_mulsh_i32, rh, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_mulsh, rh, arg1, arg2); tcg_gen_mov_i32(rl, t); tcg_temp_free_i32(t); } else if (TCG_TARGET_REG_BITS == 32) { @@ -2861,10 +2861,10 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_muls2_i64) { tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_mulsh_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); - tcg_gen_op3_i64(INDEX_op_mulsh_i64, rh, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_mulsh, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); } else if (TCG_TARGET_HAS_mulu2_i64 || diff --git a/tcg/tcg.c b/tcg/tcg.c index 4bfda0a38f..d4b5872128 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1022,8 +1022,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), - OUTOP(INDEX_op_mulsh_i32, TCGOutOpBinary, outop_mulsh), - OUTOP(INDEX_op_mulsh_i64, TCGOutOpBinary, outop_mulsh), + OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), @@ -4028,18 +4027,14 @@ liveness_pass_1(TCGContext *s) goto do_not_remove; case INDEX_op_muls2_i32: + case INDEX_op_muls2_i64: opc_new = INDEX_op_mul; - opc_new2 = INDEX_op_mulsh_i32; + opc_new2 = INDEX_op_mulsh; goto do_mul2; case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh; - goto do_mul2; - case INDEX_op_muls2_i64: - opc_new = INDEX_op_mul; - opc_new2 = INDEX_op_mulsh_i64; - goto do_mul2; do_mul2: nb_iargs = 2; nb_oargs = 2; @@ -5424,8 +5419,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_andc: case INDEX_op_eqv: case INDEX_op_mul: - case INDEX_op_mulsh_i32: - case INDEX_op_mulsh_i64: + case INDEX_op_mulsh: case INDEX_op_muluh: case INDEX_op_nand: case INDEX_op_nor: From 0cdacacebbe8a5e0d8a68a8c0007bff364c0e79a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 13:04:24 -0800 Subject: [PATCH 0400/2760] tcg: Convert div to TCGOutOpBinary For TCI, we're losing type information in the interpreter. Introduce a tci-specific opcode to handle the difference. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 17 ++++++++----- tcg/arm/tcg-target.c.inc | 28 +++++++++++++-------- tcg/i386/tcg-target.c.inc | 4 +++ tcg/loongarch64/tcg-target.c.inc | 24 +++++++++++------- tcg/mips/tcg-target.c.inc | 37 ++++++++++++++++------------ tcg/ppc/tcg-target.c.inc | 21 +++++++++------- tcg/riscv/tcg-target.c.inc | 21 +++++++++------- tcg/s390x/tcg-target.c.inc | 4 +++ tcg/sparc64/tcg-target.c.inc | 42 ++++++++++++++++++++++++++------ tcg/tcg-op.c | 8 +++--- tcg/tcg.c | 6 +++-- tcg/tci.c | 3 ++- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 17 ++++++++++--- 14 files changed, 156 insertions(+), 77 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 493c504682..52069f1445 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2157,6 +2157,17 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, SDIV, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2362,10 +2373,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_div_i64: - case INDEX_op_div_i32: - tcg_out_insn(s, 3508, SDIV, ext, a0, a1, a2); - break; case INDEX_op_divu_i64: case INDEX_op_divu_i32: tcg_out_insn(s, 3508, UDIV, ext, a0, a1, a2); @@ -3057,8 +3064,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_div_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i32: case INDEX_op_divu_i64: case INDEX_op_rem_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 1c19004e6e..e07e4c06d9 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -937,12 +937,6 @@ static void tcg_out_smull32(TCGContext *s, ARMCond cond, TCGReg rd0, (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); } -static void tcg_out_sdiv(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, TCGReg rm) -{ - tcg_out32(s, 0x0710f010 | (cond << 28) | (rd << 16) | rn | (rm << 8)); -} - static void tcg_out_udiv(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn, TCGReg rm) { @@ -1874,6 +1868,24 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static TCGConstraintSetIndex cset_idiv(TCGType type, unsigned flags) +{ + return use_idiv_instructions ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + /* sdiv */ + tcg_out32(s, 0x0710f010 | (COND_AL << 28) | (a0 << 16) | a1 | (a2 << 8)); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_idiv, + .out_rrr = tgen_divs, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -2218,9 +2230,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_div_i32: - tcg_out_sdiv(s, COND_AL, args[0], args[1], args[2]); - break; case INDEX_op_divu_i32: tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); break; @@ -2268,7 +2277,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctz_i32: return C_O1_I2(r, r, rIK); - case INDEX_op_div_i32: case INDEX_op_divu_i32: return C_O1_I2(r, r, r); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d0391157a4..e132dd0c88 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2633,6 +2633,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 7503270ca3..c42d8d690a 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1328,6 +1328,21 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_div_w(s, a0, a1, a2); + } else { + tcg_out_opc_div_d(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1671,13 +1686,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_div_i32: - tcg_out_opc_div_w(s, a0, a1, a2); - break; - case INDEX_op_div_i64: - tcg_out_opc_div_d(s, a0, a1, a2); - break; - case INDEX_op_divu_i32: tcg_out_opc_div_wu(s, a0, a1, a2); break; @@ -2357,8 +2365,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_div_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i32: case INDEX_op_divu_i64: case INDEX_op_rem_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index a1c215c25d..7762d88e6b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1712,6 +1712,27 @@ static const TCGOutOpBinary outop_andc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + if (type == TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2); + } else { + tcg_out_opc_reg(s, OPC_DDIV_R6, a0, a1, a2); + } + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_DIV : OPC_DDIV; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1939,13 +1960,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_div_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DIV_R6, a0, a1, a2); - break; - } - i1 = OPC_DIV, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_divu_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DIVU_R6, a0, a1, a2); @@ -1967,13 +1981,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DIVU, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_div_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DDIV_R6, a0, a1, a2); - break; - } - i1 = OPC_DDIV, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_divu_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DDIVU_R6, a0, a1, a2); @@ -2253,12 +2260,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 7ebadf396a..9fdf8df082 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2960,6 +2960,18 @@ static void tgen_eqv(TCGContext *s, TCGType type, tcg_out32(s, EQV | SAB(a1, a0, a2)); } +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? DIVW : DIVD; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_O1_I2(r, r, r), .out_rrr = tgen_eqv, @@ -3209,10 +3221,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_div_i32: - tcg_out32(s, DIVW | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_divu_i32: tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2])); break; @@ -3317,9 +3325,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_div_i64: - tcg_out32(s, DIVD | TAB(args[0], args[1], args[2])); - break; case INDEX_op_divu_i64: tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2])); break; @@ -4184,11 +4189,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 82f76b8e0c..15925729dc 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1997,6 +1997,18 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_DIVW : OPC_DIV; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2201,13 +2213,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_div_i32: - tcg_out_opc_reg(s, OPC_DIVW, a0, a1, a2); - break; - case INDEX_op_div_i64: - tcg_out_opc_reg(s, OPC_DIV, a0, a1, a2); - break; - case INDEX_op_divu_i32: tcg_out_opc_reg(s, OPC_DIVUW, a0, a1, a2); break; @@ -2730,11 +2735,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_div_i32: case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 2685e6ffa1..fd0e717c49 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2242,6 +2242,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 95a138ef56..779d0ce882 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1333,6 +1333,40 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_divs_rJ(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGArg a2, bool c2) +{ + uint32_t insn; + + if (type == TCG_TYPE_I32) { + /* Load Y with the sign extension of a1 to 64-bits. */ + tcg_out_arithi(s, TCG_REG_T1, a1, 31, SHIFT_SRA); + tcg_out_sety(s, TCG_REG_T1); + insn = ARITH_SDIV; + } else { + insn = ARITH_SDIVX; + } + tcg_out_arithc(s, a0, a1, a2, c2, insn); +} + +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_divs_rJ(s, type, a0, a1, a2, false); +} + +static void tgen_divsi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_divs_rJ(s, type, a0, a1, a2, true); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_divs, + .out_rri = tgen_divsi, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1532,9 +1566,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, c = SHIFT_SRA; goto do_shift32; - case INDEX_op_div_i32: - tcg_out_div32(s, a0, a1, a2, c2, 0); - break; case INDEX_op_divu_i32: tcg_out_div32(s, a0, a1, a2, c2, 1); break; @@ -1607,9 +1638,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i64: c = SHIFT_SRAX; goto do_shift64; - case INDEX_op_div_i64: - c = ARITH_SDIVX; - goto gen_arith; case INDEX_op_divu_i64: c = ARITH_UDIVX; goto gen_arith; @@ -1700,8 +1728,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_div_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i32: case INDEX_op_divu_i64: case INDEX_op_shl_i32: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 664c698187..69e50f968f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -601,7 +601,7 @@ void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_div_i32) { + if (tcg_op_supported(INDEX_op_div_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -617,7 +617,7 @@ void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div_i32) { + } else if (tcg_op_supported(INDEX_op_div_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); tcg_gen_mul_i32(t0, t0, arg2); @@ -1969,7 +1969,7 @@ void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_div_i64) { + if (tcg_op_supported(INDEX_op_div_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); @@ -1985,7 +1985,7 @@ void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div_i64) { + } else if (tcg_op_supported(INDEX_op_div_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); tcg_gen_mul_i64(t0, t0, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index d4b5872128..f99213a154 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1020,6 +1020,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_div_i32, TCGOutOpBinary, outop_divs), + OUTOP(INDEX_op_div_i64, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -2260,7 +2262,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return TCG_TARGET_HAS_negsetcond_i32; - case INDEX_op_div_i32: case INDEX_op_divu_i32: return TCG_TARGET_HAS_div_i32; case INDEX_op_rem_i32: @@ -2323,7 +2324,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return TCG_TARGET_HAS_negsetcond_i64; - case INDEX_op_div_i64: case INDEX_op_divu_i64: return TCG_TARGET_HAS_div_i64; case INDEX_op_rem_i64: @@ -5417,6 +5417,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_div_i32: + case INDEX_op_div_i64: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_mulsh: diff --git a/tcg/tci.c b/tcg/tci.c index 61c0ccf21e..4ecbb2d335 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -578,7 +578,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Arithmetic operations (32 bit). */ - case INDEX_op_div_i32: + case INDEX_op_tci_divs32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int32_t)regs[r1] / (int32_t)regs[r2]; break; @@ -1101,6 +1101,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: + case INDEX_op_tci_divs32: tci_args_rrr(insn, &r0, &r1, &r2); info->fprintf_func(info->stream, "%-12s %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2)); diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index ecc8c4e55e..f503374643 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -2,3 +2,4 @@ /* These opcodes for use between the tci generator and interpreter. */ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) +DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1dcce543ec..c8e86a3253 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_div_i32: - case INDEX_op_div_i64: case INDEX_op_divu_i32: case INDEX_op_divu_i64: case INDEX_op_rem_i32: @@ -648,6 +646,20 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_divs(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_divs32 + : INDEX_op_div_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divs = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divs, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -811,7 +823,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ - CASE_32_64(div) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(divu) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(rem) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(remu) /* Optional (TCG_TARGET_HAS_div_*). */ From b2c514f9d5cab89814dc8a6b7c98c653ca8523d3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 13:22:56 -0800 Subject: [PATCH 0401/2760] tcg: Merge INDEX_op_div_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename to INDEX_op_divs to emphasize signed inputs, and mirroring INDEX_op_divu_*. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 12 +++++++----- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 22 insertions(+), 24 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index fe922d1dac..a833b3b7b2 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -277,7 +277,7 @@ Arithmetic - | *t0* = *t1* * *t2* - * - div_i32/i64 *t0*, *t1*, *t2* + * - divs *t0*, *t1*, *t2* - | *t0* = *t1* / *t2* (signed) | Undefined behavior if division by zero or overflow. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index a9d7938a52..6d4edd0b16 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -42,6 +42,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) +DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) @@ -68,7 +69,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(div_i32, 1, 2, 0, 0) DEF(divu_i32, 1, 2, 0, 0) DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) @@ -116,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(div_i64, 1, 2, 0, 0) DEF(divu_i64, 1, 2, 0, 0) DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index fd446fc47d..af9054be37 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -556,13 +556,15 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, muls64(&l64, &h64, x, y); return h64; - case INDEX_op_div_i32: + case INDEX_op_divs: /* Avoid crashing on divide by zero, otherwise undefined. */ - return (int32_t)x / ((int32_t)y ? : 1); + if (type == TCG_TYPE_I32) { + return (int32_t)x / ((int32_t)y ? : 1); + } + return (int64_t)x / ((int64_t)y ? : 1); + case INDEX_op_divu_i32: return (uint32_t)x / ((uint32_t)y ? : 1); - case INDEX_op_div_i64: - return (int64_t)x / ((int64_t)y ? : 1); case INDEX_op_divu_i64: return (uint64_t)x / ((uint64_t)y ? : 1); @@ -2905,7 +2907,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(deposit): done = fold_deposit(&ctx, op); break; - CASE_OP_32_64(div): + case INDEX_op_divs: CASE_OP_32_64(divu): done = fold_divide(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 69e50f968f..9dba520d40 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -601,8 +601,8 @@ void tcg_gen_muli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_div_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_div_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_divs, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_sari_i32(t0, arg1, 31); @@ -617,9 +617,9 @@ void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_div_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); - tcg_gen_op3_i32(INDEX_op_div_i32, t0, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_divs, t0, arg1, arg2); tcg_gen_mul_i32(t0, t0, arg2); tcg_gen_sub_i32(ret, arg1, t0); tcg_temp_free_i32(t0); @@ -1969,8 +1969,8 @@ void tcg_gen_muli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_div_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_div_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_divs, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_sari_i64(t0, arg1, 63); @@ -1985,9 +1985,9 @@ void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_div_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - tcg_gen_op3_i64(INDEX_op_div_i64, t0, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_divs, t0, arg1, arg2); tcg_gen_mul_i64(t0, t0, arg2); tcg_gen_sub_i64(ret, arg1, t0); tcg_temp_free_i64(t0); diff --git a/tcg/tcg.c b/tcg/tcg.c index f99213a154..d4e30d0b33 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1020,8 +1020,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_div_i32, TCGOutOpBinary, outop_divs), - OUTOP(INDEX_op_div_i64, TCGOutOpBinary, outop_divs), + OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -5417,8 +5416,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: - case INDEX_op_div_i32: - case INDEX_op_div_i64: + case INDEX_op_divs: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_mulsh: diff --git a/tcg/tci.c b/tcg/tci.c index 4ecbb2d335..4b3ca53bc5 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -720,7 +720,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Arithmetic operations (64 bit). */ - case INDEX_op_div_i64: + case INDEX_op_divs: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int64_t)regs[r1] / (int64_t)regs[r2]; break; @@ -1071,6 +1071,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_divs: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_nand: @@ -1079,8 +1080,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_orc: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_div_i32: - case INDEX_op_div_i64: case INDEX_op_rem_i32: case INDEX_op_rem_i64: case INDEX_op_divu_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index c8e86a3253..4a556e2ce7 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -651,7 +651,7 @@ static void tgen_divs(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_divs32 - : INDEX_op_div_i64); + : INDEX_op_divs); tcg_out_op_rrr(s, opc, a0, a1, a2); } From 6d1a2365eaee0603347fd2fabd89a8dc935c8ac7 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 14:10:27 -0800 Subject: [PATCH 0402/2760] tcg: Convert divu to TCGOutOpBinary For TCI, we're losing type information in the interpreter. Introduce a tci-specific opcode to handle the difference. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 18 ++++++---- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 26 +++++++------- tcg/i386/tcg-target.c.inc | 4 +++ tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 24 ++++++++----- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 37 ++++++++++--------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 21 ++++++----- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 21 ++++++----- tcg/s390x/tcg-target.c.inc | 4 +++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 61 +++++++++++++++++--------------- tcg/tcg-has.h | 15 ++++---- tcg/tcg-op.c | 8 ++--- tcg/tcg.c | 8 ++--- tcg/tci.c | 3 +- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 17 +++++++-- 23 files changed, 157 insertions(+), 126 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index bde6db8f2a..e961668ef0 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,7 +13,6 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -30,7 +29,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 52069f1445..167c51c897 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2168,6 +2168,17 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, UDIV, type, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2373,11 +2384,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_divu_i64: - case INDEX_op_divu_i32: - tcg_out_insn(s, 3508, UDIV, ext, a0, a1, a2); - break; - case INDEX_op_rem_i64: case INDEX_op_rem_i32: tcg_out_insn(s, 3508, SDIV, ext, TCG_REG_TMP0, a1, a2); @@ -3064,8 +3070,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i32: case INDEX_op_rem_i64: case INDEX_op_remu_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index ab9b7b6162..6ed2b49c84 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -34,7 +34,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_div_i32 use_idiv_instructions #define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index e07e4c06d9..65d0ae83b2 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -937,12 +937,6 @@ static void tcg_out_smull32(TCGContext *s, ARMCond cond, TCGReg rd0, (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); } -static void tcg_out_udiv(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, TCGReg rm) -{ - tcg_out32(s, 0x0730f010 | (cond << 28) | (rd << 16) | rn | (rm << 8)); -} - static void tcg_out_ext8s(TCGContext *s, TCGType t, TCGReg rd, TCGReg rn) { /* sxtb */ @@ -1886,6 +1880,19 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + /* udiv */ + tcg_out32(s, 0x0730f010 | (COND_AL << 28) | (a0 << 16) | a1 | (a2 << 8)); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_idiv, + .out_rrr = tgen_divu, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -2230,10 +2237,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_divu_i32: - tcg_out_udiv(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_mb: tcg_out_mb(s, args[0]); break; @@ -2277,9 +2280,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctz_i32: return C_O1_I2(r, r, rIK); - case INDEX_op_divu_i32: - return C_O1_I2(r, r, r); - case INDEX_op_mulu2_i32: case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index e132dd0c88..f258d6383b 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2637,6 +2637,10 @@ static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index e29c892756..96a99b6d4c 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 0 -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 #define TCG_TARGET_HAS_rot_i32 1 @@ -29,7 +28,6 @@ /* 64-bit operations */ #define TCG_TARGET_HAS_negsetcond_i64 0 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index c42d8d690a..e82a62d09e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1343,6 +1343,21 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_div_wu(s, a0, a1, a2); + } else { + tcg_out_opc_div_du(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1686,13 +1701,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_divu_i32: - tcg_out_opc_div_wu(s, a0, a1, a2); - break; - case INDEX_op_divu_i64: - tcg_out_opc_div_du(s, a0, a1, a2); - break; - case INDEX_op_rem_i32: tcg_out_opc_mod_w(s, a0, a1, a2); break; @@ -2365,8 +2373,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i32: case INDEX_op_rem_i64: case INDEX_op_remu_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index ebaaa49cdd..9aa5bf9f1b 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,7 +39,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) @@ -51,7 +50,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 7762d88e6b..ab9546f104 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1733,6 +1733,27 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + if (type == TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_DIVU_R6, a0, a1, a2); + } else { + tcg_out_opc_reg(s, OPC_DDIVU_R6, a0, a1, a2); + } + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_DIVU : OPC_DDIVU; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1960,13 +1981,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_divu_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DIVU_R6, a0, a1, a2); - break; - } - i1 = OPC_DIVU, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_rem_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_MOD, a0, a1, a2); @@ -1981,13 +1995,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DIVU, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_divu_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DDIVU_R6, a0, a1, a2); - break; - } - i1 = OPC_DDIVU, i2 = OPC_MFLO; - goto do_hilo1; case INDEX_op_rem_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DMOD, a0, a1, a2); @@ -2260,11 +2267,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: case INDEX_op_setcond_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index bbbd8de2c7..f8e4c0ad3c 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,7 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 have_isa_3_00 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 @@ -35,7 +34,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 have_isa_3_00 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 9fdf8df082..b347595131 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2972,6 +2972,18 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? DIVWU : DIVDU; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_O1_I2(r, r, r), .out_rrr = tgen_eqv, @@ -3221,10 +3233,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_divu_i32: - tcg_out32(s, DIVWU | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_rem_i32: tcg_out32(s, MODSW | TAB(args[0], args[1], args[2])); break; @@ -3325,9 +3333,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_divu_i64: - tcg_out32(s, DIVDU | TAB(args[0], args[1], args[2])); - break; case INDEX_op_rem_i64: tcg_out32(s, MODSD | TAB(args[0], args[1], args[2])); break; @@ -4189,10 +4194,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: return C_O1_I2(r, r, r); diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index f7e1ef82fc..ae6624b9a4 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 1 -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_div2_i32 0 #define TCG_TARGET_HAS_rot_i32 (cpuinfo & CPUINFO_ZBB) @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_negsetcond_i64 1 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 15925729dc..74fa38d273 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2009,6 +2009,18 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_DIVUW : OPC_DIVU; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2213,13 +2225,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_divu_i32: - tcg_out_opc_reg(s, OPC_DIVUW, a0, a1, a2); - break; - case INDEX_op_divu_i64: - tcg_out_opc_reg(s, OPC_DIVU, a0, a1, a2); - break; - case INDEX_op_rem_i32: tcg_out_opc_reg(s, OPC_REMW, a0, a1, a2); break; @@ -2735,10 +2740,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_divu_i32: case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i64: case INDEX_op_remu_i64: return C_O1_I2(r, rz, rz); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index fd0e717c49..f55309f48e 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2246,6 +2246,10 @@ static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 5a517b6835..35f0dd4230 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,7 +14,6 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 0 #define TCG_TARGET_HAS_bswap16_i32 0 @@ -31,7 +30,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 779d0ce882..3a3372d7aa 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -596,21 +596,6 @@ static void tcg_out_sety(TCGContext *s, TCGReg rs) tcg_out32(s, WRY | INSN_RS1(TCG_REG_G0) | INSN_RS2(rs)); } -static void tcg_out_div32(TCGContext *s, TCGReg rd, TCGReg rs1, - int32_t val2, int val2const, int uns) -{ - /* Load Y with the sign/zero extension of RS1 to 64-bits. */ - if (uns) { - tcg_out_sety(s, TCG_REG_G0); - } else { - tcg_out_arithi(s, TCG_REG_T1, rs1, 31, SHIFT_SRA); - tcg_out_sety(s, TCG_REG_T1); - } - - tcg_out_arithc(s, rd, rs1, val2, val2const, - uns ? ARITH_UDIV : ARITH_SDIV); -} - static const uint8_t tcg_cond_to_bcond[16] = { [TCG_COND_EQ] = COND_E, [TCG_COND_NE] = COND_NE, @@ -1367,6 +1352,39 @@ static const TCGOutOpBinary outop_divs = { .out_rri = tgen_divsi, }; +static void tgen_divu_rJ(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGArg a2, bool c2) +{ + uint32_t insn; + + if (type == TCG_TYPE_I32) { + /* Load Y with the zero extension to 64-bits. */ + tcg_out_sety(s, TCG_REG_G0); + insn = ARITH_UDIV; + } else { + insn = ARITH_UDIVX; + } + tcg_out_arithc(s, a0, a1, a2, c2, insn); +} + +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_divu_rJ(s, type, a0, a1, a2, false); +} + +static void tgen_divui(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_divu_rJ(s, type, a0, a1, a2, true); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_divu, + .out_rri = tgen_divui, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -1566,10 +1584,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, c = SHIFT_SRA; goto do_shift32; - case INDEX_op_divu_i32: - tcg_out_div32(s, a0, a1, a2, c2, 1); - break; - case INDEX_op_brcond_i32: tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], arg_label(args[3])); break; @@ -1638,9 +1652,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i64: c = SHIFT_SRAX; goto do_shift64; - case INDEX_op_divu_i64: - c = ARITH_UDIVX; - goto gen_arith; case INDEX_op_brcond_i64: tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); @@ -1663,10 +1674,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const_args[4], args[5], const_args[5], true); break; - gen_arith: - tcg_out_arithc(s, a0, a1, a2, c2, c); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -1728,8 +1735,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 3d4c67698f..9680ccfc53 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -33,17 +33,16 @@ #define TCG_TARGET_HAS_sub2_i32 1 #endif -/* Only one of DIV or DIV2 should be defined. */ -#if defined(TCG_TARGET_HAS_div_i32) +#ifndef TCG_TARGET_HAS_div2_i32 #define TCG_TARGET_HAS_div2_i32 0 -#elif defined(TCG_TARGET_HAS_div2_i32) -#define TCG_TARGET_HAS_div_i32 0 +#endif +#ifndef TCG_TARGET_HAS_div2_i64 +#define TCG_TARGET_HAS_div2_i64 0 +#endif +#ifndef TCG_TARGET_HAS_rem_i32 #define TCG_TARGET_HAS_rem_i32 0 #endif -#if defined(TCG_TARGET_HAS_div_i64) -#define TCG_TARGET_HAS_div2_i64 0 -#elif defined(TCG_TARGET_HAS_div2_i64) -#define TCG_TARGET_HAS_div_i64 0 +#ifndef TCG_TARGET_HAS_rem_i64 #define TCG_TARGET_HAS_rem_i64 0 #endif diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 9dba520d40..19be461214 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -635,7 +635,7 @@ void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_div_i32) { + if (tcg_op_supported(INDEX_op_divu_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -651,7 +651,7 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div_i32) { + } else if (tcg_op_supported(INDEX_op_divu_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); tcg_gen_mul_i32(t0, t0, arg2); @@ -2003,7 +2003,7 @@ void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_div_i64) { + if (tcg_op_supported(INDEX_op_divu_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); @@ -2019,7 +2019,7 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div_i64) { + } else if (tcg_op_supported(INDEX_op_divu_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); tcg_gen_mul_i64(t0, t0, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index d4e30d0b33..a0e58c07d7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1021,6 +1021,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), + OUTOP(INDEX_op_divu_i32, TCGOutOpBinary, outop_divu), + OUTOP(INDEX_op_divu_i64, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -2261,8 +2263,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return TCG_TARGET_HAS_negsetcond_i32; - case INDEX_op_divu_i32: - return TCG_TARGET_HAS_div_i32; case INDEX_op_rem_i32: case INDEX_op_remu_i32: return TCG_TARGET_HAS_rem_i32; @@ -2323,8 +2323,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return TCG_TARGET_HAS_negsetcond_i64; - case INDEX_op_divu_i64: - return TCG_TARGET_HAS_div_i64; case INDEX_op_rem_i64: case INDEX_op_remu_i64: return TCG_TARGET_HAS_rem_i64; @@ -5417,6 +5415,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_divs: + case INDEX_op_divu_i32: + case INDEX_op_divu_i64: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_mulsh: diff --git a/tcg/tci.c b/tcg/tci.c index 4b3ca53bc5..0691824f97 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -582,7 +582,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int32_t)regs[r1] / (int32_t)regs[r2]; break; - case INDEX_op_divu_i32: + case INDEX_op_tci_divu32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint32_t)regs[r1] / (uint32_t)regs[r2]; break; @@ -1101,6 +1101,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: case INDEX_op_tci_divs32: + case INDEX_op_tci_divu32: tci_args_rrr(insn, &r0, &r1, &r2); info->fprintf_func(info->stream, "%-12s %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2)); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 0627585097..ccec96b610 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -9,7 +9,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_div_i32 1 #define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_clz_i32 1 @@ -26,7 +25,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_div_i64 1 #define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index f503374643..43c07a269f 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -3,3 +3,4 @@ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4a556e2ce7..18a10156a6 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: case INDEX_op_rem_i32: case INDEX_op_rem_i64: case INDEX_op_remu_i32: @@ -660,6 +658,20 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static void tgen_divu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_divu32 + : INDEX_op_divu_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_divu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_divu, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -823,7 +835,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ - CASE_32_64(divu) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(rem) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(remu) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ From 961b80aecd1a503eedb885c309a1d5267d89c98c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 14:27:19 -0800 Subject: [PATCH 0403/2760] tcg: Merge INDEX_op_divu_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 9 +++++---- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 20 insertions(+), 23 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index a833b3b7b2..41985be012 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -282,7 +282,7 @@ Arithmetic - | *t0* = *t1* / *t2* (signed) | Undefined behavior if division by zero or overflow. - * - divu_i32/i64 *t0*, *t1*, *t2* + * - divu *t0*, *t1*, *t2* - | *t0* = *t1* / *t2* (unsigned) | Undefined behavior if division by zero. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 6d4edd0b16..243f002a61 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) +DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) @@ -69,7 +70,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(divu_i32, 1, 2, 0, 0) DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) DEF(div2_i32, 2, 3, 0, 0) @@ -116,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(divu_i64, 1, 2, 0, 0) DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) DEF(div2_i64, 2, 3, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index af9054be37..c11cce782a 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -563,9 +563,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (int64_t)x / ((int64_t)y ? : 1); - case INDEX_op_divu_i32: - return (uint32_t)x / ((uint32_t)y ? : 1); - case INDEX_op_divu_i64: + case INDEX_op_divu: + if (type == TCG_TYPE_I32) { + return (uint32_t)x / ((uint32_t)y ? : 1); + } return (uint64_t)x / ((uint64_t)y ? : 1); case INDEX_op_rem_i32: @@ -2908,7 +2909,7 @@ void tcg_optimize(TCGContext *s) done = fold_deposit(&ctx, op); break; case INDEX_op_divs: - CASE_OP_32_64(divu): + case INDEX_op_divu: done = fold_divide(&ctx, op); break; case INDEX_op_dup_vec: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 19be461214..f326c452a4 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -635,8 +635,8 @@ void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_divu_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_divu_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_divu, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i32) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); @@ -651,9 +651,9 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (TCG_TARGET_HAS_rem_i32) { tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_divu_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); - tcg_gen_op3_i32(INDEX_op_divu_i32, t0, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_divu, t0, arg1, arg2); tcg_gen_mul_i32(t0, t0, arg2); tcg_gen_sub_i32(ret, arg1, t0); tcg_temp_free_i32(t0); @@ -2003,8 +2003,8 @@ void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_divu_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_divu_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_divu, ret, arg1, arg2); } else if (TCG_TARGET_HAS_div2_i64) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 zero = tcg_constant_i64(0); @@ -2019,9 +2019,9 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_HAS_rem_i64) { tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_divu_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - tcg_gen_op3_i64(INDEX_op_divu_i64, t0, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_divu, t0, arg1, arg2); tcg_gen_mul_i64(t0, t0, arg2); tcg_gen_sub_i64(ret, arg1, t0); tcg_temp_free_i64(t0); diff --git a/tcg/tcg.c b/tcg/tcg.c index a0e58c07d7..9aa6d40905 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1021,8 +1021,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), - OUTOP(INDEX_op_divu_i32, TCGOutOpBinary, outop_divu), - OUTOP(INDEX_op_divu_i64, TCGOutOpBinary, outop_divu), + OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -5415,8 +5414,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_divs: - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: + case INDEX_op_divu: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_mulsh: diff --git a/tcg/tci.c b/tcg/tci.c index 0691824f97..bf97849bfe 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -724,7 +724,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int64_t)regs[r1] / (int64_t)regs[r2]; break; - case INDEX_op_divu_i64: + case INDEX_op_divu: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint64_t)regs[r1] / (uint64_t)regs[r2]; break; @@ -1072,6 +1072,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_divs: + case INDEX_op_divu: case INDEX_op_eqv: case INDEX_op_mul: case INDEX_op_nand: @@ -1082,8 +1083,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_xor: case INDEX_op_rem_i32: case INDEX_op_rem_i64: - case INDEX_op_divu_i32: - case INDEX_op_divu_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: case INDEX_op_shl_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 18a10156a6..dfa8aecc7a 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -663,7 +663,7 @@ static void tgen_divu(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_divu32 - : INDEX_op_divu_i64); + : INDEX_op_divu); tcg_out_op_rrr(s, opc, a0, a1, a2); } From d6cad9c9278566deb7f646f027c056ba24f7988d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 16:32:29 -0800 Subject: [PATCH 0404/2760] tcg: Convert div2 to TCGOutOpDivRem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 4 +++ tcg/arm/tcg-target.c.inc | 4 +++ tcg/i386/tcg-target.c.inc | 17 ++++++++---- tcg/loongarch64/tcg-target.c.inc | 4 +++ tcg/mips/tcg-target.c.inc | 4 +++ tcg/ppc/tcg-target.c.inc | 4 +++ tcg/riscv/tcg-target.c.inc | 4 +++ tcg/s390x/tcg-target.c.inc | 44 ++++++++++++++++---------------- tcg/sparc64/tcg-target.c.inc | 4 +++ tcg/tcg.c | 24 +++++++++++++++-- tcg/tci/tcg-target.c.inc | 4 +++ 11 files changed, 88 insertions(+), 29 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 167c51c897..ea5766414d 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2168,6 +2168,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 65d0ae83b2..ff750e2df8 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1880,6 +1880,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index f258d6383b..9238e0e8e4 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2637,6 +2637,18 @@ static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; +static void tgen_divs2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a4) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, a4); +} + +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_O2_I3(a, d, 0, 1, r), + .out_rr01r = tgen_divs2, +}; + static const TCGOutOpBinary outop_divu = { .base.static_constraint = C_NotImplemented, }; @@ -2847,9 +2859,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(div2): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IDIV, args[4]); - break; OP_32_64(divu2): tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]); break; @@ -3789,8 +3798,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, reT, r, 0); - case INDEX_op_div2_i32: - case INDEX_op_div2_i64: case INDEX_op_divu2_i32: case INDEX_op_divu2_i64: return C_O2_I3(a, d, 0, 1, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e82a62d09e..8ec46114b8 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1343,6 +1343,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index ab9546f104..adbc7ee39d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1733,6 +1733,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index b347595131..1eb3e785c0 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2972,6 +2972,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 74fa38d273..19c690c1c2 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2009,6 +2009,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index f55309f48e..b434ce423a 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2246,6 +2246,28 @@ static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; +static void tgen_divs2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a4) +{ + tcg_debug_assert((a1 & 1) == 0); + tcg_debug_assert(a0 == a1 + 1); + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RR, DR, a1, a4); + } else { + /* + * TODO: Move the sign-extend of the numerator from a2 into a3 + * into the tcg backend, instead of in early expansion. It is + * required for 32-bit DR, but not 64-bit DSGR. + */ + tcg_out_insn(s, RRE, DSGR, a1, a4); + } +} + +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_O2_I3(o, m, 0, 1, r), + .out_rr01r = tgen_divs2, +}; + static const TCGOutOpBinary outop_divu = { .base.static_constraint = C_NotImplemented, }; @@ -2527,13 +2549,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_div2_i32: - tcg_debug_assert(args[0] == args[2]); - tcg_debug_assert(args[1] == args[3]); - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RR, DR, args[1], args[4]); - break; case INDEX_op_divu2_i32: tcg_debug_assert(args[0] == args[2]); tcg_debug_assert(args[1] == args[3]); @@ -2702,19 +2717,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; - case INDEX_op_div2_i64: - /* - * ??? We get an unnecessary sign-extension of the dividend - * into op0 with this definition, but as we do in fact always - * produce both quotient and remainder using INDEX_op_div_i64 - * instead requires jumping through even more hoops. - */ - tcg_debug_assert(args[0] == args[2]); - tcg_debug_assert(args[1] == args[3]); - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RRE, DSGR, args[1], args[4]); - break; case INDEX_op_divu2_i64: tcg_debug_assert(args[0] == args[2]); tcg_debug_assert(args[1] == args[3]); @@ -3396,8 +3398,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rI, r); - case INDEX_op_div2_i32: - case INDEX_op_div2_i64: case INDEX_op_divu2_i32: case INDEX_op_divu2_i64: return C_O2_I3(o, m, 0, 1, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 3a3372d7aa..472ccd7608 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1352,6 +1352,10 @@ static const TCGOutOpBinary outop_divs = { .out_rri = tgen_divsi, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu_rJ(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGArg a2, bool c2) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 9aa6d40905..ef3af4157a 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -986,6 +986,12 @@ typedef struct TCGOutOpBinary { TCGReg a0, TCGReg a1, tcg_target_long a2); } TCGOutOpBinary; +typedef struct TCGOutOpDivRem { + TCGOutOp base; + void (*out_rr01r)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a4); +} TCGOutOpDivRem; + typedef struct TCGOutOpUnary { TCGOutOp base; void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); @@ -1022,6 +1028,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), + OUTOP(INDEX_op_div2_i32, TCGOutOpDivRem, outop_divs2), + OUTOP(INDEX_op_div2_i64, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -2265,7 +2273,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i32: case INDEX_op_remu_i32: return TCG_TARGET_HAS_rem_i32; - case INDEX_op_div2_i32: case INDEX_op_divu2_i32: return TCG_TARGET_HAS_div2_i32; case INDEX_op_rotl_i32: @@ -2325,7 +2332,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i64: return TCG_TARGET_HAS_rem_i64; - case INDEX_op_div2_i64: case INDEX_op_divu2_i64: return TCG_TARGET_HAS_div2_i64; case INDEX_op_rotl_i64: @@ -5467,6 +5473,20 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_div2_i32: + case INDEX_op_div2_i64: + { + const TCGOutOpDivRem *out = + container_of(all_outop[op->opc], TCGOutOpDivRem, base); + + /* Only used by x86 and s390x, which use matching constraints. */ + tcg_debug_assert(new_args[0] == new_args[2]); + tcg_debug_assert(new_args[1] == new_args[3]); + tcg_debug_assert(!const_args[4]); + out->out_rr01r(s, type, new_args[0], new_args[1], new_args[4]); + } + break; + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index dfa8aecc7a..6646be224d 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -658,6 +658,10 @@ static const TCGOutOpBinary outop_divs = { .out_rrr = tgen_divs, }; +static const TCGOutOpDivRem outop_divs2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divu(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From ee1805b9e66d6b6229270a339586058bbf275412 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 16:44:23 -0800 Subject: [PATCH 0405/2760] tcg: Merge INDEX_op_div2_{i32,i64} Rename to INDEX_op_divs2 to emphasize signed inputs, and mirroring INDEX_op_divu2_*. Document the opcode. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 9 +++++++++ include/tcg/tcg-opc.h | 3 +-- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 41985be012..62af390854 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -297,6 +297,15 @@ Arithmetic - | *t0* = *t1* % *t2* (unsigned) | Undefined behavior if division by zero. + * - divs2 *q*, *r*, *nl*, *nh*, *d* + + - | *q* = *nh:nl* / *d* (signed) + | *r* = *nh:nl* % *d* + | Undefined behaviour if division by zero, or the double-word + numerator divided by the single-word divisor does not fit + within the single-word quotient. The code generator will + pass *nh* as a simple sign-extension of *nl*, so the only + overflow should be *INT_MIN* / -1. Logical ------- diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 243f002a61..36dfbf80ad 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) +DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) @@ -72,7 +73,6 @@ DEF(st_i32, 0, 2, 1, 0) /* arith */ DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) -DEF(div2_i32, 2, 3, 0, 0) DEF(divu2_i32, 2, 3, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) @@ -118,7 +118,6 @@ DEF(st_i64, 0, 2, 1, 0) /* arith */ DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) -DEF(div2_i64, 2, 3, 0, 0) DEF(divu2_i64, 2, 3, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index f326c452a4..f95beb8b5d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -603,10 +603,10 @@ void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_divs, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div2_i32) { + } else if (tcg_op_supported(INDEX_op_divs2, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_sari_i32(t0, arg1, 31); - tcg_gen_op5_i32(INDEX_op_div2_i32, ret, t0, arg1, t0, arg2); + tcg_gen_op5_i32(INDEX_op_divs2, ret, t0, arg1, t0, arg2); tcg_temp_free_i32(t0); } else { gen_helper_div_i32(ret, arg1, arg2); @@ -623,10 +623,10 @@ void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_mul_i32(t0, t0, arg2); tcg_gen_sub_i32(ret, arg1, t0); tcg_temp_free_i32(t0); - } else if (TCG_TARGET_HAS_div2_i32) { + } else if (tcg_op_supported(INDEX_op_divs2, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_sari_i32(t0, arg1, 31); - tcg_gen_op5_i32(INDEX_op_div2_i32, t0, ret, arg1, t0, arg2); + tcg_gen_op5_i32(INDEX_op_divs2, t0, ret, arg1, t0, arg2); tcg_temp_free_i32(t0); } else { gen_helper_rem_i32(ret, arg1, arg2); @@ -1971,10 +1971,10 @@ void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_divs, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div2_i64) { + } else if (tcg_op_supported(INDEX_op_divs2, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_sari_i64(t0, arg1, 63); - tcg_gen_op5_i64(INDEX_op_div2_i64, ret, t0, arg1, t0, arg2); + tcg_gen_op5_i64(INDEX_op_divs2, ret, t0, arg1, t0, arg2); tcg_temp_free_i64(t0); } else { gen_helper_div_i64(ret, arg1, arg2); @@ -1991,10 +1991,10 @@ void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_mul_i64(t0, t0, arg2); tcg_gen_sub_i64(ret, arg1, t0); tcg_temp_free_i64(t0); - } else if (TCG_TARGET_HAS_div2_i64) { + } else if (tcg_op_supported(INDEX_op_divs2, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_sari_i64(t0, arg1, 63); - tcg_gen_op5_i64(INDEX_op_div2_i64, t0, ret, arg1, t0, arg2); + tcg_gen_op5_i64(INDEX_op_divs2, t0, ret, arg1, t0, arg2); tcg_temp_free_i64(t0); } else { gen_helper_rem_i64(ret, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index ef3af4157a..30b7f8ee19 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1028,8 +1028,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), - OUTOP(INDEX_op_div2_i32, TCGOutOpDivRem, outop_divs2), - OUTOP(INDEX_op_div2_i64, TCGOutOpDivRem, outop_divs2), + OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -5473,8 +5472,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_div2_i32: - case INDEX_op_div2_i64: + case INDEX_op_divs2: { const TCGOutOpDivRem *out = container_of(all_outop[op->opc], TCGOutOpDivRem, base); From 9bf558ed17c274b172549894e8e343e6a1a1508c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 18:10:14 -0800 Subject: [PATCH 0406/2760] tcg: Convert divu2 to TCGOutOpDivRem Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 4 ++++ tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 20 +++++++++++------- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 4 ++++ tcg/mips/tcg-target.c.inc | 4 ++++ tcg/ppc/tcg-target.c.inc | 4 ++++ tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 4 ++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 36 +++++++++++++++----------------- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 7 ------- tcg/tcg-op.c | 8 +++---- tcg/tcg.c | 8 +++---- tcg/tci/tcg-target.c.inc | 4 ++++ 17 files changed, 69 insertions(+), 50 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index ea5766414d..456159cdc6 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2183,6 +2183,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index ff750e2df8..b2c08bba3e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1897,6 +1897,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 121fb95ee0..aee6066579 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,7 +26,6 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_div2_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -43,7 +42,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 9238e0e8e4..0e6b743fb2 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2653,6 +2653,18 @@ static const TCGOutOpBinary outop_divu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_divu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a4) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, a4); +} + +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_O2_I3(a, d, 0, 1, r), + .out_rr01r = tgen_divu2, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; @@ -2859,10 +2871,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(divu2): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_DIV, args[4]); - break; - OP_32_64(shl): /* For small constant 3-operand shift, use LEA. */ if (const_a2 && a0 != a1 && (a2 - 1) < 3) { @@ -3798,10 +3806,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, reT, r, 0); - case INDEX_op_divu2_i32: - case INDEX_op_divu2_i64: - return C_O2_I3(a, d, 0, 1, r); - case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: case INDEX_op_muls2_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 96a99b6d4c..aecd2879b8 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -12,7 +12,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_div2_i32 0 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 @@ -29,7 +28,6 @@ /* 64-bit operations */ #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 8ec46114b8..be09c362cb 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1362,6 +1362,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index adbc7ee39d..280afbf297 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1758,6 +1758,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 1eb3e785c0..8b14d57d1c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2988,6 +2988,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_O1_I2(r, r, r), .out_rrr = tgen_eqv, diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index ae6624b9a4..e5861e5260 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -12,7 +12,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_rem_i32 1 -#define TCG_TARGET_HAS_div2_i32 0 #define TCG_TARGET_HAS_rot_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_rem_i64 1 -#define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 19c690c1c2..72910b0f25 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2025,6 +2025,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 64f1805641..d61cc7a144 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,7 +29,6 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_div2_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -45,7 +44,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_div2_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index b434ce423a..9af626eec2 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2272,6 +2272,23 @@ static const TCGOutOpBinary outop_divu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_divu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a4) +{ + tcg_debug_assert((a1 & 1) == 0); + tcg_debug_assert(a0 == a1 + 1); + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRE, DLR, a1, a4); + } else { + tcg_out_insn(s, RRE, DLGR, a1, a4); + } +} + +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_O2_I3(o, m, 0, 1, r), + .out_rr01r = tgen_divu2, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2549,14 +2566,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_divu2_i32: - tcg_debug_assert(args[0] == args[2]); - tcg_debug_assert(args[1] == args[3]); - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RRE, DLR, args[1], args[4]); - break; - case INDEX_op_shl_i32: op = RS_SLL; op2 = RSY_SLLK; @@ -2717,13 +2726,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; - case INDEX_op_divu2_i64: - tcg_debug_assert(args[0] == args[2]); - tcg_debug_assert(args[1] == args[3]); - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RRE, DLGR, args[1], args[4]); - break; case INDEX_op_mulu2_i64: tcg_debug_assert(args[0] == args[2]); tcg_debug_assert((args[1] & 1) == 0); @@ -3398,10 +3400,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rI, r); - case INDEX_op_divu2_i32: - case INDEX_op_divu2_i64: - return C_O2_I3(o, m, 0, 1, r); - case INDEX_op_mulu2_i64: return C_O2_I2(o, m, 0, r); case INDEX_op_muls2_i64: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 472ccd7608..a4659653b3 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1389,6 +1389,10 @@ static const TCGOutOpBinary outop_divu = { .out_rri = tgen_divui, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 9680ccfc53..bae9918024 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -14,7 +14,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_div_i64 0 #define TCG_TARGET_HAS_rem_i64 0 -#define TCG_TARGET_HAS_div2_i64 0 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 @@ -33,12 +32,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #endif -#ifndef TCG_TARGET_HAS_div2_i32 -#define TCG_TARGET_HAS_div2_i32 0 -#endif -#ifndef TCG_TARGET_HAS_div2_i64 -#define TCG_TARGET_HAS_div2_i64 0 -#endif #ifndef TCG_TARGET_HAS_rem_i32 #define TCG_TARGET_HAS_rem_i32 0 #endif diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index f95beb8b5d..5511106554 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -637,7 +637,7 @@ void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_divu, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div2_i32) { + } else if (tcg_op_supported(INDEX_op_divu2_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, zero, arg2); @@ -657,7 +657,7 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_mul_i32(t0, t0, arg2); tcg_gen_sub_i32(ret, arg1, t0); tcg_temp_free_i32(t0); - } else if (TCG_TARGET_HAS_div2_i32) { + } else if (tcg_op_supported(INDEX_op_divu2_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, zero, arg2); @@ -2005,7 +2005,7 @@ void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_divu, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_div2_i64) { + } else if (tcg_op_supported(INDEX_op_divu2_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 zero = tcg_constant_i64(0); tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, zero, arg2); @@ -2025,7 +2025,7 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_mul_i64(t0, t0, arg2); tcg_gen_sub_i64(ret, arg1, t0); tcg_temp_free_i64(t0); - } else if (TCG_TARGET_HAS_div2_i64) { + } else if (tcg_op_supported(INDEX_op_divu2_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 zero = tcg_constant_i64(0); tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, zero, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 30b7f8ee19..1029cba3f0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1029,6 +1029,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), + OUTOP(INDEX_op_divu2_i32, TCGOutOpDivRem, outop_divu2), + OUTOP(INDEX_op_divu2_i64, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -2272,8 +2274,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i32: case INDEX_op_remu_i32: return TCG_TARGET_HAS_rem_i32; - case INDEX_op_divu2_i32: - return TCG_TARGET_HAS_div2_i32; case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: return TCG_TARGET_HAS_rot_i32; @@ -2331,8 +2331,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rem_i64: case INDEX_op_remu_i64: return TCG_TARGET_HAS_rem_i64; - case INDEX_op_divu2_i64: - return TCG_TARGET_HAS_div2_i64; case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: return TCG_TARGET_HAS_rot_i64; @@ -5473,6 +5471,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_divs2: + case INDEX_op_divu2_i32: + case INDEX_op_divu2_i64: { const TCGOutOpDivRem *out = container_of(all_outop[op->opc], TCGOutOpDivRem, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 6646be224d..27271c178c 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -676,6 +676,10 @@ static const TCGOutOpBinary outop_divu = { .out_rrr = tgen_divu, }; +static const TCGOutOpDivRem outop_divu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From 8109598b683ad2b6b02cd9c79dc15b7fc0b685aa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 18:23:17 -0800 Subject: [PATCH 0407/2760] tcg: Merge INDEX_op_divu2_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 10 ++++++++++ include/tcg/tcg-opc.h | 3 +-- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 62af390854..8f3b5e91b2 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -307,6 +307,16 @@ Arithmetic pass *nh* as a simple sign-extension of *nl*, so the only overflow should be *INT_MIN* / -1. + * - divu2 *q*, *r*, *nl*, *nh*, *d* + + - | *q* = *nh:nl* / *d* (unsigned) + | *r* = *nh:nl* % *d* + | Undefined behaviour if division by zero, or the double-word + numerator divided by the single-word divisor does not fit + within the single-word quotient. The code generator will + pass 0 to *nh* to make a simple zero-extension of *nl*, + so overflow should never occur. + Logical ------- diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 36dfbf80ad..61e5e185cc 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -45,6 +45,7 @@ DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) +DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) @@ -73,7 +74,6 @@ DEF(st_i32, 0, 2, 1, 0) /* arith */ DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) -DEF(divu2_i32, 2, 3, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) DEF(shr_i32, 1, 2, 0, 0) @@ -118,7 +118,6 @@ DEF(st_i64, 0, 2, 1, 0) /* arith */ DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) -DEF(divu2_i64, 2, 3, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) DEF(shr_i64, 1, 2, 0, 0) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 5511106554..7ed92157de 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -637,10 +637,10 @@ void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_divu, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_divu2_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_divu2, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); - tcg_gen_op5_i32(INDEX_op_divu2_i32, ret, t0, arg1, zero, arg2); + tcg_gen_op5_i32(INDEX_op_divu2, ret, t0, arg1, zero, arg2); tcg_temp_free_i32(t0); } else { gen_helper_divu_i32(ret, arg1, arg2); @@ -657,10 +657,10 @@ void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_mul_i32(t0, t0, arg2); tcg_gen_sub_i32(ret, arg1, t0); tcg_temp_free_i32(t0); - } else if (tcg_op_supported(INDEX_op_divu2_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_divu2, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); - tcg_gen_op5_i32(INDEX_op_divu2_i32, t0, ret, arg1, zero, arg2); + tcg_gen_op5_i32(INDEX_op_divu2, t0, ret, arg1, zero, arg2); tcg_temp_free_i32(t0); } else { gen_helper_remu_i32(ret, arg1, arg2); @@ -2005,10 +2005,10 @@ void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_divu, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_divu2_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_divu2, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 zero = tcg_constant_i64(0); - tcg_gen_op5_i64(INDEX_op_divu2_i64, ret, t0, arg1, zero, arg2); + tcg_gen_op5_i64(INDEX_op_divu2, ret, t0, arg1, zero, arg2); tcg_temp_free_i64(t0); } else { gen_helper_divu_i64(ret, arg1, arg2); @@ -2025,10 +2025,10 @@ void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_mul_i64(t0, t0, arg2); tcg_gen_sub_i64(ret, arg1, t0); tcg_temp_free_i64(t0); - } else if (tcg_op_supported(INDEX_op_divu2_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_divu2, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 zero = tcg_constant_i64(0); - tcg_gen_op5_i64(INDEX_op_divu2_i64, t0, ret, arg1, zero, arg2); + tcg_gen_op5_i64(INDEX_op_divu2, t0, ret, arg1, zero, arg2); tcg_temp_free_i64(t0); } else { gen_helper_remu_i64(ret, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 1029cba3f0..2c1307e3fc 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1029,8 +1029,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), - OUTOP(INDEX_op_divu2_i32, TCGOutOpDivRem, outop_divu2), - OUTOP(INDEX_op_divu2_i64, TCGOutOpDivRem, outop_divu2), + OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -5471,8 +5470,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_divs2: - case INDEX_op_divu2_i32: - case INDEX_op_divu2_i64: + case INDEX_op_divu2: { const TCGOutOpDivRem *out = container_of(all_outop[op->opc], TCGOutOpDivRem, base); From 646f36fead167e924e83d23d0e1dc59c37b5cca5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 18:52:30 -0800 Subject: [PATCH 0408/2760] tcg: Convert rem to TCGOutOpBinary For TCI, we're losing type information in the interpreter. Introduce a tci-specific opcode to handle the difference. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 19 ++++++++++------ tcg/arm/tcg-target.c.inc | 4 ++++ tcg/i386/tcg-target.c.inc | 4 ++++ tcg/loongarch64/tcg-target.c.inc | 24 +++++++++++++-------- tcg/mips/tcg-target.c.inc | 37 ++++++++++++++++++-------------- tcg/ppc/tcg-target.c.inc | 27 +++++++++++++++-------- tcg/riscv/tcg-target.c.inc | 21 ++++++++++-------- tcg/s390x/tcg-target.c.inc | 4 ++++ tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg.c | 6 ++++-- tcg/tci.c | 4 ++-- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 17 ++++++++++++--- 13 files changed, 115 insertions(+), 57 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 456159cdc6..6e80e18a6a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2275,6 +2275,18 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, SDIV, type, TCG_REG_TMP0, a1, a2); + tcg_out_insn(s, 3509, MSUB, type, a0, TCG_REG_TMP0, a2, a1); +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2392,11 +2404,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_rem_i64: - case INDEX_op_rem_i32: - tcg_out_insn(s, 3508, SDIV, ext, TCG_REG_TMP0, a1, a2); - tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP0, a2, a1); - break; case INDEX_op_remu_i64: case INDEX_op_remu_i32: tcg_out_insn(s, 3508, UDIV, ext, TCG_REG_TMP0, a1, a2); @@ -3078,8 +3085,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_rem_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: return C_O1_I2(r, r, r); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index b2c08bba3e..673c8fb7a6 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1955,6 +1955,10 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 0e6b743fb2..ac0721d71c 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2736,6 +2736,10 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index be09c362cb..ef37b4daa7 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1459,6 +1459,21 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_mod_w(s, a0, a1, a2); + } else { + tcg_out_opc_mod_d(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1709,13 +1724,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_rem_i32: - tcg_out_opc_mod_w(s, a0, a1, a2); - break; - case INDEX_op_rem_i64: - tcg_out_opc_mod_d(s, a0, a1, a2); - break; - case INDEX_op_remu_i32: tcg_out_opc_mod_wu(s, a0, a1, a2); break; @@ -2381,8 +2389,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_rem_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: return C_O1_I2(r, rz, rz); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 280afbf297..37b878ec61 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1866,6 +1866,27 @@ static const TCGOutOpBinary outop_orc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + if (type == TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_MOD, a0, a1, a2); + } else { + tcg_out_opc_reg(s, OPC_DMOD, a0, a1, a2); + } + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_DIV : OPC_DDIV; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFHI, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1989,13 +2010,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_rem_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_MOD, a0, a1, a2); - break; - } - i1 = OPC_DIV, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_remu_i32: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_MODU, a0, a1, a2); @@ -2003,13 +2017,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DIVU, i2 = OPC_MFHI; goto do_hilo1; - case INDEX_op_rem_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DMOD, a0, a1, a2); - break; - } - i1 = OPC_DDIV, i2 = OPC_MFHI; - goto do_hilo1; case INDEX_op_remu_i64: if (use_mips32r6_instructions) { tcg_out_opc_reg(s, OPC_DMODU, a0, a1, a2); @@ -2275,10 +2282,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_rem_i32: case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i64: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rz); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 8b14d57d1c..c331f0d672 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3091,6 +3091,24 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static TCGConstraintSetIndex cset_mod(TCGType type, unsigned flags) +{ + return have_isa_3_00 ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? MODSW : MODSD; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mod, + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3241,10 +3259,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_rem_i32: - tcg_out32(s, MODSW | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_remu_i32: tcg_out32(s, MODUW | TAB(args[0], args[1], args[2])); break; @@ -3341,9 +3355,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_rem_i64: - tcg_out32(s, MODSD | TAB(args[0], args[1], args[2])); - break; case INDEX_op_remu_i64: tcg_out32(s, MODUD | TAB(args[0], args[1], args[2])); break; @@ -4202,9 +4213,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i64: return C_O1_I2(r, r, r); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 72910b0f25..b0a98273f1 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2120,6 +2120,18 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_REMW : OPC_REM; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2233,13 +2245,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_rem_i32: - tcg_out_opc_reg(s, OPC_REMW, a0, a1, a2); - break; - case INDEX_op_rem_i64: - tcg_out_opc_reg(s, OPC_REM, a0, a1, a2); - break; - case INDEX_op_remu_i32: tcg_out_opc_reg(s, OPC_REMUW, a0, a1, a2); break; @@ -2748,9 +2753,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_rem_i32: case INDEX_op_remu_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i64: return C_O1_I2(r, rz, rz); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 9af626eec2..320268669a 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2437,6 +2437,10 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index a4659653b3..23cca5c664 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1476,6 +1476,10 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 2c1307e3fc..5af5529284 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1040,6 +1040,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_rem_i32, TCGOutOpBinary, outop_rems), + OUTOP(INDEX_op_rem_i64, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -2270,7 +2272,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return TCG_TARGET_HAS_negsetcond_i32; - case INDEX_op_rem_i32: case INDEX_op_remu_i32: return TCG_TARGET_HAS_rem_i32; case INDEX_op_rotl_i32: @@ -2327,7 +2328,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return TCG_TARGET_HAS_negsetcond_i64; - case INDEX_op_rem_i64: case INDEX_op_remu_i64: return TCG_TARGET_HAS_rem_i64; case INDEX_op_rotl_i64: @@ -5425,6 +5425,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: + case INDEX_op_rem_i32: + case INDEX_op_rem_i64: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index bf97849bfe..65f493c3d4 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -586,7 +586,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint32_t)regs[r1] / (uint32_t)regs[r2]; break; - case INDEX_op_rem_i32: + case INDEX_op_tci_rems32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int32_t)regs[r1] % (int32_t)regs[r2]; break; @@ -1081,7 +1081,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_orc: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_rem_i32: case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: @@ -1101,6 +1100,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_ctz_i64: case INDEX_op_tci_divs32: case INDEX_op_tci_divu32: + case INDEX_op_tci_rems32: tci_args_rrr(insn, &r0, &r1, &r2); info->fprintf_func(info->stream, "%-12s %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2)); diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 43c07a269f..2822fbffc8 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -4,3 +4,4 @@ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 27271c178c..4d9c142a00 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_rem_i32: - case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: case INDEX_op_shl_i32: @@ -754,6 +752,20 @@ static const TCGOutOpBinary outop_orc = { .out_rrr = tgen_orc, }; +static void tgen_rems(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_rems32 + : INDEX_op_rem_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_rems = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rems, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -843,7 +855,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ - CASE_32_64(rem) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(remu) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */ From 9a6bc1840ec105902bda1a59c42e9e0c56a9ed05 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 19:00:51 -0800 Subject: [PATCH 0409/2760] tcg: Merge INDEX_op_rem_{i32,i64} Rename to INDEX_op_rems to emphasize signed inputs, and mirroring INDEX_op_remu_*. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 12 +++++++----- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 8f3b5e91b2..1f4160a585 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -287,7 +287,7 @@ Arithmetic - | *t0* = *t1* / *t2* (unsigned) | Undefined behavior if division by zero. - * - rem_i32/i64 *t0*, *t1*, *t2* + * - rems *t0*, *t1*, *t2* - | *t0* = *t1* % *t2* (signed) | Undefined behavior if division by zero or overflow. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 61e5e185cc..040f4da835 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -56,6 +56,7 @@ DEF(nor, 1, 2, 0, TCG_OPF_INT) DEF(not, 1, 1, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) +DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -72,7 +73,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* arith */ -DEF(rem_i32, 1, 2, 0, 0) DEF(remu_i32, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) @@ -116,7 +116,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* arith */ -DEF(rem_i64, 1, 2, 0, 0) DEF(remu_i64, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index c11cce782a..01ec365175 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -569,12 +569,14 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (uint64_t)x / ((uint64_t)y ? : 1); - case INDEX_op_rem_i32: - return (int32_t)x % ((int32_t)y ? : 1); + case INDEX_op_rems: + if (type == TCG_TYPE_I32) { + return (int32_t)x % ((int32_t)y ? : 1); + } + return (int64_t)x % ((int64_t)y ? : 1); + case INDEX_op_remu_i32: return (uint32_t)x % ((uint32_t)y ? : 1); - case INDEX_op_rem_i64: - return (int64_t)x % ((int64_t)y ? : 1); case INDEX_op_remu_i64: return (uint64_t)x % ((uint64_t)y ? : 1); @@ -3021,7 +3023,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_qemu_st_i128: done = fold_qemu_st(&ctx, op); break; - CASE_OP_32_64(rem): + case INDEX_op_rems: CASE_OP_32_64(remu): done = fold_remainder(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7ed92157de..6da8b30547 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -615,8 +615,8 @@ void tcg_gen_div_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_rem_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_rem_i32) { - tcg_gen_op3_i32(INDEX_op_rem_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_rems, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_rems, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_divs, t0, arg1, arg2); @@ -1983,8 +1983,8 @@ void tcg_gen_div_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_rem_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_rem_i64) { - tcg_gen_op3_i64(INDEX_op_rem_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_rems, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_rems, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divs, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_divs, t0, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 5af5529284..fad828fa2f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1040,8 +1040,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), - OUTOP(INDEX_op_rem_i32, TCGOutOpBinary, outop_rems), - OUTOP(INDEX_op_rem_i64, TCGOutOpBinary, outop_rems), + OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -5425,8 +5424,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: - case INDEX_op_rem_i32: - case INDEX_op_rem_i64: + case INDEX_op_rems: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index 65f493c3d4..6ca033f3be 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -728,7 +728,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint64_t)regs[r1] / (uint64_t)regs[r2]; break; - case INDEX_op_rem_i64: + case INDEX_op_rems: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int64_t)regs[r1] % (int64_t)regs[r2]; break; @@ -1079,9 +1079,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_nor: case INDEX_op_or: case INDEX_op_orc: + case INDEX_op_rems: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_rem_i64: case INDEX_op_remu_i32: case INDEX_op_remu_i64: case INDEX_op_shl_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4d9c142a00..2b05da7d06 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -757,7 +757,7 @@ static void tgen_rems(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_rems32 - : INDEX_op_rem_i64); + : INDEX_op_rems); tcg_out_op_rrr(s, opc, a0, a1, a2); } From 967e7ccd9c5c6a5a2cc5d7a101cd24acced22749 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 20:12:08 -0800 Subject: [PATCH 0410/2760] tcg: Convert remu to TCGOutOpBinary For TCI, we're losing type information in the interpreter. Introduce a tci-specific opcode to handle the difference. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 22 ++++++++------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 +++ tcg/i386/tcg-target.c.inc | 4 +++ tcg/loongarch64/tcg-target-con-set.h | 1 - tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 26 ++++++++++-------- tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 41 ++++++++++++++-------------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 25 +++++++++-------- tcg/riscv/tcg-target-con-set.h | 1 - tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 23 ++++++++-------- tcg/s390x/tcg-target.c.inc | 4 +++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 +++ tcg/tcg-has.h | 9 ------ tcg/tcg-op.c | 4 +-- tcg/tcg.c | 8 +++--- tcg/tci.c | 4 +-- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 17 ++++++++++-- 25 files changed, 112 insertions(+), 101 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index e961668ef0..1fdff25d05 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,7 +13,6 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_rot_i32 1 @@ -29,7 +28,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 6e80e18a6a..8aa11e9d9d 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2287,6 +2287,18 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, UDIV, type, TCG_REG_TMP0, a1, a2); + tcg_out_insn(s, 3509, MSUB, type, a0, TCG_REG_TMP0, a2, a1); +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2404,12 +2416,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_remu_i64: - case INDEX_op_remu_i32: - tcg_out_insn(s, 3508, UDIV, ext, TCG_REG_TMP0, a1, a2); - tcg_out_insn(s, 3509, MSUB, ext, a0, TCG_REG_TMP0, a2, a1); - break; - case INDEX_op_shl_i64: case INDEX_op_shl_i32: if (c2) { @@ -3085,10 +3091,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: - return C_O1_I2(r, r, r); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 6ed2b49c84..32d73d3443 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -34,7 +34,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_muls2_i32 1 -#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 673c8fb7a6..c08cd712b1 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1959,6 +1959,10 @@ static const TCGOutOpBinary outop_rems = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index ac0721d71c..02dd440052 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2740,6 +2740,10 @@ static const TCGOutOpBinary outop_rems = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index b4af4f5423..da84e4d49c 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -31,7 +31,6 @@ C_O1_I2(r, r, rW) C_O1_I2(r, 0, rz) C_O1_I2(r, rz, ri) C_O1_I2(r, rz, rJ) -C_O1_I2(r, rz, rz) C_O1_I2(w, w, w) C_O1_I2(w, w, wM) C_O1_I2(w, w, wA) diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index aecd2879b8..5dfc69ae6a 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 0 -#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 @@ -27,7 +26,6 @@ /* 64-bit operations */ #define TCG_TARGET_HAS_negsetcond_i64 0 -#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index ef37b4daa7..a0313b1140 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1474,6 +1474,21 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_mod_wu(s, a0, a1, a2); + } else { + tcg_out_opc_mod_du(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1724,13 +1739,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_remu_i32: - tcg_out_opc_mod_wu(s, a0, a1, a2); - break; - case INDEX_op_remu_i64: - tcg_out_opc_mod_du(s, a0, a1, a2); - break; - case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], a0, a1, a2, c2); @@ -2389,10 +2397,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rJ); - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: - return C_O1_I2(r, rz, rz); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, rz, rJ, rz, rz); diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 9aa5bf9f1b..ab6a134796 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,7 +39,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_bswap16_i32 1 @@ -50,7 +49,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 37b878ec61..bd38c7ab95 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1887,6 +1887,27 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + if (type == TCG_TYPE_I32) { + tcg_out_opc_reg(s, OPC_MODU, a0, a1, a2); + } else { + tcg_out_opc_reg(s, OPC_DMODU, a0, a1, a2); + } + } else { + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_DIVU : OPC_DDIVU; + tcg_out_opc_reg(s, insn, 0, a1, a2); + tcg_out_opc_reg(s, OPC_MFHI, a0, 0, 0); + } +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2010,24 +2031,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_remu_i32: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_MODU, a0, a1, a2); - break; - } - i1 = OPC_DIVU, i2 = OPC_MFHI; - goto do_hilo1; - case INDEX_op_remu_i64: - if (use_mips32r6_instructions) { - tcg_out_opc_reg(s, OPC_DMODU, a0, a1, a2); - break; - } - i1 = OPC_DDIVU, i2 = OPC_MFHI; - do_hilo1: - tcg_out_opc_reg(s, i1, 0, a1, a2); - tcg_out_opc_reg(s, i2, a0, 0, 0); - break; - case INDEX_op_muls2_i32: i1 = OPC_MULT; goto do_hilo2; @@ -2282,9 +2285,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_remu_i32: case INDEX_op_setcond_i32: - case INDEX_op_remu_i64: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rz); case INDEX_op_muls2_i32: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index f8e4c0ad3c..37e88a3193 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,7 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_rem_i32 have_isa_3_00 #define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 @@ -34,7 +33,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_rem_i64 have_isa_3_00 #define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index c331f0d672..80ee4d04c9 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3109,6 +3109,19 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? MODUW : MODUD; + tcg_out32(s, insn | TAB(a0, a1, a2)); +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mod, + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3259,10 +3272,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_remu_i32: - tcg_out32(s, MODUW | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_shl_i32: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -3355,10 +3364,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_remu_i64: - tcg_out32(s, MODUD | TAB(args[0], args[1], args[2])); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -4213,10 +4218,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: - return C_O1_I2(r, r, r); - case INDEX_op_clz_i32: case INDEX_op_ctz_i32: case INDEX_op_clz_i64: diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index f3a6f7a7ed..f0d3cb81bd 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -16,7 +16,6 @@ C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) -C_O1_I2(r, rz, rz) C_N1_I2(r, r, rM) C_O1_I4(r, r, rI, rM, rM) C_O2_I4(r, r, rz, rz, rM, rM) diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index e5861e5260..b3c6899887 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 1 -#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_rot_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 @@ -26,7 +25,6 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_negsetcond_i64 1 -#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index b0a98273f1..38ba898042 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2132,6 +2132,18 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_REMUW : OPC_REMU; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2245,13 +2257,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_remu_i32: - tcg_out_opc_reg(s, OPC_REMUW, a0, a1, a2); - break; - case INDEX_op_remu_i64: - tcg_out_opc_reg(s, OPC_REMU, a0, a1, a2); - break; - case INDEX_op_shl_i32: if (c2) { tcg_out_opc_imm(s, OPC_SLLIW, a0, a1, a2 & 0x1f); @@ -2753,10 +2758,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: - return C_O1_I2(r, rz, rz); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 320268669a..8702d8c928 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2441,6 +2441,10 @@ static const TCGOutOpBinary outop_rems = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 35f0dd4230..42de99efbf 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,7 +14,6 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_rem_i32 0 #define TCG_TARGET_HAS_rot_i32 0 #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 @@ -30,7 +29,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 23cca5c664..d465c8dd06 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1480,6 +1480,10 @@ static const TCGOutOpBinary outop_rems = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index bae9918024..0bb829be36 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,8 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_div_i64 0 -#define TCG_TARGET_HAS_rem_i64 0 #define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 @@ -32,13 +30,6 @@ #define TCG_TARGET_HAS_sub2_i32 1 #endif -#ifndef TCG_TARGET_HAS_rem_i32 -#define TCG_TARGET_HAS_rem_i32 0 -#endif -#ifndef TCG_TARGET_HAS_rem_i64 -#define TCG_TARGET_HAS_rem_i64 0 -#endif - #if !defined(TCG_TARGET_HAS_v64) \ && !defined(TCG_TARGET_HAS_v128) \ && !defined(TCG_TARGET_HAS_v256) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 6da8b30547..4ff6c9f0ab 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -649,7 +649,7 @@ void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_rem_i32) { + if (tcg_op_supported(INDEX_op_remu_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2017,7 +2017,7 @@ void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_rem_i64) { + if (tcg_op_supported(INDEX_op_remu_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index fad828fa2f..537b665d07 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1041,6 +1041,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), + OUTOP(INDEX_op_remu_i32, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_remu_i64, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -2271,8 +2273,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return TCG_TARGET_HAS_negsetcond_i32; - case INDEX_op_remu_i32: - return TCG_TARGET_HAS_rem_i32; case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: return TCG_TARGET_HAS_rot_i32; @@ -2327,8 +2327,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return TCG_TARGET_HAS_negsetcond_i64; - case INDEX_op_remu_i64: - return TCG_TARGET_HAS_rem_i64; case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: return TCG_TARGET_HAS_rot_i64; @@ -5425,6 +5423,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_or: case INDEX_op_orc: case INDEX_op_rems: + case INDEX_op_remu_i32: + case INDEX_op_remu_i64: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index 6ca033f3be..bd5817a382 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -590,7 +590,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int32_t)regs[r1] % (int32_t)regs[r2]; break; - case INDEX_op_remu_i32: + case INDEX_op_tci_remu32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint32_t)regs[r1] % (uint32_t)regs[r2]; break; @@ -1082,7 +1082,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_rems: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_remu_i32: case INDEX_op_remu_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: @@ -1101,6 +1100,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_tci_divs32: case INDEX_op_tci_divu32: case INDEX_op_tci_rems32: + case INDEX_op_tci_remu32: tci_args_rrr(insn, &r0, &r1, &r2); info->fprintf_func(info->stream, "%-12s %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2)); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index ccec96b610..bd51b9346d 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -9,7 +9,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_rem_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 @@ -25,7 +24,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_rem_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 2822fbffc8..82d2a38cae 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -5,3 +5,4 @@ DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2b05da7d06..421a2a8ac7 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: @@ -766,6 +764,20 @@ static const TCGOutOpBinary outop_rems = { .out_rrr = tgen_rems, }; +static void tgen_remu(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_remu32 + : INDEX_op_remu_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_remu = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_remu, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -855,7 +867,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ - CASE_32_64(remu) /* Optional (TCG_TARGET_HAS_div_*). */ CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */ tcg_out_op_rrr(s, opc, args[0], args[1], args[2]); From cd9acd2049a385e54314d58f35b4bfce7c031d55 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 20:25:14 -0800 Subject: [PATCH 0411/2760] tcg: Merge INDEX_op_remu_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 5 +---- tcg/optimize.c | 9 +++++---- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 6 ++---- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 1f4160a585..bceecb0596 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -292,7 +292,7 @@ Arithmetic - | *t0* = *t1* % *t2* (signed) | Undefined behavior if division by zero or overflow. - * - remu_i32/i64 *t0*, *t1*, *t2* + * - remu *t0*, *t1*, *t2* - | *t0* = *t1* % *t2* (unsigned) | Undefined behavior if division by zero. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 040f4da835..ebb23347e9 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -57,6 +57,7 @@ DEF(not, 1, 1, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) +DEF(remu, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -72,8 +73,6 @@ DEF(ld_i32, 1, 1, 1, 0) DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) -/* arith */ -DEF(remu_i32, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i32, 1, 2, 0, 0) DEF(shr_i32, 1, 2, 0, 0) @@ -115,8 +114,6 @@ DEF(st8_i64, 0, 2, 1, 0) DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) -/* arith */ -DEF(remu_i64, 1, 2, 0, 0) /* shifts/rotates */ DEF(shl_i64, 1, 2, 0, 0) DEF(shr_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 01ec365175..69f9ba1555 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -575,9 +575,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (int64_t)x % ((int64_t)y ? : 1); - case INDEX_op_remu_i32: - return (uint32_t)x % ((uint32_t)y ? : 1); - case INDEX_op_remu_i64: + case INDEX_op_remu: + if (type == TCG_TYPE_I32) { + return (uint32_t)x % ((uint32_t)y ? : 1); + } return (uint64_t)x % ((uint64_t)y ? : 1); default: @@ -3024,7 +3025,7 @@ void tcg_optimize(TCGContext *s) done = fold_qemu_st(&ctx, op); break; case INDEX_op_rems: - CASE_OP_32_64(remu): + case INDEX_op_remu: done = fold_remainder(&ctx, op); break; CASE_OP_32_64(rotl): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 4ff6c9f0ab..0f1e83a49f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -649,8 +649,8 @@ void tcg_gen_divu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_remu_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_remu_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_remu_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_remu, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_remu, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_divu, t0, arg1, arg2); @@ -2017,8 +2017,8 @@ void tcg_gen_divu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_remu_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_remu_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_remu_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_remu, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_remu, ret, arg1, arg2); } else if (tcg_op_supported(INDEX_op_divu, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_divu, t0, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index 537b665d07..cd89ef1faa 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1041,8 +1041,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), - OUTOP(INDEX_op_remu_i32, TCGOutOpBinary, outop_remu), - OUTOP(INDEX_op_remu_i64, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -5423,8 +5422,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_or: case INDEX_op_orc: case INDEX_op_rems: - case INDEX_op_remu_i32: - case INDEX_op_remu_i64: + case INDEX_op_remu: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index bd5817a382..5d2cba4941 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -732,7 +732,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int64_t)regs[r1] % (int64_t)regs[r2]; break; - case INDEX_op_remu_i64: + case INDEX_op_remu: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint64_t)regs[r1] % (uint64_t)regs[r2]; break; @@ -1080,9 +1080,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_or: case INDEX_op_orc: case INDEX_op_rems: + case INDEX_op_remu: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_remu_i64: case INDEX_op_shl_i32: case INDEX_op_shl_i64: case INDEX_op_shr_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 421a2a8ac7..eb30fd04ba 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -769,7 +769,7 @@ static void tgen_remu(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_remu32 - : INDEX_op_remu_i64); + : INDEX_op_remu); tcg_out_op_rrr(s, opc, a0, a1, a2); } From 27d21ee7c79133e5dfdab8f160f547e833dc5dd0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 21:33:33 -0800 Subject: [PATCH 0412/2760] tcg: Convert shl to TCGOutOpBinary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 38 ++++++++++---------- tcg/arm/tcg-target.c.inc | 25 +++++++++---- tcg/i386/tcg-target.c.inc | 60 +++++++++++++++++++++++--------- tcg/loongarch64/tcg-target.c.inc | 43 ++++++++++++++--------- tcg/mips/tcg-target.c.inc | 35 ++++++++++++------- tcg/ppc/tcg-target.c.inc | 42 ++++++++++++---------- tcg/riscv/tcg-target.c.inc | 38 +++++++++++--------- tcg/s390x/tcg-target.c.inc | 37 ++++++++++++++++---- tcg/sparc64/tcg-target.c.inc | 27 ++++++++++---- tcg/tcg.c | 6 ++-- tcg/tci/tcg-target.c.inc | 14 ++++++-- 11 files changed, 241 insertions(+), 124 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 8aa11e9d9d..b57baa1eec 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1347,14 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a); } -static inline void tcg_out_shl(TCGContext *s, TCGType ext, - TCGReg rd, TCGReg rn, unsigned int m) -{ - int bits = ext ? 64 : 32; - int max = bits - 1; - tcg_out_ubfm(s, ext, rd, rn, (bits - m) & max, (max - m) & max); -} - static inline void tcg_out_shr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) { @@ -2299,6 +2291,25 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, LSLV, type, a0, a1, a2); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int max = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_ubfm(s, type, a0, a1, -a2 & max, ~a2 & max); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2416,15 +2427,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_shl_i64: - case INDEX_op_shl_i32: - if (c2) { - tcg_out_shl(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3508, LSLV, ext, a0, a1, a2); - } - break; - case INDEX_op_shr_i64: case INDEX_op_shr_i32: if (c2) { @@ -3091,12 +3093,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index c08cd712b1..2b9e52914c 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1963,6 +1963,25 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_REG_LSL(a2)); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, + SHIFT_IMM_LSL(a2 & 0x1f)); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2114,11 +2133,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_muls2_i32: tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - /* XXX: Perhaps args[2] & 0x1f is wrong */ - case INDEX_op_shl_i32: - c = const_args[2] ? - SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]); - goto gen_shift32; case INDEX_op_shr_i32: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); @@ -2300,7 +2314,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 02dd440052..648d9ee66c 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2744,6 +2744,49 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static TCGConstraintSetIndex cset_shift(TCGType type, unsigned flags) +{ + return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); +} + +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + if (have_bmi2) { + tcg_out_vex_modrm(s, OPC_SHLX + rexw, a0, a2, a1); + } else { + tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SHL, a0); + } +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + /* For small constant 3-operand shift, use LEA. */ + if (a0 != a1 && a2 >= 1 && a2 <= 3) { + if (a2 == 1) { + /* shl $1,a1,a0 -> lea (a1,a1),a0 */ + tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a1, 0, 0); + } else { + /* shl $n,a1,a0 -> lea 0(,a1,n),a0 */ + tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, -1, a1, a2, 0); + } + return; + } + tcg_out_mov(s, type, a0, a1); + tcg_out_shifti(s, SHIFT_SHL + rexw, a0, a2); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_shift, + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2879,21 +2922,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(shl): - /* For small constant 3-operand shift, use LEA. */ - if (const_a2 && a0 != a1 && (a2 - 1) < 3) { - if (a2 - 1 == 0) { - /* shl $1,a1,a0 -> lea (a1,a1),a0 */ - tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, a1, a1, 0, 0); - } else { - /* shl $n,a1,a0 -> lea 0(,a1,n),a0 */ - tcg_out_modrm_sib_offset(s, OPC_LEA + rexw, a0, -1, a1, a2, 0); - } - break; - } - c = SHIFT_SHL; - vexop = OPC_SHLX; - goto gen_shift_maybe_vex; OP_32_64(shr): c = SHIFT_SHR; vexop = OPC_SHRX; @@ -3759,8 +3787,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i32: case INDEX_op_shr_i64: case INDEX_op_sar_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index a0313b1140..9e34c37e62 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1489,6 +1489,32 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sll_w(s, a0, a1, a2); + } else { + tcg_out_opc_sll_d(s, a0, a1, a2); + } +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_slli_w(s, a0, a1, a2 & 0x1f); + } else { + tcg_out_opc_slli_d(s, a0, a1, a2 & 0x3f); + } +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1660,21 +1686,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); break; - case INDEX_op_shl_i32: - if (c2) { - tcg_out_opc_slli_w(s, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_sll_w(s, a0, a1, a2); - } - break; - case INDEX_op_shl_i64: - if (c2) { - tcg_out_opc_slli_d(s, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_sll_d(s, a0, a1, a2); - } - break; - case INDEX_op_shr_i32: if (c2) { tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); @@ -2369,8 +2380,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i32: case INDEX_op_shr_i64: case INDEX_op_sar_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index bd38c7ab95..30d8872b4f 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1908,6 +1908,29 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_SLLV : OPC_DSLLV; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sa(s, OPC_SLL, a0, a1, a2); + } else { + tcg_out_dsll(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2068,9 +2091,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i32: i1 = OPC_SRAV, i2 = OPC_SRA; goto do_shift; - case INDEX_op_shl_i32: - i1 = OPC_SLLV, i2 = OPC_SLL; - goto do_shift; case INDEX_op_shr_i32: i1 = OPC_SRLV, i2 = OPC_SRL; goto do_shift; @@ -2099,13 +2119,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DSRAV; goto do_shiftv; - case INDEX_op_shl_i64: - if (c2) { - tcg_out_dsll(s, a0, a1, a2); - break; - } - i1 = OPC_DSLLV; - goto do_shiftv; case INDEX_op_shr_i64: if (c2) { tcg_out_dsrl(s, a0, a1, a2); @@ -2293,12 +2306,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotr_i32: case INDEX_op_rotl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotr_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 80ee4d04c9..88cfcd1d91 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3122,6 +3122,30 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SLW : SLD; + tcg_out32(s, insn | SAB(a1, a0, a2)); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* Limit immediate shift count lest we create an illegal insn. */ + if (type == TCG_TYPE_I32) { + tcg_out_shli32(s, a0, a1, a2 & 31); + } else { + tcg_out_shli64(s, a0, a1, a2 & 63); + } +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3272,14 +3296,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_shl_i32: - if (const_args[2]) { - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_shli32(s, args[0], args[1], args[2] & 31); - } else { - tcg_out32(s, SLW | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_shr_i32: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -3325,14 +3341,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_shl_i64: - if (const_args[2]) { - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_shli64(s, args[0], args[1], args[2] & 63); - } else { - tcg_out32(s, SLD | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_shr_i64: if (const_args[2]) { /* Limit immediate shift count lest we create an illegal insn. */ @@ -4206,12 +4214,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 38ba898042..372c4e1651 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2144,6 +2144,27 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SLLW : OPC_SLL; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SLLIW : OPC_SLLI; + unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_opc_imm(s, insn, a0, a1, a2 & mask); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2257,21 +2278,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_shl_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_SLLIW, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_reg(s, OPC_SLLW, a0, a1, a2); - } - break; - case INDEX_op_shl_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_SLLI, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_reg(s, OPC_SLL, a0, a1, a2); - } - break; - case INDEX_op_shr_i32: if (c2) { tcg_out_opc_imm(s, OPC_SRLIW, a0, a1, a2 & 0x1f); @@ -2758,12 +2764,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 8702d8c928..ed68054664 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2445,6 +2445,36 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_shl_int(TCGContext *s, TCGType type, TCGReg dst, + TCGReg src, TCGReg v, tcg_target_long i) +{ + if (type != TCG_TYPE_I32) { + tcg_out_sh64(s, RSY_SLLG, dst, src, v, i); + } else if (dst == src) { + tcg_out_sh32(s, RS_SLL, dst, v, i); + } else { + tcg_out_sh64(s, RSY_SLLK, dst, src, v, i); + } +} + +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_shl_int(s, type, a0, a1, a2, 0); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_shl_int(s, type, a0, a1, TCG_REG_NONE, a2); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2574,9 +2604,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_shl_i32: - op = RS_SLL; - op2 = RSY_SLLK; do_shift32: a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; if (a0 == a1) { @@ -2746,8 +2773,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]); break; - case INDEX_op_shl_i64: - op = RSY_SLLG; do_shift64: if (const_args[2]) { tcg_out_sh64(s, op, args[0], args[1], TCG_REG_NONE, args[2]); @@ -3346,7 +3371,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i32: @@ -3363,7 +3387,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_clz_i64: return C_O1_I2(r, r, rI); - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: return C_O1_I2(r, r, ri); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d465c8dd06..6b320a8622 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1484,6 +1484,27 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SLL : SHIFT_SLLX; + tcg_out_arith(s, a0, a1, a2, insn); +} + +static void tgen_shli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SLL : SHIFT_SLLX; + uint32_t mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_arithi(s, a0, a1, a2 & mask, insn); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_shl, + .out_rri = tgen_shli, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1587,8 +1608,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st32_i64: tcg_out_ldst(s, a0, a1, a2, STW); break; - case INDEX_op_shl_i32: - c = SHIFT_SLL; do_shift32: /* Limit immediate shift count lest we create an illegal insn. */ tcg_out_arithc(s, a0, a1, a2 & 31, c2, c); @@ -1656,8 +1675,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st_i64: tcg_out_ldst(s, a0, a1, a2, STX); break; - case INDEX_op_shl_i64: - c = SHIFT_SLLX; do_shift64: /* Limit immediate shift count lest we create an illegal insn. */ tcg_out_arithc(s, a0, a1, a2 & 63, c2, c); @@ -1751,8 +1768,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i32: case INDEX_op_shr_i64: case INDEX_op_sar_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index cd89ef1faa..369a1e6d48 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,6 +1042,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_shl_i32, TCGOutOpBinary, outop_shl), + OUTOP(INDEX_op_shl_i64, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -2262,7 +2264,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_shl_i32: case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_extract_i32: @@ -2314,7 +2315,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_shl_i64: case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_ext_i32_i64: @@ -5423,6 +5423,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_shl_i32: + case INDEX_op_shl_i64: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index eb30fd04ba..748bb8118f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i32: case INDEX_op_shr_i64: case INDEX_op_sar_i32: @@ -778,6 +776,17 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_shl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, glue(INDEX_op_shl_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_shl = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_shl, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -862,7 +871,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(shl) CASE_32_64(shr) CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ From 6ca594517ab389f3095c4aab745e168cdd8e8ff5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 21:50:04 -0800 Subject: [PATCH 0413/2760] tcg: Merge INDEX_op_shl_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 10 +++++----- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 6 ++---- tcg/tci.c | 13 ++++--------- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 17 insertions(+), 25 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index bceecb0596..f64c881530 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -379,10 +379,10 @@ Shifts/Rotates .. list-table:: - * - shl_i32/i64 *t0*, *t1*, *t2* + * - shl *t0*, *t1*, *t2* - | *t0* = *t1* << *t2* - | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + | Unspecified behavior for negative or out-of-range shifts. * - shr_i32/i64 *t0*, *t1*, *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index ebb23347e9..c2ac25d1b6 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -58,6 +58,7 @@ DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) +DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -74,7 +75,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ -DEF(shl_i32, 1, 2, 0, 0) DEF(shr_i32, 1, 2, 0, 0) DEF(sar_i32, 1, 2, 0, 0) DEF(rotl_i32, 1, 2, 0, 0) @@ -115,7 +115,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ -DEF(shl_i64, 1, 2, 0, 0) DEF(shr_i64, 1, 2, 0, 0) DEF(sar_i64, 1, 2, 0, 0) DEF(rotl_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 69f9ba1555..3142daa800 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -446,10 +446,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, case INDEX_op_xor_vec: return x ^ y; - case INDEX_op_shl_i32: - return (uint32_t)x << (y & 31); - - case INDEX_op_shl_i64: + case INDEX_op_shl: + if (type == TCG_TYPE_I32) { + return (uint32_t)x << (y & 31); + } return (uint64_t)x << (y & 63); case INDEX_op_shr_i32: @@ -3031,7 +3031,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(rotl): CASE_OP_32_64(rotr): CASE_OP_32_64(sar): - CASE_OP_32_64(shl): + case INDEX_op_shl: CASE_OP_32_64(shr): done = fold_shift(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 0f1e83a49f..c85c056726 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -481,7 +481,7 @@ void tcg_gen_not_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_shl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_shl_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_shl, ret, arg1, arg2); } void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1606,7 +1606,7 @@ void tcg_gen_xor_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_shl_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_shl, ret, arg1, arg2); } else { gen_helper_shl_i64(ret, arg1, arg2); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 369a1e6d48..50935b7e03 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,8 +1042,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), - OUTOP(INDEX_op_shl_i32, TCGOutOpBinary, outop_shl), - OUTOP(INDEX_op_shl_i64, TCGOutOpBinary, outop_shl), + OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -5423,8 +5422,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: + case INDEX_op_shl: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index 5d2cba4941..22401ce1f6 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -615,11 +615,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, break; #endif - /* Shift/rotate operations (32 bit). */ + /* Shift/rotate operations. */ - case INDEX_op_shl_i32: + case INDEX_op_shl: tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = (uint32_t)regs[r1] << (regs[r2] & 31); + regs[r0] = regs[r1] << (regs[r2] % TCG_TARGET_REG_BITS); break; case INDEX_op_shr_i32: tci_args_rrr(insn, &r0, &r1, &r2); @@ -787,10 +787,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Shift/rotate operations (64 bit). */ - case INDEX_op_shl_i64: - tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = regs[r1] << (regs[r2] & 63); - break; case INDEX_op_shr_i64: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] >> (regs[r2] & 63); @@ -1081,10 +1077,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_shl: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_shl_i32: - case INDEX_op_shl_i64: case INDEX_op_shr_i32: case INDEX_op_shr_i64: case INDEX_op_sar_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 748bb8118f..ca83a097ab 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -779,7 +779,7 @@ static const TCGOutOpBinary outop_remu = { static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { - tcg_out_op_rrr(s, glue(INDEX_op_shl_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_shl, a0, a1, a2); } static const TCGOutOpBinary outop_shl = { From edd6ba8a6bc804153a8fe643a7e2dae0802db98c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 22:22:36 -0800 Subject: [PATCH 0414/2760] tcg: Convert shr to TCGOutOpBinary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 37 ++++++++++++++------------- tcg/arm/tcg-target.c.inc | 24 ++++++++++++++---- tcg/i386/tcg-target.c.inc | 33 +++++++++++++++++++----- tcg/loongarch64/tcg-target.c.inc | 43 +++++++++++++++++++------------- tcg/mips/tcg-target.c.inc | 35 +++++++++++++++++--------- tcg/ppc/tcg-target.c.inc | 42 ++++++++++++++++++------------- tcg/riscv/tcg-target.c.inc | 38 +++++++++++++++------------- tcg/s390x/tcg-target.c.inc | 39 ++++++++++++++++++++++------- tcg/sparc64/tcg-target.c.inc | 29 +++++++++++++++------ tcg/tcg.c | 6 +++-- tcg/tci/tcg-target.c.inc | 18 ++++++++++--- 11 files changed, 229 insertions(+), 115 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index b57baa1eec..87b97e852a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1347,13 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a); } -static inline void tcg_out_shr(TCGContext *s, TCGType ext, - TCGReg rd, TCGReg rn, unsigned int m) -{ - int max = ext ? 63 : 31; - tcg_out_ubfm(s, ext, rd, rn, m & max, max); -} - static inline void tcg_out_sar(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) { @@ -2310,6 +2303,25 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, LSRV, type, a0, a1, a2); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int max = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_ubfm(s, type, a0, a1, a2 & max, max); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2427,15 +2439,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_shr_i64: - case INDEX_op_shr_i32: - if (c2) { - tcg_out_shr(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3508, LSRV, ext, a0, a1, a2); - } - break; - case INDEX_op_sar_i64: case INDEX_op_sar_i32: if (c2) { @@ -3093,11 +3096,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 2b9e52914c..247aefd0a1 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1982,6 +1982,25 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_REG_LSR(a2)); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, + SHIFT_IMM_LSR(a2 & 0x1f)); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2133,10 +2152,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_muls2_i32: tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - case INDEX_op_shr_i32: - c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) : - SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]); - goto gen_shift32; case INDEX_op_sar_i32: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); @@ -2314,7 +2329,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 648d9ee66c..93d94e7881 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2787,6 +2787,33 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + if (have_bmi2) { + tcg_out_vex_modrm(s, OPC_SHRX + rexw, a0, a2, a1); + } else { + tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SHR, a0); + } +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + tcg_out_mov(s, type, a0, a1); + tcg_out_shifti(s, SHIFT_SHR + rexw, a0, a2); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_shift, + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2922,10 +2949,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(shr): - c = SHIFT_SHR; - vexop = OPC_SHRX; - goto gen_shift_maybe_vex; OP_32_64(sar): c = SHIFT_SAR; vexop = OPC_SARX; @@ -3787,8 +3810,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i32: case INDEX_op_sar_i64: return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 9e34c37e62..2699079073 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1515,6 +1515,32 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_srl_w(s, a0, a1, a2); + } else { + tcg_out_opc_srl_d(s, a0, a1, a2); + } +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); + } else { + tcg_out_opc_srli_d(s, a0, a1, a2 & 0x3f); + } +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1686,21 +1712,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); break; - case INDEX_op_shr_i32: - if (c2) { - tcg_out_opc_srli_w(s, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_srl_w(s, a0, a1, a2); - } - break; - case INDEX_op_shr_i64: - if (c2) { - tcg_out_opc_srli_d(s, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_srl_d(s, a0, a1, a2); - } - break; - case INDEX_op_sar_i32: if (c2) { tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); @@ -2380,8 +2391,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i32: case INDEX_op_sar_i64: case INDEX_op_rotl_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 30d8872b4f..03b4248ea9 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1931,6 +1931,29 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_SRLV : OPC_DSRLV; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sa(s, OPC_SRL, a0, a1, a2); + } else { + tcg_out_dsrl(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2091,9 +2114,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_sar_i32: i1 = OPC_SRAV, i2 = OPC_SRA; goto do_shift; - case INDEX_op_shr_i32: - i1 = OPC_SRLV, i2 = OPC_SRL; - goto do_shift; case INDEX_op_rotr_i32: i1 = OPC_ROTRV, i2 = OPC_ROTR; do_shift: @@ -2119,13 +2139,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } i1 = OPC_DSRAV; goto do_shiftv; - case INDEX_op_shr_i64: - if (c2) { - tcg_out_dsrl(s, a0, a1, a2); - break; - } - i1 = OPC_DSRLV; - goto do_shiftv; case INDEX_op_rotr_i64: if (c2) { tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2); @@ -2306,11 +2319,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotr_i32: case INDEX_op_rotl_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotr_i64: case INDEX_op_rotl_i64: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 88cfcd1d91..2012734bb3 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3146,6 +3146,30 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SRW : SRD; + tcg_out32(s, insn | SAB(a1, a0, a2)); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* Limit immediate shift count lest we create an illegal insn. */ + if (type == TCG_TYPE_I32) { + tcg_out_shri32(s, a0, a1, a2 & 31); + } else { + tcg_out_shri64(s, a0, a1, a2 & 63); + } +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3296,14 +3320,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_shr_i32: - if (const_args[2]) { - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_shri32(s, args[0], args[1], args[2] & 31); - } else { - tcg_out32(s, SRW | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_sar_i32: if (const_args[2]) { tcg_out_sari32(s, args[0], args[1], args[2]); @@ -3341,14 +3357,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_shr_i64: - if (const_args[2]) { - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_shri64(s, args[0], args[1], args[2] & 63); - } else { - tcg_out32(s, SRD | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_sar_i64: if (const_args[2]) { tcg_out_sari64(s, args[0], args[1], args[2]); @@ -4214,11 +4222,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 372c4e1651..8020cc0b3f 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2165,6 +2165,27 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SRLW : OPC_SRL; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SRLIW : OPC_SRLI; + unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_opc_imm(s, insn, a0, a1, a2 & mask); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2278,21 +2299,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_shr_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_SRLIW, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_reg(s, OPC_SRLW, a0, a1, a2); - } - break; - case INDEX_op_shr_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_SRLI, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_reg(s, OPC_SRL, a0, a1, a2); - } - break; - case INDEX_op_sar_i32: if (c2) { tcg_out_opc_imm(s, OPC_SRAIW, a0, a1, a2 & 0x1f); @@ -2764,11 +2770,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index ed68054664..0417bbef50 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2475,6 +2475,36 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr_int(TCGContext *s, TCGType type, TCGReg dst, + TCGReg src, TCGReg v, tcg_target_long i) +{ + if (type != TCG_TYPE_I32) { + tcg_out_sh64(s, RSY_SRLG, dst, src, v, i); + } else if (dst == src) { + tcg_out_sh32(s, RS_SRL, dst, v, i); + } else { + tcg_out_sh64(s, RSY_SRLK, dst, src, v, i); + } +} + +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_shr_int(s, type, a0, a1, a2, 0); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_shr_int(s, type, a0, a1, TCG_REG_NONE, a2); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2621,10 +2651,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } } break; - case INDEX_op_shr_i32: - op = RS_SRL; - op2 = RSY_SRLK; - goto do_shift32; case INDEX_op_sar_i32: op = RS_SRA; op2 = RSY_SRAK; @@ -2780,9 +2806,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_sh64(s, op, args[0], args[1], args[2], 0); } break; - case INDEX_op_shr_i64: - op = RSY_SRLG; - goto do_shift64; case INDEX_op_sar_i64: op = RSY_SRAG; goto do_shift64; @@ -3371,7 +3394,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: @@ -3387,7 +3409,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_clz_i64: return C_O1_I2(r, r, rI); - case INDEX_op_shr_i32: case INDEX_op_sar_i32: return C_O1_I2(r, r, ri); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 6b320a8622..f679fa04ea 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1505,6 +1505,27 @@ static const TCGOutOpBinary outop_shl = { .out_rri = tgen_shli, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SRL : SHIFT_SRLX; + tcg_out_arith(s, a0, a1, a2, insn); +} + +static void tgen_shri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SRL : SHIFT_SRLX; + uint32_t mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_arithi(s, a0, a1, a2 & mask, insn); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_shr, + .out_rri = tgen_shri, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1612,9 +1633,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, /* Limit immediate shift count lest we create an illegal insn. */ tcg_out_arithc(s, a0, a1, a2 & 31, c2, c); break; - case INDEX_op_shr_i32: - c = SHIFT_SRL; - goto do_shift32; case INDEX_op_sar_i32: c = SHIFT_SRA; goto do_shift32; @@ -1679,9 +1697,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, /* Limit immediate shift count lest we create an illegal insn. */ tcg_out_arithc(s, a0, a1, a2 & 63, c2, c); break; - case INDEX_op_shr_i64: - c = SHIFT_SRLX; - goto do_shift64; case INDEX_op_sar_i64: c = SHIFT_SRAX; goto do_shift64; @@ -1768,8 +1783,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i32: case INDEX_op_sar_i64: case INDEX_op_setcond_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 50935b7e03..134ab9c6c2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1043,6 +1043,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), + OUTOP(INDEX_op_shr_i32, TCGOutOpBinary, outop_shr), + OUTOP(INDEX_op_shr_i64, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -2263,7 +2265,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_shr_i32: case INDEX_op_sar_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: @@ -2314,7 +2315,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_shr_i64: case INDEX_op_sar_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: @@ -5423,6 +5423,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_rems: case INDEX_op_remu: case INDEX_op_shl: + case INDEX_op_shr_i32: + case INDEX_op_shr_i64: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ca83a097ab..5651833ac9 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i32: case INDEX_op_sar_i64: case INDEX_op_rotl_i32: @@ -787,6 +785,21 @@ static const TCGOutOpBinary outop_shl = { .out_rrr = tgen_shl, }; +static void tgen_shr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type < TCG_TYPE_REG) { + tcg_out_ext32u(s, TCG_REG_TMP, a1); + a1 = TCG_REG_TMP; + } + tcg_out_op_rrr(s, glue(INDEX_op_shr_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_shr = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_shr, +}; + static void tgen_sub(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -871,7 +884,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(shr) CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ From 74dbd36f1f87bd7fc4705644d63c5561a23b0567 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 22:52:10 -0800 Subject: [PATCH 0415/2760] tcg: Merge INDEX_op_shr_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 17 +++++++---------- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 6 ++---- tcg/tci.c | 11 +++-------- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 18 insertions(+), 29 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index f64c881530..f9fd4b0087 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -384,10 +384,10 @@ Shifts/Rotates - | *t0* = *t1* << *t2* | Unspecified behavior for negative or out-of-range shifts. - * - shr_i32/i64 *t0*, *t1*, *t2* + * - shr *t0*, *t1*, *t2* - | *t0* = *t1* >> *t2* (unsigned) - | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + | Unspecified behavior for negative or out-of-range shifts. * - sar_i32/i64 *t0*, *t1*, *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index c2ac25d1b6..35e0be8f80 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -59,6 +59,7 @@ DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) +DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -75,7 +76,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ -DEF(shr_i32, 1, 2, 0, 0) DEF(sar_i32, 1, 2, 0, 0) DEF(rotl_i32, 1, 2, 0, 0) DEF(rotr_i32, 1, 2, 0, 0) @@ -115,7 +115,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ -DEF(shr_i64, 1, 2, 0, 0) DEF(sar_i64, 1, 2, 0, 0) DEF(rotl_i64, 1, 2, 0, 0) DEF(rotr_i64, 1, 2, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 3142daa800..43db079693 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -452,10 +452,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (uint64_t)x << (y & 63); - case INDEX_op_shr_i32: - return (uint32_t)x >> (y & 31); - - case INDEX_op_shr_i64: + case INDEX_op_shr: + if (type == TCG_TYPE_I32) { + return (uint32_t)x >> (y & 31); + } return (uint64_t)x >> (y & 63); case INDEX_op_sar_i32: @@ -2342,7 +2342,6 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode shr_opc; TCGOpcode uext_opc = 0, sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; @@ -2364,7 +2363,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - shr_opc = INDEX_op_shr_i32; if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) { uext_opc = INDEX_op_extract_i32; } @@ -2373,7 +2371,6 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } break; case TCG_TYPE_I64: - shr_opc = INDEX_op_shr_i64; if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) { uext_opc = INDEX_op_extract_i64; } @@ -2402,7 +2399,7 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op->args[3] = 1; } else { if (sh) { - op2 = opt_insert_before(ctx, op, shr_opc, 3); + op2 = opt_insert_before(ctx, op, INDEX_op_shr, 3); op2->args[0] = ret; op2->args[1] = src1; op2->args[2] = arg_new_constant(ctx, sh); @@ -2609,7 +2606,7 @@ static bool fold_shift(OptContext *ctx, TCGOp *op) * input sign repetitions. */ return fold_masks_s(ctx, op, s_mask); - CASE_OP_32_64(shr): + case INDEX_op_shr: /* * If the sign bit is known zero, then logical right shift * will not reduce the number of input sign repetitions. @@ -3032,7 +3029,7 @@ void tcg_optimize(TCGContext *s) CASE_OP_32_64(rotr): CASE_OP_32_64(sar): case INDEX_op_shl: - CASE_OP_32_64(shr): + case INDEX_op_shr: done = fold_shift(&ctx, op); break; CASE_OP_32_64(setcond): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c85c056726..ef8cf5a1ac 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -496,7 +496,7 @@ void tcg_gen_shli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_shr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_shr_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_shr, ret, arg1, arg2); } void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1615,7 +1615,7 @@ void tcg_gen_shl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_shr_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_shr, ret, arg1, arg2); } else { gen_helper_shr_i64(ret, arg1, arg2); } diff --git a/tcg/tcg.c b/tcg/tcg.c index 134ab9c6c2..939bbe86e9 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1043,8 +1043,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), - OUTOP(INDEX_op_shr_i32, TCGOutOpBinary, outop_shr), - OUTOP(INDEX_op_shr_i64, TCGOutOpBinary, outop_shr), + OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), }; @@ -5423,8 +5422,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_rems: case INDEX_op_remu: case INDEX_op_shl: - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: + case INDEX_op_shr: case INDEX_op_xor: { const TCGOutOpBinary *out = diff --git a/tcg/tci.c b/tcg/tci.c index 22401ce1f6..376b1b1ece 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -621,9 +621,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] << (regs[r2] % TCG_TARGET_REG_BITS); break; - case INDEX_op_shr_i32: + case INDEX_op_shr: tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = (uint32_t)regs[r1] >> (regs[r2] & 31); + regs[r0] = regs[r1] >> (regs[r2] % TCG_TARGET_REG_BITS); break; case INDEX_op_sar_i32: tci_args_rrr(insn, &r0, &r1, &r2); @@ -787,10 +787,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Shift/rotate operations (64 bit). */ - case INDEX_op_shr_i64: - tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = regs[r1] >> (regs[r2] & 63); - break; case INDEX_op_sar_i64: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (int64_t)regs[r1] >> (regs[r2] & 63); @@ -1078,10 +1074,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_rems: case INDEX_op_remu: case INDEX_op_shl: + case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_shr_i32: - case INDEX_op_shr_i64: case INDEX_op_sar_i32: case INDEX_op_sar_i64: case INDEX_op_rotl_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 5651833ac9..c0dbe873f1 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -792,7 +792,7 @@ static void tgen_shr(TCGContext *s, TCGType type, tcg_out_ext32u(s, TCG_REG_TMP, a1); a1 = TCG_REG_TMP; } - tcg_out_op_rrr(s, glue(INDEX_op_shr_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_shr, a0, a1, a2); } static const TCGOutOpBinary outop_shr = { From b5aafbaa834653abd4c208794bacbc53a4c1bc16 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 7 Jan 2025 23:36:22 -0800 Subject: [PATCH 0416/2760] tcg: Convert sar to TCGOutOpBinary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 37 ++++++++--------- tcg/arm/tcg-target.c.inc | 26 ++++++++---- tcg/i386/tcg-target.c.inc | 46 ++++++++++++--------- tcg/loongarch64/tcg-target.c.inc | 43 ++++++++++++-------- tcg/mips/tcg-target.c.inc | 36 +++++++++++------ tcg/ppc/tcg-target.c.inc | 40 +++++++++++-------- tcg/riscv/tcg-target.c.inc | 38 ++++++++++-------- tcg/s390x/tcg-target.c.inc | 68 ++++++++++++++------------------ tcg/sparc64/tcg-target.c.inc | 37 +++++++++-------- tcg/tcg.c | 6 ++- tcg/tci/tcg-target.c.inc | 17 +++++++- 11 files changed, 230 insertions(+), 164 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 87b97e852a..90bdbf8387 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1347,13 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a); } -static inline void tcg_out_sar(TCGContext *s, TCGType ext, - TCGReg rd, TCGReg rn, unsigned int m) -{ - int max = ext ? 63 : 31; - tcg_out_sbfm(s, ext, rd, rn, m & max, max); -} - static inline void tcg_out_rotr(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned int m) { @@ -2284,6 +2277,25 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, ASRV, type, a0, a1, a2); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int max = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_sbfm(s, type, a0, a1, a2 & max, max); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2439,15 +2451,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_sar_i64: - case INDEX_op_sar_i32: - if (c2) { - tcg_out_sar(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3508, ASRV, ext, a0, a1, a2); - } - break; - case INDEX_op_rotr_i64: case INDEX_op_rotr_i32: if (c2) { @@ -3096,10 +3099,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 247aefd0a1..058677650b 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1963,6 +1963,25 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_REG_ASR(a2)); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, + SHIFT_IMM_ASR(a2 & 0x1f)); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2152,15 +2171,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_muls2_i32: tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - case INDEX_op_sar_i32: - c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) : - SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]); - goto gen_shift32; case INDEX_op_rotr_i32: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) : SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]); - /* Fall through. */ - gen_shift32: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); break; @@ -2329,7 +2342,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: return C_O1_I2(r, r, ri); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 93d94e7881..1e81455461 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2749,6 +2749,33 @@ static TCGConstraintSetIndex cset_shift(TCGType type, unsigned flags) return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); } +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + if (have_bmi2) { + tcg_out_vex_modrm(s, OPC_SARX + rexw, a0, a2, a1); + } else { + tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_SAR, a0); + } +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + tcg_out_mov(s, type, a0, a1); + tcg_out_shifti(s, SHIFT_SAR + rexw, a0, a2); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_shift, + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2874,7 +2901,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int c, const_a2, vexop, rexw; + int c, const_a2, rexw; #if TCG_TARGET_REG_BITS == 64 # define OP_32_64(x) \ @@ -2949,25 +2976,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(sar): - c = SHIFT_SAR; - vexop = OPC_SARX; - goto gen_shift_maybe_vex; OP_32_64(rotl): c = SHIFT_ROL; goto gen_shift; OP_32_64(rotr): c = SHIFT_ROR; goto gen_shift; - gen_shift_maybe_vex: - if (have_bmi2) { - if (!const_a2) { - tcg_out_vex_modrm(s, vexop + rexw, a0, a2, a1); - break; - } - tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, a0, a1); - } - /* FALLTHRU */ gen_shift: if (const_a2) { tcg_out_shifti(s, c + rexw, a0, a2); @@ -3810,10 +3824,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: - return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); - case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 2699079073..aae0f03505 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1489,6 +1489,32 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sra_w(s, a0, a1, a2); + } else { + tcg_out_opc_sra_d(s, a0, a1, a2); + } +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); + } else { + tcg_out_opc_srai_d(s, a0, a1, a2 & 0x3f); + } +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1712,21 +1738,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); break; - case INDEX_op_sar_i32: - if (c2) { - tcg_out_opc_srai_w(s, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_sra_w(s, a0, a1, a2); - } - break; - case INDEX_op_sar_i64: - if (c2) { - tcg_out_opc_srai_d(s, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_sra_d(s, a0, a1, a2); - } - break; - case INDEX_op_rotl_i32: /* transform into equivalent rotr/rotri */ if (c2) { @@ -2391,8 +2402,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 03b4248ea9..16c3d59c19 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1908,6 +1908,29 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_SRAV : OPC_DSRAV; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sa(s, OPC_SRA, a0, a1, a2); + } else { + tcg_out_dsra(s, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2111,12 +2134,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_dsra(s, a0, a1, 32); break; - case INDEX_op_sar_i32: - i1 = OPC_SRAV, i2 = OPC_SRA; - goto do_shift; case INDEX_op_rotr_i32: i1 = OPC_ROTRV, i2 = OPC_ROTR; - do_shift: if (c2) { tcg_out_opc_sa(s, i2, a0, a1, a2); break; @@ -2132,13 +2151,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1); } break; - case INDEX_op_sar_i64: - if (c2) { - tcg_out_dsra(s, a0, a1, a2); - break; - } - i1 = OPC_DSRAV; - goto do_shiftv; case INDEX_op_rotr_i64: if (c2) { tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2); @@ -2319,10 +2331,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_sar_i32: case INDEX_op_rotr_i32: case INDEX_op_rotl_i32: - case INDEX_op_sar_i64: case INDEX_op_rotr_i64: case INDEX_op_rotl_i64: return C_O1_I2(r, r, ri); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 2012734bb3..24e8f675bb 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3122,6 +3122,30 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SRAW : SRAD; + tcg_out32(s, insn | SAB(a1, a0, a2)); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* Limit immediate shift count lest we create an illegal insn. */ + if (type == TCG_TYPE_I32) { + tcg_out_sari32(s, a0, a1, a2 & 31); + } else { + tcg_out_sari64(s, a0, a1, a2 & 63); + } +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3320,13 +3344,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_sar_i32: - if (const_args[2]) { - tcg_out_sari32(s, args[0], args[1], args[2]); - } else { - tcg_out32(s, SRAW | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_rotl_i32: if (const_args[2]) { tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31); @@ -3357,13 +3374,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_sar_i64: - if (const_args[2]) { - tcg_out_sari64(s, args[0], args[1], args[2]); - } else { - tcg_out32(s, SRAD | SAB(args[1], args[0], args[2])); - } - break; case INDEX_op_rotl_i64: if (const_args[2]) { tcg_out_rld(s, RLDICL, args[0], args[1], args[2], 0); @@ -4222,10 +4232,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 8020cc0b3f..8cab07a392 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2144,6 +2144,27 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SRAW : OPC_SRA; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_SRAIW : OPC_SRAI; + unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_opc_imm(s, insn, a0, a1, a2 & mask); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2299,21 +2320,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_sar_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_SRAIW, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_reg(s, OPC_SRAW, a0, a1, a2); - } - break; - case INDEX_op_sar_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_SRAI, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_reg(s, OPC_SRA, a0, a1, a2); - } - break; - case INDEX_op_rotl_i32: if (c2) { tcg_out_opc_imm(s, OPC_RORIW, a0, a1, -a2 & 0x1f); @@ -2770,10 +2776,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_sar_i32: case INDEX_op_rotl_i32: case INDEX_op_rotr_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i64: case INDEX_op_rotr_i64: return C_O1_I2(r, r, ri); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 0417bbef50..1cf4920276 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2445,6 +2445,36 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sar_int(TCGContext *s, TCGType type, TCGReg dst, + TCGReg src, TCGReg v, tcg_target_long i) +{ + if (type != TCG_TYPE_I32) { + tcg_out_sh64(s, RSY_SRAG, dst, src, v, i); + } else if (dst == src) { + tcg_out_sh32(s, RS_SRA, dst, v, i); + } else { + tcg_out_sh64(s, RSY_SRAK, dst, src, v, i); + } +} + +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_sar_int(s, type, a0, a1, a2, 0); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_sar_int(s, type, a0, a1, TCG_REG_NONE, a2); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl_int(TCGContext *s, TCGType type, TCGReg dst, TCGReg src, TCGReg v, tcg_target_long i) { @@ -2586,7 +2616,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - S390Opcode op, op2; TCGArg a0, a1, a2; switch (opc) { @@ -2634,28 +2663,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - do_shift32: - a0 = args[0], a1 = args[1], a2 = (int32_t)args[2]; - if (a0 == a1) { - if (const_args[2]) { - tcg_out_sh32(s, op, a0, TCG_REG_NONE, a2); - } else { - tcg_out_sh32(s, op, a0, a2, 0); - } - } else { - /* Using tcg_out_sh64 here for the format; it is a 32-bit shift. */ - if (const_args[2]) { - tcg_out_sh64(s, op2, a0, a1, TCG_REG_NONE, a2); - } else { - tcg_out_sh64(s, op2, a0, a1, a2, 0); - } - } - break; - case INDEX_op_sar_i32: - op = RS_SRA; - op2 = RSY_SRAK; - goto do_shift32; - case INDEX_op_rotl_i32: /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol. */ if (const_args[2]) { @@ -2799,17 +2806,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]); break; - do_shift64: - if (const_args[2]) { - tcg_out_sh64(s, op, args[0], args[1], TCG_REG_NONE, args[2]); - } else { - tcg_out_sh64(s, op, args[0], args[1], args[2], 0); - } - break; - case INDEX_op_sar_i64: - op = RSY_SRAG; - goto do_shift64; - case INDEX_op_rotl_i64: if (const_args[2]) { tcg_out_sh64(s, RSY_RLLG, args[0], args[1], @@ -3394,7 +3390,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_sar_i64: case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: @@ -3409,9 +3404,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_clz_i64: return C_O1_I2(r, r, rI); - case INDEX_op_sar_i32: - return C_O1_I2(r, r, ri); - case INDEX_op_brcond_i32: return C_O0_I2(r, ri); case INDEX_op_brcond_i64: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index f679fa04ea..42d81c1e6c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1484,6 +1484,27 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SRA : SHIFT_SRAX; + tcg_out_arith(s, a0, a1, a2, insn); +} + +static void tgen_sari(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? SHIFT_SRA : SHIFT_SRAX; + uint32_t mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_arithi(s, a0, a1, a2 & mask, insn); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_sar, + .out_rri = tgen_sari, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1629,13 +1650,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st32_i64: tcg_out_ldst(s, a0, a1, a2, STW); break; - do_shift32: - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_arithc(s, a0, a1, a2 & 31, c2, c); - break; - case INDEX_op_sar_i32: - c = SHIFT_SRA; - goto do_shift32; case INDEX_op_brcond_i32: tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], arg_label(args[3])); @@ -1693,13 +1707,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_st_i64: tcg_out_ldst(s, a0, a1, a2, STX); break; - do_shift64: - /* Limit immediate shift count lest we create an illegal insn. */ - tcg_out_arithc(s, a0, a1, a2 & 63, c2, c); - break; - case INDEX_op_sar_i64: - c = SHIFT_SRAX; - goto do_shift64; case INDEX_op_brcond_i64: tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); @@ -1783,8 +1790,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: case INDEX_op_negsetcond_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 939bbe86e9..ffe9efbf79 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,6 +1042,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_sar_i32, TCGOutOpBinary, outop_sar), + OUTOP(INDEX_op_sar_i64, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -2264,7 +2266,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_sar_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_deposit_i32: @@ -2314,7 +2315,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st16_i64: case INDEX_op_st32_i64: case INDEX_op_st_i64: - case INDEX_op_sar_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i64: @@ -5421,6 +5421,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_sar_i32: + case INDEX_op_sar_i64: case INDEX_op_shl: case INDEX_op_shr: case INDEX_op_xor: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index c0dbe873f1..f50a2d6574 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,8 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: @@ -774,6 +772,21 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_sar(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type < TCG_TYPE_REG) { + tcg_out_ext32s(s, TCG_REG_TMP, a1); + a1 = TCG_REG_TMP; + } + tcg_out_op_rrr(s, glue(INDEX_op_sar_i,TCG_TARGET_REG_BITS), a0, a1, a2); +} + +static const TCGOutOpBinary outop_sar = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_sar, +}; + static void tgen_shl(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From 3949f365eb6e7c934831c65c67b729562846ede9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 08:05:18 -0800 Subject: [PATCH 0417/2760] tcg: Merge INDEX_op_sar_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 12 ++++++------ tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 6 ++---- tcg/tci.c | 12 ++++-------- tcg/tci/tcg-target.c.inc | 3 +-- 7 files changed, 18 insertions(+), 26 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index f9fd4b0087..be82fed41a 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -389,10 +389,10 @@ Shifts/Rotates - | *t0* = *t1* >> *t2* (unsigned) | Unspecified behavior for negative or out-of-range shifts. - * - sar_i32/i64 *t0*, *t1*, *t2* + * - sar *t0*, *t1*, *t2* - | *t0* = *t1* >> *t2* (signed) - | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + | Unspecified behavior for negative or out-of-range shifts. * - rotl_i32/i64 *t0*, *t1*, *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 35e0be8f80..cb8c134e94 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -58,6 +58,7 @@ DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) +DEF(sar, 1, 2, 0, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) @@ -76,7 +77,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ -DEF(sar_i32, 1, 2, 0, 0) DEF(rotl_i32, 1, 2, 0, 0) DEF(rotr_i32, 1, 2, 0, 0) DEF(deposit_i32, 1, 2, 2, 0) @@ -115,7 +115,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ -DEF(sar_i64, 1, 2, 0, 0) DEF(rotl_i64, 1, 2, 0, 0) DEF(rotr_i64, 1, 2, 0, 0) DEF(deposit_i64, 1, 2, 2, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 43db079693..f94be19b72 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -458,10 +458,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (uint64_t)x >> (y & 63); - case INDEX_op_sar_i32: - return (int32_t)x >> (y & 31); - - case INDEX_op_sar_i64: + case INDEX_op_sar: + if (type == TCG_TYPE_I32) { + return (int32_t)x >> (y & 31); + } return (int64_t)x >> (y & 63); case INDEX_op_rotr_i32: @@ -2600,7 +2600,7 @@ static bool fold_shift(OptContext *ctx, TCGOp *op) } switch (op->opc) { - CASE_OP_32_64(sar): + case INDEX_op_sar: /* * Arithmetic right shift will not reduce the number of * input sign repetitions. @@ -3027,7 +3027,7 @@ void tcg_optimize(TCGContext *s) break; CASE_OP_32_64(rotl): CASE_OP_32_64(rotr): - CASE_OP_32_64(sar): + case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: done = fold_shift(&ctx, op); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ef8cf5a1ac..43848ebc4f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -511,7 +511,7 @@ void tcg_gen_shri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_sar_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - tcg_gen_op3_i32(INDEX_op_sar_i32, ret, arg1, arg2); + tcg_gen_op3_i32(INDEX_op_sar, ret, arg1, arg2); } void tcg_gen_sari_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) @@ -1624,7 +1624,7 @@ void tcg_gen_shr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_sar_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op3_i64(INDEX_op_sar_i64, ret, arg1, arg2); + tcg_gen_op3_i64(INDEX_op_sar, ret, arg1, arg2); } else { gen_helper_sar_i64(ret, arg1, arg2); } diff --git a/tcg/tcg.c b/tcg/tcg.c index ffe9efbf79..8f67107190 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,8 +1042,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), - OUTOP(INDEX_op_sar_i32, TCGOutOpBinary, outop_sar), - OUTOP(INDEX_op_sar_i64, TCGOutOpBinary, outop_sar), + OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -5421,8 +5420,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: + case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: case INDEX_op_xor: diff --git a/tcg/tci.c b/tcg/tci.c index 376b1b1ece..2a2f216898 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -625,9 +625,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] >> (regs[r2] % TCG_TARGET_REG_BITS); break; - case INDEX_op_sar_i32: + case INDEX_op_sar: tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = (int32_t)regs[r1] >> (regs[r2] & 31); + regs[r0] = ((tcg_target_long)regs[r1] + >> (regs[r2] % TCG_TARGET_REG_BITS)); break; #if TCG_TARGET_HAS_rot_i32 case INDEX_op_rotl_i32: @@ -787,10 +788,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Shift/rotate operations (64 bit). */ - case INDEX_op_sar_i64: - tci_args_rrr(insn, &r0, &r1, &r2); - regs[r0] = (int64_t)regs[r1] >> (regs[r2] & 63); - break; #if TCG_TARGET_HAS_rot_i64 case INDEX_op_rotl_i64: tci_args_rrr(insn, &r0, &r1, &r2); @@ -1073,12 +1070,11 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_sar_i32: - case INDEX_op_sar_i64: case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: case INDEX_op_rotr_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index f50a2d6574..feaa13dff0 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -779,7 +779,7 @@ static void tgen_sar(TCGContext *s, TCGType type, tcg_out_ext32s(s, TCG_REG_TMP, a1); a1 = TCG_REG_TMP; } - tcg_out_op_rrr(s, glue(INDEX_op_sar_i,TCG_TARGET_REG_BITS), a0, a1, a2); + tcg_out_op_rrr(s, INDEX_op_sar, a0, a1, a2); } static const TCGOutOpBinary outop_sar = { @@ -897,7 +897,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(sar) CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ From 8726c7d79967c740f7d5a963ac2d855354805cd2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 09:53:38 -0800 Subject: [PATCH 0418/2760] tcg: Do not require both rotr and rotl from the backend Many host architectures do not implement both rotate right and rotate left and require the compiler to negate the shift count to rotate the opposite direction. We have been requiring the backend to perform this transformation. Do this during opcode expansion so that the next patch can drop support where possible in the backend. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 98 +++++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 43848ebc4f..8c8b9d179b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -829,15 +829,18 @@ void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_rot_i32) { + if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + tcg_gen_neg_i32(t0, arg2); + tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, t0); + tcg_temp_free_i32(t0); } else { - TCGv_i32 t0, t1; - - t0 = tcg_temp_ebb_new_i32(); - t1 = tcg_temp_ebb_new_i32(); + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); tcg_gen_shl_i32(t0, arg1, arg2); - tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_neg_i32(t1, arg2); tcg_gen_shr_i32(t1, arg1, t1); tcg_gen_or_i32(ret, t0, t1); tcg_temp_free_i32(t0); @@ -851,12 +854,15 @@ void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); - } else if (TCG_TARGET_HAS_rot_i32) { - tcg_gen_rotl_i32(ret, arg1, tcg_constant_i32(arg2)); + } else if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_constant_i32(arg2); + tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, t0); + } else if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_constant_i32(32 - arg2); + tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, t0); } else { - TCGv_i32 t0, t1; - t0 = tcg_temp_ebb_new_i32(); - t1 = tcg_temp_ebb_new_i32(); + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); tcg_gen_shli_i32(t0, arg1, arg2); tcg_gen_shri_i32(t1, arg1, 32 - arg2); tcg_gen_or_i32(ret, t0, t1); @@ -867,15 +873,18 @@ void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_rot_i32) { + if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + tcg_gen_neg_i32(t0, arg2); + tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, t0); + tcg_temp_free_i32(t0); } else { - TCGv_i32 t0, t1; - - t0 = tcg_temp_ebb_new_i32(); - t1 = tcg_temp_ebb_new_i32(); + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); tcg_gen_shr_i32(t0, arg1, arg2); - tcg_gen_subfi_i32(t1, 32, arg2); + tcg_gen_neg_i32(t1, arg2); tcg_gen_shl_i32(t1, arg1, t1); tcg_gen_or_i32(ret, t0, t1); tcg_temp_free_i32(t0); @@ -886,12 +895,7 @@ void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_rotri_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) { tcg_debug_assert(arg2 >= 0 && arg2 < 32); - /* some cases can be optimized here */ - if (arg2 == 0) { - tcg_gen_mov_i32(ret, arg1); - } else { - tcg_gen_rotli_i32(ret, arg1, 32 - arg2); - } + tcg_gen_rotli_i32(ret, arg1, -arg2 & 31); } void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, @@ -2437,14 +2441,18 @@ void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_rot_i64) { + if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + tcg_gen_neg_i64(t0, arg2); + tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, t0); + tcg_temp_free_i64(t0); } else { - TCGv_i64 t0, t1; - t0 = tcg_temp_ebb_new_i64(); - t1 = tcg_temp_ebb_new_i64(); + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + TCGv_i64 t1 = tcg_temp_ebb_new_i64(); tcg_gen_shl_i64(t0, arg1, arg2); - tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_neg_i64(t1, arg2); tcg_gen_shr_i64(t1, arg1, t1); tcg_gen_or_i64(ret, t0, t1); tcg_temp_free_i64(t0); @@ -2458,12 +2466,15 @@ void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); - } else if (TCG_TARGET_HAS_rot_i64) { - tcg_gen_rotl_i64(ret, arg1, tcg_constant_i64(arg2)); + } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + TCGv_i64 t0 = tcg_constant_i64(arg2); + tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, t0); + } else if (tcg_op_supported(INDEX_op_rotr_i64, TCG_TYPE_I64, 0)) { + TCGv_i64 t0 = tcg_constant_i64(64 - arg2); + tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, t0); } else { - TCGv_i64 t0, t1; - t0 = tcg_temp_ebb_new_i64(); - t1 = tcg_temp_ebb_new_i64(); + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + TCGv_i64 t1 = tcg_temp_ebb_new_i64(); tcg_gen_shli_i64(t0, arg1, arg2); tcg_gen_shri_i64(t1, arg1, 64 - arg2); tcg_gen_or_i64(ret, t0, t1); @@ -2474,14 +2485,18 @@ void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_rot_i64) { + if (tcg_op_supported(INDEX_op_rotr_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + tcg_gen_neg_i64(t0, arg2); + tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, t0); + tcg_temp_free_i64(t0); } else { - TCGv_i64 t0, t1; - t0 = tcg_temp_ebb_new_i64(); - t1 = tcg_temp_ebb_new_i64(); + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + TCGv_i64 t1 = tcg_temp_ebb_new_i64(); tcg_gen_shr_i64(t0, arg1, arg2); - tcg_gen_subfi_i64(t1, 64, arg2); + tcg_gen_neg_i64(t1, arg2); tcg_gen_shl_i64(t1, arg1, t1); tcg_gen_or_i64(ret, t0, t1); tcg_temp_free_i64(t0); @@ -2492,12 +2507,7 @@ void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_rotri_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) { tcg_debug_assert(arg2 >= 0 && arg2 < 64); - /* some cases can be optimized here */ - if (arg2 == 0) { - tcg_gen_mov_i64(ret, arg1); - } else { - tcg_gen_rotli_i64(ret, arg1, 64 - arg2); - } + tcg_gen_rotli_i64(ret, arg1, -arg2 & 63); } void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, From 03568c0d539581c6e86263d2fd7396f5a1e25a6b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 10:22:53 -0800 Subject: [PATCH 0419/2760] tcg: Convert rotl, rotr to TCGOutOpBinary For aarch64, arm, loongarch64, mips, we can drop rotl. For ppc, s390x we can drop rotr. Only x86, riscv, tci have both rotl and rotr. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 - tcg/aarch64/tcg-target.c.inc | 62 +++++++++--------------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 44 ++++++++--------- tcg/i386/tcg-target-has.h | 2 - tcg/i386/tcg-target.c.inc | 62 ++++++++++++++++-------- tcg/loongarch64/tcg-target-has.h | 2 - tcg/loongarch64/tcg-target.c.inc | 70 ++++++++++++--------------- tcg/mips/tcg-target-has.h | 2 - tcg/mips/tcg-target.c.inc | 75 +++++++++++++---------------- tcg/ppc/tcg-target-has.h | 2 - tcg/ppc/tcg-target.c.inc | 70 ++++++++++++--------------- tcg/riscv/tcg-target-has.h | 2 - tcg/riscv/tcg-target.c.inc | 83 ++++++++++++++++++-------------- tcg/s390x/tcg-target-has.h | 2 - tcg/s390x/tcg-target.c.inc | 72 +++++++++++---------------- tcg/sparc64/tcg-target-has.h | 2 - tcg/sparc64/tcg-target.c.inc | 8 +++ tcg/tcg-has.h | 1 - tcg/tcg.c | 14 +++--- tcg/tci.c | 12 ++--- tcg/tci/tcg-target-has.h | 2 - tcg/tci/tcg-target-opc.h.inc | 2 + tcg/tci/tcg-target.c.inc | 34 ++++++++++--- 24 files changed, 306 insertions(+), 322 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 1fdff25d05..fa79cbc1f0 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -15,7 +15,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -31,7 +30,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 90bdbf8387..00fca43840 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1347,20 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a); } -static inline void tcg_out_rotr(TCGContext *s, TCGType ext, - TCGReg rd, TCGReg rn, unsigned int m) -{ - int max = ext ? 63 : 31; - tcg_out_extr(s, ext, rd, rn, rn, m & max); -} - -static inline void tcg_out_rotl(TCGContext *s, TCGType ext, - TCGReg rd, TCGReg rn, unsigned int m) -{ - int max = ext ? 63 : 31; - tcg_out_extr(s, ext, rd, rn, rn, -m & max); -} - static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd, TCGReg rn, unsigned lsb, unsigned width) { @@ -2277,6 +2263,29 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_NotImplemented, +}; + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3508, RORV, type, a0, a1, a2); +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int max = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_extr(s, type, a0, a1, a1, a2 & max); +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2451,25 +2460,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_rotr_i64: - case INDEX_op_rotr_i32: - if (c2) { - tcg_out_rotr(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3508, RORV, ext, a0, a1, a2); - } - break; - - case INDEX_op_rotl_i64: - case INDEX_op_rotl_i32: - if (c2) { - tcg_out_rotl(s, ext, a0, a1, a2); - } else { - tcg_out_insn(s, 3502, SUB, 0, TCG_REG_TMP0, TCG_REG_XZR, a2); - tcg_out_insn(s, 3508, RORV, ext, a0, a1, TCG_REG_TMP0); - } - break; - case INDEX_op_clz_i64: case INDEX_op_clz_i32: tcg_out_cltz(s, ext, a0, a1, a2, c2, false); @@ -3099,12 +3089,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i64: - return C_O1_I2(r, r, ri); - case INDEX_op_clz_i32: case INDEX_op_ctz_i32: case INDEX_op_clz_i64: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 32d73d3443..12ffbcda2b 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -26,7 +26,6 @@ extern bool use_neon_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions #define TCG_TARGET_HAS_ctpop_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 058677650b..462f0ec08d 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1963,6 +1963,28 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_NotImplemented, +}; + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_REG_ROR(a2)); +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_MOV, a0, 0, a1, SHIFT_IMM_ROR(a2 & 0x1f)); +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2171,24 +2193,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_muls2_i32: tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - case INDEX_op_rotr_i32: - c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ROR(args[2] & 0x1f) : - SHIFT_IMM_LSL(0) : SHIFT_REG_ROR(args[2]); - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c); - break; - - case INDEX_op_rotl_i32: - if (const_args[2]) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], - ((0x20 - args[2]) & 0x1f) ? - SHIFT_IMM_ROR((0x20 - args[2]) & 0x1f) : - SHIFT_IMM_LSL(0)); - } else { - tcg_out_dat_imm(s, COND_AL, ARITH_RSB, TCG_REG_TMP, args[2], 0x20); - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], - SHIFT_REG_ROR(TCG_REG_TMP)); - } - break; case INDEX_op_ctz_i32: tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0); @@ -2342,10 +2346,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i32: - return C_O1_I2(r, r, ri); - case INDEX_op_brcond_i32: return C_O0_I2(r, rIN); case INDEX_op_deposit_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index aee6066579..a7199463df 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,7 +26,6 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -42,7 +41,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1e81455461..dd35bba57f 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2744,6 +2744,46 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_rotl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROL, a0); +} + +static void tgen_rotli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_shifti(s, SHIFT_ROL + rexw, a0, a2); +} + +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_O1_I2(r, 0, ci), + .out_rrr = tgen_rotl, + .out_rri = tgen_rotli, +}; + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_SHIFT_cl + rexw, SHIFT_ROR, a0); +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_shifti(s, SHIFT_ROR + rexw, a0, a2); +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_O1_I2(r, 0, ci), + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + static TCGConstraintSetIndex cset_shift(TCGType type, unsigned flags) { return have_bmi2 ? C_O1_I2(r, r, ri) : C_O1_I2(r, 0, ci); @@ -2901,7 +2941,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int c, const_a2, rexw; + int const_a2, rexw; #if TCG_TARGET_REG_BITS == 64 # define OP_32_64(x) \ @@ -2976,20 +3016,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(rotl): - c = SHIFT_ROL; - goto gen_shift; - OP_32_64(rotr): - c = SHIFT_ROR; - goto gen_shift; - gen_shift: - if (const_a2) { - tcg_out_shifti(s, c + rexw, a0, a2); - } else { - tcg_out_modrm(s, OPC_SHIFT_cl + rexw, c, a0); - } - break; - OP_32_64(ctz): tcg_out_ctz(s, rexw, args[0], args[1], args[2], const_args[2]); break; @@ -3824,12 +3850,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: - case INDEX_op_rotr_i64: - return C_O1_I2(r, 0, ci); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(r, reT); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 5dfc69ae6a..303134390a 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 0 -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 @@ -26,7 +25,6 @@ /* 64-bit operations */ #define TCG_TARGET_HAS_negsetcond_i64 0 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_bswap16_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index aae0f03505..26cf982780 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1489,6 +1489,36 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_NotImplemented, +}; + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_rotr_w(s, a0, a1, a2); + } else { + tcg_out_opc_rotr_d(s, a0, a1, a2); + } +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f); + } else { + tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f); + } +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1738,40 +1768,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); break; - case INDEX_op_rotl_i32: - /* transform into equivalent rotr/rotri */ - if (c2) { - tcg_out_opc_rotri_w(s, a0, a1, (32 - a2) & 0x1f); - } else { - tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); - tcg_out_opc_rotr_w(s, a0, a1, TCG_REG_TMP0); - } - break; - case INDEX_op_rotl_i64: - /* transform into equivalent rotr/rotri */ - if (c2) { - tcg_out_opc_rotri_d(s, a0, a1, (64 - a2) & 0x3f); - } else { - tcg_out_opc_sub_w(s, TCG_REG_TMP0, TCG_REG_ZERO, a2); - tcg_out_opc_rotr_d(s, a0, a1, TCG_REG_TMP0); - } - break; - - case INDEX_op_rotr_i32: - if (c2) { - tcg_out_opc_rotri_w(s, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_rotr_w(s, a0, a1, a2); - } - break; - case INDEX_op_rotr_i64: - if (c2) { - tcg_out_opc_rotri_d(s, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_rotr_d(s, a0, a1, a2); - } - break; - case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], a0, a1, a2, c2); @@ -2402,12 +2398,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: - case INDEX_op_rotr_i64: - return C_O1_I2(r, r, ri); - case INDEX_op_clz_i32: case INDEX_op_clz_i64: case INDEX_op_ctz_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index ab6a134796..880eb084eb 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -60,7 +60,6 @@ extern bool use_mips32r2_instructions; /* optional instructions detected at runtime */ #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_rot_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 @@ -71,7 +70,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_rot_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 16c3d59c19..fb9fe0c40e 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1908,6 +1908,39 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_NotImplemented, +}; + +static TCGConstraintSetIndex cset_rotr(TCGType type, unsigned flags) +{ + return use_mips32r2_instructions ? C_O1_I2(r, r, ri) : C_NotImplemented; +} + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_ROTRV : OPC_DROTRV; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_sa(s, OPC_ROTR, a0, a1, a2); + } else { + tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2); + } +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_rotr, + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2032,14 +2065,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - MIPSInsn i1, i2; + MIPSInsn i1; TCGArg a0, a1, a2; - int c2; a0 = args[0]; a1 = args[1]; a2 = args[2]; - c2 = const_args[2]; switch (opc) { case INDEX_op_goto_ptr: @@ -2134,39 +2165,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_dsra(s, a0, a1, 32); break; - case INDEX_op_rotr_i32: - i1 = OPC_ROTRV, i2 = OPC_ROTR; - if (c2) { - tcg_out_opc_sa(s, i2, a0, a1, a2); - break; - } - do_shiftv: - tcg_out_opc_reg(s, i1, a0, a2, a1); - break; - case INDEX_op_rotl_i32: - if (c2) { - tcg_out_opc_sa(s, OPC_ROTR, a0, a1, 32 - a2); - } else { - tcg_out_opc_reg(s, OPC_SUBU, TCG_TMP0, TCG_REG_ZERO, a2); - tcg_out_opc_reg(s, OPC_ROTRV, a0, TCG_TMP0, a1); - } - break; - case INDEX_op_rotr_i64: - if (c2) { - tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, a2); - break; - } - i1 = OPC_DROTRV; - goto do_shiftv; - case INDEX_op_rotl_i64: - if (c2) { - tcg_out_opc_sa64(s, OPC_DROTR, OPC_DROTR32, a0, a1, 64 - a2); - } else { - tcg_out_opc_reg(s, OPC_DSUBU, TCG_TMP0, TCG_REG_ZERO, a2); - tcg_out_opc_reg(s, OPC_DROTRV, a0, TCG_TMP0, a1); - } - break; - case INDEX_op_clz_i32: tcg_out_clz(s, OPC_CLZ, OPC_CLZ_R6, 32, a0, a1, a2); break; @@ -2331,11 +2329,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_rotr_i32: - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i64: - case INDEX_op_rotl_i64: - return C_O1_I2(r, r, ri); case INDEX_op_clz_i32: case INDEX_op_clz_i64: return C_O1_I2(r, r, rzW); diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 37e88a3193..71c02d88b9 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,7 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_clz_i32 1 @@ -33,7 +32,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 24e8f675bb..687b66af54 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3122,6 +3122,36 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_rotl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out32(s, RLWNM | SAB(a1, a0, a2) | MB(0) | ME(31)); + } else { + tcg_out32(s, RLDCL | SAB(a1, a0, a2) | MB64(0)); + } +} + +static void tgen_rotli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_rlw(s, RLWINM, a0, a1, a2, 0, 31); + } else { + tcg_out_rld(s, RLDICL, a0, a1, a2, 0); + } +} + +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_rotl, + .out_rri = tgen_rotli, +}; + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3344,24 +3374,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; - case INDEX_op_rotl_i32: - if (const_args[2]) { - tcg_out_rlw(s, RLWINM, args[0], args[1], args[2], 0, 31); - } else { - tcg_out32(s, RLWNM | SAB(args[1], args[0], args[2]) - | MB(0) | ME(31)); - } - break; - case INDEX_op_rotr_i32: - if (const_args[2]) { - tcg_out_rlw(s, RLWINM, args[0], args[1], 32 - args[2], 0, 31); - } else { - tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 32)); - tcg_out32(s, RLWNM | SAB(args[1], args[0], TCG_REG_R0) - | MB(0) | ME(31)); - } - break; - case INDEX_op_brcond_i32: tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], arg_label(args[3]), TCG_TYPE_I32); @@ -3374,22 +3386,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args, const_args); break; - case INDEX_op_rotl_i64: - if (const_args[2]) { - tcg_out_rld(s, RLDICL, args[0], args[1], args[2], 0); - } else { - tcg_out32(s, RLDCL | SAB(args[1], args[0], args[2]) | MB64(0)); - } - break; - case INDEX_op_rotr_i64: - if (const_args[2]) { - tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 0); - } else { - tcg_out32(s, SUBFIC | TAI(TCG_REG_R0, args[2], 64)); - tcg_out32(s, RLDCL | SAB(args[1], args[0], TCG_REG_R0) | MB64(0)); - } - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -4232,12 +4228,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i64: - return C_O1_I2(r, r, ri); - case INDEX_op_clz_i32: case INDEX_op_ctz_i32: case INDEX_op_clz_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index b3c6899887..c7745a6462 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -11,7 +11,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_negsetcond_i32 1 -#define TCG_TARGET_HAS_rot_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 @@ -25,7 +24,6 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_negsetcond_i64 1 -#define TCG_TARGET_HAS_rot_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 8cab07a392..4dd892d98d 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2144,6 +2144,53 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static TCGConstraintSetIndex cset_rot(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBB ? C_O1_I2(r, r, ri) : C_NotImplemented; +} + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_RORW : OPC_ROR; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_rotri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_RORIW : OPC_RORI; + unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_opc_imm(s, insn, a0, a1, a2 & mask); +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_rot, + .out_rrr = tgen_rotr, + .out_rri = tgen_rotri, +}; + +static void tgen_rotl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_ROLW : OPC_ROL; + tcg_out_opc_reg(s, insn, a0, a1, a2); +} + +static void tgen_rotli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_rotri(s, type, a0, a1, -a2); +} + +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_rot, + .out_rrr = tgen_rotl, + .out_rri = tgen_rotli, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2320,36 +2367,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_rotl_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_RORIW, a0, a1, -a2 & 0x1f); - } else { - tcg_out_opc_reg(s, OPC_ROLW, a0, a1, a2); - } - break; - case INDEX_op_rotl_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_RORI, a0, a1, -a2 & 0x3f); - } else { - tcg_out_opc_reg(s, OPC_ROL, a0, a1, a2); - } - break; - - case INDEX_op_rotr_i32: - if (c2) { - tcg_out_opc_imm(s, OPC_RORIW, a0, a1, a2 & 0x1f); - } else { - tcg_out_opc_reg(s, OPC_RORW, a0, a1, a2); - } - break; - case INDEX_op_rotr_i64: - if (c2) { - tcg_out_opc_imm(s, OPC_RORI, a0, a1, a2 & 0x3f); - } else { - tcg_out_opc_reg(s, OPC_ROR, a0, a1, a2); - } - break; - case INDEX_op_bswap64_i64: tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); break; @@ -2776,12 +2793,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i64: - return C_O1_I2(r, r, ri); - case INDEX_op_clz_i32: case INDEX_op_clz_i64: case INDEX_op_ctz_i32: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index d61cc7a144..eaddf7005e 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,7 +29,6 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_clz_i32 0 @@ -44,7 +43,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 1cf4920276..76180dabcb 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2445,6 +2445,35 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static void tgen_rotl_int(TCGContext *s, TCGType type, TCGReg dst, + TCGReg src, TCGReg v, tcg_target_long i) +{ + S390Opcode insn = type == TCG_TYPE_I32 ? RSY_RLL : RSY_RLLG; + tcg_out_sh64(s, insn, dst, src, v, i); +} + +static void tgen_rotl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_rotl_int(s, type, a0, a1, a2, 0); +} + +static void tgen_rotli(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_rotl_int(s, type, a0, a1, TCG_REG_NONE, a2); +} + +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_O1_I2(r, r, ri), + .out_rrr = tgen_rotl, + .out_rri = tgen_rotli, +}; + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sar_int(TCGContext *s, TCGType type, TCGReg dst, TCGReg src, TCGReg v, tcg_target_long i) { @@ -2663,24 +2692,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_rotl_i32: - /* ??? Using tcg_out_sh64 here for the format; it is a 32-bit rol. */ - if (const_args[2]) { - tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_REG_NONE, args[2]); - } else { - tcg_out_sh64(s, RSY_RLL, args[0], args[1], args[2], 0); - } - break; - case INDEX_op_rotr_i32: - if (const_args[2]) { - tcg_out_sh64(s, RSY_RLL, args[0], args[1], - TCG_REG_NONE, (32 - args[2]) & 31); - } else { - tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]); - tcg_out_sh64(s, RSY_RLL, args[0], args[1], TCG_TMP0, 0); - } - break; - case INDEX_op_bswap16_i32: a0 = args[0], a1 = args[1], a2 = args[2]; tcg_out_insn(s, RRE, LRVR, a0, a1); @@ -2806,26 +2817,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]); break; - case INDEX_op_rotl_i64: - if (const_args[2]) { - tcg_out_sh64(s, RSY_RLLG, args[0], args[1], - TCG_REG_NONE, args[2]); - } else { - tcg_out_sh64(s, RSY_RLLG, args[0], args[1], args[2], 0); - } - break; - case INDEX_op_rotr_i64: - if (const_args[2]) { - tcg_out_sh64(s, RSY_RLLG, args[0], args[1], - TCG_REG_NONE, (64 - args[2]) & 63); - } else { - /* We can use the smaller 32-bit negate because only the - low 6 bits are examined for the rotate. */ - tcg_out_insn(s, RR, LCR, TCG_TMP0, args[2]); - tcg_out_sh64(s, RSY_RLLG, args[0], args[1], TCG_TMP0, 0); - } - break; - case INDEX_op_add2_i64: if (const_args[4]) { if ((int64_t)args[4] >= 0) { @@ -3390,11 +3381,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: - case INDEX_op_rotr_i64: - return C_O1_I2(r, r, ri); case INDEX_op_setcond_i32: case INDEX_op_negsetcond_i32: case INDEX_op_setcond_i64: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 42de99efbf..1dd86c363d 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,7 +14,6 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_rot_i32 0 #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_clz_i32 0 @@ -29,7 +28,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 42d81c1e6c..57b26ae33b 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1484,6 +1484,14 @@ static const TCGOutOpBinary outop_remu = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 0bb829be36..7bfa55adb1 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_rot_i64 0 #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 diff --git a/tcg/tcg.c b/tcg/tcg.c index 8f67107190..40a3e44b7c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,6 +1042,10 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), + OUTOP(INDEX_op_rotl_i32, TCGOutOpBinary, outop_rotl), + OUTOP(INDEX_op_rotl_i64, TCGOutOpBinary, outop_rotl), + OUTOP(INDEX_op_rotr_i32, TCGOutOpBinary, outop_rotr), + OUTOP(INDEX_op_rotr_i64, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), @@ -2272,9 +2276,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return TCG_TARGET_HAS_negsetcond_i32; - case INDEX_op_rotl_i32: - case INDEX_op_rotr_i32: - return TCG_TARGET_HAS_rot_i32; case INDEX_op_extract2_i32: return TCG_TARGET_HAS_extract2_i32; case INDEX_op_add2_i32: @@ -2323,9 +2324,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return TCG_TARGET_HAS_negsetcond_i64; - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i64: - return TCG_TARGET_HAS_rot_i64; case INDEX_op_extract2_i64: return TCG_TARGET_HAS_extract2_i64; case INDEX_op_extrl_i64_i32: @@ -5420,6 +5418,10 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_rotl_i32: + case INDEX_op_rotl_i64: + case INDEX_op_rotr_i32: + case INDEX_op_rotr_i64: case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: diff --git a/tcg/tci.c b/tcg/tci.c index 2a2f216898..0fb13ff61d 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -630,16 +630,14 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = ((tcg_target_long)regs[r1] >> (regs[r2] % TCG_TARGET_REG_BITS)); break; -#if TCG_TARGET_HAS_rot_i32 - case INDEX_op_rotl_i32: + case INDEX_op_tci_rotl32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = rol32(regs[r1], regs[r2] & 31); break; - case INDEX_op_rotr_i32: + case INDEX_op_tci_rotr32: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ror32(regs[r1], regs[r2] & 31); break; -#endif case INDEX_op_deposit_i32: tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit32(regs[r1], pos, len, regs[r2]); @@ -788,7 +786,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Shift/rotate operations (64 bit). */ -#if TCG_TARGET_HAS_rot_i64 case INDEX_op_rotl_i64: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = rol64(regs[r1], regs[r2] & 63); @@ -797,7 +794,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ror64(regs[r1], regs[r2] & 63); break; -#endif case INDEX_op_deposit_i64: tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit64(regs[r1], pos, len, regs[r2]); @@ -1075,9 +1071,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_rotl_i32: case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: case INDEX_op_rotr_i64: case INDEX_op_clz_i32: case INDEX_op_clz_i64: @@ -1087,6 +1081,8 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_tci_divu32: case INDEX_op_tci_rems32: case INDEX_op_tci_remu32: + case INDEX_op_tci_rotl32: + case INDEX_op_tci_rotr32: tci_args_rrr(insn, &r0, &r1, &r2); info->fprintf_func(info->stream, "%-12s %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2)); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index bd51b9346d..04d341a8d2 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -13,7 +13,6 @@ #define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 -#define TCG_TARGET_HAS_rot_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -27,7 +26,6 @@ #define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 -#define TCG_TARGET_HAS_rot_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 #define TCG_TARGET_HAS_add2_i32 1 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 82d2a38cae..cff215490a 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -6,3 +6,5 @@ DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_rotl32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_rotr32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index feaa13dff0..0a2da3ba47 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,10 +79,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_rotl_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: - case INDEX_op_rotr_i64: case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: case INDEX_op_deposit_i32: @@ -772,6 +768,34 @@ static const TCGOutOpBinary outop_remu = { .out_rrr = tgen_remu, }; +static void tgen_rotl(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_rotl32 + : INDEX_op_rotl_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_rotl = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rotl, +}; + +static void tgen_rotr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_rotr32 + : INDEX_op_rotr_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_rotr = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_rotr, +}; + static void tgen_sar(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -897,8 +921,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(rotl) /* Optional (TCG_TARGET_HAS_rot_*). */ - CASE_32_64(rotr) /* Optional (TCG_TARGET_HAS_rot_*). */ CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */ tcg_out_op_rrr(s, opc, args[0], args[1], args[2]); From 005a87e148dc20f59835b328336240759703d63d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 10:42:16 -0800 Subject: [PATCH 0420/2760] tcg: Merge INDEX_op_rot{l,r}_{i32,i64} Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 8 +++---- include/tcg/tcg-opc.h | 6 ++--- tcg/optimize.c | 20 ++++++++--------- tcg/tcg-op.c | 48 ++++++++++++++++++++-------------------- tcg/tcg.c | 12 ++++------ tcg/tci.c | 8 +++---- tcg/tci/tcg-target.c.inc | 4 ++-- 7 files changed, 50 insertions(+), 56 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index be82fed41a..c3a6499d01 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -394,15 +394,15 @@ Shifts/Rotates - | *t0* = *t1* >> *t2* (signed) | Unspecified behavior for negative or out-of-range shifts. - * - rotl_i32/i64 *t0*, *t1*, *t2* + * - rotl *t0*, *t1*, *t2* - | Rotation of *t2* bits to the left - | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + | Unspecified behavior for negative or out-of-range shifts. - * - rotr_i32/i64 *t0*, *t1*, *t2* + * - rotr *t0*, *t1*, *t2* - | Rotation of *t2* bits to the right. - | Unspecified behavior if *t2* < 0 or *t2* >= 32 (resp 64) + | Unspecified behavior for negative or out-of-range shifts. Misc diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index cb8c134e94..25fd93eb28 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -58,6 +58,8 @@ DEF(or, 1, 2, 0, TCG_OPF_INT) DEF(orc, 1, 2, 0, TCG_OPF_INT) DEF(rems, 1, 2, 0, TCG_OPF_INT) DEF(remu, 1, 2, 0, TCG_OPF_INT) +DEF(rotl, 1, 2, 0, TCG_OPF_INT) +DEF(rotr, 1, 2, 0, TCG_OPF_INT) DEF(sar, 1, 2, 0, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) @@ -77,8 +79,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ -DEF(rotl_i32, 1, 2, 0, 0) -DEF(rotr_i32, 1, 2, 0, 0) DEF(deposit_i32, 1, 2, 2, 0) DEF(extract_i32, 1, 1, 2, 0) DEF(sextract_i32, 1, 1, 2, 0) @@ -115,8 +115,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ -DEF(rotl_i64, 1, 2, 0, 0) -DEF(rotr_i64, 1, 2, 0, 0) DEF(deposit_i64, 1, 2, 2, 0) DEF(extract_i64, 1, 1, 2, 0) DEF(sextract_i64, 1, 1, 2, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index f94be19b72..97a566a617 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -464,16 +464,16 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return (int64_t)x >> (y & 63); - case INDEX_op_rotr_i32: - return ror32(x, y & 31); - - case INDEX_op_rotr_i64: + case INDEX_op_rotr: + if (type == TCG_TYPE_I32) { + return ror32(x, y & 31); + } return ror64(x, y & 63); - case INDEX_op_rotl_i32: - return rol32(x, y & 31); - - case INDEX_op_rotl_i64: + case INDEX_op_rotl: + if (type == TCG_TYPE_I32) { + return rol32(x, y & 31); + } return rol64(x, y & 63); case INDEX_op_not: @@ -3025,8 +3025,8 @@ void tcg_optimize(TCGContext *s) case INDEX_op_remu: done = fold_remainder(&ctx, op); break; - CASE_OP_32_64(rotl): - CASE_OP_32_64(rotr): + case INDEX_op_rotl: + case INDEX_op_rotr: case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 8c8b9d179b..1989d8d12c 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -829,12 +829,12 @@ void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) void tcg_gen_rotl_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_rotl, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotr, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_neg_i32(t0, arg2); - tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, t0); + tcg_gen_op3_i32(INDEX_op_rotr, ret, arg1, t0); tcg_temp_free_i32(t0); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -854,12 +854,12 @@ void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i32(ret, arg1); - } else if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { + } else if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_constant_i32(arg2); - tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, t0); - } else if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_rotl, ret, arg1, t0); + } else if (tcg_op_supported(INDEX_op_rotr, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_constant_i32(32 - arg2); - tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, t0); + tcg_gen_op3_i32(INDEX_op_rotr, ret, arg1, t0); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); @@ -873,12 +873,12 @@ void tcg_gen_rotli_i32(TCGv_i32 ret, TCGv_i32 arg1, int32_t arg2) void tcg_gen_rotr_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_rotr_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_rotr_i32, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_rotl_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_rotr, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_rotr, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I32, 0)) { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_neg_i32(t0, arg2); - tcg_gen_op3_i32(INDEX_op_rotl_i32, ret, arg1, t0); + tcg_gen_op3_i32(INDEX_op_rotl, ret, arg1, t0); tcg_temp_free_i32(t0); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2441,12 +2441,12 @@ void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_rotl, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_neg_i64(t0, arg2); - tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, t0); + tcg_gen_op3_i64(INDEX_op_rotr, ret, arg1, t0); tcg_temp_free_i64(t0); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); @@ -2466,12 +2466,12 @@ void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) /* some cases can be optimized here */ if (arg2 == 0) { tcg_gen_mov_i64(ret, arg1); - } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_constant_i64(arg2); - tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, t0); - } else if (tcg_op_supported(INDEX_op_rotr_i64, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_rotl, ret, arg1, t0); + } else if (tcg_op_supported(INDEX_op_rotr, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_constant_i64(64 - arg2); - tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, t0); + tcg_gen_op3_i64(INDEX_op_rotr, ret, arg1, t0); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); @@ -2485,12 +2485,12 @@ void tcg_gen_rotli_i64(TCGv_i64 ret, TCGv_i64 arg1, int64_t arg2) void tcg_gen_rotr_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_rotr_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_rotr_i64, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_rotl_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_rotr, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_rotr, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_rotl, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_neg_i64(t0, arg2); - tcg_gen_op3_i64(INDEX_op_rotl_i64, ret, arg1, t0); + tcg_gen_op3_i64(INDEX_op_rotl, ret, arg1, t0); tcg_temp_free_i64(t0); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 40a3e44b7c..182f19e5f0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1042,10 +1042,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), - OUTOP(INDEX_op_rotl_i32, TCGOutOpBinary, outop_rotl), - OUTOP(INDEX_op_rotl_i64, TCGOutOpBinary, outop_rotl), - OUTOP(INDEX_op_rotr_i32, TCGOutOpBinary, outop_rotr), - OUTOP(INDEX_op_rotr_i64, TCGOutOpBinary, outop_rotr), + OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), + OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), @@ -5418,10 +5416,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: - case INDEX_op_rotl_i32: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i32: - case INDEX_op_rotr_i64: + case INDEX_op_rotl: + case INDEX_op_rotr: case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: diff --git a/tcg/tci.c b/tcg/tci.c index 0fb13ff61d..b1ee14e65f 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -786,11 +786,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Shift/rotate operations (64 bit). */ - case INDEX_op_rotl_i64: + case INDEX_op_rotl: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = rol64(regs[r1], regs[r2] & 63); break; - case INDEX_op_rotr_i64: + case INDEX_op_rotr: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ror64(regs[r1], regs[r2] & 63); break; @@ -1066,13 +1066,13 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_orc: case INDEX_op_rems: case INDEX_op_remu: + case INDEX_op_rotl: + case INDEX_op_rotr: case INDEX_op_sar: case INDEX_op_shl: case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_rotl_i64: - case INDEX_op_rotr_i64: case INDEX_op_clz_i32: case INDEX_op_clz_i64: case INDEX_op_ctz_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 0a2da3ba47..0d15547c9f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -773,7 +773,7 @@ static void tgen_rotl(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_rotl32 - : INDEX_op_rotl_i64); + : INDEX_op_rotl); tcg_out_op_rrr(s, opc, a0, a1, a2); } @@ -787,7 +787,7 @@ static void tgen_rotr(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_rotr32 - : INDEX_op_rotr_i64); + : INDEX_op_rotr); tcg_out_op_rrr(s, opc, a0, a1, a2); } From 8b915879b0fdd05afab41f0ca156113811ebac38 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 14:16:04 -0800 Subject: [PATCH 0421/2760] tcg: Convert clz to TCGOutOpBinary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 - tcg/aarch64/tcg-target.c.inc | 83 +++++++++++++----------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 47 +++++++++----- tcg/i386/tcg-target-has.h | 2 - tcg/i386/tcg-target.c.inc | 72 +++++++++++---------- tcg/loongarch64/tcg-target-has.h | 2 - tcg/loongarch64/tcg-target.c.inc | 36 ++++++++--- tcg/mips/tcg-target-has.h | 2 - tcg/mips/tcg-target.c.inc | 86 +++++++++++++----------- tcg/ppc/tcg-target-has.h | 2 - tcg/ppc/tcg-target.c.inc | 30 ++++++--- tcg/riscv/tcg-target-has.h | 2 - tcg/riscv/tcg-target.c.inc | 34 +++++++--- tcg/s390x/tcg-target-has.h | 2 - tcg/s390x/tcg-target.c.inc | 75 +++++++++++++-------- tcg/sparc64/tcg-target-has.h | 2 - tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 108 ++++++++++++++++--------------- tcg/tcg.c | 8 +-- tcg/tci.c | 8 +-- tcg/tci/tcg-target-has.h | 2 - tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 17 ++++- 25 files changed, 365 insertions(+), 264 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index fa79cbc1f0..8c839d8949 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -15,7 +15,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 @@ -30,7 +29,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 00fca43840..3bd8231117 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1618,37 +1618,6 @@ static inline void tcg_out_mb(TCGContext *s, TCGArg a0) tcg_out32(s, sync[a0 & TCG_MO_ALL]); } -static void tcg_out_cltz(TCGContext *s, TCGType ext, TCGReg d, - TCGReg a0, TCGArg b, bool const_b, bool is_ctz) -{ - TCGReg a1 = a0; - if (is_ctz) { - a1 = TCG_REG_TMP0; - tcg_out_insn(s, 3507, RBIT, ext, a1, a0); - } - if (const_b && b == (ext ? 64 : 32)) { - tcg_out_insn(s, 3507, CLZ, ext, d, a1); - } else { - AArch64Insn sel = I3506_CSEL; - - tcg_out_cmp(s, ext, TCG_COND_NE, a0, 0, 1); - tcg_out_insn(s, 3507, CLZ, ext, TCG_REG_TMP0, a1); - - if (const_b) { - if (b == -1) { - b = TCG_REG_XZR; - sel = I3506_CSINV; - } else if (b == 0) { - b = TCG_REG_XZR; - } else { - tcg_out_movi(s, ext, d, b); - b = d; - } - } - tcg_out_insn_3506(s, sel, ext, d, TCG_REG_TMP0, b, TCG_COND_NE); - } -} - typedef struct { TCGReg base; TCGReg index; @@ -2121,6 +2090,45 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_cmp(s, type, TCG_COND_NE, a1, 0, true); + tcg_out_insn(s, 3507, CLZ, type, TCG_REG_TMP0, a1); + tcg_out_insn(s, 3506, CSEL, type, a0, TCG_REG_TMP0, a2, TCG_COND_NE); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 == (type == TCG_TYPE_I32 ? 32 : 64)) { + tcg_out_insn(s, 3507, CLZ, type, a0, a1); + return; + } + + tcg_out_cmp(s, type, TCG_COND_NE, a1, 0, true); + tcg_out_insn(s, 3507, CLZ, type, a0, a1); + + switch (a2) { + case -1: + tcg_out_insn(s, 3506, CSINV, type, a0, a0, TCG_REG_XZR, TCG_COND_NE); + break; + case 0: + tcg_out_insn(s, 3506, CSEL, type, a0, a0, TCG_REG_XZR, TCG_COND_NE); + break; + default: + tcg_out_movi(s, type, TCG_REG_TMP0, a2); + tcg_out_insn(s, 3506, CSEL, type, a0, a0, TCG_REG_TMP0, TCG_COND_NE); + break; + } +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_O1_I2(r, r, rAL), + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2460,13 +2468,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_clz_i64: - case INDEX_op_clz_i32: - tcg_out_cltz(s, ext, a0, a1, a2, c2, false); - break; case INDEX_op_ctz_i64: case INDEX_op_ctz_i32: - tcg_out_cltz(s, ext, a0, a1, a2, c2, true); + tcg_out_insn(s, 3507, RBIT, ext, TCG_REG_TMP0, a1); + if (c2) { + tgen_clzi(s, ext, a0, TCG_REG_TMP0, a2); + } else { + tgen_clz(s, ext, a0, TCG_REG_TMP0, a2); + } break; case INDEX_op_brcond_i32: @@ -3089,9 +3098,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_clz_i32: case INDEX_op_ctz_i32: - case INDEX_op_clz_i64: case INDEX_op_ctz_i64: return C_O1_I2(r, r, rAL); diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 12ffbcda2b..fceec2f0ca 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -26,7 +26,6 @@ extern bool use_neon_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 462f0ec08d..681eb5aba1 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1862,6 +1862,32 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0); + tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0); + tcg_out_mov_reg(s, COND_EQ, a0, a2); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 == 32) { + tcg_out_dat_reg(s, COND_AL, INSN_CLZ, a0, 0, a1, 0); + } else { + tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0); + tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0); + tcg_out_movi32(s, COND_EQ, a0, a2); + } +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_O1_I2(r, r, rIK), + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static TCGConstraintSetIndex cset_idiv(TCGType type, unsigned flags) { return use_idiv_instructions ? C_O1_I2(r, r, r) : C_NotImplemented; @@ -2196,23 +2222,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_ctz_i32: tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0); - a1 = TCG_REG_TMP; - goto do_clz; - - case INDEX_op_clz_i32: - a1 = args[1]; - do_clz: - a0 = args[0]; - a2 = args[2]; - c = const_args[2]; - if (c && a2 == 32) { - tcg_out_dat_reg(s, COND_AL, INSN_CLZ, a0, 0, a1, 0); - break; - } - tcg_out_dat_imm(s, COND_AL, ARITH_CMP, 0, a1, 0); - tcg_out_dat_reg(s, COND_NE, INSN_CLZ, a0, 0, a1, 0); - if (c || a0 != a2) { - tcg_out_dat_rIK(s, COND_EQ, ARITH_MOV, ARITH_MVN, a0, 0, a2, c); + if (const_args[2]) { + tgen_clzi(s, TCG_TYPE_I32, args[0], TCG_REG_TMP, args[2]); + } else { + tgen_clz(s, TCG_TYPE_I32, args[0], TCG_REG_TMP, args[2]); } break; diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index a7199463df..2277872ff3 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -28,7 +28,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 have_popcnt #define TCG_TARGET_HAS_extract2_i32 1 @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 have_popcnt #define TCG_TARGET_HAS_extract2_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index dd35bba57f..0edd4cbc07 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1869,32 +1869,6 @@ static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1, } } -static void tcg_out_clz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1, - TCGArg arg2, bool const_a2) -{ - if (have_lzcnt) { - tcg_out_modrm(s, OPC_LZCNT + rexw, dest, arg1); - if (const_a2) { - tcg_debug_assert(arg2 == (rexw ? 64 : 32)); - } else { - tcg_debug_assert(dest != arg2); - tcg_out_cmov(s, JCC_JB, rexw, dest, arg2); - } - } else { - tcg_debug_assert(!const_a2); - tcg_debug_assert(dest != arg1); - tcg_debug_assert(dest != arg2); - - /* Recall that the output of BSR is the index not the count. */ - tcg_out_modrm(s, OPC_BSR + rexw, dest, arg1); - tgen_arithi(s, ARITH_XOR + rexw, dest, rexw ? 63 : 31, 0); - - /* Since we have destroyed the flags from BSR, we have to re-test. */ - int jcc = tcg_out_cmp(s, TCG_COND_EQ, arg1, 0, 1, rexw); - tcg_out_cmov(s, jcc, rexw, dest, arg2); - } -} - static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) { intptr_t disp = tcg_pcrel_diff(s, dest) - 5; @@ -2633,6 +2607,45 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + int jcc; + + if (have_lzcnt) { + tcg_out_modrm(s, OPC_LZCNT + rexw, a0, a1); + jcc = JCC_JB; + } else { + /* Recall that the output of BSR is the index not the count. */ + tcg_out_modrm(s, OPC_BSR + rexw, a0, a1); + tgen_arithi(s, ARITH_XOR + rexw, a0, rexw ? 63 : 31, 0); + + /* Since we have destroyed the flags from BSR, we have to re-test. */ + jcc = tcg_out_cmp(s, TCG_COND_EQ, a1, 0, 1, rexw); + } + tcg_out_cmov(s, jcc, rexw, a0, a2); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_LZCNT + rexw, a0, a1); +} + +static TCGConstraintSetIndex cset_clz(TCGType type, unsigned flags) +{ + return have_lzcnt ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_clz, + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; @@ -3019,9 +3032,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(ctz): tcg_out_ctz(s, rexw, args[0], args[1], args[2], const_args[2]); break; - OP_32_64(clz): - tcg_out_clz(s, rexw, args[0], args[1], args[2], const_args[2]); - break; OP_32_64(ctpop): tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1); break; @@ -3907,10 +3917,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ctz_i64: return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: - return have_lzcnt ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, L); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 303134390a..2eba2132b8 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -30,7 +29,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_add2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 26cf982780..332ce6c86b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1328,6 +1328,33 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* a2 is constrained to exactly the type width. */ + if (type == TCG_TYPE_I32) { + tcg_out_opc_clz_w(s, a0, a1); + } else { + tcg_out_opc_clz_d(s, a0, a1); + } +} + +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_clzi(s, type, TCG_REG_TMP0, a1, /* ignored */ 0); + /* a0 = a1 ? REG_TMP0 : a2 */ + tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); + tcg_out_opc_masknez(s, a0, a2, a1); + tcg_out_opc_or(s, a0, a0, TCG_REG_TMP0); +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_O1_I2(r, r, rW), + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1754,13 +1781,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_revb_d(s, a0, a1); break; - case INDEX_op_clz_i32: - tcg_out_clzctz(s, OPC_CLZ_W, a0, a1, a2, c2, true); - break; - case INDEX_op_clz_i64: - tcg_out_clzctz(s, OPC_CLZ_D, a0, a1, a2, c2, false); - break; - case INDEX_op_ctz_i32: tcg_out_clzctz(s, OPC_CTZ_W, a0, a1, a2, c2, true); break; @@ -2398,8 +2418,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: return C_O1_I2(r, r, rW); diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 880eb084eb..c27ca7e543 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -60,7 +60,6 @@ extern bool use_mips32r2_instructions; /* optional instructions detected at runtime */ #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_clz_i32 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -70,7 +69,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_clz_i64 use_mips32r2_instructions #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #endif diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index fb9fe0c40e..5052d6481c 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1563,33 +1563,6 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) tcg_out32(s, sync[a0 & TCG_MO_ALL]); } -static void tcg_out_clz(TCGContext *s, MIPSInsn opcv2, MIPSInsn opcv6, - int width, TCGReg a0, TCGReg a1, TCGArg a2) -{ - if (use_mips32r6_instructions) { - if (a2 == width) { - tcg_out_opc_reg(s, opcv6, a0, a1, 0); - } else { - tcg_out_opc_reg(s, opcv6, TCG_TMP0, a1, 0); - tcg_out_movcond(s, TCG_COND_EQ, a0, a1, 0, a2, TCG_TMP0); - } - } else { - if (a2 == width) { - tcg_out_opc_reg(s, opcv2, a0, a1, a1); - } else if (a0 == a2) { - tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1); - tcg_out_opc_reg(s, OPC_MOVN, a0, TCG_TMP0, a1); - } else if (a0 != a1) { - tcg_out_opc_reg(s, opcv2, a0, a1, a1); - tcg_out_opc_reg(s, OPC_MOVZ, a0, a2, a1); - } else { - tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1); - tcg_out_opc_reg(s, OPC_MOVZ, TCG_TMP0, a2, a1); - tcg_out_mov(s, TCG_TYPE_REG, a0, TCG_TMP0); - } - } -} - static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) { TCGReg base = TCG_REG_ZERO; @@ -1712,6 +1685,55 @@ static const TCGOutOpBinary outop_andc = { .base.static_constraint = C_NotImplemented, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (use_mips32r6_instructions) { + MIPSInsn opcv6 = type == TCG_TYPE_I32 ? OPC_CLZ_R6 : OPC_DCLZ_R6; + tcg_out_opc_reg(s, opcv6, TCG_TMP0, a1, 0); + tcg_out_movcond(s, TCG_COND_EQ, a0, a1, 0, a2, TCG_TMP0); + } else { + MIPSInsn opcv2 = type == TCG_TYPE_I32 ? OPC_CLZ : OPC_DCLZ; + if (a0 == a2) { + tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1); + tcg_out_opc_reg(s, OPC_MOVN, a0, TCG_TMP0, a1); + } else if (a0 != a1) { + tcg_out_opc_reg(s, opcv2, a0, a1, a1); + tcg_out_opc_reg(s, OPC_MOVZ, a0, a2, a1); + } else { + tcg_out_opc_reg(s, opcv2, TCG_TMP0, a1, a1); + tcg_out_opc_reg(s, OPC_MOVZ, TCG_TMP0, a2, a1); + tcg_out_mov(s, type, a0, TCG_TMP0); + } + } +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 == 0) { + tgen_clz(s, type, a0, a1, TCG_REG_ZERO); + } else if (use_mips32r6_instructions) { + MIPSInsn opcv6 = type == TCG_TYPE_I32 ? OPC_CLZ_R6 : OPC_DCLZ_R6; + tcg_out_opc_reg(s, opcv6, a0, a1, 0); + } else { + MIPSInsn opcv2 = type == TCG_TYPE_I32 ? OPC_CLZ : OPC_DCLZ; + tcg_out_opc_reg(s, opcv2, a0, a1, a1); + } +} + +static TCGConstraintSetIndex cset_clz(TCGType type, unsigned flags) +{ + return use_mips32r2_instructions ? C_O1_I2(r, r, rzW) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_clz, + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2165,13 +2187,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_dsra(s, a0, a1, 32); break; - case INDEX_op_clz_i32: - tcg_out_clz(s, OPC_CLZ, OPC_CLZ_R6, 32, a0, a1, a2); - break; - case INDEX_op_clz_i64: - tcg_out_clz(s, OPC_DCLZ, OPC_DCLZ_R6, 64, a0, a1, a2); - break; - case INDEX_op_deposit_i32: tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]); break; @@ -2329,9 +2344,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: - return C_O1_I2(r, r, rzW); case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 71c02d88b9..cd7346011b 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -19,7 +19,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i32 0 @@ -35,7 +34,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 687b66af54..518cf1e9ef 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2954,6 +2954,26 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? CNTLZW : CNTLZD; + tcg_out_cntxz(s, type, insn, a0, a1, a2, false); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? CNTLZW : CNTLZD; + tcg_out_cntxz(s, type, insn, a0, a1, a2, true); +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_O1_I2(r, r, rZW), + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3350,10 +3370,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_clz_i32: - tcg_out_cntxz(s, TCG_TYPE_I32, CNTLZW, args[0], args[1], - args[2], const_args[2]); - break; case INDEX_op_ctz_i32: tcg_out_cntxz(s, TCG_TYPE_I32, CNTTZW, args[0], args[1], args[2], const_args[2]); @@ -3362,10 +3378,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0)); break; - case INDEX_op_clz_i64: - tcg_out_cntxz(s, TCG_TYPE_I64, CNTLZD, args[0], args[1], - args[2], const_args[2]); - break; case INDEX_op_ctz_i64: tcg_out_cntxz(s, TCG_TYPE_I64, CNTTZD, args[0], args[1], args[2], const_args[2]); @@ -4228,9 +4240,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_clz_i32: case INDEX_op_ctz_i32: - case INDEX_op_clz_i64: case INDEX_op_ctz_i64: return C_O1_I2(r, r, rZW); diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index c7745a6462..41e287130d 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_clz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -29,7 +28,6 @@ #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_clz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 4dd892d98d..77eef02db5 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1997,6 +1997,32 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_CLZW : OPC_CLZ; + tcg_out_cltz(s, type, insn, a0, a1, a2, false); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_CLZW : OPC_CLZ; + tcg_out_cltz(s, type, insn, a0, a1, a2, true); +} + +static TCGConstraintSetIndex cset_clzctz(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBB ? C_N1_I2(r, r, rM) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_clzctz, + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2398,12 +2424,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_CPOP, a0, a1, 0); break; - case INDEX_op_clz_i32: - tcg_out_cltz(s, TCG_TYPE_I32, OPC_CLZW, a0, a1, a2, c2); - break; - case INDEX_op_clz_i64: - tcg_out_cltz(s, TCG_TYPE_I64, OPC_CLZ, a0, a1, a2, c2); - break; case INDEX_op_ctz_i32: tcg_out_cltz(s, TCG_TYPE_I32, OPC_CTZW, a0, a1, a2, c2); break; @@ -2793,8 +2813,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: return C_N1_I2(r, r, rM); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index eaddf7005e..85a4f23e95 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -31,7 +31,6 @@ extern uint64_t s390_facilities[3]; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 @@ -46,7 +45,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 76180dabcb..adfe403bef 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1514,27 +1514,6 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, tgen_movcond_int(s, type, dest, v3, v3const, v4, cc, inv_cc); } -static void tgen_clz(TCGContext *s, TCGReg dest, TCGReg a1, - TCGArg a2, int a2const) -{ - /* Since this sets both R and R+1, we have no choice but to store the - result into R0, allowing R1 == TCG_TMP0 to be clobbered as well. */ - QEMU_BUILD_BUG_ON(TCG_TMP0 != TCG_REG_R1); - tcg_out_insn(s, RRE, FLOGR, TCG_REG_R0, a1); - - if (a2const && a2 == 64) { - tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0); - return; - } - - /* - * Conditions from FLOGR are: - * 2 -> one bit found - * 8 -> no one bit found - */ - tgen_movcond_int(s, TCG_TYPE_I64, dest, a2, a2const, TCG_REG_R0, 8, 2); -} - static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) { /* With MIE3, and bit 0 of m4 set, we get the complete result. */ @@ -2242,6 +2221,53 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz_int(TCGContext *s, TCGReg dest, TCGReg a1, + TCGArg a2, int a2const) +{ + /* + * Since this sets both R and R+1, we have no choice but to store the + * result into R0, allowing R1 == TCG_TMP0 to be clobbered as well. + */ + QEMU_BUILD_BUG_ON(TCG_TMP0 != TCG_REG_R1); + tcg_out_insn(s, RRE, FLOGR, TCG_REG_R0, a1); + + if (a2const && a2 == 64) { + tcg_out_mov(s, TCG_TYPE_I64, dest, TCG_REG_R0); + return; + } + + /* + * Conditions from FLOGR are: + * 2 -> one bit found + * 8 -> no one bit found + */ + tgen_movcond_int(s, TCG_TYPE_I64, dest, a2, a2const, TCG_REG_R0, 8, 2); +} + +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_clz_int(s, a0, a1, a2, false); +} + +static void tgen_clzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_clz_int(s, a0, a1, a2, true); +} + +static TCGConstraintSetIndex cset_clz(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_I64 ? C_O1_I2(r, r, rI) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_clz, + .out_rrr = tgen_clz, + .out_rri = tgen_clzi, +}; + static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; @@ -2884,10 +2910,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_sextract(s, args[0], args[1], args[2], args[3]); break; - case INDEX_op_clz_i64: - tgen_clz(s, args[0], args[1], args[2], const_args[2]); - break; - case INDEX_op_ctpop_i32: tgen_ctpop(s, TCG_TYPE_I32, args[0], args[1]); break; @@ -3387,9 +3409,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_clz_i64: - return C_O1_I2(r, r, rI); - case INDEX_op_brcond_i32: return C_O0_I2(r, ri); case INDEX_op_brcond_i64: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 1dd86c363d..21fa0f3663 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -16,7 +16,6 @@ extern bool use_vis3_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 -#define TCG_TARGET_HAS_clz_i32 0 #define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 @@ -31,7 +30,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 57b26ae33b..a4fb41764b 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1318,6 +1318,10 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divs_rJ(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGArg a2, bool c2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 7bfa55adb1..27d6ec7636 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_clz_i64 0 #define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 1989d8d12c..e1e57ff3f8 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -723,9 +723,9 @@ void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_clz_i32) { + if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_clz_i64) { + } else if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t1, arg1); @@ -748,9 +748,13 @@ void tcg_gen_clzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { + TCGv_i32 z, t; + if (TCG_TARGET_HAS_ctz_i32) { tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_ctz_i64) { + return; + } + if (TCG_TARGET_HAS_ctz_i64) { TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t1, arg1); @@ -759,29 +763,28 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_extrl_i64_i32(ret, t1); tcg_temp_free_i64(t1); tcg_temp_free_i64(t2); - } else if (TCG_TARGET_HAS_ctpop_i32 - || TCG_TARGET_HAS_ctpop_i64 - || TCG_TARGET_HAS_clz_i32 - || TCG_TARGET_HAS_clz_i64) { - TCGv_i32 z, t = tcg_temp_ebb_new_i32(); - - if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { - tcg_gen_subi_i32(t, arg1, 1); - tcg_gen_andc_i32(t, t, arg1); - tcg_gen_ctpop_i32(t, t); - } else { - /* Since all non-x86 hosts have clz(0) == 32, don't fight it. */ - tcg_gen_neg_i32(t, arg1); - tcg_gen_and_i32(t, t, arg1); - tcg_gen_clzi_i32(t, t, 32); - tcg_gen_xori_i32(t, t, 31); - } - z = tcg_constant_i32(0); - tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t); - tcg_temp_free_i32(t); + return; + } + if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { + t = tcg_temp_ebb_new_i32(); + tcg_gen_subi_i32(t, arg1, 1); + tcg_gen_andc_i32(t, t, arg1); + tcg_gen_ctpop_i32(t, t); + } else if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0) || + tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + t = tcg_temp_ebb_new_i32(); + tcg_gen_neg_i32(t, arg1); + tcg_gen_and_i32(t, t, arg1); + tcg_gen_clzi_i32(t, t, 32); + tcg_gen_xori_i32(t, t, 31); } else { gen_helper_ctz_i32(ret, arg1, arg2); + return; } + + z = tcg_constant_i32(0); + tcg_gen_movcond_i32(TCG_COND_EQ, ret, arg1, z, arg2, t); + tcg_temp_free_i32(t); } void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) @@ -800,7 +803,8 @@ void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_clz_i32) { + if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0) || + tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_sari_i32(t, arg, 31); tcg_gen_xor_i32(t, t, arg); @@ -2336,7 +2340,7 @@ void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_clz_i64) { + if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2); } else { gen_helper_clz_i64(ret, arg1, arg2); @@ -2346,8 +2350,8 @@ void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) { if (TCG_TARGET_REG_BITS == 32 - && TCG_TARGET_HAS_clz_i32 - && arg2 <= 0xffffffffu) { + && arg2 <= 0xffffffffu + && tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_clzi_i32(t, TCGV_LOW(arg1), arg2 - 32); tcg_gen_addi_i32(t, t, 32); @@ -2361,45 +2365,47 @@ void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { + TCGv_i64 z, t; + if (TCG_TARGET_HAS_ctz_i64) { tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); - } else if (TCG_TARGET_HAS_ctpop_i64 || TCG_TARGET_HAS_clz_i64) { - TCGv_i64 z, t = tcg_temp_ebb_new_i64(); - - if (TCG_TARGET_HAS_ctpop_i64) { - tcg_gen_subi_i64(t, arg1, 1); - tcg_gen_andc_i64(t, t, arg1); - tcg_gen_ctpop_i64(t, t); - } else { - /* Since all non-x86 hosts have clz(0) == 64, don't fight it. */ - tcg_gen_neg_i64(t, arg1); - tcg_gen_and_i64(t, t, arg1); - tcg_gen_clzi_i64(t, t, 64); - tcg_gen_xori_i64(t, t, 63); - } - z = tcg_constant_i64(0); - tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t); - tcg_temp_free_i64(t); - tcg_temp_free_i64(z); + return; + } + if (TCG_TARGET_HAS_ctpop_i64) { + t = tcg_temp_ebb_new_i64(); + tcg_gen_subi_i64(t, arg1, 1); + tcg_gen_andc_i64(t, t, arg1); + tcg_gen_ctpop_i64(t, t); + } else if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + t = tcg_temp_ebb_new_i64(); + tcg_gen_neg_i64(t, arg1); + tcg_gen_and_i64(t, t, arg1); + tcg_gen_clzi_i64(t, t, 64); + tcg_gen_xori_i64(t, t, 63); } else { gen_helper_ctz_i64(ret, arg1, arg2); + return; } + + z = tcg_constant_i64(0); + tcg_gen_movcond_i64(TCG_COND_EQ, ret, arg1, z, arg2, t); + tcg_temp_free_i64(t); } void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) { if (TCG_TARGET_REG_BITS == 32 - && TCG_TARGET_HAS_ctz_i32 - && arg2 <= 0xffffffffu) { + && arg2 <= 0xffffffffu + && tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0)) { TCGv_i32 t32 = tcg_temp_ebb_new_i32(); tcg_gen_ctzi_i32(t32, TCGV_HIGH(arg1), arg2 - 32); tcg_gen_addi_i32(t32, t32, 32); tcg_gen_ctz_i32(TCGV_LOW(ret), TCGV_LOW(arg1), t32); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); tcg_temp_free_i32(t32); - } else if (!TCG_TARGET_HAS_ctz_i64 - && TCG_TARGET_HAS_ctpop_i64 - && arg2 == 64) { + } else if (arg2 == 64 + && !tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0) + && TCG_TARGET_HAS_ctpop_i64) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_subi_i64(t, arg1, 1); @@ -2413,7 +2419,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (TCG_TARGET_HAS_clz_i64 || TCG_TARGET_HAS_clz_i32) { + if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_sari_i64(t, arg, 63); tcg_gen_xor_i64(t, t, arg); diff --git a/tcg/tcg.c b/tcg/tcg.c index 182f19e5f0..e04d3adcec 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1026,6 +1026,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_clz_i32, TCGOutOpBinary, outop_clz), + OUTOP(INDEX_op_clz_i64, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -2288,8 +2290,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: return TCG_TARGET_HAS_bswap32_i32; - case INDEX_op_clz_i32: - return TCG_TARGET_HAS_clz_i32; case INDEX_op_ctz_i32: return TCG_TARGET_HAS_ctz_i32; case INDEX_op_ctpop_i32: @@ -2333,8 +2333,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: return TCG_TARGET_HAS_bswap64_i64; - case INDEX_op_clz_i64: - return TCG_TARGET_HAS_clz_i64; case INDEX_op_ctz_i64: return TCG_TARGET_HAS_ctz_i64; case INDEX_op_ctpop_i64: @@ -5404,6 +5402,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_clz_i32: + case INDEX_op_clz_i64: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: diff --git a/tcg/tci.c b/tcg/tci.c index b1ee14e65f..11b11ce642 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -594,13 +594,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint32_t)regs[r1] % (uint32_t)regs[r2]; break; -#if TCG_TARGET_HAS_clz_i32 - case INDEX_op_clz_i32: + case INDEX_op_tci_clz32: tci_args_rrr(insn, &r0, &r1, &r2); tmp32 = regs[r1]; regs[r0] = tmp32 ? clz32(tmp32) : regs[r2]; break; -#endif #if TCG_TARGET_HAS_ctz_i32 case INDEX_op_ctz_i32: tci_args_rrr(insn, &r0, &r1, &r2); @@ -735,12 +733,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint64_t)regs[r1] % (uint64_t)regs[r2]; break; -#if TCG_TARGET_HAS_clz_i64 case INDEX_op_clz_i64: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? clz64(regs[r1]) : regs[r2]; break; -#endif #if TCG_TARGET_HAS_ctz_i64 case INDEX_op_ctz_i64: tci_args_rrr(insn, &r0, &r1, &r2); @@ -1073,10 +1069,10 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_clz_i32: case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: + case INDEX_op_tci_clz32: case INDEX_op_tci_divs32: case INDEX_op_tci_divu32: case INDEX_op_tci_rems32: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 04d341a8d2..ae1f724702 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -10,7 +10,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_clz_i32 1 #define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 @@ -23,7 +22,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_clz_i64 1 #define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index cff215490a..04774ca9c4 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -2,6 +2,7 @@ /* These opcodes for use between the tci generator and interpreter. */ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) +DEF(tci_clz32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 0d15547c9f..ee7e6f15eb 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -83,8 +83,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: return C_O1_I2(r, r, r); @@ -630,6 +628,20 @@ static const TCGOutOpBinary outop_andc = { .out_rrr = tgen_andc, }; +static void tgen_clz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_clz32 + : INDEX_op_clz_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_clz = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_clz, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -921,7 +933,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(clz) /* Optional (TCG_TARGET_HAS_clz_*). */ CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */ tcg_out_op_rrr(s, opc, args[0], args[1], args[2]); break; From 5a5bb0a5a0b879c8f110c6a9bde9146181ef840c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 16:12:46 -0800 Subject: [PATCH 0422/2760] tcg: Merge INDEX_op_clz_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 10 +++++----- tcg/tcg-op.c | 22 ++++++++++------------ tcg/tcg.c | 6 ++---- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 22 insertions(+), 27 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index c3a6499d01..22f0432988 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -358,7 +358,7 @@ Logical - | *t0* = *t1* | ~\ *t2* - * - clz_i32/i64 *t0*, *t1*, *t2* + * - clz *t0*, *t1*, *t2* - | *t0* = *t1* ? clz(*t1*) : *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 25fd93eb28..ad1d193ef4 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -42,6 +42,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) +DEF(clz, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) @@ -95,7 +96,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(clz_i32, 1, 2, 0, 0) DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) @@ -130,7 +130,6 @@ DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) -DEF(clz_i64, 1, 2, 0, 0) DEF(ctz_i64, 1, 2, 0, 0) DEF(ctpop_i64, 1, 1, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 97a566a617..d8d0e728aa 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -503,10 +503,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, case INDEX_op_nor_vec: return ~(x | y); - case INDEX_op_clz_i32: - return (uint32_t)x ? clz32(x) : y; - - case INDEX_op_clz_i64: + case INDEX_op_clz: + if (type == TCG_TYPE_I32) { + return (uint32_t)x ? clz32(x) : y; + } return x ? clz64(x) : y; case INDEX_op_ctz_i32: @@ -2898,7 +2898,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_bswap64_i64: done = fold_bswap(&ctx, op); break; - CASE_OP_32_64(clz): + case INDEX_op_clz: CASE_OP_32_64(ctz): done = fold_count_zeros(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index e1e57ff3f8..76e9efc655 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -723,9 +723,9 @@ void tcg_gen_orc_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_clz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_clz_i32, ret, arg1, arg2); - } else if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_clz, ret, arg1, arg2); + } else if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_I64, 0)) { TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t1, arg1); @@ -770,8 +770,7 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_gen_subi_i32(t, arg1, 1); tcg_gen_andc_i32(t, t, arg1); tcg_gen_ctpop_i32(t, t); - } else if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0) || - tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_REG, 0)) { t = tcg_temp_ebb_new_i32(); tcg_gen_neg_i32(t, arg1); tcg_gen_and_i32(t, t, arg1); @@ -803,8 +802,7 @@ void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0) || - tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_REG, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_sari_i32(t, arg, 31); tcg_gen_xor_i32(t, t, arg); @@ -2340,8 +2338,8 @@ void tcg_gen_orc_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_clz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_clz_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_clz, ret, arg1, arg2); } else { gen_helper_clz_i64(ret, arg1, arg2); } @@ -2351,7 +2349,7 @@ void tcg_gen_clzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) { if (TCG_TARGET_REG_BITS == 32 && arg2 <= 0xffffffffu - && tcg_op_supported(INDEX_op_clz_i32, TCG_TYPE_I32, 0)) { + && tcg_op_supported(INDEX_op_clz, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_clzi_i32(t, TCGV_LOW(arg1), arg2 - 32); tcg_gen_addi_i32(t, t, 32); @@ -2376,7 +2374,7 @@ void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_subi_i64(t, arg1, 1); tcg_gen_andc_i64(t, t, arg1); tcg_gen_ctpop_i64(t, t); - } else if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + } else if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_I64, 0)) { t = tcg_temp_ebb_new_i64(); tcg_gen_neg_i64(t, arg1); tcg_gen_and_i64(t, t, arg1); @@ -2419,7 +2417,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) { - if (tcg_op_supported(INDEX_op_clz_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_clz, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_sari_i64(t, arg, 63); tcg_gen_xor_i64(t, t, arg); diff --git a/tcg/tcg.c b/tcg/tcg.c index e04d3adcec..71b0721fb5 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1026,8 +1026,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_clz_i32, TCGOutOpBinary, outop_clz), - OUTOP(INDEX_op_clz_i64, TCGOutOpBinary, outop_clz), + OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -5402,8 +5401,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: - case INDEX_op_clz_i32: - case INDEX_op_clz_i64: + case INDEX_op_clz: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: diff --git a/tcg/tci.c b/tcg/tci.c index 11b11ce642..7c2f2a524b 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -733,7 +733,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = (uint64_t)regs[r1] % (uint64_t)regs[r2]; break; - case INDEX_op_clz_i64: + case INDEX_op_clz: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? clz64(regs[r1]) : regs[r2]; break; @@ -1052,6 +1052,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: + case INDEX_op_clz: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: @@ -1069,7 +1070,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_clz_i64: case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: case INDEX_op_tci_clz32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ee7e6f15eb..0fd1f5510a 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -633,7 +633,7 @@ static void tgen_clz(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_clz32 - : INDEX_op_clz_i64); + : INDEX_op_clz); tcg_out_op_rrr(s, opc, a0, a1, a2); } From e3fcde59c92fb421789890c145d5fffdd3d1672d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 17:02:13 -0800 Subject: [PATCH 0423/2760] tcg: Convert ctz to TCGOutOpBinary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 34 ++++++++++-------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 39 ++++++++++++++------- tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 60 +++++++++++++++++++------------- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 60 ++++++++++++++------------------ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 4 +++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 39 ++++++++++++++------- tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 32 +++++++++++------ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 4 +++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 +++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 9 ++--- tcg/tcg.c | 8 ++--- tcg/tci.c | 8 ++--- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 20 +++++++---- 25 files changed, 193 insertions(+), 149 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 8c839d8949..478d59676e 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -15,7 +15,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 @@ -29,7 +28,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 3bd8231117..8441c5f4bf 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2129,6 +2129,26 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3507, RBIT, type, TCG_REG_TMP0, a1); + tgen_clz(s, type, a0, TCG_REG_TMP0, a2); +} + +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_insn(s, 3507, RBIT, type, TCG_REG_TMP0, a1); + tgen_clzi(s, type, a0, TCG_REG_TMP0, a2); +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_O1_I2(r, r, rAL), + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2468,16 +2488,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_ctz_i64: - case INDEX_op_ctz_i32: - tcg_out_insn(s, 3507, RBIT, ext, TCG_REG_TMP0, a1); - if (c2) { - tgen_clzi(s, ext, a0, TCG_REG_TMP0, a2); - } else { - tgen_clz(s, ext, a0, TCG_REG_TMP0, a2); - } - break; - case INDEX_op_brcond_i32: a1 = (int32_t)a1; /* FALLTHRU */ @@ -3098,10 +3108,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rC); - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: - return C_O1_I2(r, r, rAL); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(r, rC); diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index fceec2f0ca..1485a52c21 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -26,7 +26,6 @@ extern bool use_neon_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 681eb5aba1..c05f21c82c 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1888,6 +1888,32 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, a1, 0); + tgen_clz(s, TCG_TYPE_I32, a0, TCG_REG_TMP, a2); +} + +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, a1, 0); + tgen_clzi(s, TCG_TYPE_I32, a0, TCG_REG_TMP, a2); +} + +static TCGConstraintSetIndex cset_ctz(TCGType type, unsigned flags) +{ + return use_armv7_instructions ? C_O1_I2(r, r, rIK) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctz, + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static TCGConstraintSetIndex cset_idiv(TCGType type, unsigned flags) { return use_idiv_instructions ? C_O1_I2(r, r, r) : C_NotImplemented; @@ -2220,15 +2246,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - case INDEX_op_ctz_i32: - tcg_out_dat_reg(s, COND_AL, INSN_RBIT, TCG_REG_TMP, 0, args[1], 0); - if (const_args[2]) { - tgen_clzi(s, TCG_TYPE_I32, args[0], TCG_REG_TMP, args[2]); - } else { - tgen_clz(s, TCG_TYPE_I32, args[0], TCG_REG_TMP, args[2]); - } - break; - case INDEX_op_brcond_i32: c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[3])); @@ -2351,10 +2368,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); - case INDEX_op_clz_i32: - case INDEX_op_ctz_i32: - return C_O1_I2(r, r, rIK); - case INDEX_op_mulu2_i32: case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 2277872ff3..b8a0a5c619 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -28,7 +28,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 have_popcnt #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 @@ -43,7 +42,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 have_popcnt #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 0edd4cbc07..f7d0b93af0 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1851,24 +1851,6 @@ static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond, tcg_out_cmov(s, jcc, rexw, dest, v1); } -static void tcg_out_ctz(TCGContext *s, int rexw, TCGReg dest, TCGReg arg1, - TCGArg arg2, bool const_a2) -{ - if (have_bmi1) { - tcg_out_modrm(s, OPC_TZCNT + rexw, dest, arg1); - if (const_a2) { - tcg_debug_assert(arg2 == (rexw ? 64 : 32)); - } else { - tcg_debug_assert(dest != arg2); - tcg_out_cmov(s, JCC_JB, rexw, dest, arg2); - } - } else { - tcg_debug_assert(dest != arg2); - tcg_out_modrm(s, OPC_BSF + rexw, dest, arg1); - tcg_out_cmov(s, JCC_JE, rexw, dest, arg2); - } -} - static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) { intptr_t disp = tcg_pcrel_diff(s, dest) - 5; @@ -2646,6 +2628,41 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + int jcc; + + if (have_bmi1) { + tcg_out_modrm(s, OPC_TZCNT + rexw, a0, a1); + jcc = JCC_JB; + } else { + tcg_out_modrm(s, OPC_BSF + rexw, a0, a1); + jcc = JCC_JE; + } + tcg_out_cmov(s, jcc, rexw, a0, a2); +} + +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_TZCNT + rexw, a0, a1); +} + +static TCGConstraintSetIndex cset_ctz(TCGType type, unsigned flags) +{ + return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctz, + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; @@ -3029,9 +3046,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(ctz): - tcg_out_ctz(s, rexw, args[0], args[1], args[2], const_args[2]); - break; OP_32_64(ctpop): tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1); break; @@ -3913,10 +3927,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub2_i64: return C_N1_O1_I4(r, r, 0, 1, re, re); - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: - return have_bmi1 ? C_N1_I2(r, r, rW) : C_N1_I2(r, r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, L); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 2eba2132b8..f87d05efc6 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -29,7 +28,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 332ce6c86b..14f3ed1f5c 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -546,28 +546,6 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg ret, TCGReg arg) tcg_out_ext32s(s, ret, arg); } -static void tcg_out_clzctz(TCGContext *s, LoongArchInsn opc, - TCGReg a0, TCGReg a1, TCGReg a2, - bool c2, bool is_32bit) -{ - if (c2) { - /* - * Fast path: semantics already satisfied due to constraint and - * insn behavior, single instruction is enough. - */ - tcg_debug_assert(a2 == (is_32bit ? 32 : 64)); - /* all clz/ctz insns belong to DJ-format */ - tcg_out32(s, encode_dj_insn(opc, a0, a1)); - return; - } - - tcg_out32(s, encode_dj_insn(opc, TCG_REG_TMP0, a1)); - /* a0 = a1 ? REG_TMP0 : a2 */ - tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); - tcg_out_opc_masknez(s, a0, a2, a1); - tcg_out_opc_or(s, a0, TCG_REG_TMP0, a0); -} - #define SETCOND_INV TCG_TARGET_NB_REGS #define SETCOND_NEZ (SETCOND_INV << 1) #define SETCOND_FLAGS (SETCOND_INV | SETCOND_NEZ) @@ -1355,6 +1333,33 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* a2 is constrained to exactly the type width. */ + if (type == TCG_TYPE_I32) { + tcg_out_opc_ctz_w(s, a0, a1); + } else { + tcg_out_opc_ctz_d(s, a0, a1); + } +} + +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_ctzi(s, type, TCG_REG_TMP0, a1, /* ignored */ 0); + /* a0 = a1 ? REG_TMP0 : a2 */ + tcg_out_opc_maskeqz(s, TCG_REG_TMP0, TCG_REG_TMP0, a1); + tcg_out_opc_masknez(s, a0, a2, a1); + tcg_out_opc_or(s, a0, a0, TCG_REG_TMP0); +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_O1_I2(r, r, rW), + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1781,13 +1786,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_revb_d(s, a0, a1); break; - case INDEX_op_ctz_i32: - tcg_out_clzctz(s, OPC_CTZ_W, a0, a1, a2, c2, true); - break; - case INDEX_op_ctz_i64: - tcg_out_clzctz(s, OPC_CTZ_D, a0, a1, a2, c2, false); - break; - case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], a0, a1, a2, c2); @@ -2418,10 +2416,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: - return C_O1_I2(r, r, rW); - case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: /* Must deposit into the same register as input */ diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index c27ca7e543..ca33c9b745 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -60,7 +60,6 @@ extern bool use_mips32r2_instructions; /* optional instructions detected at runtime */ #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -69,7 +68,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #endif diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 5052d6481c..e8720b63ed 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1734,6 +1734,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index cd7346011b..2b381b99a2 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -19,7 +19,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 @@ -34,7 +33,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctz_i64 have_isa_3_00 #define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 518cf1e9ef..2cdabcf610 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2974,6 +2974,32 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? CNTTZW : CNTTZD; + tcg_out_cntxz(s, type, insn, a0, a1, a2, false); +} + +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + uint32_t insn = type == TCG_TYPE_I32 ? CNTTZW : CNTTZD; + tcg_out_cntxz(s, type, insn, a0, a1, a2, true); +} + +static TCGConstraintSetIndex cset_ctz(TCGType type, unsigned flags) +{ + return have_isa_3_00 ? C_O1_I2(r, r, rZW) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctz, + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static void tgen_eqv(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3370,18 +3396,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_ctz_i32: - tcg_out_cntxz(s, TCG_TYPE_I32, CNTTZW, args[0], args[1], - args[2], const_args[2]); - break; case INDEX_op_ctpop_i32: tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0)); break; - - case INDEX_op_ctz_i64: - tcg_out_cntxz(s, TCG_TYPE_I64, CNTTZD, args[0], args[1], - args[2], const_args[2]); - break; case INDEX_op_ctpop_i64: tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); break; @@ -4240,10 +4257,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: - return C_O1_I2(r, r, rZW); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(r, rC); diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 41e287130d..385a6736c0 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_ctz_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_ctz_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_ctpop_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 77eef02db5..1ceb1aeb1c 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2023,6 +2023,27 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_CTZW : OPC_CTZ; + tcg_out_cltz(s, type, insn, a0, a1, a2, false); +} + +static void tgen_ctzi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_CTZW : OPC_CTZ; + tcg_out_cltz(s, type, insn, a0, a1, a2, true); +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_clzctz, + .out_rrr = tgen_ctz, + .out_rri = tgen_ctzi, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2424,13 +2445,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_CPOP, a0, a1, 0); break; - case INDEX_op_ctz_i32: - tcg_out_cltz(s, TCG_TYPE_I32, OPC_CTZW, a0, a1, a2, c2); - break; - case INDEX_op_ctz_i64: - tcg_out_cltz(s, TCG_TYPE_I64, OPC_CTZ, a0, a1, a2, c2); - break; - case INDEX_op_add2_i32: tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], const_args[4], const_args[5], false, true); @@ -2813,10 +2827,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i64: return C_O1_I2(r, r, rI); - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: - return C_N1_I2(r, r, rM); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(rz, rz); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 85a4f23e95..0794394fea 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -31,7 +31,6 @@ extern uint64_t s390_facilities[3]; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 @@ -45,7 +44,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index adfe403bef..374136ed14 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2268,6 +2268,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_divs = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 21fa0f3663..56262640ff 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -16,7 +16,6 @@ extern bool use_vis3_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 -#define TCG_TARGET_HAS_ctz_i32 0 #define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 @@ -30,7 +29,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index a4fb41764b..a9257b8b93 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1322,6 +1322,10 @@ static const TCGOutOpBinary outop_clz = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_divs_rJ(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGArg a2, bool c2) { diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 27d6ec7636..6bba845944 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_ctz_i64 0 #define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 76e9efc655..b117a59f05 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -750,11 +750,11 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { TCGv_i32 z, t; - if (TCG_TARGET_HAS_ctz_i32) { + if (tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); return; } - if (TCG_TARGET_HAS_ctz_i64) { + if (tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t1, arg1); @@ -788,7 +788,8 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) { - if (!TCG_TARGET_HAS_ctz_i32 && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { + if (!tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0) + && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_subi_i32(t, arg1, 1); @@ -2365,7 +2366,7 @@ void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { TCGv_i64 z, t; - if (TCG_TARGET_HAS_ctz_i64) { + if (tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); return; } diff --git a/tcg/tcg.c b/tcg/tcg.c index 71b0721fb5..3f610e3f83 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1027,6 +1027,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), + OUTOP(INDEX_op_ctz_i32, TCGOutOpBinary, outop_ctz), + OUTOP(INDEX_op_ctz_i64, TCGOutOpBinary, outop_ctz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -2289,8 +2291,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: return TCG_TARGET_HAS_bswap32_i32; - case INDEX_op_ctz_i32: - return TCG_TARGET_HAS_ctz_i32; case INDEX_op_ctpop_i32: return TCG_TARGET_HAS_ctpop_i32; @@ -2332,8 +2332,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: return TCG_TARGET_HAS_bswap64_i64; - case INDEX_op_ctz_i64: - return TCG_TARGET_HAS_ctz_i64; case INDEX_op_ctpop_i64: return TCG_TARGET_HAS_ctpop_i64; case INDEX_op_add2_i64: @@ -5402,6 +5400,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_clz: + case INDEX_op_ctz_i32: + case INDEX_op_ctz_i64: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: diff --git a/tcg/tci.c b/tcg/tci.c index 7c2f2a524b..b505944b10 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -599,13 +599,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tmp32 = regs[r1]; regs[r0] = tmp32 ? clz32(tmp32) : regs[r2]; break; -#if TCG_TARGET_HAS_ctz_i32 - case INDEX_op_ctz_i32: + case INDEX_op_tci_ctz32: tci_args_rrr(insn, &r0, &r1, &r2); tmp32 = regs[r1]; regs[r0] = tmp32 ? ctz32(tmp32) : regs[r2]; break; -#endif #if TCG_TARGET_HAS_ctpop_i32 case INDEX_op_ctpop_i32: tci_args_rr(insn, &r0, &r1); @@ -737,12 +735,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? clz64(regs[r1]) : regs[r2]; break; -#if TCG_TARGET_HAS_ctz_i64 case INDEX_op_ctz_i64: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; break; -#endif #if TCG_TARGET_HAS_ctpop_i64 case INDEX_op_ctpop_i64: tci_args_rr(insn, &r0, &r1); @@ -1070,8 +1066,8 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_ctz_i32: case INDEX_op_ctz_i64: + case INDEX_op_tci_ctz32: case INDEX_op_tci_clz32: case INDEX_op_tci_divs32: case INDEX_op_tci_divu32: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index ae1f724702..daa6db4799 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -10,7 +10,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_ctz_i32 1 #define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 @@ -22,7 +21,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_ctz_i64 1 #define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 04774ca9c4..2bb346f4c8 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -3,6 +3,7 @@ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_clz32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_ctz32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 0fd1f5510a..47bdec5f44 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -83,8 +83,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i64: case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: return C_O1_I2(r, r, r); case INDEX_op_brcond_i32: @@ -642,6 +640,20 @@ static const TCGOutOpBinary outop_clz = { .out_rrr = tgen_clz, }; +static void tgen_ctz(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_ctz32 + : INDEX_op_ctz_i64); + tcg_out_op_rrr(s, opc, a0, a1, a2); +} + +static const TCGOutOpBinary outop_ctz = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_ctz, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -933,10 +945,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(ctz) /* Optional (TCG_TARGET_HAS_ctz_*). */ - tcg_out_op_rrr(s, opc, args[0], args[1], args[2]); - break; - CASE_32_64(deposit) tcg_out_op_rrrbb(s, opc, args[0], args[1], args[2], args[3], args[4]); break; From c96447d838d67db509cde1a190132e14b8672055 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 17:07:01 -0800 Subject: [PATCH 0424/2760] tcg: Merge INDEX_op_ctz_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 10 +++++----- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 20 insertions(+), 23 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 22f0432988..92344b8786 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -362,7 +362,7 @@ Logical - | *t0* = *t1* ? clz(*t1*) : *t2* - * - ctz_i32/i64 *t0*, *t1*, *t2* + * - ctz *t0*, *t1*, *t2* - | *t0* = *t1* ? ctz(*t1*) : *t2* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index ad1d193ef4..4dfd8708a5 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) +DEF(ctz, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) @@ -96,7 +97,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(ctz_i32, 1, 2, 0, 0) DEF(ctpop_i32, 1, 1, 0, 0) DEF(setcond_i64, 1, 2, 1, 0) @@ -130,7 +130,6 @@ DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) -DEF(ctz_i64, 1, 2, 0, 0) DEF(ctpop_i64, 1, 1, 0, 0) DEF(add2_i64, 2, 4, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index d8d0e728aa..af4e76e81b 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -509,10 +509,10 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return x ? clz64(x) : y; - case INDEX_op_ctz_i32: - return (uint32_t)x ? ctz32(x) : y; - - case INDEX_op_ctz_i64: + case INDEX_op_ctz: + if (type == TCG_TYPE_I32) { + return (uint32_t)x ? ctz32(x) : y; + } return x ? ctz64(x) : y; case INDEX_op_ctpop_i32: @@ -2899,7 +2899,7 @@ void tcg_optimize(TCGContext *s) done = fold_bswap(&ctx, op); break; case INDEX_op_clz: - CASE_OP_32_64(ctz): + case INDEX_op_ctz: done = fold_count_zeros(&ctx, op); break; CASE_OP_32_64(ctpop): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b117a59f05..7bf7de1213 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -750,11 +750,11 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) { TCGv_i32 z, t; - if (tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3_i32(INDEX_op_ctz_i32, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0)) { + tcg_gen_op3_i32(INDEX_op_ctz, ret, arg1, arg2); return; } - if (tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I64, 0)) { TCGv_i64 t1 = tcg_temp_ebb_new_i64(); TCGv_i64 t2 = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t1, arg1); @@ -788,7 +788,7 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) { - if (!tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0) + if (!tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0) && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i32 t = tcg_temp_ebb_new_i32(); @@ -2366,8 +2366,8 @@ void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) { TCGv_i64 z, t; - if (tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3_i64(INDEX_op_ctz_i64, ret, arg1, arg2); + if (tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I64, 0)) { + tcg_gen_op3_i64(INDEX_op_ctz, ret, arg1, arg2); return; } if (TCG_TARGET_HAS_ctpop_i64) { @@ -2395,7 +2395,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) { if (TCG_TARGET_REG_BITS == 32 && arg2 <= 0xffffffffu - && tcg_op_supported(INDEX_op_ctz_i32, TCG_TYPE_I32, 0)) { + && tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0)) { TCGv_i32 t32 = tcg_temp_ebb_new_i32(); tcg_gen_ctzi_i32(t32, TCGV_HIGH(arg1), arg2 - 32); tcg_gen_addi_i32(t32, t32, 32); @@ -2403,7 +2403,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) tcg_gen_movi_i32(TCGV_HIGH(ret), 0); tcg_temp_free_i32(t32); } else if (arg2 == 64 - && !tcg_op_supported(INDEX_op_ctz_i64, TCG_TYPE_I64, 0) + && !tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I64, 0) && TCG_TARGET_HAS_ctpop_i64) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i64 t = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 3f610e3f83..18b28a670e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1027,8 +1027,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), - OUTOP(INDEX_op_ctz_i32, TCGOutOpBinary, outop_ctz), - OUTOP(INDEX_op_ctz_i64, TCGOutOpBinary, outop_ctz), + OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -5400,8 +5399,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_clz: - case INDEX_op_ctz_i32: - case INDEX_op_ctz_i64: + case INDEX_op_ctz: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: diff --git a/tcg/tci.c b/tcg/tci.c index b505944b10..550f2014a8 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -735,7 +735,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? clz64(regs[r1]) : regs[r2]; break; - case INDEX_op_ctz_i64: + case INDEX_op_ctz: tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; break; @@ -1049,6 +1049,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_and: case INDEX_op_andc: case INDEX_op_clz: + case INDEX_op_ctz: case INDEX_op_divs: case INDEX_op_divu: case INDEX_op_eqv: @@ -1066,7 +1067,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shr: case INDEX_op_sub: case INDEX_op_xor: - case INDEX_op_ctz_i64: case INDEX_op_tci_ctz32: case INDEX_op_tci_clz32: case INDEX_op_tci_divs32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 47bdec5f44..d8d45e2c4b 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -645,7 +645,7 @@ static void tgen_ctz(TCGContext *s, TCGType type, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_ctz32 - : INDEX_op_ctz_i64); + : INDEX_op_ctz); tcg_out_op_rrr(s, opc, a0, a1, a2); } From f8fa1dae3db5493617ff42e8ccfd797058df243e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 17:56:01 -0800 Subject: [PATCH 0425/2760] tcg: Convert ctpop to TCGOutOpUnary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 - tcg/aarch64/tcg-target.c.inc | 4 ++ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 4 ++ tcg/i386/tcg-target-has.h | 2 - tcg/i386/tcg-target.c.inc | 23 ++++++++--- tcg/loongarch64/tcg-target-has.h | 2 - tcg/loongarch64/tcg-target.c.inc | 4 ++ tcg/mips/tcg-target-has.h | 2 - tcg/mips/tcg-target.c.inc | 4 ++ tcg/ppc/tcg-target-has.h | 2 - tcg/ppc/tcg-target.c.inc | 26 ++++++++----- tcg/riscv/tcg-target-has.h | 2 - tcg/riscv/tcg-target.c.inc | 26 ++++++++----- tcg/s390x/tcg-target-has.h | 2 - tcg/s390x/tcg-target.c.inc | 66 +++++++++++++++----------------- tcg/sparc64/tcg-target-has.h | 2 - tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 37 ++++++++++-------- tcg/tcg.c | 8 ++-- tcg/tci.c | 19 ++++----- tcg/tci/tcg-target-has.h | 2 - tcg/tci/tcg-target.c.inc | 19 +++++++-- 24 files changed, 151 insertions(+), 113 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 478d59676e..4f1840f44e 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -15,7 +15,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 8441c5f4bf..0f01fa8c20 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2129,6 +2129,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 1485a52c21..1cf3911613 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -26,7 +26,6 @@ extern bool use_neon_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index c05f21c82c..e109c65965 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1888,6 +1888,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index b8a0a5c619..a71f8c7370 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -28,7 +28,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 have_popcnt #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -42,7 +41,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctpop_i64 have_popcnt #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index f7d0b93af0..318a30ebe0 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2628,6 +2628,23 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1); +} + +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + return have_popcnt ? C_O1_I1(r, r) : C_NotImplemented; +} + +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, +}; + static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3046,10 +3063,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(ctpop): - tcg_out_modrm(s, OPC_POPCNT + rexw, a0, a1); - break; - OP_32_64(brcond): tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1], arg_label(args[3]), 0); @@ -3893,8 +3906,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: return C_O1_I1(r, r); case INDEX_op_extract2_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index f87d05efc6..33a1cf2326 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 14f3ed1f5c..4ef7c6b945 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1333,6 +1333,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_ctzi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, tcg_target_long a2) { diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index ca33c9b745..470aa16452 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -60,7 +60,6 @@ extern bool use_mips32r2_instructions; /* optional instructions detected at runtime */ #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -68,7 +67,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_ctpop_i64 0 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e8720b63ed..a94c965046 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1734,6 +1734,10 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_ctz = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 2b381b99a2..f071435d98 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -19,7 +19,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 @@ -33,7 +32,6 @@ #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctpop_i64 have_isa_2_06 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 2cdabcf610..ab56c623c7 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2974,6 +2974,23 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + uint32_t insn = type == TCG_TYPE_I32 ? CNTPOPW : CNTPOPD; + tcg_out32(s, insn | SAB(a1, a0, 0)); +} + +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + return have_isa_2_06 ? C_O1_I1(r, r) : C_NotImplemented; +} + +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, +}; + static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3396,13 +3413,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_ctpop_i32: - tcg_out32(s, CNTPOPW | SAB(args[1], args[0], 0)); - break; - case INDEX_op_ctpop_i64: - tcg_out32(s, CNTPOPD | SAB(args[1], args[0], 0)); - break; - case INDEX_op_brcond_i32: tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], arg_label(args[3]), TCG_TYPE_I32); @@ -4226,7 +4236,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_ctpop_i32: case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: @@ -4238,7 +4247,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_ctpop_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_bswap16_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 385a6736c0..a3b634570b 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -18,7 +18,6 @@ #define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_ctpop_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_negsetcond_i64 1 @@ -27,7 +26,6 @@ #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) -#define TCG_TARGET_HAS_ctpop_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 1ceb1aeb1c..a5cd18c99e 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2023,6 +2023,23 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + RISCVInsn insn = type == TCG_TYPE_I32 ? OPC_CPOPW : OPC_CPOP; + tcg_out_opc_imm(s, insn, a0, a1, 0); +} + +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBB ? C_O1_I1(r, r) : C_NotImplemented; +} + +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, +}; + static void tgen_ctz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2438,13 +2455,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_ctpop_i32: - tcg_out_opc_imm(s, OPC_CPOPW, a0, a1, 0); - break; - case INDEX_op_ctpop_i64: - tcg_out_opc_imm(s, OPC_CPOP, a0, a1, 0); - break; - case INDEX_op_add2_i32: tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], const_args[4], const_args[5], false, true); @@ -2808,8 +2818,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 0794394fea..87f117ce58 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -31,7 +31,6 @@ extern uint64_t s390_facilities[3]; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -44,7 +43,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 -#define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 374136ed14..71adb0964d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1514,32 +1514,6 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, tgen_movcond_int(s, type, dest, v3, v3const, v4, cc, inv_cc); } -static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) -{ - /* With MIE3, and bit 0 of m4 set, we get the complete result. */ - if (HAVE_FACILITY(MISC_INSN_EXT3)) { - if (type == TCG_TYPE_I32) { - tcg_out_ext32u(s, dest, src); - src = dest; - } - tcg_out_insn(s, RRFc, POPCNT, dest, src, 8); - return; - } - - /* Without MIE3, each byte gets the count of bits for the byte. */ - tcg_out_insn(s, RRFc, POPCNT, dest, src, 0); - - /* Multiply to sum each byte at the top of the word. */ - if (type == TCG_TYPE_I32) { - tcg_out_insn(s, RIL, MSFI, dest, 0x01010101); - tcg_out_sh32(s, RS_SRL, dest, TCG_REG_NONE, 24); - } else { - tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0x0101010101010101ull); - tcg_out_insn(s, RRE, MSGR, dest, TCG_TMP0); - tcg_out_sh64(s, RSY_SRLG, dest, dest, TCG_REG_NONE, 56); - } -} - static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src, int ofs, int len, int z) { @@ -2268,6 +2242,37 @@ static const TCGOutOpBinary outop_clz = { .out_rri = tgen_clzi, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg dest, TCGReg src) +{ + /* With MIE3, and bit 0 of m4 set, we get the complete result. */ + if (HAVE_FACILITY(MISC_INSN_EXT3)) { + if (type == TCG_TYPE_I32) { + tcg_out_ext32u(s, dest, src); + src = dest; + } + tcg_out_insn(s, RRFc, POPCNT, dest, src, 8); + return; + } + + /* Without MIE3, each byte gets the count of bits for the byte. */ + tcg_out_insn(s, RRFc, POPCNT, dest, src, 0); + + /* Multiply to sum each byte at the top of the word. */ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, MSFI, dest, 0x01010101); + tcg_out_sh32(s, RS_SRL, dest, TCG_REG_NONE, 24); + } else { + tcg_out_movi(s, TCG_TYPE_I64, TCG_TMP0, 0x0101010101010101ull); + tcg_out_insn(s, RRE, MSGR, dest, TCG_TMP0); + tcg_out_sh64(s, RSY_SRLG, dest, dest, TCG_REG_NONE, 56); + } +} + +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_ctpop, +}; + static const TCGOutOpBinary outop_ctz = { .base.static_constraint = C_NotImplemented, }; @@ -2914,13 +2919,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_sextract(s, args[0], args[1], args[2], args[3]); break; - case INDEX_op_ctpop_i32: - tgen_ctpop(s, TCG_TYPE_I32, args[0], args[1]); - break; - case INDEX_op_ctpop_i64: - tgen_ctpop(s, TCG_TYPE_I64, args[0], args[1]); - break; - case INDEX_op_mb: /* The host memory model is quite strong, we simply need to serialize the instruction stream. */ @@ -3429,8 +3427,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i32: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 56262640ff..40e54e1543 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -16,7 +16,6 @@ extern bool use_vis3_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 -#define TCG_TARGET_HAS_ctpop_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -29,7 +28,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index a9257b8b93..43ca23f593 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1322,6 +1322,10 @@ static const TCGOutOpBinary outop_clz = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_NotImplemented, +}; + static const TCGOutOpBinary outop_ctz = { .base.static_constraint = C_NotImplemented, }; diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 6bba845944..97f4e83303 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 -#define TCG_TARGET_HAS_ctpop_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7bf7de1213..db0e79059b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -765,7 +765,8 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_temp_free_i64(t2); return; } - if (TCG_TARGET_HAS_ctpop_i32 || TCG_TARGET_HAS_ctpop_i64) { + if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0) || + tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { t = tcg_temp_ebb_new_i32(); tcg_gen_subi_i32(t, arg1, 1); tcg_gen_andc_i32(t, t, arg1); @@ -788,8 +789,9 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) { - if (!tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0) - && TCG_TARGET_HAS_ctpop_i32 && arg2 == 32) { + if (arg2 == 32 + && !tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0) + && tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_subi_i32(t, arg1, 1); @@ -817,9 +819,9 @@ void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) { - if (TCG_TARGET_HAS_ctpop_i32) { + if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1); - } else if (TCG_TARGET_HAS_ctpop_i64) { + } else if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t, arg1); tcg_gen_ctpop_i64(t, t); @@ -2370,7 +2372,7 @@ void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_ctz, ret, arg1, arg2); return; } - if (TCG_TARGET_HAS_ctpop_i64) { + if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { t = tcg_temp_ebb_new_i64(); tcg_gen_subi_i64(t, arg1, 1); tcg_gen_andc_i64(t, t, arg1); @@ -2404,7 +2406,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) tcg_temp_free_i32(t32); } else if (arg2 == 64 && !tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I64, 0) - && TCG_TARGET_HAS_ctpop_i64) { + && tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_subi_i64(t, arg1, 1); @@ -2432,16 +2434,21 @@ void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) { - if (TCG_TARGET_HAS_ctpop_i64) { - tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); - } else if (TCG_TARGET_REG_BITS == 32 && TCG_TARGET_HAS_ctpop_i32) { - tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); - tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); - tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); - tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + if (TCG_TARGET_REG_BITS == 64) { + if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); + return; + } } else { - gen_helper_ctpop_i64(ret, arg1); + if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { + tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); + tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); + tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); + tcg_gen_movi_i32(TCGV_HIGH(ret), 0); + return; + } } + gen_helper_ctpop_i64(ret, arg1); } void tcg_gen_rotl_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) diff --git a/tcg/tcg.c b/tcg/tcg.c index 18b28a670e..94997d8610 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1027,6 +1027,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), + OUTOP(INDEX_op_ctpop_i32, TCGOutOpUnary, outop_ctpop), + OUTOP(INDEX_op_ctpop_i64, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), @@ -2290,8 +2292,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: return TCG_TARGET_HAS_bswap32_i32; - case INDEX_op_ctpop_i32: - return TCG_TARGET_HAS_ctpop_i32; case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: @@ -2331,8 +2331,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: return TCG_TARGET_HAS_bswap64_i64; - case INDEX_op_ctpop_i64: - return TCG_TARGET_HAS_ctpop_i64; case INDEX_op_add2_i64: return TCG_TARGET_HAS_add2_i64; case INDEX_op_sub2_i64: @@ -5449,6 +5447,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_ctpop_i32: + case INDEX_op_ctpop_i64: case INDEX_op_neg: case INDEX_op_not: { diff --git a/tcg/tci.c b/tcg/tci.c index 550f2014a8..8bcf48b251 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -26,6 +26,8 @@ #include +#define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS) + /* * Enable TCI assertions only when debugging TCG (and without NDEBUG defined). * Without assertions, the interpreter runs much faster. @@ -575,6 +577,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = ~regs[r1]; break; + case INDEX_op_ctpop_i32: + case INDEX_op_ctpop_i64: + tci_args_rr(insn, &r0, &r1); + regs[r0] = ctpop_tr(regs[r1]); + break; /* Arithmetic operations (32 bit). */ @@ -604,12 +611,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tmp32 = regs[r1]; regs[r0] = tmp32 ? ctz32(tmp32) : regs[r2]; break; -#if TCG_TARGET_HAS_ctpop_i32 - case INDEX_op_ctpop_i32: - tci_args_rr(insn, &r0, &r1); - regs[r0] = ctpop32(regs[r1]); - break; -#endif /* Shift/rotate operations. */ @@ -739,12 +740,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; break; -#if TCG_TARGET_HAS_ctpop_i64 - case INDEX_op_ctpop_i64: - tci_args_rr(insn, &r0, &r1); - regs[r0] = ctpop64(regs[r1]); - break; -#endif #if TCG_TARGET_HAS_mulu2_i64 case INDEX_op_mulu2_i64: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index daa6db4799..774fb149fc 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -10,7 +10,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_ctpop_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 #define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -21,7 +20,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_ctpop_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_muls2_i64 1 #define TCG_TARGET_HAS_add2_i32 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d8d45e2c4b..a931369a80 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -66,8 +66,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: @@ -883,6 +881,22 @@ static const TCGOutOpBinary outop_xor = { .out_rrr = tgen_xor, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_op_rr(s, glue(INDEX_op_ctpop_i,TCG_TARGET_REG_BITS), a0, a1); +} + +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_REG ? C_O1_I1(r, r) : C_NotImplemented; +} + +static const TCGOutOpUnary outop_ctpop = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); @@ -961,7 +975,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rl(s, opc, TCG_REG_TMP, arg_label(args[3])); break; - CASE_32_64(ctpop) /* Optional (TCG_TARGET_HAS_ctpop_*). */ case INDEX_op_bswap32_i32: /* Optional (TCG_TARGET_HAS_bswap32_i32). */ case INDEX_op_bswap64_i64: /* Optional (TCG_TARGET_HAS_bswap64_i64). */ tcg_out_op_rr(s, opc, args[0], args[1]); From 97218ae918b1504a63623130f3dc8f4b423b5f1b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 18:37:43 -0800 Subject: [PATCH 0426/2760] tcg: Merge INDEX_op_ctpop_{i32,i64} Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 6 +++--- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 9 +++------ tcg/tcg-op.c | 21 ++++++++++----------- tcg/tcg.c | 6 ++---- tcg/tci.c | 6 ++---- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 22 insertions(+), 31 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 92344b8786..fb7764e3c0 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -366,12 +366,12 @@ Logical - | *t0* = *t1* ? ctz(*t1*) : *t2* - * - ctpop_i32/i64 *t0*, *t1* + * - ctpop *t0*, *t1* - | *t0* = number of bits set in *t1* | - | With *ctpop* short for "count population", matching - | the function name used in ``include/qemu/host-utils.h``. + | The name *ctpop* is short for "count population", and matches + the function name used in ``include/qemu/host-utils.h``. Shifts/Rotates diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 4dfd8708a5..f4ccde074b 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) +DEF(ctpop, 1, 1, 0, TCG_OPF_INT) DEF(ctz, 1, 2, 0, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(divs2, 2, 3, 0, TCG_OPF_INT) @@ -97,7 +98,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(ctpop_i32, 1, 1, 0, 0) DEF(setcond_i64, 1, 2, 1, 0) DEF(negsetcond_i64, 1, 2, 1, 0) @@ -130,7 +130,6 @@ DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) -DEF(ctpop_i64, 1, 1, 0, 0) DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index af4e76e81b..bf625f770c 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -515,11 +515,8 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, } return x ? ctz64(x) : y; - case INDEX_op_ctpop_i32: - return ctpop32(x); - - case INDEX_op_ctpop_i64: - return ctpop64(x); + case INDEX_op_ctpop: + return type == TCG_TYPE_I32 ? ctpop32(x) : ctpop64(x); CASE_OP_32_64(bswap16): x = bswap16(x); @@ -2902,7 +2899,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_ctz: done = fold_count_zeros(&ctx, op); break; - CASE_OP_32_64(ctpop): + case INDEX_op_ctpop: done = fold_ctpop(&ctx, op); break; CASE_OP_32_64(deposit): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index db0e79059b..0eeec47b83 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -765,8 +765,7 @@ void tcg_gen_ctz_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2) tcg_temp_free_i64(t2); return; } - if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0) || - tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_REG, 0)) { t = tcg_temp_ebb_new_i32(); tcg_gen_subi_i32(t, arg1, 1); tcg_gen_andc_i32(t, t, arg1); @@ -791,7 +790,7 @@ void tcg_gen_ctzi_i32(TCGv_i32 ret, TCGv_i32 arg1, uint32_t arg2) { if (arg2 == 32 && !tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I32, 0) - && tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { + && tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_REG, 0)) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_subi_i32(t, arg1, 1); @@ -819,9 +818,9 @@ void tcg_gen_clrsb_i32(TCGv_i32 ret, TCGv_i32 arg) void tcg_gen_ctpop_i32(TCGv_i32 ret, TCGv_i32 arg1) { - if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op2_i32(INDEX_op_ctpop_i32, ret, arg1); - } else if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I32, 0)) { + tcg_gen_op2_i32(INDEX_op_ctpop, ret, arg1); + } else if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_extu_i32_i64(t, arg1); tcg_gen_ctpop_i64(t, t); @@ -2372,7 +2371,7 @@ void tcg_gen_ctz_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_ctz, ret, arg1, arg2); return; } - if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I64, 0)) { t = tcg_temp_ebb_new_i64(); tcg_gen_subi_i64(t, arg1, 1); tcg_gen_andc_i64(t, t, arg1); @@ -2406,7 +2405,7 @@ void tcg_gen_ctzi_i64(TCGv_i64 ret, TCGv_i64 arg1, uint64_t arg2) tcg_temp_free_i32(t32); } else if (arg2 == 64 && !tcg_op_supported(INDEX_op_ctz, TCG_TYPE_I64, 0) - && tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { + && tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I64, 0)) { /* This equivalence has the advantage of not requiring a fixup. */ TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_subi_i64(t, arg1, 1); @@ -2435,12 +2434,12 @@ void tcg_gen_clrsb_i64(TCGv_i64 ret, TCGv_i64 arg) void tcg_gen_ctpop_i64(TCGv_i64 ret, TCGv_i64 arg1) { if (TCG_TARGET_REG_BITS == 64) { - if (tcg_op_supported(INDEX_op_ctpop_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op2_i64(INDEX_op_ctpop_i64, ret, arg1); + if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I64, 0)) { + tcg_gen_op2_i64(INDEX_op_ctpop, ret, arg1); return; } } else { - if (tcg_op_supported(INDEX_op_ctpop_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_ctpop, TCG_TYPE_I32, 0)) { tcg_gen_ctpop_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1)); tcg_gen_ctpop_i32(TCGV_LOW(ret), TCGV_LOW(arg1)); tcg_gen_add_i32(TCGV_LOW(ret), TCGV_LOW(ret), TCGV_HIGH(ret)); diff --git a/tcg/tcg.c b/tcg/tcg.c index 94997d8610..5b6af803b2 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1027,8 +1027,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), - OUTOP(INDEX_op_ctpop_i32, TCGOutOpUnary, outop_ctpop), - OUTOP(INDEX_op_ctpop_i64, TCGOutOpUnary, outop_ctpop), + OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), @@ -5447,8 +5446,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: + case INDEX_op_ctpop: case INDEX_op_neg: case INDEX_op_not: { diff --git a/tcg/tci.c b/tcg/tci.c index 8bcf48b251..d58a94ff28 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -577,8 +577,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = ~regs[r1]; break; - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: + case INDEX_op_ctpop: tci_args_rr(insn, &r0, &r1); regs[r0] = ctpop_tr(regs[r1]); break; @@ -1023,6 +1022,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), s2); break; + case INDEX_op_ctpop: case INDEX_op_mov: case INDEX_op_neg: case INDEX_op_not: @@ -1033,8 +1033,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: - case INDEX_op_ctpop_i32: - case INDEX_op_ctpop_i64: tci_args_rr(insn, &r0, &r1); info->fprintf_func(info->stream, "%-12s %s, %s", op_name, str_r(r0), str_r(r1)); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index a931369a80..1d696a087e 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -883,7 +883,7 @@ static const TCGOutOpBinary outop_xor = { static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { - tcg_out_op_rr(s, glue(INDEX_op_ctpop_i,TCG_TARGET_REG_BITS), a0, a1); + tcg_out_op_rr(s, INDEX_op_ctpop, a0, a1); } static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) From 5641afdf9b496933596fd0bd5fa9cad0033405d4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 8 Jan 2025 21:52:03 -0800 Subject: [PATCH 0427/2760] tcg: Convert muls2 to TCGOutOpMul2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 4 ++++ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 25 +++++++++++++------------ tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 17 ++++++++++++----- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 4 ++++ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 28 ++++++++++++++++++++-------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 4 ++++ tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 4 ++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 27 ++++++++++++++++++++------- tcg/sparc64/tcg-target-con-set.h | 1 + tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 29 ++++++++++++++++++++++++----- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 26 ++++++++++++++++++++++---- tcg/tci.c | 23 ++++++++++------------- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 21 ++++++++++++++++++--- 25 files changed, 158 insertions(+), 79 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 4f1840f44e..c351db223d 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 -#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -32,7 +31,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 0f01fa8c20..0996c6234b 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2205,6 +2205,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_NotImplemented, +}; + static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) { return type == TCG_TYPE_I64 ? C_O1_I2(r, r, r) : C_NotImplemented; diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 1cf3911613..e1f19ffbc9 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -29,7 +29,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 -#define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index e109c65965..8c0bc78be3 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -929,14 +929,6 @@ static void tcg_out_umull32(TCGContext *s, ARMCond cond, TCGReg rd0, (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); } -static void tcg_out_smull32(TCGContext *s, ARMCond cond, TCGReg rd0, - TCGReg rd1, TCGReg rn, TCGReg rm) -{ - /* smull */ - tcg_out32(s, (cond << 28) | 0x00c00090 | - (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); -} - static void tcg_out_ext8s(TCGContext *s, TCGType t, TCGReg rd, TCGReg rn) { /* sxtb */ @@ -1973,6 +1965,19 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg rd0, TCGReg rd1, TCGReg rn, TCGReg rm) +{ + /* smull */ + tcg_out32(s, (COND_AL << 28) | 0x00c00090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_O2_I2(r, r, r, r), + .out_rrrr = tgen_muls2, +}; + static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; @@ -2246,9 +2251,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_mulu2_i32: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); break; - case INDEX_op_muls2_i32: - tcg_out_smull32(s, COND_AL, args[0], args[1], args[2], args[3]); - break; case INDEX_op_brcond_i32: c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); @@ -2373,7 +2375,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O1_I2(r, r, rIN); case INDEX_op_mulu2_i32: - case INDEX_op_muls2_i32: return C_O2_I2(r, r, r, r); case INDEX_op_brcond_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index a71f8c7370..d63b3a3a89 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -33,7 +33,6 @@ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 -#define TCG_TARGET_HAS_muls2_i32 1 #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ @@ -46,7 +45,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 -#define TCG_TARGET_HAS_muls2_i64 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else #define TCG_TARGET_HAS_qemu_st8_i32 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 318a30ebe0..43d63cab5c 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2743,6 +2743,18 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, a3); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_O2_I2(a, d, a, r), + .out_rrrr = tgen_muls2, +}; + static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; @@ -3136,9 +3148,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, OP_32_64(mulu2): tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]); break; - OP_32_64(muls2): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_IMUL, args[3]); - break; OP_32_64(add2): if (const_args[4]) { tgen_arithi(s, ARITH_ADD + rexw, a0, args[4], 1); @@ -3928,8 +3937,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: return C_O2_I2(a, d, a, r); case INDEX_op_add2_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 33a1cf2326..491ebf0d06 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_mulu2_i32 0 -#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -30,7 +29,6 @@ #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 4ef7c6b945..95a0614e6e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1421,6 +1421,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_mulsh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 470aa16452..fd0b674402 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -40,7 +40,6 @@ extern bool use_mips32r2_instructions; /* optional instructions */ #define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_muls2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 @@ -52,7 +51,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) -#define TCG_TARGET_HAS_muls2_i64 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index a94c965046..a1f9efb18b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1823,6 +1823,26 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MULT : OPC_DMULT; + tcg_out_opc_reg(s, insn, 0, a2, a3); + tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); + tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0); +} + +static TCGConstraintSetIndex cset_mul2(TCGType type, unsigned flags) +{ + return use_mips32r6_instructions ? C_NotImplemented : C_O2_I2(r, r, r, r); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_muls2, +}; + static void tgen_mulsh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2161,15 +2181,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_muls2_i32: - i1 = OPC_MULT; - goto do_hilo2; case INDEX_op_mulu2_i32: i1 = OPC_MULTU; goto do_hilo2; - case INDEX_op_muls2_i64: - i1 = OPC_DMULT; - goto do_hilo2; case INDEX_op_mulu2_i64: i1 = OPC_DMULTU; do_hilo2: @@ -2347,9 +2361,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rz); - case INDEX_op_muls2_i32: case INDEX_op_mulu2_i32: - case INDEX_op_muls2_i64: case INDEX_op_mulu2_i64: return C_O2_I2(r, r, r, r); diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index f071435d98..e711aa0731 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -22,7 +22,6 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 -#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -37,7 +36,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index ab56c623c7..d4e34e3e7d 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3079,6 +3079,10 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_mulsh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index a3b634570b..7e260da61e 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -15,7 +15,6 @@ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 -#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -29,7 +28,6 @@ #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index a5cd18c99e..316621b285 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2117,6 +2117,10 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_NotImplemented, +}; + static TCGConstraintSetIndex cset_mulh(TCGType type, unsigned flags) { return type == TCG_TYPE_I32 ? C_NotImplemented : C_O1_I2(r, r, r); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 87f117ce58..52a76fc0b5 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -36,7 +36,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 0 -#define TCG_TARGET_HAS_muls2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -48,7 +47,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 1 -#define TCG_TARGET_HAS_muls2_i64 HAVE_FACILITY(MISC_INSN_EXT2) #define TCG_TARGET_HAS_qemu_ldst_i128 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 71adb0964d..71f0eb40f8 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2391,6 +2391,26 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_debug_assert((a1 & 1) == 0); + tcg_debug_assert(a0 == a1 + 1); + tcg_out_insn(s, RRFa, MGRK, a1, a2, a3); +} + +static TCGConstraintSetIndex cset_muls2(TCGType type, unsigned flags) +{ + return (type == TCG_TYPE_I64 && HAVE_FACILITY(MISC_INSN_EXT2) + ? C_O2_I2(o, m, r, r) : C_NotImplemented); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_muls2, + .out_rrrr = tgen_muls2, +}; + static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; @@ -2846,11 +2866,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_debug_assert(args[0] == args[1] + 1); tcg_out_insn(s, RRE, MLGR, args[1], args[3]); break; - case INDEX_op_muls2_i64: - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RRFa, MGRK, args[1], args[2], args[3]); - break; case INDEX_op_add2_i64: if (const_args[4]) { @@ -3451,8 +3466,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulu2_i64: return C_O2_I2(o, m, 0, r); - case INDEX_op_muls2_i64: - return C_O2_I2(o, m, r, r); case INDEX_op_add2_i32: case INDEX_op_sub2_i32: diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index d90ba11443..d2ea184fa2 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -17,5 +17,6 @@ C_O1_I2(r, r, r) C_O1_I2(r, r, rJ) C_O1_I2(r, rz, rJ) C_O1_I4(r, rz, rJ, rI, 0) +C_O2_I2(r, r, r, r) C_O2_I2(r, r, rz, rJ) C_O2_I4(r, r, rz, rz, rJ, rJ) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 40e54e1543..dea0941cac 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -21,7 +21,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 -#define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 @@ -33,7 +32,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 43ca23f593..be2072c027 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1429,6 +1429,30 @@ static const TCGOutOpBinary outop_mul = { .out_rri = tgen_muli, }; +/* + * The 32-bit multiply insns produce a full 64-bit result. + * Supporting 32-bit mul[us]2 opcodes avoids sign/zero-extensions + * before the actual multiply; we only need extract the high part + * into the separate operand. + */ +static TCGConstraintSetIndex cset_mul2(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_I32 ? C_O2_I2(r, r, r, r) : C_NotImplemented; +} + +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_out_arith(s, a0, a2, a3, ARITH_SMUL); + tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_muls2, +}; + static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; @@ -1696,10 +1720,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; case INDEX_op_mulu2_i32: c = ARITH_UMUL; - goto do_mul2; - case INDEX_op_muls2_i32: - c = ARITH_SMUL; - do_mul2: /* The 32-bit multiply insns produce a full 64-bit result. */ tcg_out_arithc(s, a0, a2, args[3], const_args[3], c); tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); @@ -1828,7 +1848,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub2_i64: return C_O2_I4(r, r, rz, rz, rJ, rJ); case INDEX_op_mulu2_i32: - case INDEX_op_muls2_i32: return C_O2_I2(r, r, rz, rJ); default: diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 97f4e83303..ac387b2544 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_mulu2_i64 0 -#define TCG_TARGET_HAS_muls2_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 0eeec47b83..8a0846a8d2 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1162,7 +1162,7 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_muls2_i32) { + if (tcg_op_supported(INDEX_op_muls2_i32, TCG_TYPE_I32, 0)) { tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); @@ -2880,7 +2880,7 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_muls2_i64) { + if (tcg_op_supported(INDEX_op_muls2_i64, TCG_TYPE_I64, 0)) { tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 5b6af803b2..b1efc44725 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -992,6 +992,12 @@ typedef struct TCGOutOpDivRem { TCGReg a0, TCGReg a1, TCGReg a4); } TCGOutOpDivRem; +typedef struct TCGOutOpMul2 { + TCGOutOp base; + void (*out_rrrr)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3); +} TCGOutOpMul2; + typedef struct TCGOutOpUnary { TCGOutOp base; void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); @@ -1035,6 +1041,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), + OUTOP(INDEX_op_muls2_i32, TCGOutOpMul2, outop_muls2), + OUTOP(INDEX_op_muls2_i64, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), @@ -2285,8 +2293,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_sub2_i32; case INDEX_op_mulu2_i32: return TCG_TARGET_HAS_mulu2_i32; - case INDEX_op_muls2_i32: - return TCG_TARGET_HAS_muls2_i32; case INDEX_op_bswap16_i32: return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: @@ -2336,8 +2342,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_sub2_i64; case INDEX_op_mulu2_i64: return TCG_TARGET_HAS_mulu2_i64; - case INDEX_op_muls2_i64: - return TCG_TARGET_HAS_muls2_i64; case INDEX_op_mov_vec: case INDEX_op_dup_vec: @@ -5473,6 +5477,20 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_muls2_i32: + case INDEX_op_muls2_i64: + { + const TCGOutOpMul2 *out = + container_of(all_outop[op->opc], TCGOutOpMul2, base); + + tcg_debug_assert(!const_args[2]); + tcg_debug_assert(!const_args[3]); + out->out_rrrr(s, type, new_args[0], new_args[1], + new_args[2], new_args[3]); + } + break; + + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci.c b/tcg/tci.c index d58a94ff28..51cbb5760a 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -581,6 +581,16 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = ctpop_tr(regs[r1]); break; + case INDEX_op_muls2_i32: + case INDEX_op_muls2_i64: + tci_args_rrrr(insn, &r0, &r1, &r2, &r3); +#if TCG_TARGET_REG_BITS == 32 + tmp64 = (int64_t)(int32_t)regs[r2] * (int32_t)regs[r3]; + tci_write_reg64(regs, r1, r0, tmp64); +#else + muls64(®s[r0], ®s[r1], regs[r2], regs[r3]); +#endif + break; /* Arithmetic operations (32 bit). */ @@ -675,13 +685,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, tmp64); break; #endif -#if TCG_TARGET_HAS_muls2_i32 - case INDEX_op_muls2_i32: - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - tmp64 = (int64_t)(int32_t)regs[r2] * (int32_t)regs[r3]; - tci_write_reg64(regs, r1, r0, tmp64); - break; -#endif #if TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 CASE_32_64(bswap16) tci_args_rr(insn, &r0, &r1); @@ -745,12 +748,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, mulu64(®s[r0], ®s[r1], regs[r2], regs[r3]); break; #endif -#if TCG_TARGET_HAS_muls2_i64 - case INDEX_op_muls2_i64: - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - muls64(®s[r0], ®s[r1], regs[r2], regs[r3]); - break; -#endif #if TCG_TARGET_HAS_add2_i64 case INDEX_op_add2_i64: tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 774fb149fc..a3d04b0ee2 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -11,7 +11,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 0 -#define TCG_TARGET_HAS_muls2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -21,7 +20,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_negsetcond_i64 0 -#define TCG_TARGET_HAS_muls2_i64 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_mulu2_i32 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1d696a087e..f568d4edb9 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -100,8 +100,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: return C_O2_I2(r, r, r, r); case INDEX_op_movcond_i32: @@ -710,6 +708,24 @@ static const TCGOutOpBinary outop_mul = { .out_rrr = tgen_mul, }; +static TCGConstraintSetIndex cset_mul2(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_REG ? C_O2_I2(r, r, r, r) : C_NotImplemented; +} + +static void tgen_muls2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_out_op_rrrr(s, glue(INDEX_op_muls2_i,TCG_TARGET_REG_BITS), + a0, a1, a2, a3); +} + +static const TCGOutOpMul2 outop_muls2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_muls2, +}; + static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; @@ -1009,7 +1025,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, #endif CASE_32_64(mulu2) - CASE_32_64(muls2) tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], args[3]); break; From bfe964809bf6ce951b2e674929d7b730c754e298 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 07:24:32 -0800 Subject: [PATCH 0428/2760] tcg: Merge INDEX_op_muls2_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 17 +++++++++-------- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 9 +++------ tcg/tci.c | 6 ++---- tcg/tci/tcg-target.c.inc | 3 +-- 7 files changed, 21 insertions(+), 27 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index fb7764e3c0..0394767291 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -604,7 +604,7 @@ Multiword arithmetic support - | Similar to mul, except two unsigned inputs *t1* and *t2* yielding the full double-word product *t0*. The latter is returned in two single-word outputs. - * - muls2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* + * - muls2 *t0_low*, *t0_high*, *t1*, *t2* - | Similar to mulu2, except the two inputs *t1* and *t2* are signed. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index f4ccde074b..a45b22ca1a 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -51,6 +51,7 @@ DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) +DEF(muls2, 2, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) DEF(muluh, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) @@ -92,7 +93,6 @@ DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) DEF(mulu2_i32, 2, 2, 0, 0) -DEF(muls2_i32, 2, 2, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) @@ -134,7 +134,6 @@ DEF(bswap64_i64, 1, 1, 1, 0) DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) DEF(mulu2_i64, 2, 2, 0, 0) -DEF(muls2_i64, 2, 2, 0, 0) #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) diff --git a/tcg/optimize.c b/tcg/optimize.c index bf625f770c..756f681e88 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2074,16 +2074,17 @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op) h = (int32_t)(l >> 32); l = (int32_t)l; break; - case INDEX_op_muls2_i32: - l = (int64_t)(int32_t)a * (int32_t)b; - h = l >> 32; - l = (int32_t)l; - break; case INDEX_op_mulu2_i64: mulu64(&l, &h, a, b); break; - case INDEX_op_muls2_i64: - muls64(&l, &h, a, b); + case INDEX_op_muls2: + if (ctx->type == TCG_TYPE_I32) { + l = (int64_t)(int32_t)a * (int32_t)b; + h = l >> 32; + l = (int32_t)l; + } else { + muls64(&l, &h, a, b); + } break; default: g_assert_not_reached(); @@ -2973,7 +2974,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_muluh: done = fold_mul_highpart(&ctx, op); break; - CASE_OP_32_64(muls2): + case INDEX_op_muls2: CASE_OP_32_64(mulu2): done = fold_multiply2(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 8a0846a8d2..0f48484dfe 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1162,8 +1162,8 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_muls2_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op4_i32(INDEX_op_muls2_i32, rl, rh, arg1, arg2); + if (tcg_op_supported(INDEX_op_muls2, TCG_TYPE_I32, 0)) { + tcg_gen_op4_i32(INDEX_op_muls2, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); @@ -2880,8 +2880,8 @@ void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_muls2_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op4_i64(INDEX_op_muls2_i64, rl, rh, arg1, arg2); + if (tcg_op_supported(INDEX_op_muls2, TCG_TYPE_I64, 0)) { + tcg_gen_op4_i64(INDEX_op_muls2, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_mulsh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); diff --git a/tcg/tcg.c b/tcg/tcg.c index b1efc44725..5b22c75d2e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1041,8 +1041,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), - OUTOP(INDEX_op_muls2_i32, TCGOutOpMul2, outop_muls2), - OUTOP(INDEX_op_muls2_i64, TCGOutOpMul2, outop_muls2), + OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), @@ -4008,8 +4007,7 @@ liveness_pass_1(TCGContext *s) } goto do_not_remove; - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: + case INDEX_op_muls2: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh; goto do_mul2; @@ -5477,8 +5475,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: + case INDEX_op_muls2: { const TCGOutOpMul2 *out = container_of(all_outop[op->opc], TCGOutOpMul2, base); diff --git a/tcg/tci.c b/tcg/tci.c index 51cbb5760a..708ded34c7 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -581,8 +581,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = ctpop_tr(regs[r1]); break; - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: + case INDEX_op_muls2: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); #if TCG_TARGET_REG_BITS == 32 tmp64 = (int64_t)(int32_t)regs[r2] * (int32_t)regs[r3]; @@ -1095,10 +1094,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) str_r(r3), str_r(r4), str_c(c)); break; + case INDEX_op_muls2: case INDEX_op_mulu2_i32: case INDEX_op_mulu2_i64: - case INDEX_op_muls2_i32: - case INDEX_op_muls2_i64: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s", op_name, str_r(r0), str_r(r1), diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index f568d4edb9..aa3ce929b4 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -716,8 +716,7 @@ static TCGConstraintSetIndex cset_mul2(TCGType type, unsigned flags) static void tgen_muls2(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) { - tcg_out_op_rrrr(s, glue(INDEX_op_muls2_i,TCG_TARGET_REG_BITS), - a0, a1, a2, a3); + tcg_out_op_rrrr(s, INDEX_op_muls2, a0, a1, a2, a3); } static const TCGOutOpMul2 outop_muls2 = { From d37bc370fcad08698e4b6de99184361a2cf71ac0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 08:59:52 -0800 Subject: [PATCH 0429/2760] tcg: Convert mulu2 to TCGOutOpMul2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 4 ++++ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 27 +++++++++++++-------------- tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 19 ++++++++++++------- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 4 ++++ tcg/mips/tcg-target-has.h | 2 -- tcg/mips/tcg-target.c.inc | 29 +++++++++++++++-------------- tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 4 ++++ tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 4 ++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 31 +++++++++++++++++++++---------- tcg/sparc64/tcg-target-con-set.h | 1 - tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 23 ++++++++++++++--------- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 8 ++++---- tcg/tci.c | 23 ++++++++++------------- tcg/tci/tcg-target-has.h | 4 ---- tcg/tci/tcg-target.c.inc | 21 +++++++++++++-------- 25 files changed, 122 insertions(+), 106 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index c351db223d..0c370d7dda 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -30,7 +29,6 @@ #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 0 /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 0996c6234b..46ad91f40e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2226,6 +2226,10 @@ static const TCGOutOpBinary outop_mulsh = { .out_rrr = tgen_mulsh, }; +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index e1f19ffbc9..ccbc39a23e 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -28,7 +28,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 8c0bc78be3..55e9f66340 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -921,14 +921,6 @@ static void tcg_out_dat_rIN(TCGContext *s, ARMCond cond, ARMInsn opc, } } -static void tcg_out_umull32(TCGContext *s, ARMCond cond, TCGReg rd0, - TCGReg rd1, TCGReg rn, TCGReg rm) -{ - /* umull */ - tcg_out32(s, (cond << 28) | 0x00800090 | - (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); -} - static void tcg_out_ext8s(TCGContext *s, TCGType t, TCGReg rd, TCGReg rn) { /* sxtb */ @@ -1982,6 +1974,19 @@ static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg rd0, TCGReg rd1, TCGReg rn, TCGReg rm) +{ + /* umull */ + tcg_out32(s, (COND_AL << 28) | 0x00800090 | + (rd1 << 16) | (rd0 << 12) | (rm << 8) | rn); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_O2_I2(r, r, r, r), + .out_rrrr = tgen_mulu2, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; @@ -2248,9 +2253,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_mulu2_i32: - tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]); - break; case INDEX_op_brcond_i32: c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); @@ -2374,9 +2376,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond_i32: return C_O1_I2(r, r, rIN); - case INDEX_op_mulu2_i32: - return C_O2_I2(r, r, r, r); - case INDEX_op_brcond_i32: return C_O0_I2(r, rIN); case INDEX_op_deposit_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index d63b3a3a89..c92a049fd7 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -32,7 +32,6 @@ #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 1 #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ @@ -44,7 +43,6 @@ #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else #define TCG_TARGET_HAS_qemu_st8_i32 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 43d63cab5c..d1b37c4388 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2763,6 +2763,18 @@ static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, a3); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_O2_I2(a, d, a, r), + .out_rrrr = tgen_mulu2, +}; + static const TCGOutOpBinary outop_nand = { .base.static_constraint = C_NotImplemented, }; @@ -3145,9 +3157,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I128); break; - OP_32_64(mulu2): - tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_MUL, args[3]); - break; OP_32_64(add2): if (const_args[4]) { tgen_arithi(s, ARITH_ADD + rexw, a0, args[4], 1); @@ -3935,10 +3944,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, reT, r, 0); - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: - return C_O2_I2(a, d, a, r); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 491ebf0d06..12a721b4da 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -14,7 +14,6 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -28,7 +27,6 @@ #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 -#define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 95a0614e6e..fa9da82df8 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1440,6 +1440,10 @@ static const TCGOutOpBinary outop_mulsh = { .out_rrr = tgen_mulsh, }; +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index fd0b674402..05701fd228 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,7 +39,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_mulu2_i32 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_negsetcond_i32 0 @@ -50,7 +49,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 -#define TCG_TARGET_HAS_mulu2_i64 (!use_mips32r6_instructions) #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 #define TCG_TARGET_HAS_negsetcond_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index a1f9efb18b..6a97264c7c 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1861,6 +1861,21 @@ static const TCGOutOpBinary outop_mulsh = { .out_rrr = tgen_mulsh, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + MIPSInsn insn = type == TCG_TYPE_I32 ? OPC_MULTU : OPC_DMULTU; + tcg_out_opc_reg(s, insn, 0, a2, a3); + tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); + tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_mulu2, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2181,17 +2196,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_mulu2_i32: - i1 = OPC_MULTU; - goto do_hilo2; - case INDEX_op_mulu2_i64: - i1 = OPC_DMULTU; - do_hilo2: - tcg_out_opc_reg(s, i1, 0, a2, args[3]); - tcg_out_opc_reg(s, OPC_MFLO, a0, 0, 0); - tcg_out_opc_reg(s, OPC_MFHI, a1, 0, 0); - break; - case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: tcg_out_bswap16(s, a0, a1, a2); @@ -2361,9 +2365,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: return C_O1_I2(r, rz, rz); - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: - return C_O2_I2(r, r, r, r); case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index e711aa0731..5cc059fe9a 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -21,7 +21,6 @@ #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_negsetcond_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -35,7 +34,6 @@ #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 0 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index d4e34e3e7d..f2cb45029f 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3095,6 +3095,10 @@ static const TCGOutOpBinary outop_mulsh = { .out_rrr = tgen_mulsh, }; +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 7e260da61e..9b86b8bf48 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -14,7 +14,6 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -27,7 +26,6 @@ #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 316621b285..071be449f6 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2138,6 +2138,10 @@ static const TCGOutOpBinary outop_mulsh = { .out_rrr = tgen_mulsh, }; +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 52a76fc0b5..894a9f64e0 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -35,7 +35,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -46,7 +45,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 1 #define TCG_TARGET_HAS_qemu_ldst_i128 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 71f0eb40f8..18b83d5899 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2415,6 +2415,27 @@ static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_debug_assert(a0 == a2); + tcg_debug_assert((a1 & 1) == 0); + tcg_debug_assert(a0 == a1 + 1); + tcg_out_insn(s, RRE, MLGR, a1, a3); +} + +static TCGConstraintSetIndex cset_mulu2(TCGType type, unsigned flags) +{ + return (type == TCG_TYPE_I64 && HAVE_FACILITY(MISC_INSN_EXT2) + ? C_O2_I2(o, m, 0, r) : C_NotImplemented); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mulu2, + .out_rrrr = tgen_mulu2, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; @@ -2860,13 +2881,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); break; - case INDEX_op_mulu2_i64: - tcg_debug_assert(args[0] == args[2]); - tcg_debug_assert((args[1] & 1) == 0); - tcg_debug_assert(args[0] == args[1] + 1); - tcg_out_insn(s, RRE, MLGR, args[1], args[3]); - break; - case INDEX_op_add2_i64: if (const_args[4]) { if ((int64_t)args[4] >= 0) { @@ -3464,9 +3478,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rI, r); - case INDEX_op_mulu2_i64: - return C_O2_I2(o, m, 0, r); - case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_N1_O1_I4(r, r, 0, 1, ri, r); diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index d2ea184fa2..85dcfbc375 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -18,5 +18,4 @@ C_O1_I2(r, r, rJ) C_O1_I2(r, rz, rJ) C_O1_I4(r, rz, rJ, rI, 0) C_O2_I2(r, r, r, r) -C_O2_I2(r, r, rz, rJ) C_O2_I4(r, r, rz, rz, rJ, rJ) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index dea0941cac..258c978b5e 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 @@ -31,7 +30,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index be2072c027..41c4e77466 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1457,6 +1457,19 @@ static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_out_arith(s, a0, a2, a3, ARITH_UMUL); + tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_mulu2, +}; + static void tgen_muluh(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1646,7 +1659,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int c, c2; + int c2; /* Hoist the loads of the most common arguments. */ a0 = args[0]; @@ -1718,12 +1731,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[4], const_args[4], args[5], const_args[5], ARITH_SUBCC, ARITH_SUBC); break; - case INDEX_op_mulu2_i32: - c = ARITH_UMUL; - /* The 32-bit multiply insns produce a full 64-bit result. */ - tcg_out_arithc(s, a0, a2, args[3], const_args[3], c); - tcg_out_arithi(s, a1, a0, 32, SHIFT_SRLX); - break; case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); @@ -1847,8 +1854,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub2_i32: case INDEX_op_sub2_i64: return C_O2_I4(r, r, rz, rz, rJ, rJ); - case INDEX_op_mulu2_i32: - return C_O2_I2(r, r, rz, rJ); default: return C_NotImplemented; diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index ac387b2544..d4fc7148b4 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 -#define TCG_TARGET_HAS_mulu2_i64 0 /* Turn some undef macros into true macros. */ #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 0f48484dfe..a4d976242a 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1138,7 +1138,7 @@ void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { - if (TCG_TARGET_HAS_mulu2_i32) { + if (tcg_op_supported(INDEX_op_mulu2_i32, TCG_TYPE_I32, 0)) { tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); @@ -1156,7 +1156,7 @@ void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) tcg_temp_free_i64(t0); tcg_temp_free_i64(t1); } else { - qemu_build_not_reached(); + g_assert_not_reached(); } } @@ -2861,7 +2861,7 @@ void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { - if (TCG_TARGET_HAS_mulu2_i64) { + if (tcg_op_supported(INDEX_op_mulu2_i64, TCG_TYPE_I64, 0)) { tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); @@ -2888,7 +2888,7 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_mulsh, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); - } else if (TCG_TARGET_HAS_mulu2_i64 || + } else if (tcg_op_supported(INDEX_op_mulu2_i64, TCG_TYPE_I64, 0) || tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 5b22c75d2e..d38b55d04f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1043,6 +1043,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), + OUTOP(INDEX_op_mulu2_i32, TCGOutOpMul2, outop_mulu2), + OUTOP(INDEX_op_mulu2_i64, TCGOutOpMul2, outop_mulu2), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), @@ -2290,8 +2292,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_add2_i32; case INDEX_op_sub2_i32: return TCG_TARGET_HAS_sub2_i32; - case INDEX_op_mulu2_i32: - return TCG_TARGET_HAS_mulu2_i32; case INDEX_op_bswap16_i32: return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: @@ -2339,8 +2339,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_add2_i64; case INDEX_op_sub2_i64: return TCG_TARGET_HAS_sub2_i64; - case INDEX_op_mulu2_i64: - return TCG_TARGET_HAS_mulu2_i64; case INDEX_op_mov_vec: case INDEX_op_dup_vec: @@ -5476,6 +5474,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_muls2: + case INDEX_op_mulu2_i32: + case INDEX_op_mulu2_i64: { const TCGOutOpMul2 *out = container_of(all_outop[op->opc], TCGOutOpMul2, base); diff --git a/tcg/tci.c b/tcg/tci.c index 708ded34c7..5c8c62c0ef 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -588,6 +588,16 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, tmp64); #else muls64(®s[r0], ®s[r1], regs[r2], regs[r3]); +#endif + break; + case INDEX_op_mulu2_i32: + case INDEX_op_mulu2_i64: + tci_args_rrrr(insn, &r0, &r1, &r2, &r3); +#if TCG_TARGET_REG_BITS == 32 + tmp64 = (uint64_t)(uint32_t)regs[r2] * (uint32_t)regs[r3]; + tci_write_reg64(regs, r1, r0, tmp64); +#else + mulu64(®s[r0], ®s[r1], regs[r2], regs[r3]); #endif break; @@ -677,13 +687,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, T1 - T2); break; #endif -#if TCG_TARGET_HAS_mulu2_i32 - case INDEX_op_mulu2_i32: - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - tmp64 = (uint64_t)(uint32_t)regs[r2] * (uint32_t)regs[r3]; - tci_write_reg64(regs, r1, r0, tmp64); - break; -#endif #if TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 CASE_32_64(bswap16) tci_args_rr(insn, &r0, &r1); @@ -741,12 +744,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; break; -#if TCG_TARGET_HAS_mulu2_i64 - case INDEX_op_mulu2_i64: - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - mulu64(®s[r0], ®s[r1], regs[r2], regs[r3]); - break; -#endif #if TCG_TARGET_HAS_add2_i64 case INDEX_op_add2_i64: tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index a3d04b0ee2..2402889bec 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -22,12 +22,8 @@ #define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_mulu2_i32 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 -#define TCG_TARGET_HAS_mulu2_i64 1 -#else -#define TCG_TARGET_HAS_mulu2_i32 1 #endif /* TCG_TARGET_REG_BITS == 64 */ #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index aa3ce929b4..4bce206f80 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -98,10 +98,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O0_I4(r, r, r, r); #endif - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: - return C_O2_I2(r, r, r, r); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: case INDEX_op_setcond2_i32: @@ -729,6 +725,19 @@ static const TCGOutOpBinary outop_mulsh = { .base.static_constraint = C_NotImplemented, }; +static void tgen_mulu2(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) +{ + tcg_out_op_rrrr(s, glue(INDEX_op_mulu2_i,TCG_TARGET_REG_BITS), + a0, a1, a2, a3); +} + +static const TCGOutOpMul2 outop_mulu2 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_mul2, + .out_rrrr = tgen_mulu2, +}; + static const TCGOutOpBinary outop_muluh = { .base.static_constraint = C_NotImplemented, }; @@ -1023,10 +1032,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #endif - CASE_32_64(mulu2) - tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], args[3]); - break; - case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: if (TCG_TARGET_REG_BITS == 32) { From d776198cd31d1578c4b0239dc80cb2841e86f2f8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 09:11:53 -0800 Subject: [PATCH 0430/2760] tcg: Merge INDEX_op_mulu2_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 17 +++++++++-------- tcg/tcg-op.c | 10 +++++----- tcg/tcg.c | 9 +++------ tcg/tci.c | 6 ++---- tcg/tci/tcg-target.c.inc | 3 +-- 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 0394767291..592e002971 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -599,7 +599,7 @@ Multiword arithmetic support formed from two single-word arguments, and the double-word output *t0* is returned in two single-word outputs. - * - mulu2_i32/i64 *t0_low*, *t0_high*, *t1*, *t2* + * - mulu2 *t0_low*, *t0_high*, *t1*, *t2* - | Similar to mul, except two unsigned inputs *t1* and *t2* yielding the full double-word product *t0*. The latter is returned in two single-word outputs. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index a45b22ca1a..287bdf3473 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -53,6 +53,7 @@ DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(muls2, 2, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) +DEF(mulu2, 2, 2, 0, TCG_OPF_INT) DEF(muluh, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) @@ -92,7 +93,6 @@ DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) -DEF(mulu2_i32, 2, 2, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) @@ -133,7 +133,6 @@ DEF(bswap64_i64, 1, 1, 1, 0) DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) -DEF(mulu2_i64, 2, 2, 0, 0) #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) diff --git a/tcg/optimize.c b/tcg/optimize.c index 756f681e88..14d943cf97 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2069,13 +2069,14 @@ static bool fold_multiply2(OptContext *ctx, TCGOp *op) TCGOp *op2; switch (op->opc) { - case INDEX_op_mulu2_i32: - l = (uint64_t)(uint32_t)a * (uint32_t)b; - h = (int32_t)(l >> 32); - l = (int32_t)l; - break; - case INDEX_op_mulu2_i64: - mulu64(&l, &h, a, b); + case INDEX_op_mulu2: + if (ctx->type == TCG_TYPE_I32) { + l = (uint64_t)(uint32_t)a * (uint32_t)b; + h = (int32_t)(l >> 32); + l = (int32_t)l; + } else { + mulu64(&l, &h, a, b); + } break; case INDEX_op_muls2: if (ctx->type == TCG_TYPE_I32) { @@ -2975,7 +2976,7 @@ void tcg_optimize(TCGContext *s) done = fold_mul_highpart(&ctx, op); break; case INDEX_op_muls2: - CASE_OP_32_64(mulu2): + case INDEX_op_mulu2: done = fold_multiply2(&ctx, op); break; case INDEX_op_nand: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index a4d976242a..22af3b12bc 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1138,8 +1138,8 @@ void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2) { - if (tcg_op_supported(INDEX_op_mulu2_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op4_i32(INDEX_op_mulu2_i32, rl, rh, arg1, arg2); + if (tcg_op_supported(INDEX_op_mulu2, TCG_TYPE_I32, 0)) { + tcg_gen_op4_i32(INDEX_op_mulu2, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I32, 0)) { TCGv_i32 t = tcg_temp_ebb_new_i32(); tcg_gen_op3_i32(INDEX_op_mul, t, arg1, arg2); @@ -2861,8 +2861,8 @@ void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) { - if (tcg_op_supported(INDEX_op_mulu2_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op4_i64(INDEX_op_mulu2_i64, rl, rh, arg1, arg2); + if (tcg_op_supported(INDEX_op_mulu2, TCG_TYPE_I64, 0)) { + tcg_gen_op4_i64(INDEX_op_mulu2, rl, rh, arg1, arg2); } else if (tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t = tcg_temp_ebb_new_i64(); tcg_gen_op3_i64(INDEX_op_mul, t, arg1, arg2); @@ -2888,7 +2888,7 @@ void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2) tcg_gen_op3_i64(INDEX_op_mulsh, rh, arg1, arg2); tcg_gen_mov_i64(rl, t); tcg_temp_free_i64(t); - } else if (tcg_op_supported(INDEX_op_mulu2_i64, TCG_TYPE_I64, 0) || + } else if (tcg_op_supported(INDEX_op_mulu2, TCG_TYPE_I64, 0) || tcg_op_supported(INDEX_op_muluh, TCG_TYPE_I64, 0)) { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index d38b55d04f..685408f0f9 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1043,8 +1043,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), - OUTOP(INDEX_op_mulu2_i32, TCGOutOpMul2, outop_mulu2), - OUTOP(INDEX_op_mulu2_i64, TCGOutOpMul2, outop_mulu2), + OUTOP(INDEX_op_mulu2, TCGOutOpMul2, outop_mulu2), OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), @@ -4009,8 +4008,7 @@ liveness_pass_1(TCGContext *s) opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh; goto do_mul2; - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: + case INDEX_op_mulu2: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh; do_mul2: @@ -5474,8 +5472,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_muls2: - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: + case INDEX_op_mulu2: { const TCGOutOpMul2 *out = container_of(all_outop[op->opc], TCGOutOpMul2, base); diff --git a/tcg/tci.c b/tcg/tci.c index 5c8c62c0ef..569b5c7ed0 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -590,8 +590,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, muls64(®s[r0], ®s[r1], regs[r2], regs[r3]); #endif break; - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: + case INDEX_op_mulu2: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); #if TCG_TARGET_REG_BITS == 32 tmp64 = (uint64_t)(uint32_t)regs[r2] * (uint32_t)regs[r3]; @@ -1092,8 +1091,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_muls2: - case INDEX_op_mulu2_i32: - case INDEX_op_mulu2_i64: + case INDEX_op_mulu2: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s", op_name, str_r(r0), str_r(r1), diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4bce206f80..563529e055 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -728,8 +728,7 @@ static const TCGOutOpBinary outop_mulsh = { static void tgen_mulu2(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3) { - tcg_out_op_rrrr(s, glue(INDEX_op_mulu2_i,TCG_TARGET_REG_BITS), - a0, a1, a2, a3); + tcg_out_op_rrrr(s, INDEX_op_mulu2, a0, a1, a2, a3); } static const TCGOutOpMul2 outop_mulu2 = { From 84f57d50ac25a24870de6d19f5b588083a4899e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 20:22:55 +0000 Subject: [PATCH 0431/2760] tcg/loongarch64: Support negsetcond Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/loongarch64/tcg-target-con-set.h | 2 -- tcg/loongarch64/tcg-target-has.h | 4 ++-- tcg/loongarch64/tcg-target.c.inc | 34 ++++++++++++++++++++++------ 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index da84e4d49c..c145d4ab66 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -29,8 +29,6 @@ C_O1_I2(r, r, rJ) C_O1_I2(r, r, rU) C_O1_I2(r, r, rW) C_O1_I2(r, 0, rz) -C_O1_I2(r, rz, ri) -C_O1_I2(r, rz, rJ) C_O1_I2(w, w, w) C_O1_I2(w, w, wM) C_O1_I2(w, w, wA) diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 12a721b4da..e9bb913961 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -10,7 +10,7 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 @@ -19,7 +19,7 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_bswap16_i64 1 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index fa9da82df8..e7f97aaa5e 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -646,14 +646,29 @@ static int tcg_out_setcond_int(TCGContext *s, TCGCond cond, TCGReg ret, } static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg arg1, tcg_target_long arg2, bool c2) + TCGReg arg1, tcg_target_long arg2, + bool c2, bool neg) { int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2, c2); + TCGReg tmp = tmpflags & ~SETCOND_FLAGS; - if (tmpflags != ret) { - TCGReg tmp = tmpflags & ~SETCOND_FLAGS; - + if (neg) { + /* If intermediate result is zero/non-zero: test != 0. */ + if (tmpflags & SETCOND_NEZ) { + tcg_out_opc_sltu(s, ret, TCG_REG_ZERO, tmp); + tmp = ret; + } + /* Produce the 0/-1 result. */ + if (tmpflags & SETCOND_INV) { + tcg_out_opc_addi_d(s, ret, tmp, -1); + } else { + tcg_out_opc_sub_d(s, ret, TCG_REG_ZERO, tmp); + } + } else { switch (tmpflags & SETCOND_FLAGS) { + case 0: + tcg_debug_assert(tmp == ret); + break; case SETCOND_INV: /* Intermediate result is boolean: simply invert. */ tcg_out_opc_xori(s, ret, tmp, 1); @@ -1800,7 +1815,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: - tcg_out_setcond(s, args[3], a0, a1, a2, c2); + tcg_out_setcond(s, args[3], a0, a1, a2, c2, false); + break; + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: + tcg_out_setcond(s, args[3], a0, a1, a2, c2, true); break; case INDEX_op_movcond_i32: @@ -2434,9 +2453,10 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O1_I2(r, 0, rz); case INDEX_op_setcond_i32: - return C_O1_I2(r, rz, ri); case INDEX_op_setcond_i64: - return C_O1_I2(r, rz, rJ); + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: + return C_O1_I2(r, r, rJ); case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: From ce27066de1bf9e44486834bfeb0aa44022f98ab9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 12:36:32 -0800 Subject: [PATCH 0432/2760] tcg/mips: Support negsetcond Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/mips/tcg-target-has.h | 4 ++-- tcg/mips/tcg-target.c.inc | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 05701fd228..c77d4296cf 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -41,7 +41,7 @@ extern bool use_mips32r2_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 @@ -51,7 +51,7 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #endif /* optional instructions detected at runtime */ diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 6a97264c7c..759f152711 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -959,6 +959,25 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, tcg_out_setcond_end(s, ret, tmpflags); } +static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg arg1, TCGReg arg2) +{ + int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2); + TCGReg tmp = tmpflags & ~SETCOND_FLAGS; + + /* If intermediate result is zero/non-zero: test != 0. */ + if (tmpflags & SETCOND_NEZ) { + tcg_out_opc_reg(s, OPC_SLTU, ret, TCG_REG_ZERO, tmp); + tmp = ret; + } + /* Produce the 0/-1 result. */ + if (tmpflags & SETCOND_INV) { + tcg_out_opc_imm(s, OPC_ADDIU, ret, tmp, -1); + } else { + tcg_out_opc_reg(s, OPC_SUBU, ret, TCG_REG_ZERO, tmp); + } +} + static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, TCGReg arg2, TCGLabel *l) { @@ -2270,6 +2289,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_setcond_i64: tcg_out_setcond(s, args[3], a0, a1, a2); break; + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: + tcg_out_negsetcond(s, args[3], a0, a1, a2); + break; case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); break; @@ -2364,6 +2387,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: return C_O1_I2(r, rz, rz); case INDEX_op_deposit_i32: From 9204be8dec1a52e943185df392377d8853decf93 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 12:42:13 -0800 Subject: [PATCH 0433/2760] tcg/tci: Support negsetcond MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tci/tcg-target-has.h | 4 ++-- tcg/tci/tcg-target.c.inc | 13 +++++++++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 2402889bec..7787347e05 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -10,7 +10,7 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_negsetcond_i32 0 +#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -19,7 +19,7 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 0 +#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 563529e055..2eb323b5c5 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -79,6 +79,8 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond_i32: case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, r, r); @@ -966,6 +968,17 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[3], args[4], args[5]); break; + case INDEX_op_negsetcond_i32: + tcg_out_op_rrrc(s, INDEX_op_setcond_i32, + args[0], args[1], args[2], args[3]); + tcg_out_op_rr(s, INDEX_op_neg, args[0], args[0]); + break; + case INDEX_op_negsetcond_i64: + tcg_out_op_rrrc(s, INDEX_op_setcond_i64, + args[0], args[1], args[2], args[3]); + tcg_out_op_rr(s, INDEX_op_neg, args[0], args[0]); + break; + CASE_32_64(ld8u) CASE_32_64(ld8s) CASE_32_64(ld16u) From f791458932a21f8d99694af412304abfbce83765 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 9 Jan 2025 12:48:21 -0800 Subject: [PATCH 0434/2760] tcg: Remove TCG_TARGET_HAS_negsetcond_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All targets now provide negsetcond, so remove the conditional. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/arm/tcg-target-has.h | 1 - tcg/i386/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/mips/tcg-target-has.h | 2 -- tcg/optimize.c | 24 +++++++++--------------- tcg/ppc/tcg-target-has.h | 2 -- tcg/riscv/tcg-target-has.h | 2 -- tcg/s390x/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target-has.h | 2 -- tcg/tcg-has.h | 1 - tcg/tcg-op.c | 12 +++--------- tcg/tcg.c | 6 ++---- tcg/tci/tcg-target-has.h | 2 -- 14 files changed, 14 insertions(+), 48 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 0c370d7dda..22a574e703 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -16,7 +16,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 @@ -26,7 +25,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index ccbc39a23e..bfa3be8028 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -27,7 +27,6 @@ extern bool use_neon_instructions; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index c92a049fd7..aaf8764cc9 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -29,7 +29,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 @@ -40,7 +39,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index e9bb913961..90f0a131ae 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -10,7 +10,6 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 @@ -19,7 +18,6 @@ #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_bswap16_i64 1 diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index c77d4296cf..c6cecba28b 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -41,7 +41,6 @@ extern bool use_mips32r2_instructions; /* optional instructions */ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 -#define TCG_TARGET_HAS_negsetcond_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 @@ -51,7 +50,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 -#define TCG_TARGET_HAS_negsetcond_i64 1 #endif /* optional instructions detected at runtime */ diff --git a/tcg/optimize.c b/tcg/optimize.c index 14d943cf97..0affde323b 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1996,23 +1996,19 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) if (ti_is_const(tt) && ti_is_const(ft)) { uint64_t tv = ti_const_val(tt); uint64_t fv = ti_const_val(ft); - TCGOpcode opc, negopc = 0; + TCGOpcode opc, negopc; TCGCond cond = op->args[5]; switch (ctx->type) { case TCG_TYPE_I32: opc = INDEX_op_setcond_i32; - if (TCG_TARGET_HAS_negsetcond_i32) { - negopc = INDEX_op_negsetcond_i32; - } + negopc = INDEX_op_negsetcond_i32; tv = (int32_t)tv; fv = (int32_t)fv; break; case TCG_TYPE_I64: opc = INDEX_op_setcond_i64; - if (TCG_TARGET_HAS_negsetcond_i64) { - negopc = INDEX_op_negsetcond_i64; - } + negopc = INDEX_op_negsetcond_i64; break; default: g_assert_not_reached(); @@ -2024,14 +2020,12 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) } else if (fv == 1 && tv == 0) { op->opc = opc; op->args[3] = tcg_invert_cond(cond); - } else if (negopc) { - if (tv == -1 && fv == 0) { - op->opc = negopc; - op->args[3] = cond; - } else if (fv == -1 && tv == 0) { - op->opc = negopc; - op->args[3] = tcg_invert_cond(cond); - } + } else if (tv == -1 && fv == 0) { + op->opc = negopc; + op->args[3] = cond; + } else if (fv == -1 && tv == 0) { + op->opc = negopc; + op->args[3] = tcg_invert_cond(cond); } } diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 5cc059fe9a..5c4fc2bc34 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -20,7 +20,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -31,7 +30,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #endif diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 9b86b8bf48..e18b5cb8ec 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -10,7 +10,6 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 @@ -18,7 +17,6 @@ #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 894a9f64e0..41cd8a1d0d 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -32,7 +32,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 @@ -42,7 +41,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 258c978b5e..6ed27b8fcc 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -17,7 +17,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -27,7 +26,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index d4fc7148b4..315dfd05aa 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -16,7 +16,6 @@ #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 /* Turn some undef macros into true macros. */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 22af3b12bc..413b68352d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -569,11 +569,8 @@ void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, tcg_gen_movi_i32(ret, -1); } else if (cond == TCG_COND_NEVER) { tcg_gen_movi_i32(ret, 0); - } else if (TCG_TARGET_HAS_negsetcond_i32) { - tcg_gen_op4i_i32(INDEX_op_negsetcond_i32, ret, arg1, arg2, cond); } else { - tcg_gen_setcond_i32(cond, ret, arg1, arg2); - tcg_gen_neg_i32(ret, ret); + tcg_gen_op4i_i32(INDEX_op_negsetcond_i32, ret, arg1, arg2, cond); } } @@ -1950,17 +1947,14 @@ void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, tcg_gen_movi_i64(ret, -1); } else if (cond == TCG_COND_NEVER) { tcg_gen_movi_i64(ret, 0); - } else if (TCG_TARGET_HAS_negsetcond_i64) { + } else if (TCG_TARGET_REG_BITS == 64) { tcg_gen_op4i_i64(INDEX_op_negsetcond_i64, ret, arg1, arg2, cond); - } else if (TCG_TARGET_REG_BITS == 32) { + } else { tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); tcg_gen_neg_i32(TCGV_LOW(ret), TCGV_LOW(ret)); tcg_gen_mov_i32(TCGV_HIGH(ret), TCGV_LOW(ret)); - } else { - tcg_gen_setcond_i64(cond, ret, arg1, arg2); - tcg_gen_neg_i64(ret, ret); } } diff --git a/tcg/tcg.c b/tcg/tcg.c index 685408f0f9..38a329b876 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2268,6 +2268,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return has_type; case INDEX_op_setcond_i32: + case INDEX_op_negsetcond_i32: case INDEX_op_brcond_i32: case INDEX_op_movcond_i32: case INDEX_op_ld8u_i32: @@ -2283,8 +2284,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i32: return true; - case INDEX_op_negsetcond_i32: - return TCG_TARGET_HAS_negsetcond_i32; case INDEX_op_extract2_i32: return TCG_TARGET_HAS_extract2_i32; case INDEX_op_add2_i32: @@ -2301,6 +2300,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_REG_BITS == 32; case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i64: case INDEX_op_brcond_i64: case INDEX_op_movcond_i64: case INDEX_op_ld8u_i64: @@ -2321,8 +2321,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; - case INDEX_op_negsetcond_i64: - return TCG_TARGET_HAS_negsetcond_i64; case INDEX_op_extract2_i64: return TCG_TARGET_HAS_extract2_i64; case INDEX_op_extrl_i64_i32: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 7787347e05..f45a0688f9 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -10,7 +10,6 @@ #define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 -#define TCG_TARGET_HAS_negsetcond_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 @@ -19,7 +18,6 @@ #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 -#define TCG_TARGET_HAS_negsetcond_i64 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_add2_i64 1 From 5a7b38c8ca056f1ffbb488c1b7c97636b1f3b22b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 09:12:06 -0800 Subject: [PATCH 0435/2760] tcg: Convert setcond, negsetcond to TCGOutOpSetcond Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 121 ++++++++++++++++++++----------- tcg/arm/tcg-target.c.inc | 117 +++++++++++++++++++++--------- tcg/i386/tcg-target.c.inc | 57 +++++++++++---- tcg/loongarch64/tcg-target.c.inc | 51 +++++++++---- tcg/mips/tcg-target-con-set.h | 2 +- tcg/mips/tcg-target.c.inc | 39 +++++----- tcg/ppc/tcg-target.c.inc | 61 ++++++++++------ tcg/riscv/tcg-target.c.inc | 52 +++++++++---- tcg/s390x/tcg-target.c.inc | 64 +++++++++------- tcg/sparc64/tcg-target-con-set.h | 1 - tcg/sparc64/tcg-target.c.inc | 69 +++++++++++++----- tcg/tcg.c | 31 ++++++++ tcg/tci/tcg-target.c.inc | 49 +++++++------ 13 files changed, 477 insertions(+), 237 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 46ad91f40e..2524e73ff4 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1356,25 +1356,37 @@ static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_bfm(s, ext, rd, rn, a, b); } +static void tgen_cmp(TCGContext *s, TCGType ext, TCGCond cond, + TCGReg a, TCGReg b) +{ + if (is_tst_cond(cond)) { + tcg_out_insn(s, 3510, ANDS, ext, TCG_REG_XZR, a, b); + } else { + tcg_out_insn(s, 3502, SUBS, ext, TCG_REG_XZR, a, b); + } +} + +static void tgen_cmpi(TCGContext *s, TCGType ext, TCGCond cond, + TCGReg a, tcg_target_long b) +{ + if (is_tst_cond(cond)) { + tcg_out_logicali(s, I3404_ANDSI, ext, TCG_REG_XZR, a, b); + } else if (b >= 0) { + tcg_debug_assert(is_aimm(b)); + tcg_out_insn(s, 3401, SUBSI, ext, TCG_REG_XZR, a, b); + } else { + tcg_debug_assert(is_aimm(-b)); + tcg_out_insn(s, 3401, ADDSI, ext, TCG_REG_XZR, a, -b); + } +} + static void tcg_out_cmp(TCGContext *s, TCGType ext, TCGCond cond, TCGReg a, tcg_target_long b, bool const_b) { - if (is_tst_cond(cond)) { - if (!const_b) { - tcg_out_insn(s, 3510, ANDS, ext, TCG_REG_XZR, a, b); - } else { - tcg_out_logicali(s, I3404_ANDSI, ext, TCG_REG_XZR, a, b); - } + if (const_b) { + tgen_cmpi(s, ext, cond, a, b); } else { - if (!const_b) { - tcg_out_insn(s, 3502, SUBS, ext, TCG_REG_XZR, a, b); - } else if (b >= 0) { - tcg_debug_assert(is_aimm(b)); - tcg_out_insn(s, 3401, SUBSI, ext, TCG_REG_XZR, a, b); - } else { - tcg_debug_assert(is_aimm(-b)); - tcg_out_insn(s, 3401, ADDSI, ext, TCG_REG_XZR, a, -b); - } + tgen_cmp(s, ext, cond, a, b); } } @@ -2433,6 +2445,59 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_cset(TCGContext *s, TCGCond cond, TCGReg ret) +{ + /* Use CSET alias of CSINC Wd, WZR, WZR, invert(cond). */ + tcg_out_insn(s, 3506, CSINC, TCG_TYPE_I32, ret, TCG_REG_XZR, + TCG_REG_XZR, tcg_invert_cond(cond)); +} + +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_cmp(s, type, cond, a1, a2); + tgen_cset(s, cond, a0); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_cmpi(s, type, cond, a1, a2); + tgen_cset(s, cond, a0); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_csetm(TCGContext *s, TCGType ext, TCGCond cond, TCGReg ret) +{ + /* Use CSETM alias of CSINV Wd, WZR, WZR, invert(cond). */ + tcg_out_insn(s, 3506, CSINV, ext, ret, TCG_REG_XZR, + TCG_REG_XZR, tcg_invert_cond(cond)); +} + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tgen_cmp(s, type, cond, a1, a2); + tgen_csetm(s, type, cond, a0); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_cmpi(s, type, cond, a1, a2); + tgen_csetm(s, type, cond, a0); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2507,26 +2572,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); break; - case INDEX_op_setcond_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_setcond_i64: - tcg_out_cmp(s, ext, args[3], a1, a2, c2); - /* Use CSET alias of CSINC Wd, WZR, WZR, invert(cond). */ - tcg_out_insn(s, 3506, CSINC, TCG_TYPE_I32, a0, TCG_REG_XZR, - TCG_REG_XZR, tcg_invert_cond(args[3])); - break; - - case INDEX_op_negsetcond_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_negsetcond_i64: - tcg_out_cmp(s, ext, args[3], a1, a2, c2); - /* Use CSETM alias of CSINV Wd, WZR, WZR, invert(cond). */ - tcg_out_insn(s, 3506, CSINV, ext, a0, TCG_REG_XZR, - TCG_REG_XZR, tcg_invert_cond(args[3])); - break; - case INDEX_op_movcond_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3114,12 +3159,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, r, rC); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(r, rC); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 55e9f66340..0f2a029f6d 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1210,31 +1210,48 @@ static void tcg_out_mb(TCGContext *s, TCGArg a0) } } -static TCGCond tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg a, - TCGArg b, int b_const) +static TCGCond tgen_cmp(TCGContext *s, TCGCond cond, TCGReg a, TCGReg b) { + if (is_tst_cond(cond)) { + tcg_out_dat_reg(s, COND_AL, ARITH_TST, 0, a, b, SHIFT_IMM_LSL(0)); + return tcg_tst_eqne_cond(cond); + } + tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, a, b, SHIFT_IMM_LSL(0)); + return cond; +} + +static TCGCond tgen_cmpi(TCGContext *s, TCGCond cond, TCGReg a, TCGArg b) +{ + int imm12; + if (!is_tst_cond(cond)) { - tcg_out_dat_rIN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0, a, b, b_const); + tcg_out_dat_IN(s, COND_AL, ARITH_CMP, ARITH_CMN, 0, a, b); return cond; } - cond = tcg_tst_eqne_cond(cond); - if (b_const) { - int imm12 = encode_imm(b); - - /* - * The compare constraints allow rIN, but TST does not support N. - * Be prepared to load the constant into a scratch register. - */ - if (imm12 >= 0) { - tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, a, imm12); - return cond; - } + /* + * The compare constraints allow rIN, but TST does not support N. + * Be prepared to load the constant into a scratch register. + */ + imm12 = encode_imm(b); + if (imm12 >= 0) { + tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, a, imm12); + } else { tcg_out_movi32(s, COND_AL, TCG_REG_TMP, b); - b = TCG_REG_TMP; + tcg_out_dat_reg(s, COND_AL, ARITH_TST, 0, + a, TCG_REG_TMP, SHIFT_IMM_LSL(0)); + } + return tcg_tst_eqne_cond(cond); +} + +static TCGCond tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg a, + TCGArg b, int b_const) +{ + if (b_const) { + return tgen_cmpi(s, cond, a, b); + } else { + return tgen_cmp(s, cond, a, b); } - tcg_out_dat_reg(s, COND_AL, ARITH_TST, 0, a, b, SHIFT_IMM_LSL(0)); - return cond; } static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args, @@ -2164,6 +2181,52 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void finish_setcond(TCGContext *s, TCGCond cond, TCGReg ret, bool neg) +{ + tcg_out_movi32(s, tcg_cond_to_arm_cond[tcg_invert_cond(cond)], ret, 0); + tcg_out_movi32(s, tcg_cond_to_arm_cond[cond], ret, neg ? -1 : 1); +} + +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + cond = tgen_cmp(s, cond, a1, a2); + finish_setcond(s, cond, a0, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + cond = tgen_cmpi(s, cond, a1, a2); + finish_setcond(s, cond, a0, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rIN), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + cond = tgen_cmp(s, cond, a1, a2); + finish_setcond(s, cond, a0, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + cond = tgen_cmpi(s, cond, a1, a2); + finish_setcond(s, cond, a0, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rIN), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2258,20 +2321,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[3])); break; - case INDEX_op_setcond_i32: - c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], - ARITH_MOV, args[0], 0, 1); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], - ARITH_MOV, args[0], 0, 0); - break; - case INDEX_op_negsetcond_i32: - c = tcg_out_cmp(s, args[3], args[1], args[2], const_args[2]); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], - ARITH_MVN, args[0], 0, 0); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], - ARITH_MOV, args[0], 0, 0); - break; case INDEX_op_brcond2_i32: c = tcg_out_cmp2(s, args, const_args); @@ -2372,10 +2421,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_setcond_i32: - case INDEX_op_negsetcond_i32: - return C_O1_I2(r, r, rIN); - case INDEX_op_brcond_i32: return C_O0_I2(r, rIN); case INDEX_op_deposit_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d1b37c4388..d3a3f1f7fb 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1679,10 +1679,11 @@ static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, } #endif -static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, - TCGArg dest, TCGArg arg1, TCGArg arg2, - int const_arg2, bool neg) +static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGArg arg2, + bool const_arg2, bool neg) { + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; int cmp_rexw = rexw; bool inv = false; bool cleared; @@ -1757,7 +1758,7 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, case TCG_COND_LT: /* If arg2 is 0, extract the sign bit. */ if (const_arg2 && arg2 == 0) { - tcg_out_mov(s, rexw ? TCG_TYPE_I64 : TCG_TYPE_I32, dest, arg1); + tcg_out_mov(s, type, dest, arg1); if (inv) { tcg_out_modrm(s, OPC_GRP3_Ev + rexw, EXT3_NOT, dest); } @@ -1793,6 +1794,42 @@ static void tcg_out_setcond(TCGContext *s, int rexw, TCGCond cond, } } +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(q, r, reT), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(q, r, reT), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + #if TCG_TARGET_REG_BITS == 32 static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, const int *const_args) @@ -3091,12 +3128,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1], arg_label(args[3]), 0); break; - OP_32_64(setcond): - tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, false); - break; - OP_32_64(negsetcond): - tcg_out_setcond(s, rexw, args[3], a0, a1, a2, const_a2, true); - break; OP_32_64(movcond): tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]); break; @@ -3934,12 +3965,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return C_O1_I2(q, 0, qi); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(q, r, reT); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, r, reT, r, 0); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e7f97aaa5e..87e8b843f8 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -687,6 +687,42 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, false, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, true, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, false, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, true, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg c1, tcg_target_long c2, bool const2, TCGReg v1, TCGReg v2) @@ -1813,15 +1849,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_revb_d(s, a0, a1); break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - tcg_out_setcond(s, args[3], a0, a1, a2, c2, false); - break; - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - tcg_out_setcond(s, args[3], a0, a1, a2, c2, true); - break; - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: tcg_out_movcond(s, args[5], a0, a1, a2, c2, args[3], args[4]); @@ -2452,12 +2479,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) /* Must deposit into the same register as input */ return C_O1_I2(r, 0, rz); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, r, rJ); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, rz, rJ, rz, rz); diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index 248bc95d9b..67dfab2aed 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -23,8 +23,8 @@ C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) C_O1_I2(r, r, rIK) C_O1_I2(r, r, rJ) +C_O1_I2(r, r, rz) C_O1_I2(r, r, rzW) -C_O1_I2(r, rz, rz) C_O1_I4(r, rz, rz, rz, 0) C_O1_I4(r, rz, rz, rz, rz) C_O2_I1(r, r, r) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 759f152711..51b3ea4bb0 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -952,15 +952,20 @@ static void tcg_out_setcond_end(TCGContext *s, TCGReg ret, int tmpflags) } } -static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg arg1, TCGReg arg2) +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg arg1, TCGReg arg2) { int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2); tcg_out_setcond_end(s, ret, tmpflags); } -static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg arg1, TCGReg arg2) +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rz), + .out_rrr = tgen_setcond, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg arg1, TCGReg arg2) { int tmpflags = tcg_out_setcond_int(s, cond, ret, arg1, arg2); TCGReg tmp = tmpflags & ~SETCOND_FLAGS; @@ -978,6 +983,11 @@ static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rz), + .out_rrr = tgen_negsetcond, +}; + static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, TCGReg arg2, TCGLabel *l) { @@ -1041,10 +1051,11 @@ static int tcg_out_setcond2_int(TCGContext *s, TCGCond cond, TCGReg ret, break; default: - tcg_out_setcond(s, TCG_COND_EQ, TCG_TMP0, ah, bh); - tcg_out_setcond(s, tcg_unsigned_cond(cond), TCG_TMP1, al, bl); + tgen_setcond(s, TCG_TYPE_I32, TCG_COND_EQ, TCG_TMP0, ah, bh); + tgen_setcond(s, TCG_TYPE_I32, tcg_unsigned_cond(cond), + TCG_TMP1, al, bl); tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, TCG_TMP0); - tcg_out_setcond(s, tcg_high_cond(cond), TCG_TMP0, ah, bh); + tgen_setcond(s, TCG_TYPE_I32, tcg_high_cond(cond), TCG_TMP0, ah, bh); tcg_out_opc_reg(s, OPC_OR, ret, TCG_TMP0, TCG_TMP1); break; } @@ -2285,14 +2296,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_movcond(s, args[5], a0, a1, a2, args[3], args[4]); break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - tcg_out_setcond(s, args[3], a0, a1, a2); - break; - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - tcg_out_negsetcond(s, args[3], a0, a1, a2); - break; case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); break; @@ -2385,12 +2388,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, rz, rz); - case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rz); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index f2cb45029f..0a66351124 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1926,8 +1926,8 @@ static TCGReg tcg_gen_setcond_xor(TCGContext *s, TCGReg arg1, TCGArg arg2, } static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, - TCGArg arg0, TCGArg arg1, TCGArg arg2, - int const_arg2, bool neg) + TCGReg arg0, TCGReg arg1, TCGArg arg2, + bool const_arg2, bool neg) { int sh; bool inv; @@ -2072,6 +2072,42 @@ static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, } } +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tcg_out_bc(TCGContext *s, TCGCond cond, int bd) { tcg_out32(s, tcg_to_bc[cond] | bd); @@ -3465,22 +3501,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_setcond_i32: - tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2], - const_args[2], false); - break; - case INDEX_op_setcond_i64: - tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2], - const_args[2], false); - break; - case INDEX_op_negsetcond_i32: - tcg_out_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], args[2], - const_args[2], true); - break; - case INDEX_op_negsetcond_i64: - tcg_out_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], args[2], - const_args[2], true); - break; case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args, const_args); break; @@ -4276,11 +4296,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(r, rC); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, r, rC); case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rZ, rZ); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 071be449f6..05114b5c5f 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1325,6 +1325,24 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, cond, dest, arg1, arg2, true); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg arg1, tcg_target_long arg2, bool c2) { @@ -1363,6 +1381,24 @@ static void tcg_out_negsetcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_negsetcond(s, cond, dest, arg1, arg2, false); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_negsetcond(s, cond, dest, arg1, arg2, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rI), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tcg_out_movcond_zicond(TCGContext *s, TCGReg ret, TCGReg test_ne, int val1, bool c_val1, int val2, bool c_val2) @@ -2485,16 +2521,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - tcg_out_setcond(s, args[3], a0, a1, a2, c2); - break; - - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - tcg_out_negsetcond(s, args[3], a0, a1, a2, c2); - break; - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: tcg_out_movcond(s, args[5], a0, a1, a2, c2, @@ -2837,12 +2863,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, r, rI); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(rz, rz); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 18b83d5899..3c04b87109 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1370,9 +1370,9 @@ static int tgen_cmp(TCGContext *s, TCGType type, TCGCond c, TCGReg r1, return tgen_cmp2(s, type, c, r1, c2, c2const, need_carry, &inv_cc); } -static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, - TCGReg dest, TCGReg c1, TCGArg c2, - bool c2const, bool neg) +static void tgen_setcond_int(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg c1, TCGArg c2, + bool c2const, bool neg) { int cc; @@ -1464,6 +1464,42 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, tcg_out_insn(s, RRFc, LOCGR, dest, TCG_TMP0, cc); } +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tgen_setcond_int(s, type, cond, dest, arg1, arg2, false, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tgen_setcond_int(s, type, cond, dest, arg1, arg2, true, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tgen_setcond_int(s, type, cond, dest, arg1, arg2, false, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tgen_setcond_int(s, type, cond, dest, arg1, arg2, true, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rC), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tgen_movcond_int(TCGContext *s, TCGType type, TCGReg dest, TCGArg v3, int v3const, TCGReg v4, int cc, int inv_cc) @@ -2825,14 +2861,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_brcond(s, TCG_TYPE_I32, args[2], args[0], args[1], const_args[1], arg_label(args[3])); break; - case INDEX_op_setcond_i32: - tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], - args[2], const_args[2], false); - break; - case INDEX_op_negsetcond_i32: - tgen_setcond(s, TCG_TYPE_I32, args[3], args[0], args[1], - args[2], const_args[2], true); - break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2], const_args[2], args[3], const_args[3], args[4]); @@ -2910,14 +2938,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_brcond(s, TCG_TYPE_I64, args[2], args[0], args[1], const_args[1], arg_label(args[3])); break; - case INDEX_op_setcond_i64: - tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], - args[2], const_args[2], false); - break; - case INDEX_op_negsetcond_i64: - tgen_setcond(s, TCG_TYPE_I64, args[3], args[0], args[1], - args[2], const_args[2], true); - break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], args[2], const_args[2], args[3], const_args[3], args[4]); @@ -3434,12 +3454,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_setcond_i32: - case INDEX_op_negsetcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, r, rC); - case INDEX_op_brcond_i32: return C_O0_I2(r, ri); case INDEX_op_brcond_i64: diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index 85dcfbc375..ca7bbf0a2f 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -15,7 +15,6 @@ C_O0_I2(rz, rJ) C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, rJ) -C_O1_I2(r, rz, rJ) C_O1_I4(r, rz, rJ, rI, 0) C_O2_I2(r, r, r, r) C_O2_I4(r, r, rz, rz, rJ, rJ) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 41c4e77466..dcbe6a8f47 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -714,7 +714,7 @@ static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, } static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, int32_t c2, int c2const, bool neg) + TCGReg c1, int32_t c2, bool c2const, bool neg) { /* For 32-bit comparisons, we can play games with ADDC/SUBC. */ switch (cond) { @@ -788,7 +788,7 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, } static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, int32_t c2, int c2const, bool neg) + TCGReg c1, int32_t c2, bool c2const, bool neg) { int rcond; @@ -822,6 +822,53 @@ static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, + TCGArg c2, bool c2const, bool neg) +{ + if (type == TCG_TYPE_I32) { + tcg_out_setcond_i32(s, cond, ret, c1, c2, c2const, neg); + } else { + tcg_out_setcond_i64(s, cond, ret, c1, c2, c2const, neg); + } +} + +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, false); +} + +static void tgen_setcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, false); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_setcond, + .out_rri = tgen_setcondi, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, false, true); +} + +static void tgen_negsetcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, tcg_target_long arg2) +{ + tcg_out_setcond(s, type, cond, dest, arg1, arg2, true, true); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_negsetcond, + .out_rri = tgen_negsetcondi, +}; + static void tcg_out_addsub2_i32(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al, TCGReg ah, int32_t bl, int blconst, int32_t bh, int bhconst, int opl, int oph) @@ -1711,12 +1758,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_brcond_i32: tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], arg_label(args[3])); break; - case INDEX_op_setcond_i32: - tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2, false); - break; - case INDEX_op_negsetcond_i32: - tcg_out_setcond_i32(s, args[3], a0, a1, a2, c2, true); - break; case INDEX_op_movcond_i32: tcg_out_movcond_i32(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); break; @@ -1758,12 +1799,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_brcond_i64: tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); break; - case INDEX_op_setcond_i64: - tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2, false); - break; - case INDEX_op_negsetcond_i64: - tcg_out_setcond_i64(s, args[3], a0, a1, a2, c2, true); - break; case INDEX_op_movcond_i64: tcg_out_movcond_i64(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); break; @@ -1837,12 +1872,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: - return C_O1_I2(r, rz, rJ); - case INDEX_op_brcond_i32: case INDEX_op_brcond_i64: return C_O0_I2(rz, rJ); diff --git a/tcg/tcg.c b/tcg/tcg.c index 38a329b876..90e82e7ed0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1003,6 +1003,14 @@ typedef struct TCGOutOpUnary { void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); } TCGOutOpUnary; +typedef struct TCGOutOpSetcond { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg a1, TCGReg a2); + void (*out_rri)(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg a1, tcg_target_long a2); +} TCGOutOpSetcond; + typedef struct TCGOutOpSubtract { TCGOutOp base; void (*out_rrr)(TCGContext *s, TCGType type, @@ -1047,6 +1055,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), + OUTOP(INDEX_op_negsetcond_i32, TCGOutOpSetcond, outop_negsetcond), + OUTOP(INDEX_op_negsetcond_i64, TCGOutOpSetcond, outop_negsetcond), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), @@ -1056,6 +1066,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), + OUTOP(INDEX_op_setcond_i32, TCGOutOpSetcond, outop_setcond), + OUTOP(INDEX_op_setcond_i64, TCGOutOpSetcond, outop_setcond), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -5482,6 +5494,25 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_setcond_i32: + case INDEX_op_setcond_i64: + case INDEX_op_negsetcond_i32: + case INDEX_op_negsetcond_i64: + { + const TCGOutOpSetcond *out = + container_of(all_outop[op->opc], TCGOutOpSetcond, base); + TCGCond cond = new_args[3]; + + tcg_debug_assert(!const_args[1]); + if (const_args[2]) { + out->out_rri(s, type, cond, + new_args[0], new_args[1], new_args[2]); + } else { + out->out_rrr(s, type, cond, + new_args[0], new_args[1], new_args[2]); + } + } + break; default: if (def->flags & TCG_OPF_VECTOR) { diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2eb323b5c5..1b75aba698 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -77,10 +77,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, r, r); @@ -942,6 +938,32 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_setcond_i32 + : INDEX_op_setcond_i64); + tcg_out_op_rrrc(s, opc, dest, arg1, arg2, cond); +} + +static const TCGOutOpSetcond outop_setcond = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_setcond, +}; + +static void tgen_negsetcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg arg1, TCGReg arg2) +{ + tgen_setcond(s, type, cond, dest, arg1, arg2); + tgen_neg(s, type, dest, dest); +} + +static const TCGOutOpSetcond outop_negsetcond = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_negsetcond, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -958,27 +980,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_l(s, opc, arg_label(args[0])); break; - CASE_32_64(setcond) - tcg_out_op_rrrc(s, opc, args[0], args[1], args[2], args[3]); - break; - CASE_32_64(movcond) case INDEX_op_setcond2_i32: tcg_out_op_rrrrrc(s, opc, args[0], args[1], args[2], args[3], args[4], args[5]); break; - case INDEX_op_negsetcond_i32: - tcg_out_op_rrrc(s, INDEX_op_setcond_i32, - args[0], args[1], args[2], args[3]); - tcg_out_op_rr(s, INDEX_op_neg, args[0], args[0]); - break; - case INDEX_op_negsetcond_i64: - tcg_out_op_rrrc(s, INDEX_op_setcond_i64, - args[0], args[1], args[2], args[3]); - tcg_out_op_rr(s, INDEX_op_neg, args[0], args[0]); - break; - CASE_32_64(ld8u) CASE_32_64(ld8s) CASE_32_64(ld16u) @@ -1005,9 +1012,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; CASE_32_64(brcond) - tcg_out_op_rrrc(s, (opc == INDEX_op_brcond_i32 - ? INDEX_op_setcond_i32 : INDEX_op_setcond_i64), - TCG_REG_TMP, args[0], args[1], args[2]); + tgen_setcond(s, type, args[2], TCG_REG_TMP, args[0], args[1]); tcg_out_op_rl(s, opc, TCG_REG_TMP, arg_label(args[3])); break; From a363e1e179445102d7940e92d394d6c00c126f13 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 09:26:44 -0800 Subject: [PATCH 0436/2760] tcg: Merge INDEX_op_{neg}setcond_{i32,i64}` Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 6 ++---- target/sh4/translate.c | 6 +++--- tcg/optimize.c | 32 ++++++++------------------------ tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 30 ++++++++++-------------------- tcg/tci.c | 14 +++++++------- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 4 ++-- 9 files changed, 39 insertions(+), 66 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 592e002971..d3283265cd 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -499,13 +499,13 @@ Conditional moves .. list-table:: - * - setcond_i32/i64 *dest*, *t1*, *t2*, *cond* + * - setcond *dest*, *t1*, *t2*, *cond* - | *dest* = (*t1* *cond* *t2*) | | Set *dest* to 1 if (*t1* *cond* *t2*) is true, otherwise set to 0. - * - negsetcond_i32/i64 *dest*, *t1*, *t2*, *cond* + * - negsetcond *dest*, *t1*, *t2*, *cond* - | *dest* = -(*t1* *cond* *t2*) | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 287bdf3473..f40bb5796a 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -57,6 +57,7 @@ DEF(mulu2, 2, 2, 0, TCG_OPF_INT) DEF(muluh, 1, 2, 0, TCG_OPF_INT) DEF(nand, 1, 2, 0, TCG_OPF_INT) DEF(neg, 1, 1, 0, TCG_OPF_INT) +DEF(negsetcond, 1, 2, 1, TCG_OPF_INT) DEF(nor, 1, 2, 0, TCG_OPF_INT) DEF(not, 1, 1, 0, TCG_OPF_INT) DEF(or, 1, 2, 0, TCG_OPF_INT) @@ -66,13 +67,12 @@ DEF(remu, 1, 2, 0, TCG_OPF_INT) DEF(rotl, 1, 2, 0, TCG_OPF_INT) DEF(rotr, 1, 2, 0, TCG_OPF_INT) DEF(sar, 1, 2, 0, TCG_OPF_INT) +DEF(setcond, 1, 2, 1, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) -DEF(setcond_i32, 1, 2, 1, 0) -DEF(negsetcond_i32, 1, 2, 1, 0) DEF(movcond_i32, 1, 4, 1, 0) /* load/store */ DEF(ld8u_i32, 1, 1, 1, 0) @@ -99,8 +99,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(setcond_i64, 1, 2, 1, 0) -DEF(negsetcond_i64, 1, 2, 1, 0) DEF(movcond_i64, 1, 4, 1, 0) /* load/store */ DEF(ld8u_i64, 1, 1, 1, 0) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 8248648c0c..712a57fb54 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -1995,7 +1995,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) if ((ld_dst == B11_8) + (ld_dst == B7_4) != 1 || mv_src >= 0) { goto fail; } - op_opc = INDEX_op_setcond_i32; /* placeholder */ + op_opc = INDEX_op_setcond; /* placeholder */ op_src = (ld_dst == B11_8 ? B7_4 : B11_8); op_arg = REG(op_src); @@ -2030,7 +2030,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) if (ld_dst != B11_8 || ld_dst != B7_4 || mv_src >= 0) { goto fail; } - op_opc = INDEX_op_setcond_i32; + op_opc = INDEX_op_setcond; op_arg = tcg_constant_i32(0); NEXT_INSN; @@ -2147,7 +2147,7 @@ static void decode_gusa(DisasContext *ctx, CPUSH4State *env) } break; - case INDEX_op_setcond_i32: + case INDEX_op_setcond: if (st_src == ld_dst) { goto fail; } diff --git a/tcg/optimize.c b/tcg/optimize.c index 0affde323b..e53dbd4290 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1996,35 +1996,19 @@ static bool fold_movcond(OptContext *ctx, TCGOp *op) if (ti_is_const(tt) && ti_is_const(ft)) { uint64_t tv = ti_const_val(tt); uint64_t fv = ti_const_val(ft); - TCGOpcode opc, negopc; TCGCond cond = op->args[5]; - switch (ctx->type) { - case TCG_TYPE_I32: - opc = INDEX_op_setcond_i32; - negopc = INDEX_op_negsetcond_i32; - tv = (int32_t)tv; - fv = (int32_t)fv; - break; - case TCG_TYPE_I64: - opc = INDEX_op_setcond_i64; - negopc = INDEX_op_negsetcond_i64; - break; - default: - g_assert_not_reached(); - } - if (tv == 1 && fv == 0) { - op->opc = opc; + op->opc = INDEX_op_setcond; op->args[3] = cond; } else if (fv == 1 && tv == 0) { - op->opc = opc; + op->opc = INDEX_op_setcond; op->args[3] = tcg_invert_cond(cond); } else if (tv == -1 && fv == 0) { - op->opc = negopc; + op->opc = INDEX_op_negsetcond; op->args[3] = cond; } else if (fv == -1 && tv == 0) { - op->opc = negopc; + op->opc = INDEX_op_negsetcond; op->args[3] = tcg_invert_cond(cond); } } @@ -2526,14 +2510,14 @@ static bool fold_setcond2(OptContext *ctx, TCGOp *op) do_setcond_low: op->args[2] = op->args[3]; op->args[3] = cond; - op->opc = INDEX_op_setcond_i32; + op->opc = INDEX_op_setcond; return fold_setcond(ctx, op); do_setcond_high: op->args[1] = op->args[2]; op->args[2] = op->args[4]; op->args[3] = cond; - op->opc = INDEX_op_setcond_i32; + op->opc = INDEX_op_setcond; return fold_setcond(ctx, op); } @@ -3025,10 +3009,10 @@ void tcg_optimize(TCGContext *s) case INDEX_op_shr: done = fold_shift(&ctx, op); break; - CASE_OP_32_64(setcond): + case INDEX_op_setcond: done = fold_setcond(&ctx, op); break; - CASE_OP_32_64(negsetcond): + case INDEX_op_negsetcond: done = fold_negsetcond(&ctx, op); break; case INDEX_op_setcond2_i32: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 413b68352d..477dfc25b7 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -552,7 +552,7 @@ void tcg_gen_setcond_i32(TCGCond cond, TCGv_i32 ret, } else if (cond == TCG_COND_NEVER) { tcg_gen_movi_i32(ret, 0); } else { - tcg_gen_op4i_i32(INDEX_op_setcond_i32, ret, arg1, arg2, cond); + tcg_gen_op4i_i32(INDEX_op_setcond, ret, arg1, arg2, cond); } } @@ -570,7 +570,7 @@ void tcg_gen_negsetcond_i32(TCGCond cond, TCGv_i32 ret, } else if (cond == TCG_COND_NEVER) { tcg_gen_movi_i32(ret, 0); } else { - tcg_gen_op4i_i32(INDEX_op_negsetcond_i32, ret, arg1, arg2, cond); + tcg_gen_op4i_i32(INDEX_op_negsetcond, ret, arg1, arg2, cond); } } @@ -1911,7 +1911,7 @@ void tcg_gen_setcond_i64(TCGCond cond, TCGv_i64 ret, TCGV_LOW(arg2), TCGV_HIGH(arg2), cond); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } else { - tcg_gen_op4i_i64(INDEX_op_setcond_i64, ret, arg1, arg2, cond); + tcg_gen_op4i_i64(INDEX_op_setcond, ret, arg1, arg2, cond); } } } @@ -1948,7 +1948,7 @@ void tcg_gen_negsetcond_i64(TCGCond cond, TCGv_i64 ret, } else if (cond == TCG_COND_NEVER) { tcg_gen_movi_i64(ret, 0); } else if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op4i_i64(INDEX_op_negsetcond_i64, ret, arg1, arg2, cond); + tcg_gen_op4i_i64(INDEX_op_negsetcond, ret, arg1, arg2, cond); } else { tcg_gen_op6i_i32(INDEX_op_setcond2_i32, TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), diff --git a/tcg/tcg.c b/tcg/tcg.c index 90e82e7ed0..49fbf1f561 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1055,8 +1055,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_muluh, TCGOutOpBinary, outop_muluh), OUTOP(INDEX_op_nand, TCGOutOpBinary, outop_nand), OUTOP(INDEX_op_neg, TCGOutOpUnary, outop_neg), - OUTOP(INDEX_op_negsetcond_i32, TCGOutOpSetcond, outop_negsetcond), - OUTOP(INDEX_op_negsetcond_i64, TCGOutOpSetcond, outop_negsetcond), + OUTOP(INDEX_op_negsetcond, TCGOutOpSetcond, outop_negsetcond), OUTOP(INDEX_op_nor, TCGOutOpBinary, outop_nor), OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), @@ -1066,8 +1065,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), - OUTOP(INDEX_op_setcond_i32, TCGOutOpSetcond, outop_setcond), - OUTOP(INDEX_op_setcond_i64, TCGOutOpSetcond, outop_setcond), + OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -2275,12 +2273,12 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add: case INDEX_op_and: case INDEX_op_mov: + case INDEX_op_negsetcond: case INDEX_op_or: + case INDEX_op_setcond: case INDEX_op_xor: return has_type; - case INDEX_op_setcond_i32: - case INDEX_op_negsetcond_i32: case INDEX_op_brcond_i32: case INDEX_op_movcond_i32: case INDEX_op_ld8u_i32: @@ -2311,8 +2309,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i64: case INDEX_op_brcond_i64: case INDEX_op_movcond_i64: case INDEX_op_ld8u_i64: @@ -2864,14 +2860,12 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) } switch (c) { case INDEX_op_brcond_i32: - case INDEX_op_setcond_i32: - case INDEX_op_negsetcond_i32: + case INDEX_op_setcond: + case INDEX_op_negsetcond: case INDEX_op_movcond_i32: case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: case INDEX_op_brcond_i64: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i64: case INDEX_op_movcond_i64: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: @@ -5068,10 +5062,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_brcond_i64: op_cond = op->args[2]; break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: + case INDEX_op_setcond: + case INDEX_op_negsetcond: case INDEX_op_cmp_vec: op_cond = op->args[3]; break; @@ -5494,10 +5486,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: - case INDEX_op_negsetcond_i32: - case INDEX_op_negsetcond_i64: + case INDEX_op_setcond: + case INDEX_op_negsetcond: { const TCGOutOpSetcond *out = container_of(all_outop[op->opc], TCGOutOpSetcond, base); diff --git a/tcg/tci.c b/tcg/tci.c index 569b5c7ed0..d97ca1fade 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -438,10 +438,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_l(insn, tb_ptr, &ptr); tb_ptr = ptr; continue; - case INDEX_op_setcond_i32: - tci_args_rrrc(insn, &r0, &r1, &r2, &condition); - regs[r0] = tci_compare32(regs[r1], regs[r2], condition); - break; case INDEX_op_movcond_i32: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); tmp32 = tci_compare32(regs[r1], regs[r2], condition); @@ -455,7 +451,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = tci_compare64(T1, T2, condition); break; #elif TCG_TARGET_REG_BITS == 64 - case INDEX_op_setcond_i64: + case INDEX_op_setcond: tci_args_rrrc(insn, &r0, &r1, &r2, &condition); regs[r0] = tci_compare64(regs[r1], regs[r2], condition); break; @@ -628,6 +624,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tmp32 = regs[r1]; regs[r0] = tmp32 ? ctz32(tmp32) : regs[r2]; break; + case INDEX_op_tci_setcond32: + tci_args_rrrc(insn, &r0, &r1, &r2, &condition); + regs[r0] = tci_compare32(regs[r1], regs[r2], condition); + break; /* Shift/rotate operations. */ @@ -971,8 +971,8 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), ptr); break; - case INDEX_op_setcond_i32: - case INDEX_op_setcond_i64: + case INDEX_op_setcond: + case INDEX_op_tci_setcond32: tci_args_rrrc(insn, &r0, &r1, &r2, &c); info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s", op_name, str_r(r0), str_r(r1), str_r(r2), str_c(c)); diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 2bb346f4c8..27b4574e4f 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -10,3 +10,4 @@ DEF(tci_rems32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rotl32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rotr32, 1, 2, 0, TCG_OPF_NOT_PRESENT) +DEF(tci_setcond32, 1, 2, 1, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1b75aba698..d49c767de5 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -942,8 +942,8 @@ static void tgen_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg arg1, TCGReg arg2) { TCGOpcode opc = (type == TCG_TYPE_I32 - ? INDEX_op_setcond_i32 - : INDEX_op_setcond_i64); + ? INDEX_op_tci_setcond32 + : INDEX_op_setcond); tcg_out_op_rrrc(s, opc, dest, arg1, arg2, cond); } From 99ac4706b35a2c16e2bf4437e966fc39c41ed67d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 11:40:06 -0800 Subject: [PATCH 0437/2760] tcg: Convert brcond to TCGOutOpBrcond Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 39 +++++++++++++++------------- tcg/arm/tcg-target.c.inc | 27 ++++++++++++++----- tcg/i386/tcg-target.c.inc | 28 ++++++++++++++------ tcg/loongarch64/tcg-target-con-set.h | 2 +- tcg/loongarch64/tcg-target.c.inc | 18 +++++-------- tcg/mips/tcg-target-con-set.h | 4 +-- tcg/mips/tcg-target.c.inc | 20 +++++++------- tcg/ppc/tcg-target.c.inc | 31 +++++++++++----------- tcg/riscv/tcg-target-con-set.h | 2 +- tcg/riscv/tcg-target.c.inc | 18 +++++-------- tcg/s390x/tcg-target.c.inc | 31 ++++++++++++---------- tcg/sparc64/tcg-target-con-set.h | 2 +- tcg/sparc64/tcg-target.c.inc | 38 ++++++++++++++++++++------- tcg/tcg.c | 26 +++++++++++++++++++ tcg/tci.c | 9 ++----- tcg/tci/tcg-target.c.inc | 20 +++++++------- 16 files changed, 190 insertions(+), 125 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 2524e73ff4..e3d8e9090f 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1424,8 +1424,16 @@ static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) } } -static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a, - TCGArg b, bool b_const, TCGLabel *l) +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, + TCGReg a, TCGReg b, TCGLabel *l) +{ + tgen_cmp(s, type, c, a, b); + tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0); + tcg_out_insn(s, 3202, B_C, c, 0); +} + +static void tgen_brcondi(TCGContext *s, TCGType ext, TCGCond c, + TCGReg a, tcg_target_long b, TCGLabel *l) { int tbit = -1; bool need_cmp = true; @@ -1434,14 +1442,14 @@ static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a, case TCG_COND_EQ: case TCG_COND_NE: /* cmp xN,0; b.ne L -> cbnz xN,L */ - if (b_const && b == 0) { + if (b == 0) { need_cmp = false; } break; case TCG_COND_LT: case TCG_COND_GE: /* cmp xN,0; b.mi L -> tbnz xN,63,L */ - if (b_const && b == 0) { + if (b == 0) { c = (c == TCG_COND_LT ? TCG_COND_TSTNE : TCG_COND_TSTEQ); tbit = ext ? 63 : 31; need_cmp = false; @@ -1450,14 +1458,14 @@ static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a, case TCG_COND_TSTEQ: case TCG_COND_TSTNE: /* tst xN,0xffffffff; b.ne L -> cbnz wN,L */ - if (b_const && b == UINT32_MAX) { + if (b == UINT32_MAX) { c = tcg_tst_eqne_cond(c); ext = TCG_TYPE_I32; need_cmp = false; break; } /* tst xN,1< tbnz xN,B,L */ - if (b_const && is_power_of_2(b)) { + if (is_power_of_2(b)) { tbit = ctz64(b); need_cmp = false; } @@ -1467,7 +1475,7 @@ static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a, } if (need_cmp) { - tcg_out_cmp(s, ext, c, a, b, b_const); + tgen_cmpi(s, ext, c, a, b); tcg_out_reloc(s, s->code_ptr, R_AARCH64_CONDBR19, l, 0); tcg_out_insn(s, 3202, B_C, c, 0); return; @@ -1500,6 +1508,12 @@ static void tcg_out_brcond(TCGContext *s, TCGType ext, TCGCond c, TCGArg a, } } +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rC), + .out_rr = tgen_brcond, + .out_ri = tgen_brcondi, +}; + static inline void tcg_out_rev(TCGContext *s, int ext, MemOp s_bits, TCGReg rd, TCGReg rn) { @@ -2565,13 +2579,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_brcond_i32: - a1 = (int32_t)a1; - /* FALLTHRU */ - case INDEX_op_brcond_i64: - tcg_out_brcond(s, ext, a2, a0, a1, const_args[1], arg_label(args[3])); - break; - case INDEX_op_movcond_i32: a2 = (int32_t)a2; /* FALLTHRU */ @@ -3159,10 +3166,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(r, rC); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rz, rz); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 0f2a029f6d..4c7537cbeb 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2181,6 +2181,26 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, TCGReg a1, TCGLabel *l) +{ + cond = tgen_cmp(s, cond, a0, a1); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[cond], l); +} + +static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a0, tcg_target_long a1, TCGLabel *l) +{ + cond = tgen_cmpi(s, cond, a0, a1); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[cond], l); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rIN), + .out_rr = tgen_brcond, + .out_ri = tgen_brcondi, +}; + static void finish_setcond(TCGContext *s, TCGCond cond, TCGReg ret, bool neg) { tcg_out_movi32(s, tcg_cond_to_arm_cond[tcg_invert_cond(cond)], ret, 0); @@ -2317,11 +2337,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_brcond_i32: - c = tcg_out_cmp(s, args[2], args[0], args[1], const_args[1]); - tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[3])); - break; - case INDEX_op_brcond2_i32: c = tcg_out_cmp2(s, args, const_args); tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[5])); @@ -2421,8 +2436,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_brcond_i32: - return C_O0_I2(r, rIN); case INDEX_op_deposit_i32: return C_O1_I2(r, 0, rZ); case INDEX_op_extract2_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d3a3f1f7fb..d2eff3b617 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1642,6 +1642,26 @@ static void tcg_out_brcond(TCGContext *s, int rexw, TCGCond cond, tcg_out_jxx(s, jcc, label, small); } +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *label) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_brcond(s, rexw, cond, arg1, arg2, false, label, false); +} + +static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, tcg_target_long arg2, TCGLabel *label) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_brcond(s, rexw, cond, arg1, arg2, true, label, false); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, reT), + .out_rr = tgen_brcond, + .out_ri = tgen_brcondi, +}; + #if TCG_TARGET_REG_BITS == 32 static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, const int *const_args, bool small) @@ -3124,10 +3144,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(brcond): - tcg_out_brcond(s, rexw, a2, a0, a1, const_args[1], - arg_label(args[3]), 0); - break; OP_32_64(movcond): tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]); break; @@ -3936,10 +3952,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(r, reT); - case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index c145d4ab66..dfe55c6fe8 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -16,7 +16,7 @@ */ C_O0_I1(r) C_O0_I2(rz, r) -C_O0_I2(rz, rz) +C_O0_I2(r, rz) C_O0_I2(w, r) C_O0_I3(r, r, r) C_O1_I1(r, r) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 87e8b843f8..53bba07c49 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -767,8 +767,8 @@ static const struct { [TCG_COND_GTU] = { OPC_BGTU, false } }; -static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, - TCGReg arg2, TCGLabel *l) +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *l) { LoongArchInsn op = tcg_brcond_to_loongarch[cond].op; @@ -785,6 +785,11 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, tcg_out32(s, encode_djsk16_insn(op, arg1, arg2, 0)); } +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rz), + .out_rr = tgen_brcond, +}; + static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) { TCGReg link = tail ? TCG_REG_ZERO : TCG_REG_RA; @@ -1771,11 +1776,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_b(s, 0); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); - break; - case INDEX_op_extrh_i64_i32: tcg_out_opc_srai_d(s, a0, a1, 32); break; @@ -2441,10 +2441,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(r, r, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(rz, rz); - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index 67dfab2aed..a80630a8b4 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -10,12 +10,10 @@ * tcg-target-con-str.h; the constraint combination is inclusive or. */ C_O0_I1(r) +C_O0_I2(r, rz) C_O0_I2(rz, r) -C_O0_I2(rz, rz) -C_O0_I3(rz, r, r) C_O0_I3(rz, rz, r) C_O0_I4(rz, rz, rz, rz) -C_O0_I4(rz, rz, r, r) C_O1_I1(r, r) C_O1_I2(r, 0, rz) C_O1_I2(r, r, r) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 51b3ea4bb0..a942905dc4 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -988,8 +988,8 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rrr = tgen_negsetcond, }; -static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, - TCGReg arg2, TCGLabel *l) +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *l) { static const MIPSInsn b_zero[16] = { [TCG_COND_LT] = OPC_BLTZ, @@ -1034,6 +1034,11 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, tcg_out_nop(s); } +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rz), + .out_rr = tgen_brcond, +}; + static int tcg_out_setcond2_int(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) { @@ -2178,8 +2183,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; case INDEX_op_br: - tcg_out_brcond(s, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, - arg_label(a0)); + tgen_brcond(s, TCG_TYPE_I32, TCG_COND_EQ, + TCG_REG_ZERO, TCG_REG_ZERO, arg_label(a0)); break; case INDEX_op_ld8u_i32: @@ -2283,10 +2288,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); - break; case INDEX_op_brcond2_i32: tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5])); break; @@ -2391,9 +2392,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rz); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(rz, rz); case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return (use_mips32r6_instructions diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 0a66351124..819abdc906 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2124,14 +2124,26 @@ static void tcg_out_bc_lab(TCGContext *s, TCGCond cond, TCGLabel *l) tcg_out_bc(s, cond, bd); } -static void tcg_out_brcond(TCGContext *s, TCGCond cond, - TCGArg arg1, TCGArg arg2, int const_arg2, - TCGLabel *l, TCGType type) +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *l) { - tcg_out_cmp(s, cond, arg1, arg2, const_arg2, 0, type); + tcg_out_cmp(s, cond, arg1, arg2, false, 0, type); tcg_out_bc_lab(s, cond, l); } +static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, tcg_target_long arg2, TCGLabel *l) +{ + tcg_out_cmp(s, cond, arg1, arg2, true, 0, type); + tcg_out_bc_lab(s, cond, l); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rC), + .out_rr = tgen_brcond, + .out_ri = tgen_brcondi, +}; + static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond, TCGArg dest, TCGArg c1, TCGArg c2, TCGArg v1, TCGArg v2, bool const_c2) @@ -3457,14 +3469,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_brcond_i32: - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], - arg_label(args[3]), TCG_TYPE_I32); - break; - case INDEX_op_brcond_i64: - tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], - arg_label(args[3]), TCG_TYPE_I64); - break; case INDEX_op_brcond2_i32: tcg_out_brcond2(s, args, const_args); break; @@ -4293,9 +4297,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(r, rC); case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, r, rC, rZ, rZ); diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index f0d3cb81bd..5ff2c2db60 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -11,7 +11,7 @@ */ C_O0_I1(r) C_O0_I2(rz, r) -C_O0_I2(rz, rz) +C_O0_I2(r, rz) C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, ri) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 05114b5c5f..1d7194e883 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1184,8 +1184,8 @@ static const struct { [TCG_COND_GTU] = { OPC_BLTU, true } }; -static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, - TCGReg arg2, TCGLabel *l) +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *l) { RISCVInsn op = tcg_brcond_to_riscv[cond].op; @@ -1201,6 +1201,11 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGReg arg1, tcg_out_opc_branch(s, op, arg1, arg2, 0); } +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rz), + .out_rr = tgen_brcond, +}; + #define SETCOND_INV TCG_TARGET_NB_REGS #define SETCOND_NEZ (SETCOND_INV << 1) #define SETCOND_FLAGS (SETCOND_INV | SETCOND_NEZ) @@ -2516,11 +2521,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const_args[4], const_args[5], true, false); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - tcg_out_brcond(s, a2, a0, a1, arg_label(args[3])); - break; - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: tcg_out_movcond(s, args[5], a0, a1, a2, c2, @@ -2863,10 +2863,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(rz, rz); - case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, r, rI, rM, rM); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 3c04b87109..d3650636aa 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1693,6 +1693,24 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond c, tgen_branch(s, cc, l); } +static void tgen_brcondr(TCGContext *s, TCGType type, TCGCond c, + TCGReg a0, TCGReg a1, TCGLabel *l) +{ + tgen_brcond(s, type, c, a0, a1, false, l); +} + +static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond c, + TCGReg a0, tcg_target_long a1, TCGLabel *l) +{ + tgen_brcond(s, type, c, a0, a1, true, l); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rC), + .out_rr = tgen_brcondr, + .out_ri = tgen_brcondi, +}; + static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *dest) { ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1; @@ -2857,10 +2875,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_branch(s, S390_CC_ALWAYS, arg_label(args[0])); break; - case INDEX_op_brcond_i32: - tgen_brcond(s, TCG_TYPE_I32, args[2], args[0], - args[1], const_args[1], arg_label(args[3])); - break; case INDEX_op_movcond_i32: tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2], const_args[2], args[3], const_args[3], args[4]); @@ -2934,10 +2948,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, SLBGR, args[1], args[5]); break; - case INDEX_op_brcond_i64: - tgen_brcond(s, TCG_TYPE_I64, args[2], args[0], - args[1], const_args[1], arg_label(args[3])); - break; case INDEX_op_movcond_i64: tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], args[2], const_args[2], args[3], const_args[3], args[4]); @@ -3454,11 +3464,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_brcond_i32: - return C_O0_I2(r, ri); - case INDEX_op_brcond_i64: - return C_O0_I2(r, rC); - case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index ca7bbf0a2f..9f66e52ec6 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -11,7 +11,7 @@ */ C_O0_I1(r) C_O0_I2(rz, r) -C_O0_I2(rz, rJ) +C_O0_I2(r, rJ) C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, rJ) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index dcbe6a8f47..68f38b7d71 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -822,6 +822,35 @@ static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, } } +static void tcg_out_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGArg arg2, bool const_arg2, + TCGLabel *l) +{ + if (type == TCG_TYPE_I32) { + tcg_out_brcond_i32(s, cond, arg1, arg2, const_arg2, l); + } else { + tcg_out_brcond_i64(s, cond, arg1, arg2, const_arg2, l); + } +} + +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, TCGReg arg2, TCGLabel *l) +{ + tcg_out_brcond(s, type, cond, arg1, arg2, false, l); +} + +static void tgen_brcondi(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg1, tcg_target_long arg2, TCGLabel *l) +{ + tcg_out_brcond(s, type, cond, arg1, arg2, true, l); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, rJ), + .out_rr = tgen_brcond, + .out_ri = tgen_brcondi, +}; + static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg ret, TCGReg c1, TCGArg c2, bool c2const, bool neg) @@ -1755,9 +1784,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STW); break; - case INDEX_op_brcond_i32: - tcg_out_brcond_i32(s, a2, a0, a1, const_args[1], arg_label(args[3])); - break; case INDEX_op_movcond_i32: tcg_out_movcond_i32(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); break; @@ -1796,9 +1822,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STX); break; - case INDEX_op_brcond_i64: - tcg_out_brcond_i64(s, a2, a0, a1, const_args[1], arg_label(args[3])); - break; case INDEX_op_movcond_i64: tcg_out_movcond_i64(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); break; @@ -1872,9 +1895,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(rz, rJ); case INDEX_op_movcond_i32: case INDEX_op_movcond_i64: return C_O1_I4(r, rz, rJ, rI, 0); diff --git a/tcg/tcg.c b/tcg/tcg.c index 49fbf1f561..dbaa574cb5 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -986,6 +986,14 @@ typedef struct TCGOutOpBinary { TCGReg a0, TCGReg a1, tcg_target_long a2); } TCGOutOpBinary; +typedef struct TCGOutOpBrcond { + TCGOutOp base; + void (*out_rr)(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a1, TCGReg a2, TCGLabel *label); + void (*out_ri)(TCGContext *s, TCGType type, TCGCond cond, + TCGReg a1, tcg_target_long a2, TCGLabel *label); +} TCGOutOpBrcond; + typedef struct TCGOutOpDivRem { TCGOutOp base; void (*out_rr01r)(TCGContext *s, TCGType type, @@ -1040,6 +1048,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), + OUTOP(INDEX_op_brcond_i32, TCGOutOpBrcond, outop_brcond), + OUTOP(INDEX_op_brcond_i64, TCGOutOpBrcond, outop_brcond), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -5486,6 +5496,22 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: + { + const TCGOutOpBrcond *out = &outop_brcond; + TCGCond cond = new_args[2]; + TCGLabel *label = arg_label(new_args[3]); + + tcg_debug_assert(!const_args[0]); + if (const_args[1]) { + out->out_ri(s, type, cond, new_args[0], new_args[1], label); + } else { + out->out_rr(s, type, cond, new_args[0], new_args[1], label); + } + } + break; + case INDEX_op_setcond: case INDEX_op_negsetcond: { diff --git a/tcg/tci.c b/tcg/tci.c index d97ca1fade..d431cad6fd 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -665,8 +665,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = sextract32(regs[r1], pos, len); break; case INDEX_op_brcond_i32: + case INDEX_op_brcond_i64: tci_args_rl(insn, tb_ptr, &r0, &ptr); - if ((uint32_t)regs[r0]) { + if (regs[r0]) { tb_ptr = ptr; } break; @@ -784,12 +785,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrbb(insn, &r0, &r1, &pos, &len); regs[r0] = sextract64(regs[r1], pos, len); break; - case INDEX_op_brcond_i64: - tci_args_rl(insn, tb_ptr, &r0, &ptr); - if (regs[r0]) { - tb_ptr = ptr; - } - break; case INDEX_op_ext_i32_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = (int32_t)regs[r1]; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d49c767de5..2c7fb5d75f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -81,10 +81,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return C_O1_I2(r, r, r); - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: - return C_O0_I2(r, r); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: @@ -964,6 +960,17 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rrr = tgen_negsetcond, }; +static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg arg0, TCGReg arg1, TCGLabel *l) +{ + tgen_setcond(s, type, cond, TCG_REG_TMP, arg0, arg1); + tcg_out_op_rl(s, INDEX_op_brcond_i32, TCG_REG_TMP, l); +} + +static const TCGOutOpBrcond outop_brcond = { + .base.static_constraint = C_O0_I2(r, r), + .out_rr = tgen_brcond, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1011,11 +1018,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rrbb(s, opc, args[0], args[1], args[2], args[3]); break; - CASE_32_64(brcond) - tgen_setcond(s, type, args[2], TCG_REG_TMP, args[0], args[1]); - tcg_out_op_rl(s, opc, TCG_REG_TMP, arg_label(args[3])); - break; - case INDEX_op_bswap32_i32: /* Optional (TCG_TARGET_HAS_bswap32_i32). */ case INDEX_op_bswap64_i64: /* Optional (TCG_TARGET_HAS_bswap64_i64). */ tcg_out_op_rr(s, opc, args[0], args[1]); From b6d69fcefbd45ca33b896abfbc8e27e0f713bdf0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 11:49:22 -0800 Subject: [PATCH 0438/2760] tcg: Merge INDEX_op_brcond_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 4 +--- tcg/optimize.c | 6 +++--- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 24 ++++++++---------------- tcg/tci.c | 6 ++---- tcg/tci/tcg-target.c.inc | 4 ++-- 7 files changed, 19 insertions(+), 31 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index d3283265cd..18f02c5122 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -239,7 +239,7 @@ Jumps/Labels - | Jump to label. - * - brcond_i32/i64 *t0*, *t1*, *cond*, *label* + * - brcond *t0*, *t1*, *cond*, *label* - | Conditional jump if *t0* *cond* *t1* is true. *cond* can be: | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index f40bb5796a..d40ca001c2 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -34,6 +34,7 @@ DEF(set_label, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) DEF(call, 0, 0, 3, TCG_OPF_CALL_CLOBBER | TCG_OPF_NOT_PRESENT) DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) +DEF(brcond, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH | TCG_OPF_INT) DEF(mb, 0, 0, 1, TCG_OPF_NOT_PRESENT) @@ -89,8 +90,6 @@ DEF(extract_i32, 1, 1, 2, 0) DEF(sextract_i32, 1, 1, 2, 0) DEF(extract2_i32, 1, 2, 1, 0) -DEF(brcond_i32, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) - DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) @@ -124,7 +123,6 @@ DEF(extu_i32_i64, 1, 1, 0, 0) DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) -DEF(brcond_i64, 0, 2, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index e53dbd4290..d0cb4588ed 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1529,14 +1529,14 @@ static bool fold_brcond2(OptContext *ctx, TCGOp *op) break; do_brcond_low: - op->opc = INDEX_op_brcond_i32; + op->opc = INDEX_op_brcond; op->args[1] = op->args[2]; op->args[2] = cond; op->args[3] = label; return fold_brcond(ctx, op); do_brcond_high: - op->opc = INDEX_op_brcond_i32; + op->opc = INDEX_op_brcond; op->args[0] = op->args[1]; op->args[1] = op->args[3]; op->args[2] = cond; @@ -2864,7 +2864,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_andc_vec: done = fold_andc(&ctx, op); break; - CASE_OP_32_64(brcond): + case INDEX_op_brcond: done = fold_brcond(&ctx, op); break; case INDEX_op_brcond2_i32: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 477dfc25b7..041ca95f0d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -529,7 +529,7 @@ void tcg_gen_brcond_i32(TCGCond cond, TCGv_i32 arg1, TCGv_i32 arg2, TCGLabel *l) if (cond == TCG_COND_ALWAYS) { tcg_gen_br(l); } else if (cond != TCG_COND_NEVER) { - TCGOp *op = tcg_gen_op4ii_i32(INDEX_op_brcond_i32, + TCGOp *op = tcg_gen_op4ii_i32(INDEX_op_brcond, arg1, arg2, cond, label_arg(l)); add_as_label_use(l, op); } @@ -1874,7 +1874,7 @@ void tcg_gen_brcond_i64(TCGCond cond, TCGv_i64 arg1, TCGv_i64 arg2, TCGLabel *l) TCGV_HIGH(arg1), TCGV_LOW(arg2), TCGV_HIGH(arg2), cond, label_arg(l)); } else { - op = tcg_gen_op4ii_i64(INDEX_op_brcond_i64, arg1, arg2, cond, + op = tcg_gen_op4ii_i64(INDEX_op_brcond, arg1, arg2, cond, label_arg(l)); } add_as_label_use(l, op); diff --git a/tcg/tcg.c b/tcg/tcg.c index dbaa574cb5..4dc6995d00 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1048,8 +1048,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), - OUTOP(INDEX_op_brcond_i32, TCGOutOpBrcond, outop_brcond), - OUTOP(INDEX_op_brcond_i64, TCGOutOpBrcond, outop_brcond), + OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -2282,6 +2281,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add: case INDEX_op_and: + case INDEX_op_brcond: case INDEX_op_mov: case INDEX_op_negsetcond: case INDEX_op_or: @@ -2289,7 +2289,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor: return has_type; - case INDEX_op_brcond_i32: case INDEX_op_movcond_i32: case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: @@ -2319,7 +2318,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; - case INDEX_op_brcond_i64: case INDEX_op_movcond_i64: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: @@ -2869,13 +2867,12 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) op->args[k++])); } switch (c) { - case INDEX_op_brcond_i32: + case INDEX_op_brcond: case INDEX_op_setcond: case INDEX_op_negsetcond: case INDEX_op_movcond_i32: case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: - case INDEX_op_brcond_i64: case INDEX_op_movcond_i64: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: @@ -2961,8 +2958,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) switch (c) { case INDEX_op_set_label: case INDEX_op_br: - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: case INDEX_op_brcond2_i32: col += ne_fprintf(f, "%s$L%d", k ? "," : "", arg_label(op->args[k])->id); @@ -3417,8 +3413,7 @@ void tcg_op_remove(TCGContext *s, TCGOp *op) case INDEX_op_br: remove_label_use(op, 0); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: remove_label_use(op, 3); break; case INDEX_op_brcond2_i32: @@ -3519,8 +3514,7 @@ static void move_label_uses(TCGLabel *to, TCGLabel *from) case INDEX_op_br: op->args[0] = label_arg(to); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: op->args[3] = label_arg(to); break; case INDEX_op_brcond2_i32: @@ -5068,8 +5062,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) o_allocated_regs = s->reserved_regs; switch (op->opc) { - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: op_cond = op->args[2]; break; case INDEX_op_setcond: @@ -5496,8 +5489,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: { const TCGOutOpBrcond *out = &outop_brcond; TCGCond cond = new_args[2]; diff --git a/tcg/tci.c b/tcg/tci.c index d431cad6fd..4c5dc16ecb 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -664,8 +664,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrbb(insn, &r0, &r1, &pos, &len); regs[r0] = sextract32(regs[r1], pos, len); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: tci_args_rl(insn, tb_ptr, &r0, &ptr); if (regs[r0]) { tb_ptr = ptr; @@ -959,8 +958,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) info->fprintf_func(info->stream, "%-12s %d, %p", op_name, len, ptr); break; - case INDEX_op_brcond_i32: - case INDEX_op_brcond_i64: + case INDEX_op_brcond: tci_args_rl(insn, tb_ptr, &r0, &ptr); info->fprintf_func(info->stream, "%-12s %s, 0, ne, %p", op_name, str_r(r0), ptr); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2c7fb5d75f..18628b957a 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -964,7 +964,7 @@ static void tgen_brcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg arg0, TCGReg arg1, TCGLabel *l) { tgen_setcond(s, type, cond, TCG_REG_TMP, arg0, arg1); - tcg_out_op_rl(s, INDEX_op_brcond_i32, TCG_REG_TMP, l); + tcg_out_op_rl(s, INDEX_op_brcond, TCG_REG_TMP, l); } static const TCGOutOpBrcond outop_brcond = { @@ -1047,7 +1047,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_brcond2_i32: tcg_out_op_rrrrrc(s, INDEX_op_setcond2_i32, TCG_REG_TMP, args[0], args[1], args[2], args[3], args[4]); - tcg_out_op_rl(s, INDEX_op_brcond_i32, TCG_REG_TMP, arg_label(args[5])); + tcg_out_op_rl(s, INDEX_op_brcond, TCG_REG_TMP, arg_label(args[5])); break; #endif From 1f406e46785e60e274a9c581d6fd07e05a6ff4e0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 13:29:39 -0800 Subject: [PATCH 0439/2760] tcg: Convert movcond to TCGOutOpMovcond Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 26 +++++++++++++------------- tcg/arm/tcg-target.c.inc | 24 ++++++++++++++---------- tcg/i386/tcg-target.c.inc | 23 +++++++++++------------ tcg/loongarch64/tcg-target-con-set.h | 2 +- tcg/loongarch64/tcg-target.c.inc | 23 +++++++++-------------- tcg/mips/tcg-target-con-set.h | 3 ++- tcg/mips/tcg-target.c.inc | 25 ++++++++++++------------- tcg/ppc/tcg-target.c.inc | 24 ++++++++---------------- tcg/riscv/tcg-target.c.inc | 26 ++++++++++---------------- tcg/s390x/tcg-target-con-set.h | 1 - tcg/s390x/tcg-target.c.inc | 26 ++++++++------------------ tcg/sparc64/tcg-target-con-set.h | 2 +- tcg/sparc64/tcg-target.c.inc | 28 ++++++++++++++++------------ tcg/tcg.c | 23 +++++++++++++++++++++++ tcg/tci.c | 12 ++++++------ tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 18 +++++++++++++++--- 17 files changed, 150 insertions(+), 137 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index e3d8e9090f..ee45e7e244 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2513,6 +2513,19 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg vt, bool const_vt, TCGArg vf, bool const_vf) +{ + tcg_out_cmp(s, type, cond, c1, c2, const_c2); + tcg_out_insn(s, 3506, CSEL, type, ret, vt, vf, cond); +} + +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rC, rz, rz), + .out = tgen_movcond, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2521,7 +2534,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a0 = args[0]; TCGArg a1 = args[1]; TCGArg a2 = args[2]; - int c2 = const_args[2]; switch (opc) { case INDEX_op_goto_ptr: @@ -2579,14 +2591,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); break; - case INDEX_op_movcond_i32: - a2 = (int32_t)a2; - /* FALLTHRU */ - case INDEX_op_movcond_i64: - tcg_out_cmp(s, ext, args[5], a1, a2, c2); - tcg_out_insn(s, 3506, CSEL, ext, a0, args[3], args[4], args[5]); - break; - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: tcg_out_qemu_ld(s, a0, a1, a2, ext); @@ -3166,10 +3170,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, r, rC, rz, rz); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 4c7537cbeb..3d864c1c1e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2247,6 +2247,20 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf) +{ + cond = tcg_out_cmp(s, cond, c1, c2, const_c2); + tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[cond], ARITH_MOV, ARITH_MVN, + ret, 0, vt, const_vt); +} + +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rIN, rIK, 0), + .out = tgen_movcond, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2288,14 +2302,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); break; - case INDEX_op_movcond_i32: - /* Constraints mean that v2 is always in the same register as dest, - * so we only need to do "if condition passed, move v1 to dest". - */ - c = tcg_out_cmp(s, args[5], args[1], args[2], const_args[2]); - tcg_out_dat_rIK(s, tcg_cond_to_arm_cond[c], ARITH_MOV, - ARITH_MVN, args[0], 0, args[3], const_args[3]); - break; case INDEX_op_add2_i32: a0 = args[0], a1 = args[1], a2 = args[2]; a3 = args[3], a4 = args[4], a5 = args[5]; @@ -2440,8 +2446,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O1_I2(r, 0, rZ); case INDEX_op_extract2_i32: return C_O1_I2(r, rZ, rZ); - case INDEX_op_movcond_i32: - return C_O1_I4(r, r, rIN, rIK, 0); case INDEX_op_add2_i32: return C_O2_I4(r, r, r, r, rIN, rIK); case INDEX_op_sub2_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d2eff3b617..ae3a53a18a 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1900,14 +1900,21 @@ static void tcg_out_cmov(TCGContext *s, int jcc, int rexw, tcg_out_modrm(s, OPC_CMOVCC | jcc | rexw, dest, v1); } -static void tcg_out_movcond(TCGContext *s, int rexw, TCGCond cond, - TCGReg dest, TCGReg c1, TCGArg c2, int const_c2, - TCGReg v1) +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg vt, bool const_vt, + TCGArg vf, bool consf_vf) { + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; int jcc = tcg_out_cmp(s, cond, c1, c2, const_c2, rexw); - tcg_out_cmov(s, jcc, rexw, dest, v1); + tcg_out_cmov(s, jcc, rexw, dest, vt); } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, reT, r, 0), + .out = tgen_movcond, +}; + static void tcg_out_branch(TCGContext *s, int call, const tcg_insn_unit *dest) { intptr_t disp = tcg_pcrel_diff(s, dest) - 5; @@ -3144,10 +3151,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(movcond): - tcg_out_movcond(s, rexw, args[5], a0, a1, a2, const_a2, args[3]); - break; - OP_32_64(bswap16): if (a2 & TCG_BSWAP_OS) { /* Output must be sign-extended. */ @@ -3977,10 +3980,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return C_O1_I2(q, 0, qi); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, r, reT, r, 0); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/loongarch64/tcg-target-con-set.h b/tcg/loongarch64/tcg-target-con-set.h index dfe55c6fe8..fd731c0c0f 100644 --- a/tcg/loongarch64/tcg-target-con-set.h +++ b/tcg/loongarch64/tcg-target-con-set.h @@ -33,5 +33,5 @@ C_O1_I2(w, w, w) C_O1_I2(w, w, wM) C_O1_I2(w, w, wA) C_O1_I3(w, w, w, w) -C_O1_I4(r, rz, rJ, rz, rz) +C_O1_I4(r, r, rJ, rz, rz) C_N2_I1(r, r, r) diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 53bba07c49..c731096c64 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -723,11 +723,11 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; -static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, tcg_target_long c2, bool const2, - TCGReg v1, TCGReg v2) +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg v1, bool const_v1, TCGArg v2, bool const_v2) { - int tmpflags = tcg_out_setcond_int(s, cond, TCG_REG_TMP0, c1, c2, const2); + int tmpflags = tcg_out_setcond_int(s, cond, TCG_REG_TMP0, c1, c2, const_c2); TCGReg t; /* Standardize the test below to t != 0. */ @@ -747,6 +747,11 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rJ, rz, rz), + .out = tgen_movcond, +}; + /* * Branch helpers */ @@ -1759,7 +1764,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a1 = args[1]; TCGArg a2 = args[2]; TCGArg a3 = args[3]; - int c2 = const_args[2]; switch (opc) { case INDEX_op_mb: @@ -1849,11 +1853,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_revb_d(s, a0, a1); break; - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - tcg_out_movcond(s, args[5], a0, a1, a2, c2, args[3], args[4]); - break; - case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); @@ -2475,10 +2474,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) /* Must deposit into the same register as input */ return C_O1_I2(r, 0, rz); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, rz, rJ, rz, rz); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: case INDEX_op_dup_vec: diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index a80630a8b4..f5e4852b56 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -23,7 +23,8 @@ C_O1_I2(r, r, rIK) C_O1_I2(r, r, rJ) C_O1_I2(r, r, rz) C_O1_I2(r, r, rzW) -C_O1_I4(r, rz, rz, rz, 0) +C_O1_I4(r, r, rz, rz, 0) +C_O1_I4(r, r, rz, rz, rz) C_O1_I4(r, rz, rz, rz, rz) C_O2_I1(r, r, r) C_O2_I2(r, r, r, r) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index a942905dc4..3ce71a1c8d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1086,8 +1086,9 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, tcg_out_nop(s); } -static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg c1, TCGReg c2, TCGReg v1, TCGReg v2) +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg v1, bool const_v1, TCGArg v2, bool const_v2) { int tmpflags; bool eqz; @@ -1133,6 +1134,13 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = (use_mips32r6_instructions + ? C_O1_I4(r, r, rz, rz, rz) + : C_O1_I4(r, r, rz, rz, 0)), + .out = tgen_movcond, +}; + static void tcg_out_call_int(TCGContext *s, const tcg_insn_unit *arg, bool tail) { /* @@ -1726,7 +1734,8 @@ static void tgen_clz(TCGContext *s, TCGType type, if (use_mips32r6_instructions) { MIPSInsn opcv6 = type == TCG_TYPE_I32 ? OPC_CLZ_R6 : OPC_DCLZ_R6; tcg_out_opc_reg(s, opcv6, TCG_TMP0, a1, 0); - tcg_out_movcond(s, TCG_COND_EQ, a0, a1, 0, a2, TCG_TMP0); + tgen_movcond(s, TCG_TYPE_REG, TCG_COND_EQ, a0, a1, a2, false, + TCG_TMP0, false, TCG_REG_ZERO, false); } else { MIPSInsn opcv2 = type == TCG_TYPE_I32 ? OPC_CLZ : OPC_DCLZ; if (a0 == a2) { @@ -2292,11 +2301,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5])); break; - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - tcg_out_movcond(s, args[5], a0, a1, a2, args[3], args[4]); - break; - case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); break; @@ -2392,11 +2396,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rz); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return (use_mips32r6_instructions - ? C_O1_I4(r, rz, rz, rz, rz) - : C_O1_I4(r, rz, rz, rz, 0)); case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_O2_I4(r, r, rz, rz, rN, rN); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 819abdc906..339b3a0904 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2144,9 +2144,9 @@ static const TCGOutOpBrcond outop_brcond = { .out_ri = tgen_brcondi, }; -static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond, - TCGArg dest, TCGArg c1, TCGArg c2, TCGArg v1, - TCGArg v2, bool const_c2) +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg dest, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg v1, bool const_v1, TCGArg v2, bool const_v2) { /* If for some reason both inputs are zero, don't produce bad code. */ if (v1 == 0 && v2 == 0) { @@ -2192,6 +2192,11 @@ static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond, } } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rC, rZ, rZ), + .out = tgen_movcond, +}; + static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc, TCGArg a0, TCGArg a1, TCGArg a2, bool const_a2) { @@ -3578,15 +3583,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_movcond_i32: - tcg_out_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], args[2], - args[3], args[4], const_args[2]); - break; - case INDEX_op_movcond_i64: - tcg_out_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], args[2], - args[3], args[4], const_args[2]); - break; - #if TCG_TARGET_REG_BITS == 64 case INDEX_op_add2_i64: #else @@ -4297,10 +4293,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, r, rC, rZ, rZ); - case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rZ); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 1d7194e883..8d106d7f28 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1501,10 +1501,10 @@ static void tcg_out_movcond_br2(TCGContext *s, TCGCond cond, TCGReg ret, tcg_out_mov(s, TCG_TYPE_REG, ret, tmp); } -static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg cmp1, int cmp2, bool c_cmp2, - TCGReg val1, bool c_val1, - TCGReg val2, bool c_val2) +static void tcg_out_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg cmp1, TCGArg cmp2, bool c_cmp2, + TCGArg val1, bool c_val1, + TCGArg val2, bool c_val2) { int tmpflags; TCGReg t; @@ -1531,6 +1531,11 @@ static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, } } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rI, rM, rM), + .out = tcg_out_movcond, +}; + static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn, TCGReg ret, TCGReg src1, int src2, bool c_src2) { @@ -1542,7 +1547,7 @@ static void tcg_out_cltz(TCGContext *s, TCGType type, RISCVInsn insn, * Note that constraints put 'ret' in a new register, so the * computation above did not clobber either 'src1' or 'src2'. */ - tcg_out_movcond(s, TCG_COND_EQ, ret, src1, 0, true, + tcg_out_movcond(s, type, TCG_COND_EQ, ret, src1, 0, true, src2, c_src2, ret, false); } } @@ -2425,7 +2430,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a0 = args[0]; TCGArg a1 = args[1]; TCGArg a2 = args[2]; - int c2 = const_args[2]; switch (opc) { case INDEX_op_goto_ptr: @@ -2521,12 +2525,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const_args[4], const_args[5], true, false); break; - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - tcg_out_movcond(s, args[5], a0, a1, a2, c2, - args[3], const_args[3], args[4], const_args[4]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -2863,10 +2861,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, r, rI, rM, rM); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index 86af067965..78f06e3e52 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -38,7 +38,6 @@ C_O1_I2(v, v, v) C_O1_I3(v, v, v, v) C_O1_I4(v, v, v, vZ, v) C_O1_I4(v, v, v, vZM, v) -C_O1_I4(r, r, ri, rI, r) C_O1_I4(r, r, rC, rI, r) C_O2_I1(o, m, r) C_O2_I2(o, m, 0, r) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index d3650636aa..fbf39ca529 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1540,9 +1540,9 @@ static void tgen_movcond_int(TCGContext *s, TCGType type, TCGReg dest, tcg_out_insn(s, RRFc, LOCGR, dest, src, cc); } -static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, - TCGReg c1, TCGArg c2, int c2const, - TCGArg v3, int v3const, TCGReg v4) +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, + TCGReg dest, TCGReg c1, TCGArg c2, bool c2const, + TCGArg v3, bool v3const, TCGArg v4, bool v4const) { int cc, inv_cc; @@ -1550,6 +1550,11 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond c, TCGReg dest, tgen_movcond_int(s, type, dest, v3, v3const, v4, cc, inv_cc); } +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rC, rI, r), + .out = tgen_movcond, +}; + static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src, int ofs, int len, int z) { @@ -2875,11 +2880,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tgen_branch(s, S390_CC_ALWAYS, arg_label(args[0])); break; - case INDEX_op_movcond_i32: - tgen_movcond(s, TCG_TYPE_I32, args[5], args[0], args[1], - args[2], const_args[2], args[3], const_args[3], args[4]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I32); break; @@ -2948,11 +2948,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, SLBGR, args[1], args[5]); break; - case INDEX_op_movcond_i64: - tgen_movcond(s, TCG_TYPE_I64, args[5], args[0], args[1], - args[2], const_args[2], args[3], const_args[3], args[4]); - break; - OP_32_64(deposit): a0 = args[0], a1 = args[1], a2 = args[2]; if (const_args[1]) { @@ -3492,11 +3487,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return C_O1_I2(r, rZ, r); - case INDEX_op_movcond_i32: - return C_O1_I4(r, r, ri, rI, r); - case INDEX_op_movcond_i64: - return C_O1_I4(r, r, rC, rI, r); - case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_N1_O1_I4(r, r, 0, 1, ri, r); diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index 9f66e52ec6..8cec396173 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -15,6 +15,6 @@ C_O0_I2(r, rJ) C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, rJ) -C_O1_I4(r, rz, rJ, rI, 0) +C_O1_I4(r, r, rJ, rI, 0) C_O2_I2(r, r, r, r) C_O2_I4(r, r, rz, rz, rJ, rJ) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 68f38b7d71..d99b9e42ce 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -898,6 +898,22 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool c2const, + TCGArg v1, bool v1const, TCGArg v2, bool v2consf) +{ + if (type == TCG_TYPE_I32) { + tcg_out_movcond_i32(s, cond, ret, c1, c2, c2const, v1, v1const); + } else { + tcg_out_movcond_i64(s, cond, ret, c1, c2, c2const, v1, v1const); + } +} + +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, rJ, rI, 0), + .out = tgen_movcond, +}; + static void tcg_out_addsub2_i32(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al, TCGReg ah, int32_t bl, int blconst, int32_t bh, int bhconst, int opl, int oph) @@ -1735,13 +1751,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int c2; /* Hoist the loads of the most common arguments. */ a0 = args[0]; a1 = args[1]; a2 = args[2]; - c2 = const_args[2]; switch (opc) { case INDEX_op_goto_ptr: @@ -1784,10 +1798,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STW); break; - case INDEX_op_movcond_i32: - tcg_out_movcond_i32(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); - break; - case INDEX_op_add2_i32: tcg_out_addsub2_i32(s, args[0], args[1], args[2], args[3], args[4], const_args[4], args[5], const_args[5], @@ -1822,9 +1832,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STX); break; - case INDEX_op_movcond_i64: - tcg_out_movcond_i64(s, args[5], a0, a1, a2, c2, args[3], const_args[3]); - break; case INDEX_op_add2_i64: tcg_out_addsub2_i64(s, args[0], args[1], args[2], args[3], args[4], const_args[4], args[5], const_args[5], false); @@ -1895,9 +1902,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: - return C_O1_I4(r, rz, rJ, rI, 0); case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index 4dc6995d00..ba81a67e28 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1000,6 +1000,13 @@ typedef struct TCGOutOpDivRem { TCGReg a0, TCGReg a1, TCGReg a4); } TCGOutOpDivRem; +typedef struct TCGOutOpMovcond { + TCGOutOp base; + void (*out)(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf); +} TCGOutOpMovcond; + typedef struct TCGOutOpMul2 { TCGOutOp base; void (*out_rrrr)(TCGContext *s, TCGType type, @@ -1057,6 +1064,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_movcond_i32, TCGOutOpMovcond, outop_movcond), + OUTOP(INDEX_op_movcond_i64, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -5504,6 +5513,20 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_movcond_i32: + case INDEX_op_movcond_i64: + { + const TCGOutOpMovcond *out = &outop_movcond; + TCGCond cond = new_args[5]; + + tcg_debug_assert(!const_args[1]); + out->out(s, type, cond, new_args[0], + new_args[1], new_args[2], const_args[2], + new_args[3], const_args[3], + new_args[4], const_args[4]); + } + break; + case INDEX_op_setcond: case INDEX_op_negsetcond: { diff --git a/tcg/tci.c b/tcg/tci.c index 4c5dc16ecb..aef0023dc6 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -438,11 +438,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_l(insn, tb_ptr, &ptr); tb_ptr = ptr; continue; - case INDEX_op_movcond_i32: - tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); - tmp32 = tci_compare32(regs[r1], regs[r2], condition); - regs[r0] = regs[tmp32 ? r3 : r4]; - break; #if TCG_TARGET_REG_BITS == 32 case INDEX_op_setcond2_i32: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); @@ -628,6 +623,11 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrrc(insn, &r0, &r1, &r2, &condition); regs[r0] = tci_compare32(regs[r1], regs[r2], condition); break; + case INDEX_op_tci_movcond32: + tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); + tmp32 = tci_compare32(regs[r1], regs[r2], condition); + regs[r0] = regs[tmp32 ? r3 : r4]; + break; /* Shift/rotate operations. */ @@ -1074,7 +1074,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), pos, len); break; - case INDEX_op_movcond_i32: + case INDEX_op_tci_movcond32: case INDEX_op_movcond_i64: case INDEX_op_setcond2_i32: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &c); diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 27b4574e4f..672d9b7323 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -11,3 +11,4 @@ DEF(tci_remu32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rotl32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_rotr32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_setcond32, 1, 2, 1, TCG_OPF_NOT_PRESENT) +DEF(tci_movcond32, 1, 2, 1, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 18628b957a..79f9219187 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -92,8 +92,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O0_I4(r, r, r, r); #endif - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: case INDEX_op_setcond2_i32: return C_O1_I4(r, r, r, r, r); @@ -972,6 +970,21 @@ static const TCGOutOpBrcond outop_brcond = { .out_rr = tgen_brcond, }; +static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, + TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, + TCGArg vt, bool const_vt, TCGArg vf, bool consf_vf) +{ + TCGOpcode opc = (type == TCG_TYPE_I32 + ? INDEX_op_tci_movcond32 + : INDEX_op_movcond_i64); + tcg_out_op_rrrrrc(s, opc, ret, c1, c2, vt, vf, cond); +} + +static const TCGOutOpMovcond outop_movcond = { + .base.static_constraint = C_O1_I4(r, r, r, r, r), + .out = tgen_movcond, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -987,7 +1000,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_l(s, opc, arg_label(args[0])); break; - CASE_32_64(movcond) case INDEX_op_setcond2_i32: tcg_out_op_rrrrrc(s, opc, args[0], args[1], args[2], args[3], args[4], args[5]); From ea46c4bce8c8a8285e6715c1bac29f5b73f5062b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 13:41:25 -0800 Subject: [PATCH 0440/2760] tcg: Merge INDEX_op_movcond_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 2 +- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 15 +++++---------- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 18f02c5122..26dc3bad49 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -511,7 +511,7 @@ Conditional moves | | Set *dest* to -1 if (*t1* *cond* *t2*) is true, otherwise set to 0. - * - movcond_i32/i64 *dest*, *c1*, *c2*, *v1*, *v2*, *cond* + * - movcond *dest*, *c1*, *c2*, *v1*, *v2*, *cond* - | *dest* = (*c1* *cond* *c2* ? *v1* : *v2*) | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index d40ca001c2..5e085607d5 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -51,6 +51,7 @@ DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) +DEF(movcond, 1, 4, 1, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(muls2, 2, 2, 0, TCG_OPF_INT) DEF(mulsh, 1, 2, 0, TCG_OPF_INT) @@ -74,7 +75,6 @@ DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) -DEF(movcond_i32, 1, 4, 1, 0) /* load/store */ DEF(ld8u_i32, 1, 1, 1, 0) DEF(ld8s_i32, 1, 1, 1, 0) @@ -98,7 +98,6 @@ DEF(setcond2_i32, 1, 4, 1, 0) DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) -DEF(movcond_i64, 1, 4, 1, 0) /* load/store */ DEF(ld8u_i64, 1, 1, 1, 0) DEF(ld8s_i64, 1, 1, 1, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index d0cb4588ed..54606388cc 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2943,7 +2943,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_mov_vec: done = fold_mov(&ctx, op); break; - CASE_OP_32_64(movcond): + case INDEX_op_movcond: done = fold_movcond(&ctx, op); break; case INDEX_op_mul: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 041ca95f0d..3527952c66 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1095,7 +1095,7 @@ void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, } else if (cond == TCG_COND_NEVER) { tcg_gen_mov_i32(ret, v2); } else { - tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond); + tcg_gen_op6i_i32(INDEX_op_movcond, ret, c1, c2, v1, v2, cond); } } @@ -2799,7 +2799,7 @@ void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, } else if (cond == TCG_COND_NEVER) { tcg_gen_mov_i64(ret, v2); } else if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond); + tcg_gen_op6i_i64(INDEX_op_movcond, ret, c1, c2, v1, v2, cond); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 zero = tcg_constant_i32(0); diff --git a/tcg/tcg.c b/tcg/tcg.c index ba81a67e28..3f57f6aafd 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1064,8 +1064,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), - OUTOP(INDEX_op_movcond_i32, TCGOutOpMovcond, outop_movcond), - OUTOP(INDEX_op_movcond_i64, TCGOutOpMovcond, outop_movcond), + OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), OUTOP(INDEX_op_mulsh, TCGOutOpBinary, outop_mulsh), @@ -2292,13 +2291,13 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_and: case INDEX_op_brcond: case INDEX_op_mov: + case INDEX_op_movcond: case INDEX_op_negsetcond: case INDEX_op_or: case INDEX_op_setcond: case INDEX_op_xor: return has_type; - case INDEX_op_movcond_i32: case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: @@ -2327,7 +2326,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; - case INDEX_op_movcond_i64: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i64: @@ -2879,10 +2877,9 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) case INDEX_op_brcond: case INDEX_op_setcond: case INDEX_op_negsetcond: - case INDEX_op_movcond_i32: + case INDEX_op_movcond: case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: - case INDEX_op_movcond_i64: case INDEX_op_cmp_vec: case INDEX_op_cmpsel_vec: if (op->args[k] < ARRAY_SIZE(cond_name) @@ -5082,8 +5079,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_brcond2_i32: op_cond = op->args[4]; break; - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: + case INDEX_op_movcond: case INDEX_op_setcond2_i32: case INDEX_op_cmpsel_vec: op_cond = op->args[5]; @@ -5513,8 +5509,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_movcond_i32: - case INDEX_op_movcond_i64: + case INDEX_op_movcond: { const TCGOutOpMovcond *out = &outop_movcond; TCGCond cond = new_args[5]; diff --git a/tcg/tci.c b/tcg/tci.c index aef0023dc6..9c3f58242e 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -450,7 +450,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrrc(insn, &r0, &r1, &r2, &condition); regs[r0] = tci_compare64(regs[r1], regs[r2], condition); break; - case INDEX_op_movcond_i64: + case INDEX_op_movcond: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); tmp32 = tci_compare64(regs[r1], regs[r2], condition); regs[r0] = regs[tmp32 ? r3 : r4]; @@ -1075,7 +1075,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_tci_movcond32: - case INDEX_op_movcond_i64: + case INDEX_op_movcond: case INDEX_op_setcond2_i32: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &c); info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s", diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 79f9219187..99a5744ab4 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -976,7 +976,7 @@ static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, { TCGOpcode opc = (type == TCG_TYPE_I32 ? INDEX_op_tci_movcond32 - : INDEX_op_movcond_i64); + : INDEX_op_movcond); tcg_out_op_rrrrrc(s, opc, ret, c1, c2, vt, vf, cond); } From 298b3b548656ea89ff6fd4251bc7319986b79c67 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 13:52:49 -0800 Subject: [PATCH 0441/2760] tcg/ppc: Drop fallback constant loading in tcg_out_cmp Use U and C constraints for brcond2 and setcond2, so that tcg_out_cmp2 automatically passes in-range constants to tcg_out_cmp. Tested-by: Nicholas Piggin Reviewed-by: Nicholas Piggin Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target-con-set.h | 4 +-- tcg/ppc/tcg-target.c.inc | 49 ++++++++++++------------------------ 2 files changed, 18 insertions(+), 35 deletions(-) diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h index 77a1038d51..14cd217287 100644 --- a/tcg/ppc/tcg-target-con-set.h +++ b/tcg/ppc/tcg-target-con-set.h @@ -15,7 +15,7 @@ C_O0_I2(r, rC) C_O0_I2(v, r) C_O0_I3(r, r, r) C_O0_I3(o, m, r) -C_O0_I4(r, r, ri, ri) +C_O0_I4(r, r, rU, rC) C_O0_I4(r, r, r, r) C_O1_I1(r, r) C_O1_I1(v, r) @@ -34,7 +34,7 @@ C_O1_I2(v, v, v) C_O1_I3(v, v, v, v) C_O1_I4(v, v, v, vZM, v) C_O1_I4(r, r, rC, rZ, rZ) -C_O1_I4(r, r, r, ri, ri) +C_O1_I4(r, r, r, rU, rC) C_O2_I1(r, r, r) C_N1O1_I1(o, m, r) C_O2_I2(r, r, r, r) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 339b3a0904..1782d05290 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1777,9 +1777,8 @@ static void tcg_out_test(TCGContext *s, TCGReg dest, TCGReg arg1, TCGArg arg2, } static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, - int const_arg2, int cr, TCGType type) + bool const_arg2, int cr, TCGType type) { - int imm; uint32_t op; tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32); @@ -1796,18 +1795,15 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, case TCG_COND_EQ: case TCG_COND_NE: if (const_arg2) { - if ((int16_t) arg2 == arg2) { + if ((int16_t)arg2 == arg2) { op = CMPI; - imm = 1; - break; - } else if ((uint16_t) arg2 == arg2) { - op = CMPLI; - imm = 1; break; } + tcg_debug_assert((uint16_t)arg2 == arg2); + op = CMPLI; + break; } op = CMPL; - imm = 0; break; case TCG_COND_TSTEQ: @@ -1821,14 +1817,11 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, case TCG_COND_LE: case TCG_COND_GT: if (const_arg2) { - if ((int16_t) arg2 == arg2) { - op = CMPI; - imm = 1; - break; - } + tcg_debug_assert((int16_t)arg2 == arg2); + op = CMPI; + break; } op = CMP; - imm = 0; break; case TCG_COND_LTU: @@ -1836,30 +1829,20 @@ static void tcg_out_cmp(TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, case TCG_COND_LEU: case TCG_COND_GTU: if (const_arg2) { - if ((uint16_t) arg2 == arg2) { - op = CMPLI; - imm = 1; - break; - } + tcg_debug_assert((uint16_t)arg2 == arg2); + op = CMPLI; + break; } op = CMPL; - imm = 0; break; default: g_assert_not_reached(); } op |= BF(cr) | ((type == TCG_TYPE_I64) << 21); - - if (imm) { - tcg_out32(s, op | RA(arg1) | (arg2 & 0xffff)); - } else { - if (const_arg2) { - tcg_out_movi(s, type, TCG_REG_R0, arg2); - arg2 = TCG_REG_R0; - } - tcg_out32(s, op | RA(arg1) | RB(arg2)); - } + op |= RA(arg1); + op |= const_arg2 ? arg2 & 0xffff : RB(arg2); + tcg_out32(s, op); } static void tcg_out_setcond_eq0(TCGContext *s, TCGType type, @@ -4297,9 +4280,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rZ); case INDEX_op_brcond2_i32: - return C_O0_I4(r, r, ri, ri); + return C_O0_I4(r, r, rU, rC); case INDEX_op_setcond2_i32: - return C_O1_I4(r, r, r, ri, ri); + return C_O1_I4(r, r, r, rU, rC); case INDEX_op_add2_i64: case INDEX_op_add2_i32: return C_O2_I4(r, r, r, r, rI, rZM); From cd2d9b181a67517fb7bbe8f0c8a81e2284207241 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 14:52:41 -0800 Subject: [PATCH 0442/2760] tcg/arm: Expand arguments to tcg_out_cmp2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass explicit arguments instead of arrays. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 3d864c1c1e..cebd783285 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1254,17 +1254,9 @@ static TCGCond tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg a, } } -static TCGCond tcg_out_cmp2(TCGContext *s, const TCGArg *args, - const int *const_args) +static TCGCond tcg_out_cmp2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, TCGArg bh, bool const_bh) { - TCGReg al = args[0]; - TCGReg ah = args[1]; - TCGArg bl = args[2]; - TCGArg bh = args[3]; - TCGCond cond = args[4]; - int const_bl = const_args[2]; - int const_bh = const_args[3]; - switch (cond) { case TCG_COND_EQ: case TCG_COND_NE: @@ -2344,11 +2336,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; case INDEX_op_brcond2_i32: - c = tcg_out_cmp2(s, args, const_args); + c = tcg_out_cmp2(s, args[4], args[0], args[1], args[2], const_args[2], + args[3], const_args[3]); tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[5])); break; case INDEX_op_setcond2_i32: - c = tcg_out_cmp2(s, args + 1, const_args + 1); + c = tcg_out_cmp2(s, args[5], args[1], args[2], args[3], const_args[3], + args[4], const_args[4]); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], ARITH_MOV, args[0], 0, 1); tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], ARITH_MOV, args[0], 0, 0); From c1e84acb7a87c23494f706c7045956ffaff5435a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 16:41:26 -0800 Subject: [PATCH 0443/2760] tcg/ppc: Expand arguments to tcg_out_cmp2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Nicholas Piggin Reviewed-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target.c.inc | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 1782d05290..669c5eae4a 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2206,8 +2206,8 @@ static void tcg_out_cntxz(TCGContext *s, TCGType type, uint32_t opc, } } -static void tcg_out_cmp2(TCGContext *s, const TCGArg *args, - const int *const_args) +static void tcg_out_cmp2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool blconst, TCGArg bh, bool bhconst) { static const struct { uint8_t bit1, bit2; } bits[] = { [TCG_COND_LT ] = { CR_LT, CR_LT }, @@ -2220,18 +2220,9 @@ static void tcg_out_cmp2(TCGContext *s, const TCGArg *args, [TCG_COND_GEU] = { CR_GT, CR_LT }, }; - TCGCond cond = args[4], cond2; - TCGArg al, ah, bl, bh; - int blconst, bhconst; + TCGCond cond2; int op, bit1, bit2; - al = args[0]; - ah = args[1]; - bl = args[2]; - bh = args[3]; - blconst = const_args[2]; - bhconst = const_args[3]; - switch (cond) { case TCG_COND_EQ: op = CRAND; @@ -2286,7 +2277,8 @@ static void tcg_out_cmp2(TCGContext *s, const TCGArg *args, static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, const int *const_args) { - tcg_out_cmp2(s, args + 1, const_args + 1); + tcg_out_cmp2(s, args[5], args[1], args[2], args[3], const_args[3], + args[4], const_args[4]); tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(0)); tcg_out_rlw(s, RLWINM, args[0], TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31); } @@ -2294,7 +2286,8 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, const int *const_args) { - tcg_out_cmp2(s, args, const_args); + tcg_out_cmp2(s, args[4], args[0], args[1], args[2], const_args[2], + args[3], const_args[3]); tcg_out_bc_lab(s, TCG_COND_EQ, arg_label(args[5])); } From f408df587a0459c0e44414d1c0c72a7926ce8f3c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 15:51:26 -0800 Subject: [PATCH 0444/2760] tcg: Convert brcond2_i32 to TCGOutOpBrcond2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 20 +++++++---- tcg/i386/tcg-target.c.inc | 62 ++++++++++++++++++----------------- tcg/mips/tcg-target-con-set.h | 2 +- tcg/mips/tcg-target.c.inc | 19 ++++++----- tcg/ppc/tcg-target.c.inc | 25 +++++++------- tcg/tcg.c | 30 +++++++++++++++++ tcg/tci/tcg-target.c.inc | 30 +++++++++-------- 7 files changed, 118 insertions(+), 70 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index cebd783285..1c42df1092 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2253,6 +2253,19 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; +static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, TCGArg bh, bool const_bh, + TCGLabel *l) +{ + cond = tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh); + tcg_out_goto_label(s, tcg_cond_to_arm_cond[cond], l); +} + +static const TCGOutOpBrcond2 outop_brcond2 = { + .base.static_constraint = C_O0_I4(r, r, rI, rI), + .out = tgen_brcond2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2335,11 +2348,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_brcond2_i32: - c = tcg_out_cmp2(s, args[4], args[0], args[1], args[2], const_args[2], - args[3], const_args[3]); - tcg_out_goto_label(s, tcg_cond_to_arm_cond[c], arg_label(args[5])); - break; case INDEX_op_setcond2_i32: c = tcg_out_cmp2(s, args[5], args[1], args[2], args[3], const_args[3], args[4], const_args[4]); @@ -2444,8 +2452,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O2_I4(r, r, r, r, rIN, rIK); case INDEX_op_sub2_i32: return C_O2_I4(r, r, rI, rI, rIN, rIK); - case INDEX_op_brcond2_i32: - return C_O0_I4(r, r, rI, rI); case INDEX_op_setcond2_i32: return C_O1_I4(r, r, r, rI, rI); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index ae3a53a18a..b7708c945f 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1662,42 +1662,52 @@ static const TCGOutOpBrcond outop_brcond = { .out_ri = tgen_brcondi, }; -#if TCG_TARGET_REG_BITS == 32 -static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, - const int *const_args, bool small) +static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, + TCGReg ah, TCGArg bl, bool blconst, + TCGArg bh, bool bhconst, + TCGLabel *label_this, bool small) { TCGLabel *label_next = gen_new_label(); - TCGLabel *label_this = arg_label(args[5]); - TCGCond cond = args[4]; switch (cond) { case TCG_COND_EQ: case TCG_COND_TSTEQ: tcg_out_brcond(s, 0, tcg_invert_cond(cond), - args[0], args[2], const_args[2], label_next, 1); - tcg_out_brcond(s, 0, cond, args[1], args[3], const_args[3], - label_this, small); + al, bl, blconst, label_next, true); + tcg_out_brcond(s, 0, cond, ah, bh, bhconst, label_this, small); break; case TCG_COND_NE: case TCG_COND_TSTNE: - tcg_out_brcond(s, 0, cond, args[0], args[2], const_args[2], - label_this, small); - tcg_out_brcond(s, 0, cond, args[1], args[3], const_args[3], - label_this, small); + tcg_out_brcond(s, 0, cond, al, bl, blconst, label_this, small); + tcg_out_brcond(s, 0, cond, ah, bh, bhconst, label_this, small); break; default: - tcg_out_brcond(s, 0, tcg_high_cond(cond), args[1], - args[3], const_args[3], label_this, small); + tcg_out_brcond(s, 0, tcg_high_cond(cond), + ah, bh, bhconst, label_this, small); tcg_out_jxx(s, JCC_JNE, label_next, 1); - tcg_out_brcond(s, 0, tcg_unsigned_cond(cond), args[0], - args[2], const_args[2], label_this, small); + tcg_out_brcond(s, 0, tcg_unsigned_cond(cond), + al, bl, blconst, label_this, small); break; } tcg_out_label(s, label_next); } + +static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, + TCGReg ah, TCGArg bl, bool blconst, + TCGArg bh, bool bhconst, TCGLabel *l) +{ + tcg_out_brcond2(s, cond, al, ah, bl, blconst, bh, bhconst, l, false); +} + +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) #endif +static const TCGOutOpBrcond2 outop_brcond2 = { + .base.static_constraint = C_O0_I4(r, r, ri, ri), + .out = tgen_brcond2, +}; static void tcg_out_setcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg dest, TCGReg arg1, TCGArg arg2, @@ -1854,11 +1864,8 @@ static const TCGOutOpSetcond outop_negsetcond = { static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, const int *const_args) { - TCGArg new_args[6]; TCGLabel *label_true, *label_over; - memcpy(new_args, args+1, 5*sizeof(TCGArg)); - if (args[0] == args[1] || args[0] == args[2] || (!const_args[3] && args[0] == args[3]) || (!const_args[4] && args[0] == args[4])) { @@ -1867,8 +1874,8 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, label_true = gen_new_label(); label_over = gen_new_label(); - new_args[5] = label_arg(label_true); - tcg_out_brcond2(s, new_args, const_args+1, 1); + tcg_out_brcond2(s, args[5], args[1], args[2], args[3], const_args[3], + args[4], const_args[4], label_true, true); tcg_out_movi(s, TCG_TYPE_I32, args[0], 0); tcg_out_jxx(s, JCC_JMP, label_over, 1); @@ -1884,9 +1891,10 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, tcg_out_movi(s, TCG_TYPE_I32, args[0], 0); label_over = gen_new_label(); - new_args[4] = tcg_invert_cond(new_args[4]); - new_args[5] = label_arg(label_over); - tcg_out_brcond2(s, new_args, const_args+1, 1); + tcg_out_brcond2(s, tcg_invert_cond(args[5]), args[1], args[2], + args[3], const_args[3], + args[4], const_args[4], label_over, true); + tgen_arithi(s, ARITH_ADD, args[0], 1, 0); tcg_out_label(s, label_over); @@ -3233,9 +3241,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #if TCG_TARGET_REG_BITS == 32 - case INDEX_op_brcond2_i32: - tcg_out_brcond2(s, args, const_args, 0); - break; case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args, const_args); break; @@ -4007,9 +4012,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) tcg_debug_assert(TCG_TARGET_REG_BITS == 64); return C_O0_I3(L, L, L); - case INDEX_op_brcond2_i32: - return C_O0_I4(r, r, ri, ri); - case INDEX_op_setcond2_i32: return C_O1_I4(r, r, r, ri, ri); diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index f5e4852b56..9d0ea73f4f 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -13,7 +13,7 @@ C_O0_I1(r) C_O0_I2(r, rz) C_O0_I2(rz, r) C_O0_I3(rz, rz, r) -C_O0_I4(rz, rz, rz, rz) +C_O0_I4(r, r, rz, rz) C_O1_I1(r, r) C_O1_I2(r, 0, rz) C_O1_I2(r, r, r) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 3ce71a1c8d..9a9b1bb09a 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1074,8 +1074,9 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, tcg_out_setcond_end(s, ret, tmpflags); } -static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, - TCGReg bl, TCGReg bh, TCGLabel *l) +static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh, TCGLabel *l) { int tmpflags = tcg_out_setcond2_int(s, cond, TCG_TMP0, al, ah, bl, bh); TCGReg tmp = tmpflags & ~SETCOND_FLAGS; @@ -1086,6 +1087,14 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, tcg_out_nop(s); } +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpBrcond2 outop_brcond2 = { + .base.static_constraint = C_O0_I4(r, r, rz, rz), + .out = tgen_brcond2, +}; + static void tgen_movcond(TCGContext *s, TCGType type, TCGCond cond, TCGReg ret, TCGReg c1, TCGArg c2, bool const_c2, TCGArg v1, bool const_v1, TCGArg v2, bool const_v2) @@ -2297,10 +2306,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_brcond2_i32: - tcg_out_brcond2(s, args[4], a0, a1, a2, args[3], arg_label(args[5])); - break; - case INDEX_op_setcond2_i32: tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); break; @@ -2401,8 +2406,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O2_I4(r, r, rz, rz, rN, rN); case INDEX_op_setcond2_i32: return C_O1_I4(r, rz, rz, rz, rz); - case INDEX_op_brcond2_i32: - return C_O0_I4(rz, rz, rz, rz); case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 669c5eae4a..cde8a55918 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2283,14 +2283,23 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, tcg_out_rlw(s, RLWINM, args[0], TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31); } -static void tcg_out_brcond2(TCGContext *s, const TCGArg *args, - const int *const_args) +static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh, TCGLabel *l) { - tcg_out_cmp2(s, args[4], args[0], args[1], args[2], const_args[2], - args[3], const_args[3]); - tcg_out_bc_lab(s, TCG_COND_EQ, arg_label(args[5])); + assert(TCG_TARGET_REG_BITS == 32); + tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh); + tcg_out_bc_lab(s, TCG_COND_EQ, l); } +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpBrcond2 outop_brcond2 = { + .base.static_constraint = C_O0_I4(r, r, rU, rC), + .out = tgen_brcond2, +}; + static void tcg_out_mb(TCGContext *s, TCGArg a0) { uint32_t insn; @@ -3450,10 +3459,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); break; - case INDEX_op_brcond2_i32: - tcg_out_brcond2(s, args, const_args); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -4272,8 +4277,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rZ); - case INDEX_op_brcond2_i32: - return C_O0_I4(r, r, rU, rC); case INDEX_op_setcond2_i32: return C_O1_I4(r, r, r, rU, rC); case INDEX_op_add2_i64: diff --git a/tcg/tcg.c b/tcg/tcg.c index 3f57f6aafd..2a39ce3665 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -994,6 +994,13 @@ typedef struct TCGOutOpBrcond { TCGReg a1, tcg_target_long a2, TCGLabel *label); } TCGOutOpBrcond; +typedef struct TCGOutOpBrcond2 { + TCGOutOp base; + void (*out)(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh, TCGLabel *l); +} TCGOutOpBrcond2; + typedef struct TCGOutOpDivRem { TCGOutOp base; void (*out_rr01r)(TCGContext *s, TCGType type, @@ -1087,6 +1094,10 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), + +#if TCG_TARGET_REG_BITS == 32 + OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), +#endif }; #undef OUTOP @@ -5540,6 +5551,25 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; +#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_brcond2_i32: + { + const TCGOutOpBrcond2 *out = &outop_brcond2; + TCGCond cond = new_args[4]; + TCGLabel *label = arg_label(new_args[5]); + + tcg_debug_assert(!const_args[0]); + tcg_debug_assert(!const_args[1]); + out->out(s, cond, new_args[0], new_args[1], + new_args[2], const_args[2], + new_args[3], const_args[3], label); + } + break; +#else + case INDEX_op_brcond2_i32: + g_assert_not_reached(); +#endif + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 99a5744ab4..0fe365e2d4 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -87,11 +87,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub2_i64: return C_O2_I4(r, r, r, r, r, r); -#if TCG_TARGET_REG_BITS == 32 - case INDEX_op_brcond2_i32: - return C_O0_I4(r, r, r, r); -#endif - case INDEX_op_setcond2_i32: return C_O1_I4(r, r, r, r, r); @@ -985,6 +980,23 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; +static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh, TCGLabel *l) +{ + tcg_out_op_rrrrrc(s, INDEX_op_setcond2_i32, TCG_REG_TMP, + al, ah, bl, bh, cond); + tcg_out_op_rl(s, INDEX_op_brcond, TCG_REG_TMP, l); +} + +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpBrcond2 outop_brcond2 = { + .base.static_constraint = C_O0_I4(r, r, r, r), + .out = tgen_brcond2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1055,14 +1067,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[3], args[4], args[5]); break; -#if TCG_TARGET_REG_BITS == 32 - case INDEX_op_brcond2_i32: - tcg_out_op_rrrrrc(s, INDEX_op_setcond2_i32, TCG_REG_TMP, - args[0], args[1], args[2], args[3], args[4]); - tcg_out_op_rl(s, INDEX_op_brcond, TCG_REG_TMP, arg_label(args[5])); - break; -#endif - case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: if (TCG_TARGET_REG_BITS == 32) { From e579c717cb1176d2cd8bd24d9b0e9c6a4b1a0d71 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 16:57:07 -0800 Subject: [PATCH 0445/2760] tcg: Convert setcond2_i32 to TCGOutOpSetcond2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/arm/tcg-target.c.inc | 25 ++++++------ tcg/i386/tcg-target.c.inc | 71 +++++++++++++++++------------------ tcg/mips/tcg-target-con-set.h | 2 +- tcg/mips/tcg-target.c.inc | 20 ++++++---- tcg/ppc/tcg-target.c.inc | 25 ++++++------ tcg/tcg.c | 19 ++++++++++ tcg/tci/tcg-target.c.inc | 24 ++++++++---- 7 files changed, 110 insertions(+), 76 deletions(-) diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 1c42df1092..8cd82b8baf 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2266,13 +2266,25 @@ static const TCGOutOpBrcond2 outop_brcond2 = { .out = tgen_brcond2, }; +static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh) +{ + cond = tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh); + finish_setcond(s, cond, ret, false); +} + +static const TCGOutOpSetcond2 outop_setcond2 = { + .base.static_constraint = C_O1_I4(r, r, r, rI, rI), + .out = tgen_setcond2, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2, a3, a4, a5; - int c; switch (opc) { case INDEX_op_goto_ptr: @@ -2348,14 +2360,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mov_reg(s, COND_AL, args[0], a0); break; - case INDEX_op_setcond2_i32: - c = tcg_out_cmp2(s, args[5], args[1], args[2], args[3], const_args[3], - args[4], const_args[4]); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[c], ARITH_MOV, args[0], 0, 1); - tcg_out_dat_imm(s, tcg_cond_to_arm_cond[tcg_invert_cond(c)], - ARITH_MOV, args[0], 0, 0); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -2452,9 +2456,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O2_I4(r, r, r, r, rIN, rIK); case INDEX_op_sub2_i32: return C_O2_I4(r, r, rI, rI, rIN, rIK); - case INDEX_op_setcond2_i32: - return C_O1_I4(r, r, r, rI, rI); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, q); case INDEX_op_qemu_ld_i64: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index b7708c945f..6a42ffaf44 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1860,47 +1860,53 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; -#if TCG_TARGET_REG_BITS == 32 -static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, - const int *const_args) +static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh) { - TCGLabel *label_true, *label_over; + TCGLabel *label_over = gen_new_label(); - if (args[0] == args[1] || args[0] == args[2] - || (!const_args[3] && args[0] == args[3]) - || (!const_args[4] && args[0] == args[4])) { - /* When the destination overlaps with one of the argument - registers, don't do anything tricky. */ - label_true = gen_new_label(); - label_over = gen_new_label(); + if (ret == al || ret == ah + || (!const_bl && ret == bl) + || (!const_bh && ret == bh)) { + /* + * When the destination overlaps with one of the argument + * registers, don't do anything tricky. + */ + TCGLabel *label_true = gen_new_label(); - tcg_out_brcond2(s, args[5], args[1], args[2], args[3], const_args[3], - args[4], const_args[4], label_true, true); + tcg_out_brcond2(s, cond, al, ah, bl, const_bl, + bh, const_bh, label_true, true); - tcg_out_movi(s, TCG_TYPE_I32, args[0], 0); + tcg_out_movi(s, TCG_TYPE_I32, ret, 0); tcg_out_jxx(s, JCC_JMP, label_over, 1); tcg_out_label(s, label_true); - tcg_out_movi(s, TCG_TYPE_I32, args[0], 1); - tcg_out_label(s, label_over); + tcg_out_movi(s, TCG_TYPE_I32, ret, 1); } else { - /* When the destination does not overlap one of the arguments, - clear the destination first, jump if cond false, and emit an - increment in the true case. This results in smaller code. */ + /* + * When the destination does not overlap one of the arguments, + * clear the destination first, jump if cond false, and emit an + * increment in the true case. This results in smaller code. + */ + tcg_out_movi(s, TCG_TYPE_I32, ret, 0); - tcg_out_movi(s, TCG_TYPE_I32, args[0], 0); + tcg_out_brcond2(s, tcg_invert_cond(cond), al, ah, bl, const_bl, + bh, const_bh, label_over, true); - label_over = gen_new_label(); - tcg_out_brcond2(s, tcg_invert_cond(args[5]), args[1], args[2], - args[3], const_args[3], - args[4], const_args[4], label_over, true); - - - tgen_arithi(s, ARITH_ADD, args[0], 1, 0); - tcg_out_label(s, label_over); + tgen_arithi(s, ARITH_ADD, ret, 1, 0); } + tcg_out_label(s, label_over); } + +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) #endif +static const TCGOutOpSetcond2 outop_setcond2 = { + .base.static_constraint = C_O1_I4(r, r, r, ri, ri), + .out = tgen_setcond2, +}; static void tcg_out_cmov(TCGContext *s, int jcc, int rexw, TCGReg dest, TCGReg v1) @@ -3240,11 +3246,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; -#if TCG_TARGET_REG_BITS == 32 - case INDEX_op_setcond2_i32: - tcg_out_setcond2(s, args, const_args); - break; -#else /* TCG_TARGET_REG_BITS == 64 */ +#if TCG_TARGET_REG_BITS == 64 case INDEX_op_ld32s_i64: tcg_out_modrm_offset(s, OPC_MOVSLQ, a0, a1, a2); break; @@ -4012,9 +4014,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) tcg_debug_assert(TCG_TARGET_REG_BITS == 64); return C_O0_I3(L, L, L); - case INDEX_op_setcond2_i32: - return C_O1_I4(r, r, r, ri, ri); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: return C_O1_I1(x, r); diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index 9d0ea73f4f..4e09c9a400 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -25,7 +25,7 @@ C_O1_I2(r, r, rz) C_O1_I2(r, r, rzW) C_O1_I4(r, r, rz, rz, 0) C_O1_I4(r, r, rz, rz, rz) -C_O1_I4(r, rz, rz, rz, rz) +C_O1_I4(r, r, r, rz, rz) C_O2_I1(r, r, r) C_O2_I2(r, r, r, r) C_O2_I4(r, r, rz, rz, rN, rN) diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 9a9b1bb09a..e8ae65bccb 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1067,13 +1067,23 @@ static int tcg_out_setcond2_int(TCGContext *s, TCGCond cond, TCGReg ret, return ret | flags; } -static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, - TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) +static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh) { int tmpflags = tcg_out_setcond2_int(s, cond, ret, al, ah, bl, bh); tcg_out_setcond_end(s, ret, tmpflags); } +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpSetcond2 outop_setcond2 = { + .base.static_constraint = C_O1_I4(r, r, r, rz, rz), + .out = tgen_setcond2, +}; + static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, TCGArg bl, bool const_bl, TCGArg bh, bool const_bh, TCGLabel *l) @@ -2306,10 +2316,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_setcond2_i32: - tcg_out_setcond2(s, args[5], a0, a1, a2, args[3], args[4]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32); break; @@ -2404,8 +2410,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_O2_I4(r, r, rz, rz, rN, rN); - case INDEX_op_setcond2_i32: - return C_O1_I4(r, rz, rz, rz, rz); case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index cde8a55918..4cdbf246d2 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2274,15 +2274,24 @@ static void tcg_out_cmp2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, } } -static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, - const int *const_args) +static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh) { - tcg_out_cmp2(s, args[5], args[1], args[2], args[3], const_args[3], - args[4], const_args[4]); + tcg_out_cmp2(s, cond, al, ah, bl, const_bl, bh, const_bh); tcg_out32(s, MFOCRF | RT(TCG_REG_R0) | FXM(0)); - tcg_out_rlw(s, RLWINM, args[0], TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31); + tcg_out_rlw(s, RLWINM, ret, TCG_REG_R0, CR_EQ + 0*4 + 1, 31, 31); } +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpSetcond2 outop_setcond2 = { + .base.static_constraint = C_O1_I4(r, r, r, rU, rC), + .out = tgen_setcond2, +}; + static void tgen_brcond2(TCGContext *s, TCGCond cond, TCGReg al, TCGReg ah, TCGArg bl, bool const_bl, TCGArg bh, bool const_bh, TCGLabel *l) @@ -3491,10 +3500,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_setcond2_i32: - tcg_out_setcond2(s, args, const_args); - break; - case INDEX_op_bswap16_i32: case INDEX_op_bswap16_i64: tcg_out_bswap16(s, args[0], args[1], args[2]); @@ -4277,8 +4282,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_deposit_i32: case INDEX_op_deposit_i64: return C_O1_I2(r, 0, rZ); - case INDEX_op_setcond2_i32: - return C_O1_I4(r, r, r, rU, rC); case INDEX_op_add2_i64: case INDEX_op_add2_i32: return C_O2_I4(r, r, r, r, rI, rZM); diff --git a/tcg/tcg.c b/tcg/tcg.c index 2a39ce3665..735a7b95d4 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1033,6 +1033,12 @@ typedef struct TCGOutOpSetcond { TCGReg ret, TCGReg a1, tcg_target_long a2); } TCGOutOpSetcond; +typedef struct TCGOutOpSetcond2 { + TCGOutOp base; + void (*out)(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, TCGArg bh, bool const_bh); +} TCGOutOpSetcond2; + typedef struct TCGOutOpSubtract { TCGOutOp base; void (*out_rrr)(TCGContext *s, TCGType type, @@ -1097,6 +1103,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { #if TCG_TARGET_REG_BITS == 32 OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), + OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), #endif }; @@ -5565,8 +5572,20 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) new_args[3], const_args[3], label); } break; + case INDEX_op_setcond2_i32: + { + const TCGOutOpSetcond2 *out = &outop_setcond2; + TCGCond cond = new_args[5]; + + tcg_debug_assert(!const_args[1]); + tcg_debug_assert(!const_args[2]); + out->out(s, cond, new_args[0], new_args[1], new_args[2], + new_args[3], const_args[3], new_args[4], const_args[4]); + } + break; #else case INDEX_op_brcond2_i32: + case INDEX_op_setcond2_i32: g_assert_not_reached(); #endif diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 0fe365e2d4..88dc7e24e3 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -87,9 +87,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_sub2_i64: return C_O2_I4(r, r, r, r, r, r); - case INDEX_op_setcond2_i32: - return C_O1_I4(r, r, r, r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i64: @@ -997,6 +994,22 @@ static const TCGOutOpBrcond2 outop_brcond2 = { .out = tgen_brcond2, }; +static void tgen_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, + TCGReg al, TCGReg ah, + TCGArg bl, bool const_bl, + TCGArg bh, bool const_bh) +{ + tcg_out_op_rrrrrc(s, INDEX_op_setcond2_i32, ret, al, ah, bl, bh, cond); +} + +#if TCG_TARGET_REG_BITS != 32 +__attribute__((unused)) +#endif +static const TCGOutOpSetcond2 outop_setcond2 = { + .base.static_constraint = C_O1_I4(r, r, r, r, r), + .out = tgen_setcond2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1012,11 +1025,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_l(s, opc, arg_label(args[0])); break; - case INDEX_op_setcond2_i32: - tcg_out_op_rrrrrc(s, opc, args[0], args[1], args[2], - args[3], args[4], args[5]); - break; - CASE_32_64(ld8u) CASE_32_64(ld8s) CASE_32_64(ld16u) From 5fa8e13872b0ecab7e1bc1f75c65281983df52e5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 18:32:08 -0800 Subject: [PATCH 0446/2760] tcg: Convert bswap16 to TCGOutOpBswap Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 - tcg/aarch64/tcg-target.c.inc | 30 +++++++------ tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 42 +++++++++--------- tcg/i386/tcg-target-has.h | 2 - tcg/i386/tcg-target.c.inc | 48 +++++++++++--------- tcg/loongarch64/tcg-target-has.h | 2 - tcg/loongarch64/tcg-target.c.inc | 28 +++++++----- tcg/mips/tcg-target-has.h | 2 - tcg/mips/tcg-target.c.inc | 74 +++++++++++++++---------------- tcg/ppc/tcg-target-has.h | 2 - tcg/ppc/tcg-target.c.inc | 76 ++++++++++++++++---------------- tcg/riscv/tcg-target-has.h | 2 - tcg/riscv/tcg-target.c.inc | 33 +++++++++----- tcg/s390x/tcg-target-has.h | 2 - tcg/s390x/tcg-target.c.inc | 40 ++++++++--------- tcg/sparc64/tcg-target-has.h | 2 - tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 +- tcg/tcg.c | 23 ++++++++-- tcg/tci.c | 2 - tcg/tci/tcg-target-has.h | 2 - tcg/tci/tcg-target.c.inc | 21 ++++++--- 24 files changed, 235 insertions(+), 210 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 22a574e703..4797409467 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,7 +13,6 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -21,7 +20,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index ee45e7e244..03961b34aa 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2438,6 +2438,23 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_rev(s, TCG_TYPE_I32, MO_16, a0, a1); + if (flags & TCG_BSWAP_OS) { + /* Output must be sign-extended. */ + tcg_out_ext16s(s, type, a0, a0); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + /* Output must be zero-extended, but input isn't. */ + tcg_out_ext16u(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { @@ -2618,17 +2635,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_bswap32_i32: tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1); break; - case INDEX_op_bswap16_i64: - case INDEX_op_bswap16_i32: - tcg_out_rev(s, TCG_TYPE_I32, MO_16, a0, a1); - if (a2 & TCG_BSWAP_OS) { - /* Output must be sign-extended. */ - tcg_out_ext16s(s, ext, a0, a0); - } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - /* Output must be zero-extended, but input isn't. */ - tcg_out_ext16u(s, a0, a0); - } - break; case INDEX_op_deposit_i64: case INDEX_op_deposit_i32: @@ -3148,9 +3154,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index bfa3be8028..5972def558 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,7 +24,6 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 8cd82b8baf..6928f209d2 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -969,23 +969,6 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) g_assert_not_reached(); } -static void tcg_out_bswap16(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int flags) -{ - if (flags & TCG_BSWAP_OS) { - /* revsh */ - tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn); - return; - } - - /* rev16 */ - tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn); - if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - /* uxth */ - tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rd); - } -} - static void tcg_out_bswap32(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn) { /* rev */ @@ -2153,6 +2136,27 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg rd, TCGReg rn, unsigned flags) +{ + if (flags & TCG_BSWAP_OS) { + /* revsh */ + tcg_out32(s, 0x06ff0fb0 | (COND_AL << 28) | (rd << 12) | rn); + return; + } + + /* rev16 */ + tcg_out32(s, 0x06bf0fb0 | (COND_AL << 28) | (rd << 12) | rn); + if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext16u(s, rd, rd); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_subfi(s, type, a0, 0, a1); @@ -2374,9 +2378,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_bswap16_i32: - tcg_out_bswap16(s, COND_AL, args[0], args[1], args[2]); - break; case INDEX_op_bswap32_i32: tcg_out_bswap32(s, COND_AL, args[0], args[1]); break; @@ -2437,7 +2438,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index aaf8764cc9..fd44ed8168 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,7 +26,6 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 @@ -35,7 +34,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 6a42ffaf44..c74a718cee 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3062,6 +3062,34 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + if (flags & TCG_BSWAP_OS) { + /* Output must be sign-extended. */ + if (rexw) { + tcg_out_bswap64(s, a0); + tcg_out_shifti(s, SHIFT_SAR + rexw, a0, 48); + } else { + tcg_out_bswap32(s, a0); + tcg_out_shifti(s, SHIFT_SAR, a0, 16); + } + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + /* Output must be zero-extended, but input isn't. */ + tcg_out_bswap32(s, a0); + tcg_out_shifti(s, SHIFT_SHR, a0, 16); + } else { + tcg_out_rolw_8(s, a0); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; @@ -3165,24 +3193,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(bswap16): - if (a2 & TCG_BSWAP_OS) { - /* Output must be sign-extended. */ - if (rexw) { - tcg_out_bswap64(s, a0); - tcg_out_shifti(s, SHIFT_SAR + rexw, a0, 48); - } else { - tcg_out_bswap32(s, a0); - tcg_out_shifti(s, SHIFT_SAR, a0, 16); - } - } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - /* Output must be zero-extended, but input isn't. */ - tcg_out_bswap32(s, a0); - tcg_out_shifti(s, SHIFT_SHR, a0, 16); - } else { - tcg_out_rolw_8(s, a0); - } - break; OP_32_64(bswap32): tcg_out_bswap32(s, a0); if (rexw && (a2 & TCG_BSWAP_OS)) { @@ -3962,8 +3972,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 90f0a131ae..11a93afd8b 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -13,14 +13,12 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_add2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index c731096c64..8be6f69e3a 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1735,6 +1735,22 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_opc_revb_2h(s, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext16s(s, TCG_TYPE_REG, a0, a0); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext16u(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -1826,16 +1842,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); break; - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: - tcg_out_opc_revb_2h(s, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_ext16s(s, TCG_TYPE_REG, a0, a0); - } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_ext16u(s, a0, a0); - } - break; - case INDEX_op_bswap32_i32: /* All 32-bit values are computed sign-extended in the register. */ a2 = TCG_BSWAP_OS; @@ -2448,8 +2454,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index c6cecba28b..6c967d9c9f 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,7 +39,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #if TCG_TARGET_REG_BITS == 64 @@ -57,7 +56,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e8ae65bccb..258b49f9db 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -702,39 +702,6 @@ static void tcg_out_addi_ptr(TCGContext *s, TCGReg rd, TCGReg rs, g_assert_not_reached(); } -static void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg, int flags) -{ - /* ret and arg can't be register tmp0 */ - tcg_debug_assert(ret != TCG_TMP0); - tcg_debug_assert(arg != TCG_TMP0); - - /* With arg = abcd: */ - if (use_mips32r2_instructions) { - tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); /* badc */ - if (flags & TCG_BSWAP_OS) { - tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret); /* ssdc */ - } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xffff); /* 00dc */ - } - return; - } - - tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8); /* 0abc */ - if (!(flags & TCG_BSWAP_IZ)) { - tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, TCG_TMP0, 0x00ff); /* 000c */ - } - if (flags & TCG_BSWAP_OS) { - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); /* d000 */ - tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); /* ssd0 */ - } else { - tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); /* bcd0 */ - if (flags & TCG_BSWAP_OZ) { - tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); /* 00d0 */ - } - } - tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0); /* ssdc */ -} - static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub) { if (!tcg_out_opc_jmp(s, OPC_JAL, sub)) { @@ -2168,6 +2135,41 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg ret, TCGReg arg, unsigned flags) +{ + /* With arg = abcd: */ + if (use_mips32r2_instructions) { + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); /* badc */ + if (flags & TCG_BSWAP_OS) { + tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret); /* ssdc */ + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xffff); /* 00dc */ + } + return; + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, arg, 8); /* 0abc */ + if (!(flags & TCG_BSWAP_IZ)) { + tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, TCG_TMP0, 0x00ff); /* 000c */ + } + if (flags & TCG_BSWAP_OS) { + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); /* d000 */ + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); /* ssd0 */ + } else { + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); /* bcd0 */ + if (flags & TCG_BSWAP_OZ) { + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); /* 00d0 */ + } + } + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_TMP0); /* ssdc */ +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2259,10 +2261,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: - tcg_out_bswap16(s, a0, a1, a2); - break; case INDEX_op_bswap32_i32: tcg_out_bswap32(s, a0, a1, 0); break; @@ -2373,7 +2371,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: @@ -2384,7 +2381,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 5c4fc2bc34..b73fca9789 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,7 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -26,7 +25,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 4cdbf246d2..3454254624 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1012,38 +1012,6 @@ static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm) tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2); } -static void tcg_out_bswap16(TCGContext *s, TCGReg dst, TCGReg src, int flags) -{ - TCGReg tmp = dst == src ? TCG_REG_R0 : dst; - - if (have_isa_3_10) { - tcg_out32(s, BRH | RA(dst) | RS(src)); - if (flags & TCG_BSWAP_OS) { - tcg_out_ext16s(s, TCG_TYPE_REG, dst, dst); - } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_ext16u(s, dst, dst); - } - return; - } - - /* - * In the following, - * dep(a, b, m) -> (a & ~m) | (b & m) - * - * Begin with: src = xxxxabcd - */ - /* tmp = rol32(src, 24) & 0x000000ff = 0000000c */ - tcg_out_rlw(s, RLWINM, tmp, src, 24, 24, 31); - /* tmp = dep(tmp, rol32(src, 8), 0x0000ff00) = 000000dc */ - tcg_out_rlw(s, RLWIMI, tmp, src, 8, 16, 23); - - if (flags & TCG_BSWAP_OS) { - tcg_out_ext16s(s, TCG_TYPE_REG, dst, tmp); - } else { - tcg_out_mov(s, TCG_TYPE_REG, dst, tmp); - } -} - static void tcg_out_bswap32(TCGContext *s, TCGReg dst, TCGReg src, int flags) { TCGReg tmp = dst == src ? TCG_REG_R0 : dst; @@ -3378,6 +3346,44 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg dst, TCGReg src, unsigned flags) +{ + TCGReg tmp = dst == src ? TCG_REG_R0 : dst; + + if (have_isa_3_10) { + tcg_out32(s, BRH | RA(dst) | RS(src)); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext16s(s, TCG_TYPE_REG, dst, dst); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext16u(s, dst, dst); + } + return; + } + + /* + * In the following, + * dep(a, b, m) -> (a & ~m) | (b & m) + * + * Begin with: src = xxxxabcd + */ + /* tmp = rol32(src, 24) & 0x000000ff = 0000000c */ + tcg_out_rlw(s, RLWINM, tmp, src, 24, 24, 31); + /* tmp = dep(tmp, rol32(src, 8), 0x0000ff00) = 000000dc */ + tcg_out_rlw(s, RLWIMI, tmp, src, 8, 16, 23); + + if (flags & TCG_BSWAP_OS) { + tcg_out_ext16s(s, TCG_TYPE_REG, dst, tmp); + } else { + tcg_out_mov(s, TCG_TYPE_REG, dst, tmp); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out32(s, NEG | RT(a0) | RA(a1)); @@ -3500,10 +3506,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: - tcg_out_bswap16(s, args[0], args[1], args[2]); - break; case INDEX_op_bswap32_i32: tcg_out_bswap32(s, args[0], args[1], 0); break; @@ -4250,7 +4252,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: @@ -4263,7 +4264,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_extract_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index e18b5cb8ec..85bb5cd591 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -13,13 +13,11 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_bswap16_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap16_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 8d106d7f28..c6cd2100f8 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2402,6 +2402,28 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static TCGConstraintSetIndex cset_bswap(TCGType type, unsigned flags) +{ + return cpuinfo & CPUINFO_ZBB ? C_O1_I1(r, r) : C_NotImplemented; +} + +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); + if (flags & TCG_BSWAP_OZ) { + tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 48); + } else { + tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 48); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_bswap, + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2498,15 +2520,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 32); } break; - case INDEX_op_bswap16_i64: - case INDEX_op_bswap16_i32: - tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); - if (a2 & TCG_BSWAP_OZ) { - tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 48); - } else { - tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 48); - } - break; case INDEX_op_add2_i32: tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], @@ -2845,9 +2858,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap16_i32: case INDEX_op_bswap32_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 41cd8a1d0d..6cd92fa240 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,7 +29,6 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 @@ -37,7 +36,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index fbf39ca529..e90c03628a 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2741,6 +2741,25 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori_3, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRE, LRVR, a0, a1); + tcg_out_sh32(s, (flags & TCG_BSWAP_OS ? RS_SRA : RS_SRL), + a0, TCG_REG_NONE, 16); + } else { + tcg_out_insn(s, RRE, LRVGR, a0, a1); + tcg_out_sh64(s, (flags & TCG_BSWAP_OS ? RSY_SRAG : RSY_SRLG), + a0, a0, TCG_REG_NONE, 48); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { if (type == TCG_TYPE_I32) { @@ -2827,25 +2846,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_bswap16_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - tcg_out_insn(s, RRE, LRVR, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_sh32(s, RS_SRA, a0, TCG_REG_NONE, 16); - } else { - tcg_out_sh32(s, RS_SRL, a0, TCG_REG_NONE, 16); - } - break; - case INDEX_op_bswap16_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - tcg_out_insn(s, RRE, LRVGR, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_sh64(s, RSY_SRAG, a0, a0, TCG_REG_NONE, 48); - } else { - tcg_out_sh64(s, RSY_SRLG, a0, a0, TCG_REG_NONE, 48); - } - break; - case INDEX_op_bswap32_i32: tcg_out_insn(s, RRE, LRVR, args[0], args[1]); break; @@ -3459,8 +3459,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 6ed27b8fcc..eb1e16c0e2 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,7 +14,6 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap16_i32 0 #define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 @@ -22,7 +21,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d99b9e42ce..5111f173e1 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1725,6 +1725,10 @@ static const TCGOutOpBinary outop_xor = { .out_rri = tgen_xori, }; +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_G0, a1); diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 315dfd05aa..3d1c805d59 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 0 #define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 3527952c66..c5b3bc8148 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1257,7 +1257,7 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) /* Only one extension flag may be present. */ tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); - if (TCG_TARGET_HAS_bswap16_i32) { + if (tcg_op_supported(INDEX_op_bswap16_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3i_i32(INDEX_op_bswap16_i32, ret, arg, flags); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2087,7 +2087,7 @@ void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } - } else if (TCG_TARGET_HAS_bswap16_i64) { + } else if (tcg_op_supported(INDEX_op_bswap16_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3i_i64(INDEX_op_bswap16_i64, ret, arg, flags); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 735a7b95d4..25834f40a0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1001,6 +1001,12 @@ typedef struct TCGOutOpBrcond2 { TCGArg bh, bool const_bh, TCGLabel *l); } TCGOutOpBrcond2; +typedef struct TCGOutOpBswap { + TCGOutOp base; + void (*out_rr)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags); +} TCGOutOpBswap; + typedef struct TCGOutOpDivRem { TCGOutOp base; void (*out_rr01r)(TCGContext *s, TCGType type, @@ -1069,6 +1075,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), + OUTOP(INDEX_op_bswap16_i32, TCGOutOpBswap, outop_bswap16), + OUTOP(INDEX_op_bswap16_i64, TCGOutOpBswap, outop_bswap16), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -2335,8 +2343,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_add2_i32; case INDEX_op_sub2_i32: return TCG_TARGET_HAS_sub2_i32; - case INDEX_op_bswap16_i32: - return TCG_TARGET_HAS_bswap16_i32; case INDEX_op_bswap32_i32: return TCG_TARGET_HAS_bswap32_i32; @@ -2367,8 +2373,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return TCG_TARGET_HAS_extr_i64_i32; - case INDEX_op_bswap16_i64: - return TCG_TARGET_HAS_bswap16_i64; case INDEX_op_bswap32_i64: return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: @@ -5485,6 +5489,17 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_bswap16_i32: + case INDEX_op_bswap16_i64: + { + const TCGOutOpBswap *out = + container_of(all_outop[op->opc], TCGOutOpBswap, base); + + tcg_debug_assert(!const_args[1]); + out->out_rr(s, type, new_args[0], new_args[1], new_args[2]); + } + break; + case INDEX_op_divs2: case INDEX_op_divu2: { diff --git a/tcg/tci.c b/tcg/tci.c index 9c3f58242e..ae447e91bd 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -686,12 +686,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, T1 - T2); break; #endif -#if TCG_TARGET_HAS_bswap16_i32 || TCG_TARGET_HAS_bswap16_i64 CASE_32_64(bswap16) tci_args_rr(insn, &r0, &r1); regs[r0] = bswap16(regs[r1]); break; -#endif #if TCG_TARGET_HAS_bswap32_i32 || TCG_TARGET_HAS_bswap32_i64 CASE_32_64(bswap32) tci_args_rr(insn, &r0, &r1); diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index f45a0688f9..d7228246ab 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -7,14 +7,12 @@ #ifndef TCG_TARGET_HAS_H #define TCG_TARGET_HAS_H -#define TCG_TARGET_HAS_bswap16_i32 1 #define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap16_i64 1 #define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 88dc7e24e3..2a8ba07e37 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,8 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: @@ -904,6 +902,20 @@ static const TCGOutOpUnary outop_ctpop = { .out_rr = tgen_ctpop, }; +static void tgen_bswap16(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_op_rr(s, INDEX_op_bswap16_i32, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_sextract(s, TCG_TYPE_REG, a0, a0, 0, 16); + } +} + +static const TCGOutOpBswap outop_bswap16 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap16, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); @@ -1055,13 +1067,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rr(s, opc, args[0], args[1]); break; - case INDEX_op_bswap16_i32: /* Optional (TCG_TARGET_HAS_bswap16_i32). */ - case INDEX_op_bswap16_i64: /* Optional (TCG_TARGET_HAS_bswap16_i64). */ - width = 16; - goto do_bswap; case INDEX_op_bswap32_i64: /* Optional (TCG_TARGET_HAS_bswap32_i64). */ width = 32; - do_bswap: /* The base tci bswaps zero-extend, and ignore high bits. */ tcg_out_op_rr(s, opc, args[0], args[1]); if (args[2] & TCG_BSWAP_OS) { From 0dd07ee1122abaf1adb4f1e00a8e0b89937f53bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 18:51:16 -0800 Subject: [PATCH 0447/2760] tcg: Merge INDEX_op_bswap16_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 7 +++---- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 9 +++------ tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 15 insertions(+), 21 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 26dc3bad49..509cfe7db1 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -415,7 +415,7 @@ Misc - | *t0* = *t1* | Move *t1* to *t0*. - * - bswap16_i32/i64 *t0*, *t1*, *flags* + * - bswap16 *t0*, *t1*, *flags* - | 16 bit byte swap on the low bits of a 32/64 bit input. | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 5e085607d5..acfbaa05b4 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -43,6 +43,7 @@ DEF(mov, 1, 1, 0, TCG_OPF_INT | TCG_OPF_NOT_PRESENT) DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) +DEF(bswap16, 1, 1, 1, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) DEF(ctpop, 1, 1, 0, TCG_OPF_INT) DEF(ctz, 1, 2, 0, TCG_OPF_INT) @@ -95,7 +96,6 @@ DEF(sub2_i32, 2, 4, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) -DEF(bswap16_i32, 1, 1, 1, 0) DEF(bswap32_i32, 1, 1, 1, 0) /* load/store */ @@ -122,7 +122,6 @@ DEF(extu_i32_i64, 1, 1, 0, 0) DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) -DEF(bswap16_i64, 1, 1, 1, 0) DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 54606388cc..1d535a9fae 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -518,7 +518,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, case INDEX_op_ctpop: return type == TCG_TYPE_I32 ? ctpop32(x) : ctpop64(x); - CASE_OP_32_64(bswap16): + case INDEX_op_bswap16: x = bswap16(x); return y & TCG_BSWAP_OS ? (int16_t)x : x; @@ -1572,8 +1572,7 @@ static bool fold_bswap(OptContext *ctx, TCGOp *op) z_mask = t1->z_mask; switch (op->opc) { - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: + case INDEX_op_bswap16: z_mask = bswap16(z_mask); sign = INT16_MIN; break; @@ -2870,7 +2869,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_brcond2_i32: done = fold_brcond2(&ctx, op); break; - CASE_OP_32_64(bswap16): + case INDEX_op_bswap16: CASE_OP_32_64(bswap32): case INDEX_op_bswap64_i64: done = fold_bswap(&ctx, op); diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index c5b3bc8148..917f52b04a 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1257,8 +1257,8 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) /* Only one extension flag may be present. */ tcg_debug_assert(!(flags & TCG_BSWAP_OS) || !(flags & TCG_BSWAP_OZ)); - if (tcg_op_supported(INDEX_op_bswap16_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3i_i32(INDEX_op_bswap16_i32, ret, arg, flags); + if (tcg_op_supported(INDEX_op_bswap16, TCG_TYPE_I32, 0)) { + tcg_gen_op3i_i32(INDEX_op_bswap16, ret, arg, flags); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); @@ -2087,8 +2087,8 @@ void tcg_gen_bswap16_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } - } else if (tcg_op_supported(INDEX_op_bswap16_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3i_i64(INDEX_op_bswap16_i64, ret, arg, flags); + } else if (tcg_op_supported(INDEX_op_bswap16, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_bswap16, ret, arg, flags); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 25834f40a0..ae68ce88b7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1075,8 +1075,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), - OUTOP(INDEX_op_bswap16_i32, TCGOutOpBswap, outop_bswap16), - OUTOP(INDEX_op_bswap16_i64, TCGOutOpBswap, outop_bswap16), + OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -2941,8 +2940,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) i = 1; } break; - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: + case INDEX_op_bswap16: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: @@ -5489,8 +5487,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: + case INDEX_op_bswap16: { const TCGOutOpBswap *out = container_of(all_outop[op->opc], TCGOutOpBswap, base); diff --git a/tcg/tci.c b/tcg/tci.c index ae447e91bd..905ca154fc 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -686,7 +686,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_write_reg64(regs, r1, r0, T1 - T2); break; #endif - CASE_32_64(bswap16) + case INDEX_op_bswap16: tci_args_rr(insn, &r0, &r1); regs[r0] = bswap16(regs[r1]); break; @@ -1005,14 +1005,13 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), s2); break; + case INDEX_op_bswap16: case INDEX_op_ctpop: case INDEX_op_mov: case INDEX_op_neg: case INDEX_op_not: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap16_i32: - case INDEX_op_bswap16_i64: case INDEX_op_bswap32_i32: case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2a8ba07e37..4d3d9569cc 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -905,7 +905,7 @@ static const TCGOutOpUnary outop_ctpop = { static void tgen_bswap16(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned flags) { - tcg_out_op_rr(s, INDEX_op_bswap16_i32, a0, a1); + tcg_out_op_rr(s, INDEX_op_bswap16, a0, a1); if (flags & TCG_BSWAP_OS) { tcg_out_sextract(s, TCG_TYPE_REG, a0, a0, 0, 16); } From d7b15a25a707f977e39af20c9f14a5ac4971c762 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 19:49:20 -0800 Subject: [PATCH 0448/2760] tcg: Convert bswap32 to TCGOutOpBswap Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 - tcg/aarch64/tcg-target.c.inc | 25 +++++----- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 23 ++++----- tcg/i386/tcg-target-has.h | 2 - tcg/i386/tcg-target.c.inc | 23 +++++---- tcg/loongarch64/tcg-target-has.h | 2 - tcg/loongarch64/tcg-target.c.inc | 33 +++++++------ tcg/mips/tcg-target-has.h | 2 - tcg/mips/tcg-target.c.inc | 54 ++++++++++---------- tcg/ppc/tcg-target-has.h | 2 - tcg/ppc/tcg-target.c.inc | 84 ++++++++++++++++---------------- tcg/riscv/tcg-target-has.h | 2 - tcg/riscv/tcg-target.c.inc | 30 +++++++----- tcg/s390x/tcg-target-has.h | 2 - tcg/s390x/tcg-target.c.inc | 31 ++++++------ tcg/sparc64/tcg-target-has.h | 2 - tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 4 +- tcg/tcg.c | 8 +-- tcg/tci.c | 2 - tcg/tci/tcg-target-has.h | 2 - tcg/tci/tcg-target.c.inc | 28 +++++------ 24 files changed, 182 insertions(+), 187 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 4797409467..7c3d3fc637 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,14 +13,12 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 03961b34aa..a2e45ca5c8 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2456,6 +2456,20 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_XZR, a1); @@ -2626,15 +2640,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_bswap64_i64: tcg_out_rev(s, TCG_TYPE_I64, MO_64, a0, a1); break; - case INDEX_op_bswap32_i64: - tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_ext32s(s, a0, a0); - } - break; - case INDEX_op_bswap32_i32: - tcg_out_rev(s, TCG_TYPE_I32, MO_32, a0, a1); - break; case INDEX_op_deposit_i64: case INDEX_op_deposit_i32: @@ -3154,8 +3159,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 5972def558..c85b5da1e5 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,7 +24,6 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 6928f209d2..4ca23bb718 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -969,12 +969,6 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) g_assert_not_reached(); } -static void tcg_out_bswap32(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn) -{ - /* rev */ - tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn); -} - static void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd, TCGArg a1, int ofs, int len, bool const_a1) { @@ -2157,6 +2151,18 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg rd, TCGReg rn, unsigned flags) +{ + /* rev */ + tcg_out32(s, 0x06bf0f30 | (COND_AL << 28) | (rd << 12) | rn); +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_subfi(s, type, a0, 0, a1); @@ -2378,10 +2384,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_bswap32_i32: - tcg_out_bswap32(s, COND_AL, args[0], args[1]); - break; - case INDEX_op_deposit_i32: tcg_out_deposit(s, COND_AL, args[0], args[2], args[3], args[4], const_args[2]); @@ -2438,7 +2440,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: return C_O1_I1(r, r); diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index fd44ed8168..ca533ab5cf 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,7 +26,6 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 @@ -34,7 +33,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index c74a718cee..6d90666ba7 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3090,6 +3090,20 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_bswap32(s, a0); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; @@ -3193,13 +3207,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(bswap32): - tcg_out_bswap32(s, a0); - if (rexw && (a2 & TCG_BSWAP_OS)) { - tcg_out_ext32s(s, a0, a0); - } - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I32); break; @@ -3972,8 +3979,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 11a93afd8b..e66df31954 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -13,13 +13,11 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 8be6f69e3a..d4bcb06a5f 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1751,6 +1751,24 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_opc_revb_2w(s, a0, a1); + + /* All 32-bit values are computed sign-extended in the register. */ + if (type == TCG_TYPE_I32 || (flags & TCG_BSWAP_OS)) { + tcg_out_ext32s(s, a0, a0); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext32u(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -1842,19 +1860,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); break; - case INDEX_op_bswap32_i32: - /* All 32-bit values are computed sign-extended in the register. */ - a2 = TCG_BSWAP_OS; - /* fallthrough */ - case INDEX_op_bswap32_i64: - tcg_out_opc_revb_2w(s, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_ext32s(s, a0, a0); - } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_ext32u(s, a0, a0); - } - break; - case INDEX_op_bswap64_i64: tcg_out_opc_revb_d(s, a0, a1); break; @@ -2454,8 +2459,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 6c967d9c9f..2391f5d8bf 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,7 +39,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 @@ -56,7 +55,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #endif diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 258b49f9db..ab8f8c9994 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -710,26 +710,6 @@ static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub) } } -static void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg, int flags) -{ - if (use_mips32r2_instructions) { - tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); - tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16); - if (flags & TCG_BSWAP_OZ) { - tcg_out_opc_bf(s, OPC_DEXT, ret, ret, 31, 0); - } - } else { - if (flags & TCG_BSWAP_OZ) { - tcg_out_bswap_subr(s, bswap32u_addr); - } else { - tcg_out_bswap_subr(s, bswap32_addr); - } - /* delay slot -- never omit the insn, like tcg_out_mov might. */ - tcg_out_opc_reg(s, OPC_OR, TCG_TMP0, arg, TCG_REG_ZERO); - tcg_out_mov(s, TCG_TYPE_I32, ret, TCG_TMP3); - } -} - static void tcg_out_bswap64(TCGContext *s, TCGReg ret, TCGReg arg) { if (use_mips32r2_instructions) { @@ -2170,6 +2150,32 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg ret, TCGReg arg, unsigned flags) +{ + if (use_mips32r2_instructions) { + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); + tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16); + if (flags & TCG_BSWAP_OZ) { + tcg_out_opc_bf(s, OPC_DEXT, ret, ret, 31, 0); + } + } else { + if (flags & TCG_BSWAP_OZ) { + tcg_out_bswap_subr(s, bswap32u_addr); + } else { + tcg_out_bswap_subr(s, bswap32_addr); + } + /* delay slot -- never omit the insn, like tcg_out_mov might. */ + tcg_out_opc_reg(s, OPC_OR, TCG_TMP0, arg, TCG_REG_ZERO); + tcg_out_mov(s, TCG_TYPE_I32, ret, TCG_TMP3); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2261,12 +2267,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_bswap32_i32: - tcg_out_bswap32(s, a0, a1, 0); - break; - case INDEX_op_bswap32_i64: - tcg_out_bswap32(s, a0, a1, a2); - break; case INDEX_op_bswap64_i64: tcg_out_bswap64(s, a0, a1); break; @@ -2371,7 +2371,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: @@ -2381,7 +2380,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index b73fca9789..ad0885d635 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,7 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 @@ -25,7 +24,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 3454254624..4527ed3eee 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1012,41 +1012,6 @@ static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm) tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2); } -static void tcg_out_bswap32(TCGContext *s, TCGReg dst, TCGReg src, int flags) -{ - TCGReg tmp = dst == src ? TCG_REG_R0 : dst; - - if (have_isa_3_10) { - tcg_out32(s, BRW | RA(dst) | RS(src)); - if (flags & TCG_BSWAP_OS) { - tcg_out_ext32s(s, dst, dst); - } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_ext32u(s, dst, dst); - } - return; - } - - /* - * Stolen from gcc's builtin_bswap32. - * In the following, - * dep(a, b, m) -> (a & ~m) | (b & m) - * - * Begin with: src = xxxxabcd - */ - /* tmp = rol32(src, 8) & 0xffffffff = 0000bcda */ - tcg_out_rlw(s, RLWINM, tmp, src, 8, 0, 31); - /* tmp = dep(tmp, rol32(src, 24), 0xff000000) = 0000dcda */ - tcg_out_rlw(s, RLWIMI, tmp, src, 24, 0, 7); - /* tmp = dep(tmp, rol32(src, 24), 0x0000ff00) = 0000dcba */ - tcg_out_rlw(s, RLWIMI, tmp, src, 24, 16, 23); - - if (flags & TCG_BSWAP_OS) { - tcg_out_ext32s(s, dst, tmp); - } else { - tcg_out_mov(s, TCG_TYPE_REG, dst, tmp); - } -} - static void tcg_out_bswap64(TCGContext *s, TCGReg dst, TCGReg src) { TCGReg t0 = dst == src ? TCG_REG_R0 : dst; @@ -3384,6 +3349,47 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg dst, TCGReg src, unsigned flags) +{ + TCGReg tmp = dst == src ? TCG_REG_R0 : dst; + + if (have_isa_3_10) { + tcg_out32(s, BRW | RA(dst) | RS(src)); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, dst, dst); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext32u(s, dst, dst); + } + return; + } + + /* + * Stolen from gcc's builtin_bswap32. + * In the following, + * dep(a, b, m) -> (a & ~m) | (b & m) + * + * Begin with: src = xxxxabcd + */ + /* tmp = rol32(src, 8) & 0xffffffff = 0000bcda */ + tcg_out_rlw(s, RLWINM, tmp, src, 8, 0, 31); + /* tmp = dep(tmp, rol32(src, 24), 0xff000000) = 0000dcda */ + tcg_out_rlw(s, RLWIMI, tmp, src, 24, 0, 7); + /* tmp = dep(tmp, rol32(src, 24), 0x0000ff00) = 0000dcba */ + tcg_out_rlw(s, RLWIMI, tmp, src, 24, 16, 23); + + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, dst, tmp); + } else { + tcg_out_mov(s, TCG_TYPE_REG, dst, tmp); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out32(s, NEG | RT(a0) | RA(a1)); @@ -3506,12 +3512,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_bswap32_i32: - tcg_out_bswap32(s, args[0], args[1], 0); - break; - case INDEX_op_bswap32_i64: - tcg_out_bswap32(s, args[0], args[1], args[2]); - break; case INDEX_op_bswap64_i64: tcg_out_bswap64(s, args[0], args[1]); break; @@ -4252,7 +4252,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_bswap32_i32: case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: @@ -4264,7 +4263,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_extract_i64: case INDEX_op_sextract_i64: diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 85bb5cd591..fbe294474a 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -13,12 +13,10 @@ #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 -#define TCG_TARGET_HAS_bswap32_i32 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap32_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index c6cd2100f8..9b6ca54ae7 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2424,6 +2424,23 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); + if (flags & TCG_BSWAP_OZ) { + tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 32); + } else { + tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 32); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_bswap, + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2509,17 +2526,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_bswap64_i64: tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); break; - case INDEX_op_bswap32_i32: - a2 = 0; - /* fall through */ - case INDEX_op_bswap32_i64: - tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); - if (a2 & TCG_BSWAP_OZ) { - tcg_out_opc_imm(s, OPC_SRLI, a0, a0, 32); - } else { - tcg_out_opc_imm(s, OPC_SRAI, a0, a0, 32); - } - break; case INDEX_op_add2_i32: tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], @@ -2858,8 +2864,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 6cd92fa240..76cfe4f323 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,14 +29,12 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e90c03628a..ed2da3f31d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2760,6 +2760,22 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_insn(s, RRE, LRVR, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_ext32s(s, a0, a0); + } else if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { + tcg_out_ext32u(s, a0, a0); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { if (type == TCG_TYPE_I32) { @@ -2846,19 +2862,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_bswap32_i32: - tcg_out_insn(s, RRE, LRVR, args[0], args[1]); - break; - case INDEX_op_bswap32_i64: - a0 = args[0], a1 = args[1], a2 = args[2]; - tcg_out_insn(s, RRE, LRVR, a0, a1); - if (a2 & TCG_BSWAP_OS) { - tcg_out_ext32s(s, a0, a0); - } else if ((a2 & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) { - tcg_out_ext32u(s, a0, a0); - } - break; - case INDEX_op_add2_i32: if (const_args[4]) { tcg_out_insn(s, RIL, ALFI, args[0], args[4]); @@ -3459,8 +3462,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index eb1e16c0e2..22837beca9 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,14 +14,12 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_bswap32_i32 0 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 5111f173e1..cbe9c759ec 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1729,6 +1729,10 @@ static const TCGOutOpBswap outop_bswap16 = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_G0, a1); diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 3d1c805d59..4034c73cca 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 0 #define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 917f52b04a..68e53a9c85 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1294,7 +1294,7 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) */ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (TCG_TARGET_HAS_bswap32_i32) { + if (tcg_op_supported(INDEX_op_bswap32_i32, TCG_TYPE_I32, 0)) { tcg_gen_op3i_i32(INDEX_op_bswap32_i32, ret, arg, 0); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2137,7 +2137,7 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } - } else if (TCG_TARGET_HAS_bswap32_i64) { + } else if (tcg_op_supported(INDEX_op_bswap32_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3i_i64(INDEX_op_bswap32_i64, ret, arg, flags); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index ae68ce88b7..89ef2ef89c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1076,6 +1076,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16), + OUTOP(INDEX_op_bswap32_i32, TCGOutOpBswap, outop_bswap32), + OUTOP(INDEX_op_bswap32_i64, TCGOutOpBswap, outop_bswap32), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -2342,8 +2344,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return TCG_TARGET_HAS_add2_i32; case INDEX_op_sub2_i32: return TCG_TARGET_HAS_sub2_i32; - case INDEX_op_bswap32_i32: - return TCG_TARGET_HAS_bswap32_i32; case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: @@ -2372,8 +2372,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return TCG_TARGET_HAS_extr_i64_i32; - case INDEX_op_bswap32_i64: - return TCG_TARGET_HAS_bswap32_i64; case INDEX_op_bswap64_i64: return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_add2_i64: @@ -5488,6 +5486,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_bswap16: + case INDEX_op_bswap32_i32: + case INDEX_op_bswap32_i64: { const TCGOutOpBswap *out = container_of(all_outop[op->opc], TCGOutOpBswap, base); diff --git a/tcg/tci.c b/tcg/tci.c index 905ca154fc..0cb89f3256 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -690,12 +690,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = bswap16(regs[r1]); break; -#if TCG_TARGET_HAS_bswap32_i32 || TCG_TARGET_HAS_bswap32_i64 CASE_32_64(bswap32) tci_args_rr(insn, &r0, &r1); regs[r0] = bswap32(regs[r1]); break; -#endif #if TCG_TARGET_REG_BITS == 64 /* Load/store operations (64 bit). */ diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index d7228246ab..c5c64f4f5d 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -7,13 +7,11 @@ #ifndef TCG_TARGET_HAS_H #define TCG_TARGET_HAS_H -#define TCG_TARGET_HAS_bswap32_i32 1 #define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap32_i64 1 #define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i32 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4d3d9569cc..1b2f18e370 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,8 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: case INDEX_op_extract_i32: case INDEX_op_extract_i64: @@ -916,6 +914,20 @@ static const TCGOutOpBswap outop_bswap16 = { .out_rr = tgen_bswap16, }; +static void tgen_bswap32(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, unsigned flags) +{ + tcg_out_op_rr(s, INDEX_op_bswap32_i32, a0, a1); + if (flags & TCG_BSWAP_OS) { + tcg_out_sextract(s, TCG_TYPE_REG, a0, a0, 0, 32); + } +} + +static const TCGOutOpBswap outop_bswap32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap32, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); @@ -1026,8 +1038,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - int width; - switch (opc) { case INDEX_op_goto_ptr: tcg_out_op_r(s, opc, args[0]); @@ -1062,20 +1072,10 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rrbb(s, opc, args[0], args[1], args[2], args[3]); break; - case INDEX_op_bswap32_i32: /* Optional (TCG_TARGET_HAS_bswap32_i32). */ case INDEX_op_bswap64_i64: /* Optional (TCG_TARGET_HAS_bswap64_i64). */ tcg_out_op_rr(s, opc, args[0], args[1]); break; - case INDEX_op_bswap32_i64: /* Optional (TCG_TARGET_HAS_bswap32_i64). */ - width = 32; - /* The base tci bswaps zero-extend, and ignore high bits. */ - tcg_out_op_rr(s, opc, args[0], args[1]); - if (args[2] & TCG_BSWAP_OS) { - tcg_out_sextract(s, TCG_TYPE_REG, args[0], args[0], 0, width); - } - break; - CASE_32_64(add2) CASE_32_64(sub2) tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2], From 7498d882cbe39ae7df4315ea006830e640f0d47b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 19:53:51 -0800 Subject: [PATCH 0449/2760] tcg: Merge INDEX_op_bswap32_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 13 ++++++------- include/tcg/tcg-opc.h | 4 +--- tcg/optimize.c | 7 +++---- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 9 +++------ tcg/tci.c | 5 ++--- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 20 insertions(+), 28 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 509cfe7db1..e89ede54fa 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -425,16 +425,15 @@ Misc | | If neither ``TCG_BSWAP_OZ`` nor ``TCG_BSWAP_OS`` are set, then the bits of *t0* above bit 15 may contain any value. - * - bswap32_i64 *t0*, *t1*, *flags* + * - bswap32 *t0*, *t1*, *flags* - - | 32 bit byte swap on a 64-bit value. The flags are the same as for bswap16, - except they apply from bit 31 instead of bit 15. + - | 32 bit byte swap. The flags are the same as for bswap16, except + they apply from bit 31 instead of bit 15. On TCG_TYPE_I32, the + flags should be zero. - * - bswap32_i32 *t0*, *t1*, *flags* + * - bswap64_i64 *t0*, *t1*, *flags* - bswap64_i64 *t0*, *t1*, *flags* - - - | 32/64 bit byte swap. The flags are ignored, but still present + - | 64 bit byte swap. The flags are ignored, but still present for consistency with the other bswap opcodes. * - discard_i32/i64 *t0* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index acfbaa05b4..296dffe99a 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -44,6 +44,7 @@ DEF(add, 1, 2, 0, TCG_OPF_INT) DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(bswap16, 1, 1, 1, TCG_OPF_INT) +DEF(bswap32, 1, 1, 1, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) DEF(ctpop, 1, 1, 0, TCG_OPF_INT) DEF(ctz, 1, 2, 0, TCG_OPF_INT) @@ -96,8 +97,6 @@ DEF(sub2_i32, 2, 4, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) -DEF(bswap32_i32, 1, 1, 1, 0) - /* load/store */ DEF(ld8u_i64, 1, 1, 1, 0) DEF(ld8s_i64, 1, 1, 1, 0) @@ -122,7 +121,6 @@ DEF(extu_i32_i64, 1, 1, 0, 0) DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) -DEF(bswap32_i64, 1, 1, 1, 0) DEF(bswap64_i64, 1, 1, 1, 0) DEF(add2_i64, 2, 4, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 1d535a9fae..6fa968624d 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -522,7 +522,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, x = bswap16(x); return y & TCG_BSWAP_OS ? (int16_t)x : x; - CASE_OP_32_64(bswap32): + case INDEX_op_bswap32: x = bswap32(x); return y & TCG_BSWAP_OS ? (int32_t)x : x; @@ -1576,8 +1576,7 @@ static bool fold_bswap(OptContext *ctx, TCGOp *op) z_mask = bswap16(z_mask); sign = INT16_MIN; break; - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: + case INDEX_op_bswap32: z_mask = bswap32(z_mask); sign = INT32_MIN; break; @@ -2870,7 +2869,7 @@ void tcg_optimize(TCGContext *s) done = fold_brcond2(&ctx, op); break; case INDEX_op_bswap16: - CASE_OP_32_64(bswap32): + case INDEX_op_bswap32: case INDEX_op_bswap64_i64: done = fold_bswap(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 68e53a9c85..b1174f60cc 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1294,8 +1294,8 @@ void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg, int flags) */ void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg) { - if (tcg_op_supported(INDEX_op_bswap32_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op3i_i32(INDEX_op_bswap32_i32, ret, arg, 0); + if (tcg_op_supported(INDEX_op_bswap32, TCG_TYPE_I32, 0)) { + tcg_gen_op3i_i32(INDEX_op_bswap32, ret, arg, 0); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); @@ -2137,8 +2137,8 @@ void tcg_gen_bswap32_i64(TCGv_i64 ret, TCGv_i64 arg, int flags) } else { tcg_gen_movi_i32(TCGV_HIGH(ret), 0); } - } else if (tcg_op_supported(INDEX_op_bswap32_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3i_i64(INDEX_op_bswap32_i64, ret, arg, flags); + } else if (tcg_op_supported(INDEX_op_bswap32, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_bswap32, ret, arg, flags); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 89ef2ef89c..571f15626c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1076,8 +1076,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), OUTOP(INDEX_op_bswap16, TCGOutOpBswap, outop_bswap16), - OUTOP(INDEX_op_bswap32_i32, TCGOutOpBswap, outop_bswap32), - OUTOP(INDEX_op_bswap32_i64, TCGOutOpBswap, outop_bswap32), + OUTOP(INDEX_op_bswap32, TCGOutOpBswap, outop_bswap32), OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), @@ -2939,8 +2938,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) } break; case INDEX_op_bswap16: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: + case INDEX_op_bswap32: case INDEX_op_bswap64_i64: { TCGArg flags = op->args[k]; @@ -5486,8 +5484,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_bswap16: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: + case INDEX_op_bswap32: { const TCGOutOpBswap *out = container_of(all_outop[op->opc], TCGOutOpBswap, base); diff --git a/tcg/tci.c b/tcg/tci.c index 0cb89f3256..f98c437100 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -690,7 +690,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = bswap16(regs[r1]); break; - CASE_32_64(bswap32) + case INDEX_op_bswap32: tci_args_rr(insn, &r0, &r1); regs[r0] = bswap32(regs[r1]); break; @@ -1004,14 +1004,13 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_bswap16: + case INDEX_op_bswap32: case INDEX_op_ctpop: case INDEX_op_mov: case INDEX_op_neg: case INDEX_op_not: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap32_i32: - case INDEX_op_bswap32_i64: case INDEX_op_bswap64_i64: tci_args_rr(insn, &r0, &r1); info->fprintf_func(info->stream, "%-12s %s, %s", diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1b2f18e370..7478ada393 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -917,7 +917,7 @@ static const TCGOutOpBswap outop_bswap16 = { static void tgen_bswap32(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned flags) { - tcg_out_op_rr(s, INDEX_op_bswap32_i32, a0, a1); + tcg_out_op_rr(s, INDEX_op_bswap32, a0, a1); if (flags & TCG_BSWAP_OS) { tcg_out_sextract(s, TCG_TYPE_REG, a0, a0, 0, 32); } From 613b571c93db4cec7d0023b857c1b857af7a3324 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 21:46:38 -0800 Subject: [PATCH 0450/2760] tcg: Convert bswap64 to TCGOutOpUnary Use TCGOutOpUnary instead of TCGOutOpBswap because the flags are not used with this opcode; they are merely present for uniformity with the smaller bswaps. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 1 - tcg/aarch64/tcg-target.c.inc | 15 ++++-- tcg/arm/tcg-target.c.inc | 4 ++ tcg/i386/tcg-target-has.h | 1 - tcg/i386/tcg-target.c.inc | 16 ++++-- tcg/loongarch64/tcg-target-has.h | 1 - tcg/loongarch64/tcg-target.c.inc | 15 ++++-- tcg/mips/tcg-target-has.h | 1 - tcg/mips/tcg-target.c.inc | 37 ++++++++------ tcg/ppc/tcg-target-has.h | 1 - tcg/ppc/tcg-target.c.inc | 88 ++++++++++++++++---------------- tcg/riscv/tcg-target-has.h | 1 - tcg/riscv/tcg-target.c.inc | 16 ++++-- tcg/s390x/tcg-target-has.h | 1 - tcg/s390x/tcg-target.c.inc | 15 ++++-- tcg/sparc64/tcg-target-has.h | 1 - tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 2 +- tcg/tcg.c | 7 ++- tcg/tci.c | 2 - tcg/tci/tcg-target-has.h | 1 - tcg/tci/tcg-target.c.inc | 17 ++++-- 23 files changed, 144 insertions(+), 104 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 7c3d3fc637..82d8cd5965 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -19,7 +19,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index a2e45ca5c8..79c0e2e097 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2470,6 +2470,16 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_rev(s, TCG_TYPE_I64, MO_64, a0, a1); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_XZR, a1); @@ -2637,10 +2647,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; - case INDEX_op_bswap64_i64: - tcg_out_rev(s, TCG_TYPE_I64, MO_64, a0, a1); - break; - case INDEX_op_deposit_i64: case INDEX_op_deposit_i32: tcg_out_dep(s, ext, a0, a2, args[3], args[4]); @@ -3159,7 +3165,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 4ca23bb718..3bbc28c63c 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2163,6 +2163,10 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_subfi(s, type, a0, 0, a1); diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index ca533ab5cf..6b91b23fe8 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -33,7 +33,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 6d90666ba7..347e01c076 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3104,6 +3104,18 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_bswap64(s, a0); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_bswap64, +}; +#endif + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; @@ -3279,9 +3291,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_bswap64_i64: - tcg_out_bswap64(s, a0); - break; case INDEX_op_extrh_i64_i32: tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32); break; @@ -3979,7 +3988,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_bswap64_i64: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index e66df31954..10090102f7 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -18,7 +18,6 @@ /* 64-bit operations */ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index d4bcb06a5f..f3b2f709d2 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1769,6 +1769,16 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_revb_d(s, a0, a1); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -1860,10 +1870,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); break; - case INDEX_op_bswap64_i64: - tcg_out_opc_revb_d(s, a0, a1); - break; - case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); @@ -2459,7 +2465,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap64_i64: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: case INDEX_op_ld8u_i32: diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 2391f5d8bf..24b00f1eec 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -55,7 +55,6 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #endif diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index ab8f8c9994..baaf0e416b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -710,19 +710,6 @@ static void tcg_out_bswap_subr(TCGContext *s, const tcg_insn_unit *sub) } } -static void tcg_out_bswap64(TCGContext *s, TCGReg ret, TCGReg arg) -{ - if (use_mips32r2_instructions) { - tcg_out_opc_reg(s, OPC_DSBH, ret, 0, arg); - tcg_out_opc_reg(s, OPC_DSHD, ret, 0, ret); - } else { - tcg_out_bswap_subr(s, bswap64_addr); - /* delay slot -- never omit the insn, like tcg_out_mov might. */ - tcg_out_opc_reg(s, OPC_OR, TCG_TMP0, arg, TCG_REG_ZERO); - tcg_out_mov(s, TCG_TYPE_I32, ret, TCG_TMP3); - } -} - static void tcg_out_ext32u(TCGContext *s, TCGReg ret, TCGReg arg) { tcg_debug_assert(TCG_TARGET_REG_BITS == 64); @@ -2176,6 +2163,26 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) +{ + if (use_mips32r2_instructions) { + tcg_out_opc_reg(s, OPC_DSBH, ret, 0, arg); + tcg_out_opc_reg(s, OPC_DSHD, ret, 0, ret); + } else { + tcg_out_bswap_subr(s, bswap64_addr); + /* delay slot -- never omit the insn, like tcg_out_mov might. */ + tcg_out_opc_reg(s, OPC_OR, TCG_TMP0, arg, TCG_REG_ZERO); + tcg_out_mov(s, TCG_TYPE_I32, ret, TCG_TMP3); + } +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; +#endif /* TCG_TARGET_REG_BITS == 64 */ + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2267,9 +2274,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_bswap64_i64: - tcg_out_bswap64(s, a0, a1); - break; case INDEX_op_extrh_i64_i32: tcg_out_dsra(s, a0, a1, 32); break; @@ -2380,7 +2384,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index ad0885d635..bd9c3d92ed 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -24,7 +24,6 @@ #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 4527ed3eee..083137d211 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1012,44 +1012,6 @@ static void tcg_out_addpcis(TCGContext *s, TCGReg dst, intptr_t imm) tcg_out32(s, ADDPCIS | RT(dst) | (d1 << 16) | (d0 << 6) | d2); } -static void tcg_out_bswap64(TCGContext *s, TCGReg dst, TCGReg src) -{ - TCGReg t0 = dst == src ? TCG_REG_R0 : dst; - TCGReg t1 = dst == src ? dst : TCG_REG_R0; - - if (have_isa_3_10) { - tcg_out32(s, BRD | RA(dst) | RS(src)); - return; - } - - /* - * In the following, - * dep(a, b, m) -> (a & ~m) | (b & m) - * - * Begin with: src = abcdefgh - */ - /* t0 = rol32(src, 8) & 0xffffffff = 0000fghe */ - tcg_out_rlw(s, RLWINM, t0, src, 8, 0, 31); - /* t0 = dep(t0, rol32(src, 24), 0xff000000) = 0000hghe */ - tcg_out_rlw(s, RLWIMI, t0, src, 24, 0, 7); - /* t0 = dep(t0, rol32(src, 24), 0x0000ff00) = 0000hgfe */ - tcg_out_rlw(s, RLWIMI, t0, src, 24, 16, 23); - - /* t0 = rol64(t0, 32) = hgfe0000 */ - tcg_out_rld(s, RLDICL, t0, t0, 32, 0); - /* t1 = rol64(src, 32) = efghabcd */ - tcg_out_rld(s, RLDICL, t1, src, 32, 0); - - /* t0 = dep(t0, rol32(t1, 24), 0xffffffff) = hgfebcda */ - tcg_out_rlw(s, RLWIMI, t0, t1, 8, 0, 31); - /* t0 = dep(t0, rol32(t1, 24), 0xff000000) = hgfedcda */ - tcg_out_rlw(s, RLWIMI, t0, t1, 24, 0, 7); - /* t0 = dep(t0, rol32(t1, 24), 0x0000ff00) = hgfedcba */ - tcg_out_rlw(s, RLWIMI, t0, t1, 24, 16, 23); - - tcg_out_mov(s, TCG_TYPE_REG, dst, t0); -} - /* Emit a move into ret of arg, if it can be done in one insn. */ static bool tcg_out_movi_one(TCGContext *s, TCGReg ret, tcg_target_long arg) { @@ -3390,6 +3352,51 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg dst, TCGReg src) +{ + TCGReg t0 = dst == src ? TCG_REG_R0 : dst; + TCGReg t1 = dst == src ? dst : TCG_REG_R0; + + if (have_isa_3_10) { + tcg_out32(s, BRD | RA(dst) | RS(src)); + return; + } + + /* + * In the following, + * dep(a, b, m) -> (a & ~m) | (b & m) + * + * Begin with: src = abcdefgh + */ + /* t0 = rol32(src, 8) & 0xffffffff = 0000fghe */ + tcg_out_rlw(s, RLWINM, t0, src, 8, 0, 31); + /* t0 = dep(t0, rol32(src, 24), 0xff000000) = 0000hghe */ + tcg_out_rlw(s, RLWIMI, t0, src, 24, 0, 7); + /* t0 = dep(t0, rol32(src, 24), 0x0000ff00) = 0000hgfe */ + tcg_out_rlw(s, RLWIMI, t0, src, 24, 16, 23); + + /* t0 = rol64(t0, 32) = hgfe0000 */ + tcg_out_rld(s, RLDICL, t0, t0, 32, 0); + /* t1 = rol64(src, 32) = efghabcd */ + tcg_out_rld(s, RLDICL, t1, src, 32, 0); + + /* t0 = dep(t0, rol32(t1, 24), 0xffffffff) = hgfebcda */ + tcg_out_rlw(s, RLWIMI, t0, t1, 8, 0, 31); + /* t0 = dep(t0, rol32(t1, 24), 0xff000000) = hgfedcda */ + tcg_out_rlw(s, RLWIMI, t0, t1, 24, 0, 7); + /* t0 = dep(t0, rol32(t1, 24), 0x0000ff00) = hgfedcba */ + tcg_out_rlw(s, RLWIMI, t0, t1, 24, 16, 23); + + tcg_out_mov(s, TCG_TYPE_REG, dst, t0); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; +#endif /* TCG_TARGET_REG_BITS == 64 */ + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out32(s, NEG | RT(a0) | RA(a1)); @@ -3512,10 +3519,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_bswap64_i64: - tcg_out_bswap64(s, args[0], args[1]); - break; - case INDEX_op_deposit_i32: if (const_args[2]) { uint32_t mask = ((2u << (args[4] - 1)) - 1) << args[3]; @@ -4263,7 +4266,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap64_i64: case INDEX_op_extract_i64: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index fbe294474a..88fadc2428 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -17,7 +17,6 @@ #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_bswap64_i64 (cpuinfo & CPUINFO_ZBB) #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 9b6ca54ae7..00b097d171 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2441,6 +2441,17 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_bswap, + .out_rr = tgen_bswap64, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_ZERO, a1); @@ -2523,10 +2534,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_bswap64_i64: - tcg_out_opc_imm(s, OPC_REV8, a0, a1, 0); - break; - case INDEX_op_add2_i32: tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], const_args[4], const_args[5], false, true); @@ -2864,7 +2871,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: - case INDEX_op_bswap64_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 76cfe4f323..95407f61cf 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -35,7 +35,6 @@ extern uint64_t s390_facilities[3]; #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index ed2da3f31d..2ed288cfe0 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2776,6 +2776,16 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_insn(s, RRE, LRVGR, a0, a1); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { if (type == TCG_TYPE_I32) { @@ -2922,10 +2932,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_bswap64_i64: - tcg_out_insn(s, RRE, LRVGR, args[0], args[1]); - break; - case INDEX_op_add2_i64: if (const_args[4]) { if ((int64_t)args[4] >= 0) { @@ -3462,7 +3468,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_bswap64_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extract_i32: diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 22837beca9..2ced6f7c1c 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -20,7 +20,6 @@ extern bool use_vis3_instructions; #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index cbe9c759ec..96ffba9af6 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1733,6 +1733,10 @@ static const TCGOutOpBswap outop_bswap32 = { .base.static_constraint = C_NotImplemented, }; +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tgen_sub(s, type, a0, TCG_REG_G0, a1); diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 4034c73cca..21bef070fe 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 0 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b1174f60cc..27e700161f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2184,7 +2184,7 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) tcg_gen_mov_i32(TCGV_HIGH(ret), t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - } else if (TCG_TARGET_HAS_bswap64_i64) { + } else if (tcg_op_supported(INDEX_op_bswap64_i64, TCG_TYPE_I64, 0)) { tcg_gen_op3i_i64(INDEX_op_bswap64_i64, ret, arg, 0); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 571f15626c..f2f2c0dd74 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1112,6 +1112,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { #if TCG_TARGET_REG_BITS == 32 OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), +#else + OUTOP(INDEX_op_bswap64_i64, TCGOutOpUnary, outop_bswap64), #endif }; @@ -2371,8 +2373,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return TCG_TARGET_HAS_extr_i64_i32; - case INDEX_op_bswap64_i64: - return TCG_TARGET_HAS_bswap64_i64; case INDEX_op_add2_i64: return TCG_TARGET_HAS_add2_i64; case INDEX_op_sub2_i64: @@ -5470,6 +5470,9 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_bswap64_i64: + assert(TCG_TARGET_REG_BITS == 64); + /* fall through */ case INDEX_op_ctpop: case INDEX_op_neg: case INDEX_op_not: diff --git a/tcg/tci.c b/tcg/tci.c index f98c437100..903f996f02 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -788,12 +788,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = (uint32_t)regs[r1]; break; -#if TCG_TARGET_HAS_bswap64_i64 case INDEX_op_bswap64_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = bswap64(regs[r1]); break; -#endif #endif /* TCG_TARGET_REG_BITS == 64 */ /* QEMU specific operations. */ diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index c5c64f4f5d..90aa5c8bbb 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_bswap64_i64 1 #define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 7478ada393..cbfe92adf3 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,7 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap64_i64: case INDEX_op_extract_i32: case INDEX_op_extract_i64: case INDEX_op_sextract_i32: @@ -928,6 +927,18 @@ static const TCGOutOpBswap outop_bswap32 = { .out_rr = tgen_bswap32, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_op_rr(s, INDEX_op_bswap64_i64, a0, a1); +} + +static const TCGOutOpUnary outop_bswap64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_bswap64, +}; +#endif + static void tgen_neg(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { tcg_out_op_rr(s, INDEX_op_neg, a0, a1); @@ -1072,10 +1083,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rrbb(s, opc, args[0], args[1], args[2], args[3]); break; - case INDEX_op_bswap64_i64: /* Optional (TCG_TARGET_HAS_bswap64_i64). */ - tcg_out_op_rr(s, opc, args[0], args[1]); - break; - CASE_32_64(add2) CASE_32_64(sub2) tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2], From 3ad5d4ccb4bdebdff4e90957bb2b8a93e5e418e2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 10 Jan 2025 21:54:44 -0800 Subject: [PATCH 0451/2760] tcg: Rename INDEX_op_bswap64_i64 to INDEX_op_bswap64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Even though bswap64 can only be used with TCG_TYPE_I64, rename the opcode to maintain uniformity. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 5 +++-- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 6 +++--- tcg/tcg-op.c | 4 ++-- tcg/tcg.c | 6 +++--- tcg/tci.c | 4 ++-- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index e89ede54fa..72a23d6ea2 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -431,10 +431,11 @@ Misc they apply from bit 31 instead of bit 15. On TCG_TYPE_I32, the flags should be zero. - * - bswap64_i64 *t0*, *t1*, *flags* + * - bswap64 *t0*, *t1*, *flags* - | 64 bit byte swap. The flags are ignored, but still present - for consistency with the other bswap opcodes. + for consistency with the other bswap opcodes. For future + compatibility, the flags should be zero. * - discard_i32/i64 *t0* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 296dffe99a..1d27b882fe 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -45,6 +45,7 @@ DEF(and, 1, 2, 0, TCG_OPF_INT) DEF(andc, 1, 2, 0, TCG_OPF_INT) DEF(bswap16, 1, 1, 1, TCG_OPF_INT) DEF(bswap32, 1, 1, 1, TCG_OPF_INT) +DEF(bswap64, 1, 1, 1, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) DEF(ctpop, 1, 1, 0, TCG_OPF_INT) DEF(ctz, 1, 2, 0, TCG_OPF_INT) @@ -121,8 +122,6 @@ DEF(extu_i32_i64, 1, 1, 0, 0) DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) -DEF(bswap64_i64, 1, 1, 1, 0) - DEF(add2_i64, 2, 4, 0, 0) DEF(sub2_i64, 2, 4, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 6fa968624d..a860b62109 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -526,7 +526,7 @@ static uint64_t do_constant_folding_2(TCGOpcode op, TCGType type, x = bswap32(x); return y & TCG_BSWAP_OS ? (int32_t)x : x; - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: return bswap64(x); case INDEX_op_ext_i32_i64: @@ -1580,7 +1580,7 @@ static bool fold_bswap(OptContext *ctx, TCGOp *op) z_mask = bswap32(z_mask); sign = INT32_MIN; break; - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: z_mask = bswap64(z_mask); sign = INT64_MIN; break; @@ -2870,7 +2870,7 @@ void tcg_optimize(TCGContext *s) break; case INDEX_op_bswap16: case INDEX_op_bswap32: - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: done = fold_bswap(&ctx, op); break; case INDEX_op_clz: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 27e700161f..ba062191ac 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2184,8 +2184,8 @@ void tcg_gen_bswap64_i64(TCGv_i64 ret, TCGv_i64 arg) tcg_gen_mov_i32(TCGV_HIGH(ret), t0); tcg_temp_free_i32(t0); tcg_temp_free_i32(t1); - } else if (tcg_op_supported(INDEX_op_bswap64_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op3i_i64(INDEX_op_bswap64_i64, ret, arg, 0); + } else if (tcg_op_supported(INDEX_op_bswap64, TCG_TYPE_I64, 0)) { + tcg_gen_op3i_i64(INDEX_op_bswap64, ret, arg, 0); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index f2f2c0dd74..1ba86dd515 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1113,7 +1113,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), #else - OUTOP(INDEX_op_bswap64_i64, TCGOutOpUnary, outop_bswap64), + OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64), #endif }; @@ -2939,7 +2939,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) break; case INDEX_op_bswap16: case INDEX_op_bswap32: - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: { TCGArg flags = op->args[k]; const char *name = NULL; @@ -5470,7 +5470,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: assert(TCG_TARGET_REG_BITS == 64); /* fall through */ case INDEX_op_ctpop: diff --git a/tcg/tci.c b/tcg/tci.c index 903f996f02..30928c3412 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -788,7 +788,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = (uint32_t)regs[r1]; break; - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: tci_args_rr(insn, &r0, &r1); regs[r0] = bswap64(regs[r1]); break; @@ -1009,7 +1009,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_not: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_bswap64_i64: + case INDEX_op_bswap64: tci_args_rr(insn, &r0, &r1); info->fprintf_func(info->stream, "%-12s %s, %s", op_name, str_r(r0), str_r(r1)); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index cbfe92adf3..4fc857ad35 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -930,7 +930,7 @@ static const TCGOutOpBswap outop_bswap32 = { #if TCG_TARGET_REG_BITS == 64 static void tgen_bswap64(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) { - tcg_out_op_rr(s, INDEX_op_bswap64_i64, a0, a1); + tcg_out_op_rr(s, INDEX_op_bswap64, a0, a1); } static const TCGOutOpUnary outop_bswap64 = { From 5a4d034f3cbc6d3bffc983b24a2746e9fe9b91cd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 11 Jan 2025 07:55:47 -0800 Subject: [PATCH 0452/2760] tcg: Convert extract to TCGOutOpExtract Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 28 +++++++----- tcg/arm/tcg-target.c.inc | 23 +++++----- tcg/i386/tcg-target.c.inc | 77 +++++++++++++++++--------------- tcg/loongarch64/tcg-target.c.inc | 33 +++++++------- tcg/mips/tcg-target.c.inc | 35 +++++++-------- tcg/ppc/tcg-target.c.inc | 35 +++++++-------- tcg/riscv/tcg-target.c.inc | 54 +++++++++++----------- tcg/s390x/tcg-target.c.inc | 14 +++--- tcg/sparc64/tcg-target.c.inc | 16 ++++--- tcg/tcg.c | 20 +++++++++ tcg/tci/tcg-target.c.inc | 8 ++-- 11 files changed, 191 insertions(+), 152 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 79c0e2e097..6c9d6094a2 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2567,6 +2567,22 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + uint64_t mask = MAKE_64BIT_MASK(0, len); + tcg_out_logicali(s, I3404_ANDI, type, a0, a1, mask); + } else { + tcg_out_ubfm(s, type, a0, a1, ofs, ofs + len - 1); + } +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2652,16 +2668,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_dep(s, ext, a0, a2, args[3], args[4]); break; - case INDEX_op_extract_i64: - case INDEX_op_extract_i32: - if (a2 == 0) { - uint64_t mask = MAKE_64BIT_MASK(0, args[3]); - tcg_out_logicali(s, I3404_ANDI, ext, a0, a1, mask); - } else { - tcg_out_ubfm(s, ext, a0, a1, a2, a2 + args[3] - 1); - } - break; - case INDEX_op_sextract_i64: case INDEX_op_sextract_i32: tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1); @@ -3167,8 +3173,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 3bbc28c63c..bc060b20f2 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -981,19 +981,19 @@ static void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd, | (ofs << 7) | ((ofs + len - 1) << 16)); } -static void tcg_out_extract(TCGContext *s, ARMCond cond, TCGReg rd, - TCGReg rn, int ofs, int len) +static void tgen_extract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, + unsigned ofs, unsigned len) { /* According to gcc, AND can be faster. */ if (ofs == 0 && len <= 8) { - tcg_out_dat_imm(s, cond, ARITH_AND, rd, rn, + tcg_out_dat_imm(s, COND_AL, ARITH_AND, rd, rn, encode_imm_nofail((1 << len) - 1)); return; } if (use_armv7_instructions) { /* ubfx */ - tcg_out32(s, 0x07e00050 | (cond << 28) | (rd << 12) | rn + tcg_out32(s, 0x07e00050 | (COND_AL << 28) | (rd << 12) | rn | (ofs << 7) | ((len - 1) << 16)); return; } @@ -1002,17 +1002,24 @@ static void tcg_out_extract(TCGContext *s, ARMCond cond, TCGReg rd, switch (len) { case 8: /* uxtb */ - tcg_out32(s, 0x06ef0070 | (cond << 28) | (rd << 12) | (ofs << 7) | rn); + tcg_out32(s, 0x06ef0070 | (COND_AL << 28) | + (rd << 12) | (ofs << 7) | rn); break; case 16: /* uxth */ - tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | (ofs << 7) | rn); + tcg_out32(s, 0x06ff0070 | (COND_AL << 28) | + (rd << 12) | (ofs << 7) | rn); break; default: g_assert_not_reached(); } } +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; + static void tcg_out_sextract(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn, int ofs, int len) { @@ -2392,9 +2399,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_deposit(s, COND_AL, args[0], args[2], args[3], args[4], const_args[2]); break; - case INDEX_op_extract_i32: - tcg_out_extract(s, COND_AL, args[0], args[1], args[2], args[3]); - break; case INDEX_op_sextract_i32: tcg_out_sextract(s, COND_AL, args[0], args[1], args[2], args[3]); break; @@ -2444,7 +2448,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_extract_i32: case INDEX_op_sextract_i32: return C_O1_I1(r, r); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 347e01c076..b26c93bdb1 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3138,6 +3138,47 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8u(s, a0, a1); + return; + case 16: + tcg_out_ext16u(s, a0, a1); + return; + case 32: + tcg_out_ext32u(s, a0, a1); + return; + } + } else if (TCG_TARGET_REG_BITS == 64 && ofs + len == 32) { + /* This is a 32-bit zero-extending right shift. */ + tcg_out_mov(s, TCG_TYPE_I32, a0, a1); + tcg_out_shifti(s, SHIFT_SHR, a0, ofs); + return; + } else if (ofs == 8 && len == 8) { + /* + * On the off-chance that we can use the high-byte registers. + * Otherwise we emit the same ext16 + shift pattern that we + * would have gotten from the normal tcg-op.c expansion. + */ + if (a1 < 4 && (TCG_TARGET_REG_BITS == 32 || a0 < 8)) { + tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4); + } else { + tcg_out_ext16u(s, a0, a1); + tcg_out_shifti(s, SHIFT_SHR, a0, 8); + } + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3328,40 +3369,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_extract_i64: - if (a2 + args[3] == 32) { - if (a2 == 0) { - tcg_out_ext32u(s, a0, a1); - break; - } - /* This is a 32-bit zero-extending right shift. */ - tcg_out_mov(s, TCG_TYPE_I32, a0, a1); - tcg_out_shifti(s, SHIFT_SHR, a0, a2); - break; - } - /* FALLTHRU */ - case INDEX_op_extract_i32: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8u(s, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16u(s, a0, a1); - } else if (a2 == 8 && args[3] == 8) { - /* - * On the off-chance that we can use the high-byte registers. - * Otherwise we emit the same ext16 + shift pattern that we - * would have gotten from the normal tcg-op.c expansion. - */ - if (a1 < 4 && a0 < 8) { - tcg_out_modrm(s, OPC_MOVZBL, a0, a1 + 4); - } else { - tcg_out_ext16u(s, a0, a1); - tcg_out_shifti(s, SHIFT_SHR, a0, 8); - } - } else { - g_assert_not_reached(); - } - break; - case INDEX_op_sextract_i64: if (a2 == 0 && args[3] == 8) { tcg_out_ext8s(s, TCG_TYPE_I64, a0, a1); @@ -3994,8 +4001,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index f3b2f709d2..f63d33e9ac 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1799,6 +1799,22 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0 && len <= 12) { + tcg_out_opc_andi(s, a0, a1, (1 << len) - 1); + } else if (type == TCG_TYPE_I32) { + tcg_out_opc_bstrpick_w(s, a0, a1, ofs, ofs + len - 1); + } else { + tcg_out_opc_bstrpick_d(s, a0, a1, ofs, ofs + len - 1); + } +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1828,21 +1844,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_srai_d(s, a0, a1, 32); break; - case INDEX_op_extract_i32: - if (a2 == 0 && args[3] <= 12) { - tcg_out_opc_andi(s, a0, a1, (1 << args[3]) - 1); - } else { - tcg_out_opc_bstrpick_w(s, a0, a1, a2, a2 + args[3] - 1); - } - break; - case INDEX_op_extract_i64: - if (a2 == 0 && args[3] <= 12) { - tcg_out_opc_andi(s, a0, a1, (1 << args[3]) - 1); - } else { - tcg_out_opc_bstrpick_d(s, a0, a1, a2, a2 + args[3] - 1); - } - break; - case INDEX_op_sextract_i64: if (a2 + args[3] == 32) { if (a2 == 0) { @@ -2461,8 +2462,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: case INDEX_op_ld8s_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index baaf0e416b..dbb4b9355d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2203,6 +2203,23 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0 && len <= 16) { + tcg_out_opc_imm(s, OPC_ANDI, a0, a1, (1 << len) - 1); + } else if (type == TCG_TYPE_I32) { + tcg_out_opc_bf(s, OPC_EXT, a0, a1, len - 1, ofs); + } else { + tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, + a0, a1, len - 1, ofs); + } +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2286,22 +2303,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[3] + args[4] - 1, args[3]); break; - case INDEX_op_extract_i32: - if (a2 == 0 && args[3] <= 16) { - tcg_out_opc_imm(s, OPC_ANDI, a0, a1, (1 << args[3]) - 1); - } else { - tcg_out_opc_bf(s, OPC_EXT, a0, a1, args[3] - 1, a2); - } - break; - case INDEX_op_extract_i64: - if (a2 == 0 && args[3] <= 16) { - tcg_out_opc_imm(s, OPC_ANDI, a0, a1, (1 << args[3]) - 1); - } else { - tcg_out_opc_bf64(s, OPC_DEXT, OPC_DEXTM, OPC_DEXTU, - a0, a1, args[3] - 1, a2); - } - break; - case INDEX_op_sextract_i64: if (a2 == 0 && args[3] == 32) { tcg_out_ext32s(s, a0, a1); @@ -2375,7 +2376,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: @@ -2388,7 +2388,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 083137d211..a8558a47b7 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3417,6 +3417,23 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0 && len <= 16) { + tgen_andi(s, TCG_TYPE_I32, a0, a1, (1 << len) - 1); + } else if (type == TCG_TYPE_I32) { + tcg_out_rlw(s, RLWINM, a0, a1, 32 - ofs, 32 - len, 31); + } else { + tcg_out_rld(s, RLDICL, a0, a1, 64 - ofs, 64 - len); + } +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3538,22 +3555,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_extract_i32: - if (args[2] == 0 && args[3] <= 16) { - tcg_out32(s, ANDI | SAI(args[1], args[0], (1 << args[3]) - 1)); - break; - } - tcg_out_rlw(s, RLWINM, args[0], args[1], - 32 - args[2], 32 - args[3], 31); - break; - case INDEX_op_extract_i64: - if (args[2] == 0 && args[3] <= 16) { - tcg_out32(s, ANDI | SAI(args[1], args[0], (1 << args[3]) - 1)); - break; - } - tcg_out_rld(s, RLDICL, args[0], args[1], 64 - args[2], 64 - args[3]); - break; - case INDEX_op_sextract_i64: if (args[2] + args[3] == 32) { if (args[2] == 0) { @@ -4255,7 +4256,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: @@ -4266,7 +4266,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i64: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 00b097d171..85d978763c 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2472,6 +2472,34 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 16: + tcg_out_ext16u(s, a0, a1); + return; + case 32: + tcg_out_ext32u(s, a0, a1); + return; + } + } + if (ofs + len == 32) { + tgen_shli(s, TCG_TYPE_I32, a0, a1, ofs); + return; + } + if (len == 1) { + tcg_out_opc_imm(s, OPC_BEXTI, a0, a1, ofs); + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2572,30 +2600,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, a0); break; - case INDEX_op_extract_i64: - if (a2 + args[3] == 32) { - if (a2 == 0) { - tcg_out_ext32u(s, a0, a1); - } else { - tcg_out_opc_imm(s, OPC_SRLIW, a0, a1, a2); - } - break; - } - /* FALLTHRU */ - case INDEX_op_extract_i32: - switch (args[3]) { - case 1: - tcg_out_opc_imm(s, OPC_BEXTI, a0, a1, a2); - break; - case 16: - tcg_debug_assert(a2 == 0); - tcg_out_ext16u(s, a0, a1); - break; - default: - g_assert_not_reached(); - } - break; - case INDEX_op_sextract_i64: if (a2 + args[3] == 32) { if (a2 == 0) { @@ -2867,8 +2871,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 2ed288cfe0..96e2dc0ad5 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1563,8 +1563,8 @@ static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src, tcg_out_risbg(s, dest, src, msb, lsb, ofs, z); } -static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src, - int ofs, int len) +static void tgen_extract(TCGContext *s, TCGType type, TCGReg dest, + TCGReg src, unsigned ofs, unsigned len) { if (ofs == 0) { switch (len) { @@ -1582,6 +1582,11 @@ static void tgen_extract(TCGContext *s, TCGReg dest, TCGReg src, tcg_out_risbg(s, dest, src, 64 - len, 63, 64 - ofs, 1); } +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; + static void tgen_sextract(TCGContext *s, TCGReg dest, TCGReg src, int ofs, int len) { @@ -2975,9 +2980,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(extract): - tgen_extract(s, args[0], args[1], args[2], args[3]); - break; OP_32_64(sextract): tgen_sextract(s, args[0], args[1], args[2], args[3]); break; @@ -3470,8 +3472,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: return C_O1_I1(r, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 96ffba9af6..cba1dd009c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1757,6 +1757,17 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + tcg_debug_assert(ofs + len == 32); + tcg_out_arithi(s, a0, a1, ofs, SHIFT_SRL); +} + +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extract, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1857,10 +1868,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, a0); break; - case INDEX_op_extract_i64: - tcg_debug_assert(a2 + args[3] == 32); - tcg_out_arithi(s, a0, a1, a2, SHIFT_SRL); - break; case INDEX_op_sextract_i64: tcg_debug_assert(a2 + args[3] == 32); tcg_out_arithi(s, a0, a1, a2, SHIFT_SRA); @@ -1897,7 +1904,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i64: case INDEX_op_sextract_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: diff --git a/tcg/tcg.c b/tcg/tcg.c index 1ba86dd515..36c5e9c847 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1013,6 +1013,12 @@ typedef struct TCGOutOpDivRem { TCGReg a0, TCGReg a1, TCGReg a4); } TCGOutOpDivRem; +typedef struct TCGOutOpExtract { + TCGOutOp base; + void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len); +} TCGOutOpExtract; + typedef struct TCGOutOpMovcond { TCGOutOp base; void (*out)(TCGContext *s, TCGType type, TCGCond cond, @@ -1085,6 +1091,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), + OUTOP(INDEX_op_extract_i32, TCGOutOpExtract, outop_extract), + OUTOP(INDEX_op_extract_i64, TCGOutOpExtract, outop_extract), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -5511,6 +5519,18 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_extract_i32: + case INDEX_op_extract_i64: + { + const TCGOutOpExtract *out = + container_of(all_outop[op->opc], TCGOutOpExtract, base); + + tcg_debug_assert(!const_args[1]); + out->out_rr(s, type, new_args[0], new_args[1], + new_args[2], new_args[3]); + } + break; + case INDEX_op_muls2: case INDEX_op_mulu2: { diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 4fc857ad35..d8cf5d237b 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,8 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: return C_O1_I1(r, r); @@ -444,6 +442,11 @@ static void tcg_out_extract(TCGContext *s, TCGType type, TCGReg rd, tcg_out_op_rrbb(s, opc, rd, rs, pos, len); } +static const TCGOutOpExtract outop_extract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tcg_out_extract, +}; + static void tcg_out_sextract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs, unsigned pos, unsigned len) { @@ -1078,7 +1081,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rrrbb(s, opc, args[0], args[1], args[2], args[3], args[4]); break; - CASE_32_64(extract) /* Optional (TCG_TARGET_HAS_extract_*). */ CASE_32_64(sextract) /* Optional (TCG_TARGET_HAS_sextract_*). */ tcg_out_op_rrbb(s, opc, args[0], args[1], args[2], args[3]); break; From 07d5d502f2b4a8eedda3c6bdfcab31dc36d1d1d5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 11 Jan 2025 09:01:46 -0800 Subject: [PATCH 0453/2760] tcg: Merge INDEX_op_extract_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 6 +++--- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 14 ++++---------- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 9 +++------ tcg/tci.c | 12 ++++-------- tcg/tci/tcg-target.c.inc | 5 +---- 7 files changed, 20 insertions(+), 37 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 72a23d6ea2..2843f88772 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -456,7 +456,7 @@ Misc | | *dest* = (*t1* & ~0x0f00) | ((*t2* << 8) & 0x0f00) - * - extract_i32/i64 *dest*, *t1*, *pos*, *len* + * - extract *dest*, *t1*, *pos*, *len* sextract_i32/i64 *dest*, *t1*, *pos*, *len* @@ -467,12 +467,12 @@ Misc to the left with zeros; for sextract_*, the result will be extended to the left with copies of the bitfield sign bit at *pos* + *len* - 1. | - | For example, "sextract_i32 dest, t1, 8, 4" indicates a 4-bit field + | For example, "sextract dest, t1, 8, 4" indicates a 4-bit field at bit 8. This operation would be equivalent to | | *dest* = (*t1* << 20) >> 28 | - | (using an arithmetic right shift). + | (using an arithmetic right shift) on TCG_TYPE_I32. * - extract2_i32/i64 *dest*, *t1*, *t2*, *pos* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 1d27b882fe..a8c304ca63 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -54,6 +54,7 @@ DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) +DEF(extract, 1, 1, 2, TCG_OPF_INT) DEF(movcond, 1, 4, 1, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(muls2, 2, 2, 0, TCG_OPF_INT) @@ -89,7 +90,6 @@ DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ DEF(deposit_i32, 1, 2, 2, 0) -DEF(extract_i32, 1, 1, 2, 0) DEF(sextract_i32, 1, 1, 2, 0) DEF(extract2_i32, 1, 2, 1, 0) @@ -112,7 +112,6 @@ DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ DEF(deposit_i64, 1, 2, 2, 0) -DEF(extract_i64, 1, 1, 2, 0) DEF(sextract_i64, 1, 1, 2, 0) DEF(extract2_i64, 1, 2, 1, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index a860b62109..fbfcbf23cd 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2317,7 +2317,7 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode uext_opc = 0, sext_opc = 0; + TCGOpcode sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; TCGOp *op2; @@ -2338,17 +2338,11 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) switch (ctx->type) { case TCG_TYPE_I32: - if (TCG_TARGET_extract_valid(TCG_TYPE_I32, sh, 1)) { - uext_opc = INDEX_op_extract_i32; - } if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, sh, 1)) { sext_opc = INDEX_op_sextract_i32; } break; case TCG_TYPE_I64: - if (TCG_TARGET_extract_valid(TCG_TYPE_I64, sh, 1)) { - uext_opc = INDEX_op_extract_i64; - } if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, sh, 1)) { sext_opc = INDEX_op_sextract_i64; } @@ -2367,8 +2361,8 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) op->args[2] = sh; op->args[3] = 1; return; - } else if (sh && uext_opc) { - op->opc = uext_opc; + } else if (sh && TCG_TARGET_extract_valid(ctx->type, sh, 1)) { + op->opc = INDEX_op_extract; op->args[1] = src1; op->args[2] = sh; op->args[3] = 1; @@ -2897,7 +2891,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_eqv_vec: done = fold_eqv(&ctx, op); break; - CASE_OP_32_64(extract): + case INDEX_op_extract: done = fold_extract(&ctx, op); break; CASE_OP_32_64(extract2): diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ba062191ac..ddade73b7b 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -998,7 +998,7 @@ void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, } if (TCG_TARGET_extract_valid(TCG_TYPE_I32, ofs, len)) { - tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, ofs, len); + tcg_gen_op4ii_i32(INDEX_op_extract, ret, arg, ofs, len); return; } if (ofs == 0) { @@ -1008,7 +1008,7 @@ void tcg_gen_extract_i32(TCGv_i32 ret, TCGv_i32 arg, /* Assume that zero-extension, if available, is cheaper than a shift. */ if (TCG_TARGET_extract_valid(TCG_TYPE_I32, 0, ofs + len)) { - tcg_gen_op4ii_i32(INDEX_op_extract_i32, ret, arg, 0, ofs + len); + tcg_gen_op4ii_i32(INDEX_op_extract, ret, arg, 0, ofs + len); tcg_gen_shri_i32(ret, ret, ofs); return; } @@ -2670,7 +2670,7 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, } if (TCG_TARGET_extract_valid(TCG_TYPE_I64, ofs, len)) { - tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, ofs, len); + tcg_gen_op4ii_i64(INDEX_op_extract, ret, arg, ofs, len); return; } if (ofs == 0) { @@ -2680,7 +2680,7 @@ void tcg_gen_extract_i64(TCGv_i64 ret, TCGv_i64 arg, /* Assume that zero-extension, if available, is cheaper than a shift. */ if (TCG_TARGET_extract_valid(TCG_TYPE_I64, 0, ofs + len)) { - tcg_gen_op4ii_i64(INDEX_op_extract_i64, ret, arg, 0, ofs + len); + tcg_gen_op4ii_i64(INDEX_op_extract, ret, arg, 0, ofs + len); tcg_gen_shri_i64(ret, ret, ofs); return; } diff --git a/tcg/tcg.c b/tcg/tcg.c index 36c5e9c847..ce0d862b19 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1091,8 +1091,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), - OUTOP(INDEX_op_extract_i32, TCGOutOpExtract, outop_extract), - OUTOP(INDEX_op_extract_i64, TCGOutOpExtract, outop_extract), + OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -2326,6 +2325,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add: case INDEX_op_and: case INDEX_op_brcond: + case INDEX_op_extract: case INDEX_op_mov: case INDEX_op_movcond: case INDEX_op_negsetcond: @@ -2342,7 +2342,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_extract_i32: case INDEX_op_sextract_i32: case INDEX_op_deposit_i32: return true; @@ -2371,7 +2370,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_extract_i64: case INDEX_op_sextract_i64: case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; @@ -5519,8 +5517,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: + case INDEX_op_extract: { const TCGOutOpExtract *out = container_of(all_outop[op->opc], TCGOutOpExtract, base); diff --git a/tcg/tci.c b/tcg/tci.c index 30928c3412..6345029802 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -27,6 +27,7 @@ #define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS) +#define extract_tr glue(extract, TCG_TARGET_REG_BITS) /* * Enable TCI assertions only when debugging TCG (and without NDEBUG defined). @@ -656,9 +657,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit32(regs[r1], pos, len, regs[r2]); break; - case INDEX_op_extract_i32: + case INDEX_op_extract: tci_args_rrbb(insn, &r0, &r1, &pos, &len); - regs[r0] = extract32(regs[r1], pos, len); + regs[r0] = extract_tr(regs[r1], pos, len); break; case INDEX_op_sextract_i32: tci_args_rrbb(insn, &r0, &r1, &pos, &len); @@ -772,10 +773,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit64(regs[r1], pos, len, regs[r2]); break; - case INDEX_op_extract_i64: - tci_args_rrbb(insn, &r0, &r1, &pos, &len); - regs[r0] = extract64(regs[r1], pos, len); - break; case INDEX_op_sextract_i64: tci_args_rrbb(insn, &r0, &r1, &pos, &len); regs[r0] = sextract64(regs[r1], pos, len); @@ -1057,8 +1054,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), str_r(r2), pos, len); break; - case INDEX_op_extract_i32: - case INDEX_op_extract_i64: + case INDEX_op_extract: case INDEX_op_sextract_i32: case INDEX_op_sextract_i64: tci_args_rrbb(insn, &r0, &r1, &pos, &len); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d8cf5d237b..ede11d9e70 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -436,10 +436,7 @@ static void tcg_out_movi(TCGContext *s, TCGType type, static void tcg_out_extract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs, unsigned pos, unsigned len) { - TCGOpcode opc = type == TCG_TYPE_I32 ? - INDEX_op_extract_i32 : - INDEX_op_extract_i64; - tcg_out_op_rrbb(s, opc, rd, rs, pos, len); + tcg_out_op_rrbb(s, INDEX_op_extract, rd, rs, pos, len); } static const TCGOutOpExtract outop_extract = { From 05a1129e23bfed1fe799a169e0eca0f676fa5016 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 11:44:30 -0800 Subject: [PATCH 0454/2760] tcg: Convert sextract to TCGOutOpExtract Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 18 +++++---- tcg/arm/tcg-target.c.inc | 21 ++++++----- tcg/i386/tcg-target.c.inc | 63 ++++++++++++++++---------------- tcg/loongarch64/tcg-target.c.inc | 49 ++++++++++++++----------- tcg/mips/tcg-target.c.inc | 42 ++++++++++++--------- tcg/ppc/tcg-target.c.inc | 49 ++++++++++++++----------- tcg/riscv/tcg-target.c.inc | 49 ++++++++++++++----------- tcg/s390x/tcg-target.c.inc | 15 ++++---- tcg/sparc64/tcg-target.c.inc | 18 ++++++--- tcg/tcg.c | 4 ++ tcg/tci/tcg-target.c.inc | 11 +++--- 11 files changed, 188 insertions(+), 151 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 6c9d6094a2..00400f6ea7 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2583,6 +2583,17 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + tcg_out_sbfm(s, type, a0, a1, ofs, ofs + len - 1); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2668,11 +2679,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_dep(s, ext, a0, a2, args[3], args[4]); break; - case INDEX_op_sextract_i64: - case INDEX_op_sextract_i32: - tcg_out_sbfm(s, ext, a0, a1, a2, a2 + args[3] - 1); - break; - case INDEX_op_extract2_i64: case INDEX_op_extract2_i32: tcg_out_extr(s, ext, a0, a2, a1, args[3]); @@ -3173,8 +3179,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index bc060b20f2..aebe48679c 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1020,12 +1020,12 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; -static void tcg_out_sextract(TCGContext *s, ARMCond cond, TCGReg rd, - TCGReg rn, int ofs, int len) +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, + unsigned ofs, unsigned len) { if (use_armv7_instructions) { /* sbfx */ - tcg_out32(s, 0x07a00050 | (cond << 28) | (rd << 12) | rn + tcg_out32(s, 0x07a00050 | (COND_AL << 28) | (rd << 12) | rn | (ofs << 7) | ((len - 1) << 16)); return; } @@ -1034,17 +1034,24 @@ static void tcg_out_sextract(TCGContext *s, ARMCond cond, TCGReg rd, switch (len) { case 8: /* sxtb */ - tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | (ofs << 7) | rn); + tcg_out32(s, 0x06af0070 | (COND_AL << 28) | + (rd << 12) | (ofs << 7) | rn); break; case 16: /* sxth */ - tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | (ofs << 7) | rn); + tcg_out32(s, 0x06bf0070 | (COND_AL << 28) | + (rd << 12) | (ofs << 7) | rn); break; default: g_assert_not_reached(); } } +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_ld32u(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn, int32_t offset) @@ -2399,9 +2406,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_deposit(s, COND_AL, args[0], args[2], args[3], args[4], const_args[2]); break; - case INDEX_op_sextract_i32: - tcg_out_sextract(s, COND_AL, args[0], args[1], args[2], args[3]); - break; case INDEX_op_extract2_i32: /* ??? These optimization vs zero should be generic. */ /* ??? But we can't substitute 2 for 1 in the opcode stream yet. */ @@ -2448,7 +2452,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_sextract_i32: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index b26c93bdb1..6a5414ab3a 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3180,6 +3180,38 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8s(s, type, a0, a1); + return; + case 16: + tcg_out_ext16s(s, type, a0, a1); + return; + case 32: + tcg_out_ext32s(s, a0, a1); + return; + } + } else if (ofs == 8 && len == 8) { + if (type == TCG_TYPE_I32 && a1 < 4 && a0 < 8) { + tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4); + } else { + tcg_out_ext16s(s, type, a0, a1); + tgen_sari(s, type, a0, a0, 8); + } + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -3369,35 +3401,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_sextract_i64: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_I64, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_I64, a0, a1); - } else if (a2 == 0 && args[3] == 32) { - tcg_out_ext32s(s, a0, a1); - } else { - g_assert_not_reached(); - } - break; - - case INDEX_op_sextract_i32: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_I32, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1); - } else if (a2 == 8 && args[3] == 8) { - if (a1 < 4 && a0 < 8) { - tcg_out_modrm(s, OPC_MOVSBL, a0, a1 + 4); - } else { - tcg_out_ext16s(s, TCG_TYPE_I32, a0, a1); - tcg_out_shifti(s, SHIFT_SAR, a0, 8); - } - } else { - g_assert_not_reached(); - } - break; - OP_32_64(extract2): /* Note that SHRD outputs to the r/m operand. */ tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0); @@ -4001,8 +4004,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_extract2_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index f63d33e9ac..2ea5234097 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1816,6 +1816,33 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8s(s, type, a0, a1); + return; + case 16: + tcg_out_ext16s(s, type, a0, a1); + return; + case 32: + tcg_out_ext32s(s, a0, a1); + return; + } + } else if (ofs + len == 32) { + tcg_out_opc_srai_w(s, a0, a1, ofs); + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1844,26 +1871,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_srai_d(s, a0, a1, 32); break; - case INDEX_op_sextract_i64: - if (a2 + args[3] == 32) { - if (a2 == 0) { - tcg_out_ext32s(s, a0, a1); - } else { - tcg_out_opc_srai_w(s, a0, a1, a2); - } - break; - } - /* FALLTHRU */ - case INDEX_op_sextract_i32: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_REG, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_REG, a0, a1); - } else { - g_assert_not_reached(); - } - break; - case INDEX_op_deposit_i32: tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); break; @@ -2462,8 +2469,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: case INDEX_op_ld8u_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index dbb4b9355d..56c58bf82d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2221,6 +2221,30 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8s(s, type, a0, a1); + return; + case 16: + tcg_out_ext16s(s, type, a0, a1); + return; + case 32: + tcg_out_ext32s(s, a0, a1); + return; + } + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2303,22 +2327,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, args[3] + args[4] - 1, args[3]); break; - case INDEX_op_sextract_i64: - if (a2 == 0 && args[3] == 32) { - tcg_out_ext32s(s, a0, a1); - break; - } - /* FALLTHRU */ - case INDEX_op_sextract_i32: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_REG, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_REG, a0, a1); - } else { - g_assert_not_reached(); - } - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32); break; @@ -2376,7 +2384,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i64: @@ -2388,7 +2395,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index a8558a47b7..3d1ffa9130 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3434,6 +3434,33 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8s(s, type, a0, a1); + return; + case 16: + tcg_out_ext16s(s, type, a0, a1); + return; + case 32: + tcg_out_ext32s(s, a0, a1); + return; + } + } else if (ofs + len == 32) { + tcg_out_sari32(s, a0, a1, ofs); + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3555,26 +3582,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_sextract_i64: - if (args[2] + args[3] == 32) { - if (args[2] == 0) { - tcg_out_ext32s(s, args[0], args[1]); - } else { - tcg_out_sari32(s, args[0], args[1], args[2]); - } - break; - } - /* FALLTHRU */ - case INDEX_op_sextract_i32: - if (args[2] == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_I32, args[0], args[1]); - } else if (args[2] == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_I32, args[0], args[1]); - } else { - g_assert_not_reached(); - } - break; - #if TCG_TARGET_REG_BITS == 64 case INDEX_op_add2_i64: #else @@ -4256,7 +4263,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld16u_i32: case INDEX_op_ld16s_i32: case INDEX_op_ld_i32: - case INDEX_op_sextract_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i64: case INDEX_op_ld16u_i64: @@ -4266,7 +4272,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 85d978763c..dc2b487844 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2501,6 +2501,33 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + if (ofs == 0) { + switch (len) { + case 8: + tcg_out_ext8s(s, type, a0, a1); + return; + case 16: + tcg_out_ext16s(s, type, a0, a1); + return; + case 32: + tcg_out_ext32s(s, a0, a1); + return; + } + } else if (ofs + len == 32) { + tgen_sari(s, TCG_TYPE_I32, a0, a1, ofs); + return; + } + g_assert_not_reached(); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2600,26 +2627,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, a0); break; - case INDEX_op_sextract_i64: - if (a2 + args[3] == 32) { - if (a2 == 0) { - tcg_out_ext32s(s, a0, a1); - } else { - tcg_out_opc_imm(s, OPC_SRAIW, a0, a1, a2); - } - break; - } - /* FALLTHRU */ - case INDEX_op_sextract_i32: - if (a2 == 0 && args[3] == 8) { - tcg_out_ext8s(s, TCG_TYPE_REG, a0, a1); - } else if (a2 == 0 && args[3] == 16) { - tcg_out_ext16s(s, TCG_TYPE_REG, a0, a1); - } else { - g_assert_not_reached(); - } - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ @@ -2871,8 +2878,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ext_i32_i64: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 96e2dc0ad5..ab178bebc8 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1587,8 +1587,8 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; -static void tgen_sextract(TCGContext *s, TCGReg dest, TCGReg src, - int ofs, int len) +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg dest, + TCGReg src, unsigned ofs, unsigned len) { if (ofs == 0) { switch (len) { @@ -1606,6 +1606,11 @@ static void tgen_sextract(TCGContext *s, TCGReg dest, TCGReg src, g_assert_not_reached(); } +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest) { ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1; @@ -2980,10 +2985,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - OP_32_64(sextract): - tgen_sextract(s, args[0], args[1], args[2], args[3]); - break; - case INDEX_op_mb: /* The host memory model is quite strong, we simply need to serialize the instruction stream. */ @@ -3472,8 +3473,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i32: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index cba1dd009c..0f2bec21e9 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1769,6 +1769,18 @@ static const TCGOutOpExtract outop_extract = { .out_rr = tgen_extract, }; +static void tgen_sextract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + unsigned ofs, unsigned len) +{ + tcg_debug_assert(ofs + len == 32); + tcg_out_arithi(s, a0, a1, ofs, SHIFT_SRA); +} + +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_sextract, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1868,11 +1880,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_mb(s, a0); break; - case INDEX_op_sextract_i64: - tcg_debug_assert(a2 + args[3] == 32); - tcg_out_arithi(s, a0, a1, a2, SHIFT_SRA); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ @@ -1904,7 +1911,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/tcg.c b/tcg/tcg.c index ce0d862b19..7f5fa25062 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1111,6 +1111,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond), + OUTOP(INDEX_op_sextract_i32, TCGOutOpExtract, outop_sextract), + OUTOP(INDEX_op_sextract_i64, TCGOutOpExtract, outop_sextract), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -5518,6 +5520,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_extract: + case INDEX_op_sextract_i32: + case INDEX_op_sextract_i64: { const TCGOutOpExtract *out = container_of(all_outop[op->opc], TCGOutOpExtract, base); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ede11d9e70..e013321ac7 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -57,8 +57,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: @@ -453,6 +451,11 @@ static void tcg_out_sextract(TCGContext *s, TCGType type, TCGReg rd, tcg_out_op_rrbb(s, opc, rd, rs, pos, len); } +static const TCGOutOpExtract outop_sextract = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tcg_out_sextract, +}; + static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { tcg_out_sextract(s, type, rd, rs, 0, 8); @@ -1078,10 +1081,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_rrrbb(s, opc, args[0], args[1], args[2], args[3], args[4]); break; - CASE_32_64(sextract) /* Optional (TCG_TARGET_HAS_sextract_*). */ - tcg_out_op_rrbb(s, opc, args[0], args[1], args[2], args[3]); - break; - CASE_32_64(add2) CASE_32_64(sub2) tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2], From fa361eefac24dcaa1d6dfbc433fce0652fdd8ba8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 11:50:09 -0800 Subject: [PATCH 0455/2760] tcg: Merge INDEX_op_sextract_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 2 +- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 22 +++------------------- tcg/tcg-op.c | 12 ++++++------ tcg/tcg.c | 9 +++------ tcg/tci.c | 12 ++++-------- tcg/tci/tcg-target.c.inc | 5 +---- 7 files changed, 19 insertions(+), 46 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 2843f88772..ca7550f68c 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -458,7 +458,7 @@ Misc * - extract *dest*, *t1*, *pos*, *len* - sextract_i32/i64 *dest*, *t1*, *pos*, *len* + sextract *dest*, *t1*, *pos*, *len* - | Extract a bitfield from *t1*, placing the result in *dest*. | diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index a8c304ca63..4ace1f85c4 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -74,6 +74,7 @@ DEF(rotl, 1, 2, 0, TCG_OPF_INT) DEF(rotr, 1, 2, 0, TCG_OPF_INT) DEF(sar, 1, 2, 0, TCG_OPF_INT) DEF(setcond, 1, 2, 1, TCG_OPF_INT) +DEF(sextract, 1, 1, 2, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) @@ -90,7 +91,6 @@ DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ DEF(deposit_i32, 1, 2, 2, 0) -DEF(sextract_i32, 1, 1, 2, 0) DEF(extract2_i32, 1, 2, 1, 0) DEF(add2_i32, 2, 4, 0, 0) @@ -112,7 +112,6 @@ DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ DEF(deposit_i64, 1, 2, 2, 0) -DEF(sextract_i64, 1, 1, 2, 0) DEF(extract2_i64, 1, 2, 1, 0) /* size changing ops */ diff --git a/tcg/optimize.c b/tcg/optimize.c index fbfcbf23cd..d324cbf7fe 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2317,7 +2317,6 @@ static int fold_setcond_zmask(OptContext *ctx, TCGOp *op, bool neg) static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) { - TCGOpcode sext_opc = 0; TCGCond cond = op->args[3]; TCGArg ret, src1, src2; TCGOp *op2; @@ -2336,27 +2335,12 @@ static void fold_setcond_tst_pow2(OptContext *ctx, TCGOp *op, bool neg) } sh = ctz64(val); - switch (ctx->type) { - case TCG_TYPE_I32: - if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, sh, 1)) { - sext_opc = INDEX_op_sextract_i32; - } - break; - case TCG_TYPE_I64: - if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, sh, 1)) { - sext_opc = INDEX_op_sextract_i64; - } - break; - default: - g_assert_not_reached(); - } - ret = op->args[0]; src1 = op->args[1]; inv = cond == TCG_COND_TSTEQ; - if (sh && sext_opc && neg && !inv) { - op->opc = sext_opc; + if (sh && neg && !inv && TCG_TARGET_sextract_valid(ctx->type, sh, 1)) { + op->opc = INDEX_op_sextract; op->args[1] = src1; op->args[2] = sh; op->args[3] = 1; @@ -3019,7 +3003,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_bitsel_vec: done = fold_bitsel_vec(&ctx, op); break; - CASE_OP_32_64(sextract): + case INDEX_op_sextract: done = fold_sextract(&ctx, op); break; case INDEX_op_sub: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index ddade73b7b..d3f3c9d248 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1043,19 +1043,19 @@ void tcg_gen_sextract_i32(TCGv_i32 ret, TCGv_i32 arg, } if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, ofs, len)) { - tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, ofs, len); + tcg_gen_op4ii_i32(INDEX_op_sextract, ret, arg, ofs, len); return; } /* Assume that sign-extension, if available, is cheaper than a shift. */ if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, 0, ofs + len)) { - tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, arg, 0, ofs + len); + tcg_gen_op4ii_i32(INDEX_op_sextract, ret, arg, 0, ofs + len); tcg_gen_sari_i32(ret, ret, ofs); return; } if (TCG_TARGET_sextract_valid(TCG_TYPE_I32, 0, len)) { tcg_gen_shri_i32(ret, arg, ofs); - tcg_gen_op4ii_i32(INDEX_op_sextract_i32, ret, ret, 0, len); + tcg_gen_op4ii_i32(INDEX_op_sextract, ret, ret, 0, len); return; } @@ -2747,19 +2747,19 @@ void tcg_gen_sextract_i64(TCGv_i64 ret, TCGv_i64 arg, } if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, ofs, len)) { - tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, ofs, len); + tcg_gen_op4ii_i64(INDEX_op_sextract, ret, arg, ofs, len); return; } /* Assume that sign-extension, if available, is cheaper than a shift. */ if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, 0, ofs + len)) { - tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, arg, 0, ofs + len); + tcg_gen_op4ii_i64(INDEX_op_sextract, ret, arg, 0, ofs + len); tcg_gen_sari_i64(ret, ret, ofs); return; } if (TCG_TARGET_sextract_valid(TCG_TYPE_I64, 0, len)) { tcg_gen_shri_i64(ret, arg, ofs); - tcg_gen_op4ii_i64(INDEX_op_sextract_i64, ret, ret, 0, len); + tcg_gen_op4ii_i64(INDEX_op_sextract, ret, ret, 0, len); return; } diff --git a/tcg/tcg.c b/tcg/tcg.c index 7f5fa25062..c7ce13cda0 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1111,8 +1111,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_rotr, TCGOutOpBinary, outop_rotr), OUTOP(INDEX_op_sar, TCGOutOpBinary, outop_sar), OUTOP(INDEX_op_setcond, TCGOutOpSetcond, outop_setcond), - OUTOP(INDEX_op_sextract_i32, TCGOutOpExtract, outop_sextract), - OUTOP(INDEX_op_sextract_i64, TCGOutOpExtract, outop_sextract), + OUTOP(INDEX_op_sextract, TCGOutOpExtract, outop_sextract), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), @@ -2333,6 +2332,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_negsetcond: case INDEX_op_or: case INDEX_op_setcond: + case INDEX_op_sextract: case INDEX_op_xor: return has_type; @@ -2344,7 +2344,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_sextract_i32: case INDEX_op_deposit_i32: return true; @@ -2372,7 +2371,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: - case INDEX_op_sextract_i64: case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; @@ -5520,8 +5518,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_extract: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: + case INDEX_op_sextract: { const TCGOutOpExtract *out = container_of(all_outop[op->opc], TCGOutOpExtract, base); diff --git a/tcg/tci.c b/tcg/tci.c index 6345029802..5a07d65db8 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -28,6 +28,7 @@ #define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS) #define extract_tr glue(extract, TCG_TARGET_REG_BITS) +#define sextract_tr glue(sextract, TCG_TARGET_REG_BITS) /* * Enable TCI assertions only when debugging TCG (and without NDEBUG defined). @@ -661,9 +662,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrbb(insn, &r0, &r1, &pos, &len); regs[r0] = extract_tr(regs[r1], pos, len); break; - case INDEX_op_sextract_i32: + case INDEX_op_sextract: tci_args_rrbb(insn, &r0, &r1, &pos, &len); - regs[r0] = sextract32(regs[r1], pos, len); + regs[r0] = sextract_tr(regs[r1], pos, len); break; case INDEX_op_brcond: tci_args_rl(insn, tb_ptr, &r0, &ptr); @@ -773,10 +774,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit64(regs[r1], pos, len, regs[r2]); break; - case INDEX_op_sextract_i64: - tci_args_rrbb(insn, &r0, &r1, &pos, &len); - regs[r0] = sextract64(regs[r1], pos, len); - break; case INDEX_op_ext_i32_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = (int32_t)regs[r1]; @@ -1055,8 +1052,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_extract: - case INDEX_op_sextract_i32: - case INDEX_op_sextract_i64: + case INDEX_op_sextract: tci_args_rrbb(insn, &r0, &r1, &pos, &len); info->fprintf_func(info->stream, "%-12s %s,%s,%d,%d", op_name, str_r(r0), str_r(r1), pos, len); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index e013321ac7..9ba108ef8d 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -445,10 +445,7 @@ static const TCGOutOpExtract outop_extract = { static void tcg_out_sextract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs, unsigned pos, unsigned len) { - TCGOpcode opc = type == TCG_TYPE_I32 ? - INDEX_op_sextract_i32 : - INDEX_op_sextract_i64; - tcg_out_op_rrbb(s, opc, rd, rs, pos, len); + tcg_out_op_rrbb(s, INDEX_op_sextract, rd, rs, pos, len); } static const TCGOutOpExtract outop_sextract = { From b7b7347fe391f134c7ea616c0593d3ea835d5eea Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 12:22:45 -0800 Subject: [PATCH 0456/2760] tcg: Convert ext_i32_i64 to TCGOutOpUnary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 -- tcg/i386/tcg-target.c.inc | 2 -- tcg/loongarch64/tcg-target.c.inc | 2 -- tcg/mips/tcg-target.c.inc | 2 -- tcg/ppc/tcg-target.c.inc | 2 -- tcg/riscv/tcg-target.c.inc | 2 -- tcg/s390x/tcg-target.c.inc | 2 -- tcg/sparc64/tcg-target.c.inc | 2 -- tcg/tcg.c | 22 +++++++++++++++++++--- tcg/tci/tcg-target.c.inc | 2 -- 10 files changed, 19 insertions(+), 21 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 00400f6ea7..68f7a1cec2 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2710,7 +2710,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -3177,7 +3176,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 6a5414ab3a..14b912beb7 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3413,7 +3413,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -4001,7 +4000,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 2ea5234097..2a9c7fc10a 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1943,7 +1943,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2468,7 +2467,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: - case INDEX_op_ext_i32_i64: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: case INDEX_op_ld8u_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 56c58bf82d..e992a468eb 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2364,7 +2364,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2391,7 +2390,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 3d1ffa9130..fea767573c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3640,7 +3640,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -4270,7 +4269,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index dc2b487844..e5fe15c338 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2630,7 +2630,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -2877,7 +2876,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: - case INDEX_op_ext_i32_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index ab178bebc8..5c5a38c2c8 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2997,7 +2997,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: @@ -3471,7 +3470,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 0f2bec21e9..e93ef8e7f2 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1883,7 +1883,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: default: g_assert_not_reached(); @@ -1909,7 +1908,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: diff --git a/tcg/tcg.c b/tcg/tcg.c index c7ce13cda0..6bce097eac 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1068,6 +1068,23 @@ QEMU_BUILD_BUG_ON((int)(offsetof(CPUNegativeOffsetState, tlb.f[0]) - < MIN_TLB_MASK_TABLE_OFS); #endif +#if TCG_TARGET_REG_BITS == 64 +/* + * We require these functions for slow-path function calls. + * Adapt them generically for opcode output. + */ + +static void tgen_exts_i32_i64(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_exts_i32_i64(s, a0, a1); +} + +static const TCGOutOpUnary outop_exts_i32_i64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_exts_i32_i64, +}; +#endif + /* * Register V as the TCGOutOp for O. * This verifies that V is of type T, otherwise give a nice compiler error. @@ -1122,6 +1139,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), #else OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64), + OUTOP(INDEX_op_ext_i32_i64, TCGOutOpUnary, outop_exts_i32_i64), #endif }; @@ -5412,9 +5430,6 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* emit instruction */ TCGType type = TCGOP_TYPE(op); switch (op->opc) { - case INDEX_op_ext_i32_i64: - tcg_out_exts_i32_i64(s, new_args[0], new_args[1]); - break; case INDEX_op_extu_i32_i64: tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); break; @@ -5477,6 +5492,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_bswap64: + case INDEX_op_ext_i32_i64: assert(TCG_TARGET_REG_BITS == 64); /* fall through */ case INDEX_op_ctpop: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 9ba108ef8d..ecff90404f 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -55,7 +55,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); @@ -1109,7 +1108,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_ext_i32_i64: /* Always emitted via tcg_reg_alloc_op. */ case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: From c1ad25de11ccf47a650c860f490864dcf7fe7675 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 12:34:45 -0800 Subject: [PATCH 0457/2760] tcg: Convert extu_i32_i64 to TCGOutOpUnary Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 2 -- tcg/i386/tcg-target.c.inc | 2 -- tcg/loongarch64/tcg-target.c.inc | 2 -- tcg/mips/tcg-target.c.inc | 2 -- tcg/ppc/tcg-target.c.inc | 2 -- tcg/riscv/tcg-target.c.inc | 2 -- tcg/s390x/tcg-target.c.inc | 4 ---- tcg/sparc64/tcg-target.c.inc | 2 -- tcg/tcg.c | 15 ++++++++++++--- tcg/tci/tcg-target.c.inc | 2 -- 10 files changed, 12 insertions(+), 23 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 68f7a1cec2..44314f6a0f 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2710,7 +2710,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -3176,7 +3175,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 14b912beb7..8371cfaf5a 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3413,7 +3413,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -4000,7 +3999,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 2a9c7fc10a..60356d5dfd 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1943,7 +1943,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -2464,7 +2463,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(r, r, r); - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ld8s_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e992a468eb..b6b7070fbb 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2364,7 +2364,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -2390,7 +2389,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index fea767573c..e1767f1d6c 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3640,7 +3640,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -4269,7 +4268,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index e5fe15c338..48d4325097 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2630,7 +2630,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -2873,7 +2872,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 5c5a38c2c8..d81b8fb8f4 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2997,7 +2997,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); @@ -3470,9 +3469,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_extu_i32_i64: - return C_O1_I1(r, r); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index e93ef8e7f2..d52907f7e3 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1883,7 +1883,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: default: g_assert_not_reached(); } @@ -1908,7 +1907,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/tcg.c b/tcg/tcg.c index 6bce097eac..0b2dc17600 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1083,6 +1083,16 @@ static const TCGOutOpUnary outop_exts_i32_i64 = { .base.static_constraint = C_O1_I1(r, r), .out_rr = tgen_exts_i32_i64, }; + +static void tgen_extu_i32_i64(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_extu_i32_i64(s, a0, a1); +} + +static const TCGOutOpUnary outop_extu_i32_i64 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extu_i32_i64, +}; #endif /* @@ -1140,6 +1150,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { #else OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64), OUTOP(INDEX_op_ext_i32_i64, TCGOutOpUnary, outop_exts_i32_i64), + OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64), #endif }; @@ -5430,9 +5441,6 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* emit instruction */ TCGType type = TCGOP_TYPE(op); switch (op->opc) { - case INDEX_op_extu_i32_i64: - tcg_out_extu_i32_i64(s, new_args[0], new_args[1]); - break; case INDEX_op_extrl_i64_i32: tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); break; @@ -5493,6 +5501,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_bswap64: case INDEX_op_ext_i32_i64: + case INDEX_op_extu_i32_i64: assert(TCG_TARGET_REG_BITS == 64); /* fall through */ case INDEX_op_ctpop: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ecff90404f..3cf2913acd 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -55,7 +55,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32u_i64: case INDEX_op_ld32s_i64: case INDEX_op_ld_i64: - case INDEX_op_extu_i32_i64: return C_O1_I1(r, r); case INDEX_op_st8_i32: @@ -1108,7 +1107,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); From 1e6fec9dd90756b22331a3c4c6859c51ad3a2c3e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 12:57:13 -0800 Subject: [PATCH 0458/2760] tcg: Convert extrl_i64_i32 to TCGOutOpUnary Drop the cast from TCGv_i64 to TCGv_i32 in tcg_gen_extrl_i64_i32 an emit extrl_i64_i32 unconditionally. Move that special case to tcg_gen_code when we find out if the output is live or dead. In this way even hosts that canonicalize truncations can make use of a store directly from the 64-bit host register. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 1 - tcg/i386/tcg-target.c.inc | 4 ---- tcg/loongarch64/tcg-target.c.inc | 2 -- tcg/mips/tcg-target.c.inc | 2 -- tcg/ppc/tcg-target.c.inc | 1 - tcg/riscv/tcg-target.c.inc | 2 -- tcg/s390x/tcg-target.c.inc | 1 - tcg/tcg-op.c | 4 +--- tcg/tcg.c | 35 +++++++++++++++++++++++++++----- tcg/tci/tcg-target.c.inc | 1 - 10 files changed, 31 insertions(+), 22 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 44314f6a0f..8abc5f26da 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2710,7 +2710,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 8371cfaf5a..9bae60d3b6 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3413,7 +3413,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } @@ -3999,9 +3998,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return C_O1_I1(r, 0); - case INDEX_op_extrl_i64_i32: - return C_O1_I1(r, r); - case INDEX_op_extract2_i32: case INDEX_op_extract2_i64: return C_O1_I2(r, 0, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 60356d5dfd..fae1a58c94 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1943,7 +1943,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } @@ -2463,7 +2462,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(r, r, r); - case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index b6b7070fbb..095eb8f672 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2364,7 +2364,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } @@ -2389,7 +2388,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index e1767f1d6c..bb03efe055 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3640,7 +3640,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 48d4325097..76ad2df410 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2630,7 +2630,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } @@ -2872,7 +2871,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index d81b8fb8f4..1ea041c75f 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2997,7 +2997,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index d3f3c9d248..7ecd1f6c8f 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2962,11 +2962,9 @@ void tcg_gen_extrl_i64_i32(TCGv_i32 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { tcg_gen_mov_i32(ret, TCGV_LOW(arg)); - } else if (TCG_TARGET_HAS_extr_i64_i32) { + } else { tcg_gen_op2(INDEX_op_extrl_i64_i32, TCG_TYPE_I32, tcgv_i32_arg(ret), tcgv_i64_arg(arg)); - } else { - tcg_gen_mov_i32(ret, (TCGv_i32)arg); } } diff --git a/tcg/tcg.c b/tcg/tcg.c index 0b2dc17600..8fcaf54d32 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1093,6 +1093,16 @@ static const TCGOutOpUnary outop_extu_i32_i64 = { .base.static_constraint = C_O1_I1(r, r), .out_rr = tgen_extu_i32_i64, }; + +static void tgen_extrl_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_extrl_i64_i32(s, a0, a1); +} + +static const TCGOutOpUnary outop_extrl_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = TCG_TARGET_HAS_extr_i64_i32 ? tgen_extrl_i64_i32 : NULL, +}; #endif /* @@ -1151,6 +1161,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_bswap64, TCGOutOpUnary, outop_bswap64), OUTOP(INDEX_op_ext_i32_i64, TCGOutOpUnary, outop_exts_i32_i64), OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64), + OUTOP(INDEX_op_extrl_i64_i32, TCGOutOpUnary, outop_extrl_i64_i32), #endif }; @@ -2400,12 +2411,12 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: + case INDEX_op_extrl_i64_i32: case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; case INDEX_op_extract2_i64: return TCG_TARGET_HAS_extract2_i64; - case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: return TCG_TARGET_HAS_extr_i64_i32; case INDEX_op_add2_i64: @@ -5441,10 +5452,6 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* emit instruction */ TCGType type = TCGOP_TYPE(op); switch (op->opc) { - case INDEX_op_extrl_i64_i32: - tcg_out_extrl_i64_i32(s, new_args[0], new_args[1]); - break; - case INDEX_op_add: case INDEX_op_and: case INDEX_op_andc: @@ -5502,6 +5509,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_bswap64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: + case INDEX_op_extrl_i64_i32: assert(TCG_TARGET_REG_BITS == 64); /* fall through */ case INDEX_op_ctpop: @@ -6660,6 +6668,22 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) TCGOpcode opc = op->opc; switch (opc) { + case INDEX_op_extrl_i64_i32: + assert(TCG_TARGET_REG_BITS == 64); + /* + * If TCG_TYPE_I32 is represented in some canonical form, + * e.g. zero or sign-extended, then emit as a unary op. + * Otherwise we can treat this as a plain move. + * If the output dies, treat this as a plain move, because + * this will be implemented with a store. + */ + if (TCG_TARGET_HAS_extr_i64_i32) { + TCGLifeData arg_life = op->life; + if (!IS_DEAD_ARG(0)) { + goto do_default; + } + } + /* fall through */ case INDEX_op_mov: case INDEX_op_mov_vec: tcg_reg_alloc_mov(s, op); @@ -6702,6 +6726,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) } /* fall through */ default: + do_default: /* Sanity check that we've not introduced any unhandled opcodes. */ tcg_debug_assert(tcg_op_supported(opc, TCGOP_TYPE(op), TCGOP_FLAGS(op))); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 3cf2913acd..e9b46d5e66 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -1107,7 +1107,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - case INDEX_op_extrl_i64_i32: default: g_assert_not_reached(); } From b3b139766424d022dc3455b711837dc6acf0724b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 13:37:28 -0800 Subject: [PATCH 0459/2760] tcg: Convert extrh_i64_i32 to TCGOutOpUnary At the same time, make extrh_i64_i32 mandatory. This closes a hole in which move arguments could be cast between TCGv_i32 and TCGv_i64. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 10 ++++++++++ tcg/i386/tcg-target.c.inc | 20 +++++++++++++------- tcg/loongarch64/tcg-target.c.inc | 15 ++++++++++----- tcg/mips/tcg-target.c.inc | 17 ++++++++++++----- tcg/ppc/tcg-target.c.inc | 12 ++++++++++++ tcg/riscv/tcg-target.c.inc | 15 ++++++++++----- tcg/s390x/tcg-target.c.inc | 10 ++++++++++ tcg/sparc64/tcg-target.c.inc | 10 ++++++++++ tcg/tcg-op.c | 7 +------ tcg/tcg.c | 5 +++-- tcg/tci/tcg-target.c.inc | 12 ++++++++++++ 11 files changed, 103 insertions(+), 30 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 8abc5f26da..4ea1aebc5e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2220,6 +2220,16 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_ubfm(s, TCG_TYPE_I64, a0, a1, 32, 63); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 9bae60d3b6..63c9aae26e 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2794,6 +2794,18 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, 0), + .out_rr = tgen_extrh_i64_i32, +}; +#endif /* TCG_TARGET_REG_BITS == 64 */ + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3212,6 +3224,7 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -3363,10 +3376,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, a0, a1, a2); } break; - - case INDEX_op_extrh_i64_i32: - tcg_out_shifti(s, SHIFT_SHR + P_REXW, a0, 32); - break; #endif OP_32_64(deposit): @@ -3995,9 +4004,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_extrh_i64_i32: - return C_O1_I1(r, 0); - case INDEX_op_extract2_i32: case INDEX_op_extract2_i64: return C_O1_I2(r, 0, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index fae1a58c94..1062eb1883 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1467,6 +1467,16 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_srai_d(s, a0, a1, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1867,10 +1877,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_b(s, 0); break; - case INDEX_op_extrh_i64_i32: - tcg_out_opc_srai_d(s, a0, a1, 32); - break; - case INDEX_op_deposit_i32: tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); break; @@ -2462,7 +2468,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(r, r, r); - case INDEX_op_extrh_i64_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: case INDEX_op_ld8u_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 095eb8f672..ad0482902d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1793,6 +1793,18 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_dsra(s, a0, a1, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; +#endif + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2315,10 +2327,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_extrh_i64_i32: - tcg_out_dsra(s, a0, a1, 32); - break; - case INDEX_op_deposit_i32: tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]); break; @@ -2388,7 +2396,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index bb03efe055..ba6d7556f7 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2965,6 +2965,18 @@ static void tgen_eqv(TCGContext *s, TCGType type, tcg_out32(s, EQV | SAB(a1, a0, a2)); } +#if TCG_TARGET_REG_BITS == 64 +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_shri64(s, a0, a1, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; +#endif + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 76ad2df410..46b4e1167c 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2151,6 +2151,16 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_opc_imm(s, OPC_SRAI, a0, a1, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2619,10 +2629,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); break; - case INDEX_op_extrh_i64_i32: - tcg_out_opc_imm(s, OPC_SRAI, a0, a1, 32); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -2871,7 +2877,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ld32s_i64: case INDEX_op_ld32u_i64: case INDEX_op_ld_i64: - case INDEX_op_extrh_i64_i32: return C_O1_I1(r, r); case INDEX_op_st8_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 1ea041c75f..3b3749efd3 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2409,6 +2409,16 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_sh64(s, RSY_SRLG, a0, a1, TCG_REG_NONE, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d52907f7e3..c1cce7c196 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1501,6 +1501,16 @@ static const TCGOutOpBinary outop_eqv = { .base.static_constraint = C_NotImplemented, }; +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_arithi(s, a0, a1, 32, SHIFT_SRLX); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 7ecd1f6c8f..b88f411ece 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -2972,14 +2972,9 @@ void tcg_gen_extrh_i64_i32(TCGv_i32 ret, TCGv_i64 arg) { if (TCG_TARGET_REG_BITS == 32) { tcg_gen_mov_i32(ret, TCGV_HIGH(arg)); - } else if (TCG_TARGET_HAS_extr_i64_i32) { + } else { tcg_gen_op2(INDEX_op_extrh_i64_i32, TCG_TYPE_I32, tcgv_i32_arg(ret), tcgv_i64_arg(arg)); - } else { - TCGv_i64 t = tcg_temp_ebb_new_i64(); - tcg_gen_shri_i64(t, arg, 32); - tcg_gen_mov_i32(ret, (TCGv_i32)t); - tcg_temp_free_i64(t); } } diff --git a/tcg/tcg.c b/tcg/tcg.c index 8fcaf54d32..ce583b824c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1162,6 +1162,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_ext_i32_i64, TCGOutOpUnary, outop_exts_i32_i64), OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64), OUTOP(INDEX_op_extrl_i64_i32, TCGOutOpUnary, outop_extrl_i64_i32), + OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), #endif }; @@ -2412,13 +2413,12 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: + case INDEX_op_extrh_i64_i32: case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; case INDEX_op_extract2_i64: return TCG_TARGET_HAS_extract2_i64; - case INDEX_op_extrh_i64_i32: - return TCG_TARGET_HAS_extr_i64_i32; case INDEX_op_add2_i64: return TCG_TARGET_HAS_add2_i64; case INDEX_op_sub2_i64: @@ -5510,6 +5510,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: + case INDEX_op_extrh_i64_i32: assert(TCG_TARGET_REG_BITS == 64); /* fall through */ case INDEX_op_ctpop: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index e9b46d5e66..d84d01e098 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -670,6 +670,18 @@ static const TCGOutOpBinary outop_eqv = { .out_rrr = tgen_eqv, }; +#if TCG_TARGET_REG_BITS == 64 +static void tgen_extrh_i64_i32(TCGContext *s, TCGType t, TCGReg a0, TCGReg a1) +{ + tcg_out_extract(s, TCG_TYPE_I64, a0, a1, 32, 32); +} + +static const TCGOutOpUnary outop_extrh_i64_i32 = { + .base.static_constraint = C_O1_I1(r, r), + .out_rr = tgen_extrh_i64_i32, +}; +#endif + static void tgen_mul(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From cf4905c03135f1181e86c618426f8d6c703b38c0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 20:29:41 -0800 Subject: [PATCH 0460/2760] tcg: Convert deposit to TCGOutOpDeposit Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 30 +++++-------- tcg/arm/tcg-target.c.inc | 29 ++++++------ tcg/i386/tcg-target.c.inc | 76 ++++++++++++++++---------------- tcg/loongarch64/tcg-target.c.inc | 27 +++++++----- tcg/mips/tcg-target.c.inc | 27 +++++++----- tcg/ppc/tcg-target.c.inc | 44 +++++++++--------- tcg/riscv/tcg-target.c.inc | 4 ++ tcg/s390x/tcg-target.c.inc | 60 +++++++++++++------------ tcg/sparc64/tcg-target.c.inc | 4 ++ tcg/tcg.c | 33 ++++++++++++++ tcg/tci.c | 8 ++-- tcg/tci/tcg-target.c.inc | 19 ++++---- 12 files changed, 206 insertions(+), 155 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 4ea1aebc5e..62b045c222 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1347,15 +1347,6 @@ static inline void tcg_out_extr(TCGContext *s, TCGType ext, TCGReg rd, tcg_out_insn(s, 3403, EXTR, ext, rd, rn, rm, a); } -static inline void tcg_out_dep(TCGContext *s, TCGType ext, TCGReg rd, - TCGReg rn, unsigned lsb, unsigned width) -{ - unsigned size = ext ? 64 : 32; - unsigned a = (size - lsb) & (size - 1); - unsigned b = width - 1; - tcg_out_bfm(s, ext, rd, rn, a, b); -} - static void tgen_cmp(TCGContext *s, TCGType ext, TCGCond cond, TCGReg a, TCGReg b) { @@ -2577,6 +2568,18 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_bfm(s, type, a0, a2, -ofs & mask, len - 1); +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, 0, rz), + .out_rrr = tgen_deposit, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { @@ -2684,11 +2687,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; - case INDEX_op_deposit_i64: - case INDEX_op_deposit_i32: - tcg_out_dep(s, ext, a0, a2, args[3], args[4]); - break; - case INDEX_op_extract2_i64: case INDEX_op_extract2_i32: tcg_out_extr(s, ext, a0, a2, a1, args[3]); @@ -3206,10 +3204,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(rz, rz, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(r, 0, rz); - case INDEX_op_extract2_i32: case INDEX_op_extract2_i64: return C_O1_I2(r, rz, rz); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index aebe48679c..2bf6bfe274 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -969,18 +969,27 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) g_assert_not_reached(); } -static void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd, - TCGArg a1, int ofs, int len, bool const_a1) +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) { - if (const_a1) { - /* bfi becomes bfc with rn == 15. */ - a1 = 15; - } /* bfi/bfc */ - tcg_out32(s, 0x07c00010 | (cond << 28) | (rd << 12) | a1 + tcg_out32(s, 0x07c00010 | (COND_AL << 28) | (a0 << 12) | a1 | (ofs << 7) | ((ofs + len - 1) << 16)); } +static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, unsigned ofs, unsigned len) +{ + /* bfi becomes bfc with rn == 15. */ + tgen_deposit(s, type, a0, a1, 15, ofs, len); +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, 0, rZ), + .out_rrr = tgen_deposit, + .out_rri = tgen_depositi, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg rd, TCGReg rn, unsigned ofs, unsigned len) { @@ -2402,10 +2411,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_deposit_i32: - tcg_out_deposit(s, COND_AL, args[0], args[2], - args[3], args[4], const_args[2]); - break; case INDEX_op_extract2_i32: /* ??? These optimization vs zero should be generic. */ /* ??? But we can't substitute 2 for 1 in the opcode stream yet. */ @@ -2459,8 +2464,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_deposit_i32: - return C_O1_I2(r, 0, rZ); case INDEX_op_extract2_i32: return C_O1_I2(r, rZ, rZ); case INDEX_op_add2_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 63c9aae26e..1dd9741f45 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3150,6 +3150,43 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + if (ofs == 0 && len == 8) { + tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0); + } else if (ofs == 0 && len == 16) { + tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0); + } else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) { + tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4); + } else { + g_assert_not_reached(); + } +} + +static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, unsigned ofs, unsigned len) +{ + if (ofs == 0 && len == 8) { + tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0), 0, a0, 0); + tcg_out8(s, a2); + } else if (ofs == 0 && len == 16) { + tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0), 0, a0, 0); + tcg_out16(s, a2); + } else if (TCG_TARGET_REG_BITS == 32 && ofs == 8 && len == 8) { + tcg_out8(s, OPC_MOVB_Ib + a0 + 4); + tcg_out8(s, a2); + } else { + g_assert_not_reached(); + } +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(q, 0, qi), + .out_rrr = tgen_deposit, + .out_rri = tgen_depositi, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { @@ -3230,7 +3267,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int const_a2, rexw; + int rexw; #if TCG_TARGET_REG_BITS == 64 # define OP_32_64(x) \ @@ -3245,7 +3282,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a0 = args[0]; a1 = args[1]; a2 = args[2]; - const_a2 = const_args[2]; rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; switch (opc) { @@ -3378,38 +3414,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #endif - OP_32_64(deposit): - if (args[3] == 0 && args[4] == 8) { - /* load bits 0..7 */ - if (const_a2) { - tcg_out_opc(s, OPC_MOVB_Ib | P_REXB_RM | LOWREGMASK(a0), - 0, a0, 0); - tcg_out8(s, a2); - } else { - tcg_out_modrm(s, OPC_MOVB_EvGv | P_REXB_R | P_REXB_RM, a2, a0); - } - } else if (TCG_TARGET_REG_BITS == 32 && args[3] == 8 && args[4] == 8) { - /* load bits 8..15 */ - if (const_a2) { - tcg_out8(s, OPC_MOVB_Ib + a0 + 4); - tcg_out8(s, a2); - } else { - tcg_out_modrm(s, OPC_MOVB_EvGv, a2, a0 + 4); - } - } else if (args[3] == 0 && args[4] == 16) { - /* load bits 0..15 */ - if (const_a2) { - tcg_out_opc(s, OPC_MOVL_Iv | P_DATA16 | LOWREGMASK(a0), - 0, a0, 0); - tcg_out16(s, a2); - } else { - tcg_out_modrm(s, OPC_MOVL_EvGv | P_DATA16, a2, a0); - } - } else { - g_assert_not_reached(); - } - break; - OP_32_64(extract2): /* Note that SHRD outputs to the r/m operand. */ tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0); @@ -4008,10 +4012,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extract2_i64: return C_O1_I2(r, 0, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(q, 0, qi); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 1062eb1883..0b64efc078 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1809,6 +1809,21 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_bstrins_w(s, a0, a2, ofs, ofs + len - 1); + } else { + tcg_out_opc_bstrins_d(s, a0, a2, ofs, ofs + len - 1); + } +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, 0, rz), + .out_rrr = tgen_deposit, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { @@ -1877,13 +1892,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_b(s, 0); break; - case INDEX_op_deposit_i32: - tcg_out_opc_bstrins_w(s, a0, a2, args[3], args[3] + args[4] - 1); - break; - case INDEX_op_deposit_i64: - tcg_out_opc_bstrins_d(s, a0, a2, args[3], args[3] + args[4] - 1); - break; - case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); @@ -2484,11 +2492,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - /* Must deposit into the same register as input */ - return C_O1_I2(r, 0, rz); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: case INDEX_op_dup_vec: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index ad0482902d..cd648ab1df 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2215,6 +2215,22 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + if (type == TCG_TYPE_I32) { + tcg_out_opc_bf(s, OPC_INS, a0, a2, ofs + len - 1, ofs); + } else { + tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2, + ofs + len - 1, ofs); + } +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, 0, rz), + .out_rrr = tgen_deposit, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { @@ -2327,14 +2343,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, i1, a0, a1, a2); break; - case INDEX_op_deposit_i32: - tcg_out_opc_bf(s, OPC_INS, a0, a2, args[3] + args[4] - 1, args[3]); - break; - case INDEX_op_deposit_i64: - tcg_out_opc_bf64(s, OPC_DINS, OPC_DINSM, OPC_DINSU, a0, a2, - args[3] + args[4] - 1, args[3]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32); break; @@ -2407,9 +2415,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(r, 0, rz); case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_O2_I4(r, r, rz, rz, rN, rN); diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index ba6d7556f7..fc92a4896d 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3429,6 +3429,28 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + if (type == TCG_TYPE_I32) { + tcg_out_rlw(s, RLWIMI, a0, a2, ofs, 32 - ofs - len, 31 - ofs); + } else { + tcg_out_rld(s, RLDIMI, a0, a2, ofs, 64 - ofs - len); + } +} + +static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, unsigned ofs, unsigned len) +{ + tgen_andi(s, type, a0, a1, ~MAKE_64BIT_MASK(ofs, len)); +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, 0, rZ), + .out_rrr = tgen_deposit, + .out_rri = tgen_depositi, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { @@ -3575,25 +3597,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_deposit_i32: - if (const_args[2]) { - uint32_t mask = ((2u << (args[4] - 1)) - 1) << args[3]; - tcg_out_andi32(s, args[0], args[0], ~mask); - } else { - tcg_out_rlw(s, RLWIMI, args[0], args[2], args[3], - 32 - args[3] - args[4], 31 - args[3]); - } - break; - case INDEX_op_deposit_i64: - if (const_args[2]) { - uint64_t mask = ((2ull << (args[4] - 1)) - 1) << args[3]; - tcg_out_andi64(s, args[0], args[0], ~mask); - } else { - tcg_out_rld(s, RLDIMI, args[0], args[2], args[3], - 64 - args[3] - args[4]); - } - break; - #if TCG_TARGET_REG_BITS == 64 case INDEX_op_add2_i64: #else @@ -4290,9 +4293,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(r, 0, rZ); case INDEX_op_add2_i64: case INDEX_op_add2_i32: return C_O2_I4(r, r, r, r, rI, rZM); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 46b4e1167c..371e0c24c8 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2482,6 +2482,10 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 3b3749efd3..d72393315d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1555,14 +1555,40 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; -static void tgen_deposit(TCGContext *s, TCGReg dest, TCGReg src, - int ofs, int len, int z) +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) { - int lsb = (63 - ofs); - int msb = lsb - (len - 1); - tcg_out_risbg(s, dest, src, msb, lsb, ofs, z); + unsigned lsb = (63 - ofs); + unsigned msb = lsb - (len - 1); + + /* + * Since we can't support "0Z" as a constraint, we allow a1 in + * any register. Fix things up as if a matching constraint. + */ + if (a0 != a1) { + if (a0 == a2) { + tcg_out_mov(s, type, TCG_TMP0, a2); + a2 = TCG_TMP0; + } + tcg_out_mov(s, type, a0, a1); + } + tcg_out_risbg(s, a0, a2, msb, lsb, ofs, false); } +static void tgen_depositz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a2, + unsigned ofs, unsigned len) +{ + unsigned lsb = (63 - ofs); + unsigned msb = lsb - (len - 1); + tcg_out_risbg(s, a0, a2, msb, lsb, ofs, true); +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, rZ, r), + .out_rrr = tgen_deposit, + .out_rzr = tgen_depositz, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg dest, TCGReg src, unsigned ofs, unsigned len) { @@ -2845,7 +2871,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2; + TCGArg a0; switch (opc) { case INDEX_op_goto_ptr: @@ -2977,24 +3003,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_insn(s, RRE, SLBGR, args[1], args[5]); break; - OP_32_64(deposit): - a0 = args[0], a1 = args[1], a2 = args[2]; - if (const_args[1]) { - tgen_deposit(s, a0, a2, args[3], args[4], 1); - } else { - /* Since we can't support "0Z" as a constraint, we allow a1 in - any register. Fix things up as if a matching constraint. */ - if (a0 != a1) { - if (a0 == a2) { - tcg_out_mov(s, type, TCG_TMP0, a2); - a2 = TCG_TMP0; - } - tcg_out_mov(s, type, a0, a1); - } - tgen_deposit(s, a0, a2, args[3], args[4], 0); - } - break; - case INDEX_op_mb: /* The host memory model is quite strong, we simply need to serialize the instruction stream. */ @@ -3489,10 +3497,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(o, m, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(r, rZ, r); - case INDEX_op_add2_i32: case INDEX_op_sub2_i32: return C_N1_O1_I4(r, r, 0, 1, ri, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index c1cce7c196..741de260e9 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1767,6 +1767,10 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, unsigned ofs, unsigned len) { diff --git a/tcg/tcg.c b/tcg/tcg.c index ce583b824c..b9e9454654 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1007,6 +1007,16 @@ typedef struct TCGOutOpBswap { TCGReg a0, TCGReg a1, unsigned flags); } TCGOutOpBswap; +typedef struct TCGOutOpDeposit { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len); + void (*out_rri)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, unsigned ofs, unsigned len); + void (*out_rzr)(TCGContext *s, TCGType type, TCGReg a0, + TCGReg a2, unsigned ofs, unsigned len); +} TCGOutOpDeposit; + typedef struct TCGOutOpDivRem { TCGOutOp base; void (*out_rr01r)(TCGContext *s, TCGType type, @@ -1123,6 +1133,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), + OUTOP(INDEX_op_deposit_i32, TCGOutOpDeposit, outop_deposit), + OUTOP(INDEX_op_deposit_i64, TCGOutOpDeposit, outop_deposit), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -5537,6 +5549,27 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: + { + const TCGOutOpDeposit *out = &outop_deposit; + + if (const_args[2]) { + tcg_debug_assert(!const_args[1]); + out->out_rri(s, type, new_args[0], new_args[1], + new_args[2], new_args[3], new_args[4]); + } else if (const_args[1]) { + tcg_debug_assert(new_args[1] == 0); + tcg_debug_assert(!const_args[2]); + out->out_rzr(s, type, new_args[0], new_args[2], + new_args[3], new_args[4]); + } else { + out->out_rrr(s, type, new_args[0], new_args[1], + new_args[2], new_args[3], new_args[4]); + } + } + break; + case INDEX_op_divs2: case INDEX_op_divu2: { diff --git a/tcg/tci.c b/tcg/tci.c index 5a07d65db8..595416a192 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -27,6 +27,7 @@ #define ctpop_tr glue(ctpop, TCG_TARGET_REG_BITS) +#define deposit_tr glue(deposit, TCG_TARGET_REG_BITS) #define extract_tr glue(extract, TCG_TARGET_REG_BITS) #define sextract_tr glue(sextract, TCG_TARGET_REG_BITS) @@ -655,8 +656,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, regs[r0] = ror32(regs[r1], regs[r2] & 31); break; case INDEX_op_deposit_i32: + case INDEX_op_deposit_i64: tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); - regs[r0] = deposit32(regs[r1], pos, len, regs[r2]); + regs[r0] = deposit_tr(regs[r1], pos, len, regs[r2]); break; case INDEX_op_extract: tci_args_rrbb(insn, &r0, &r1, &pos, &len); @@ -770,10 +772,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ror64(regs[r1], regs[r2] & 63); break; - case INDEX_op_deposit_i64: - tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); - regs[r0] = deposit64(regs[r1], pos, len, regs[r2]); - break; case INDEX_op_ext_i32_i64: tci_args_rr(insn, &r0, &r1); regs[r0] = (int32_t)regs[r1]; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d84d01e098..566c2fb0d0 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -66,10 +66,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: - return C_O1_I2(r, r, r); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: @@ -623,6 +619,17 @@ static const TCGOutOpBinary outop_ctz = { .out_rrr = tgen_ctz, }; +static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned ofs, unsigned len) +{ + tcg_out_op_rrrbb(s, INDEX_op_deposit_i64, a0, a1, a2, ofs, len); +} + +static const TCGOutOpDeposit outop_deposit = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_deposit, +}; + static void tgen_divs(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1084,10 +1091,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(deposit) - tcg_out_op_rrrbb(s, opc, args[0], args[1], args[2], args[3], args[4]); - break; - CASE_32_64(add2) CASE_32_64(sub2) tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2], From a5a8dd33aad1ada9b05968e8b93033bdbdfdbca2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 20:42:13 -0800 Subject: [PATCH 0461/2760] tcg/aarch64: Improve deposit Use ANDI for deposit 0 into a register. Use UBFIZ, aka UBFM, for deposit register into 0. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-con-set.h | 2 +- tcg/aarch64/tcg-target.c.inc | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/tcg/aarch64/tcg-target-con-set.h b/tcg/aarch64/tcg-target-con-set.h index 1281e5efc0..2eda499cd3 100644 --- a/tcg/aarch64/tcg-target-con-set.h +++ b/tcg/aarch64/tcg-target-con-set.h @@ -18,7 +18,6 @@ C_O1_I1(r, r) C_O1_I1(w, r) C_O1_I1(w, w) C_O1_I1(w, wr) -C_O1_I2(r, 0, rz) C_O1_I2(r, r, r) C_O1_I2(r, r, rA) C_O1_I2(r, r, rAL) @@ -26,6 +25,7 @@ C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rL) C_O1_I2(r, rz, rz) +C_O1_I2(r, rZ, rZ) C_O1_I2(w, 0, w) C_O1_I2(w, w, w) C_O1_I2(w, w, wN) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 62b045c222..dee4afcce1 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2572,12 +2572,39 @@ static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2, unsigned ofs, unsigned len) { unsigned mask = type == TCG_TYPE_I32 ? 31 : 63; + + /* + * Since we can't support "0Z" as a constraint, we allow a1 in + * any register. Fix things up as if a matching constraint. + */ + if (a0 != a1) { + if (a0 == a2) { + tcg_out_mov(s, type, TCG_REG_TMP0, a2); + a2 = TCG_REG_TMP0; + } + tcg_out_mov(s, type, a0, a1); + } tcg_out_bfm(s, type, a0, a2, -ofs & mask, len - 1); } +static void tgen_depositi(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + tcg_target_long a2, unsigned ofs, unsigned len) +{ + tgen_andi(s, type, a0, a1, ~MAKE_64BIT_MASK(ofs, len)); +} + +static void tgen_depositz(TCGContext *s, TCGType type, TCGReg a0, TCGReg a2, + unsigned ofs, unsigned len) +{ + int max = type == TCG_TYPE_I32 ? 31 : 63; + tcg_out_ubfm(s, type, a0, a2, -ofs & max, len - 1); +} + static const TCGOutOpDeposit outop_deposit = { - .base.static_constraint = C_O1_I2(r, 0, rz), + .base.static_constraint = C_O1_I2(r, rZ, rZ), .out_rrr = tgen_deposit, + .out_rri = tgen_depositi, + .out_rzr = tgen_depositz, }; static void tgen_extract(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, From 4d137ff819bae33d045f13bb9186e3a2c71cb7e4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 20:48:57 -0800 Subject: [PATCH 0462/2760] tcg: Merge INDEX_op_deposit_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 6 ++++-- include/tcg/tcg-opc.h | 3 +-- tcg/optimize.c | 2 +- tcg/tcg-op.c | 8 ++++---- tcg/tcg.c | 9 +++------ tcg/tci.c | 6 ++---- tcg/tci/tcg-target.c.inc | 2 +- 7 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index ca7550f68c..aea8a897bd 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -442,7 +442,7 @@ Misc - | Indicate that the value of *t0* won't be used later. It is useful to force dead code elimination. - * - deposit_i32/i64 *dest*, *t1*, *t2*, *pos*, *len* + * - deposit *dest*, *t1*, *t2*, *pos*, *len* - | Deposit *t2* as a bitfield into *t1*, placing the result in *dest*. | @@ -451,10 +451,12 @@ Misc | *len* - the length of the bitfield | *pos* - the position of the first bit, counting from the LSB | - | For example, "deposit_i32 dest, t1, t2, 8, 4" indicates a 4-bit field + | For example, "deposit dest, t1, t2, 8, 4" indicates a 4-bit field at bit 8. This operation would be equivalent to | | *dest* = (*t1* & ~0x0f00) | ((*t2* << 8) & 0x0f00) + | + | on TCG_TYPE_I32. * - extract *dest*, *t1*, *pos*, *len* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 4ace1f85c4..c6848b3c63 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -49,6 +49,7 @@ DEF(bswap64, 1, 1, 1, TCG_OPF_INT) DEF(clz, 1, 2, 0, TCG_OPF_INT) DEF(ctpop, 1, 1, 0, TCG_OPF_INT) DEF(ctz, 1, 2, 0, TCG_OPF_INT) +DEF(deposit, 1, 2, 2, TCG_OPF_INT) DEF(divs, 1, 2, 0, TCG_OPF_INT) DEF(divs2, 2, 3, 0, TCG_OPF_INT) DEF(divu, 1, 2, 0, TCG_OPF_INT) @@ -90,7 +91,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) /* shifts/rotates */ -DEF(deposit_i32, 1, 2, 2, 0) DEF(extract2_i32, 1, 2, 1, 0) DEF(add2_i32, 2, 4, 0, 0) @@ -111,7 +111,6 @@ DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) /* shifts/rotates */ -DEF(deposit_i64, 1, 2, 2, 0) DEF(extract2_i64, 1, 2, 1, 0) /* size changing ops */ diff --git a/tcg/optimize.c b/tcg/optimize.c index d324cbf7fe..acc566ed76 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2858,7 +2858,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_ctpop: done = fold_ctpop(&ctx, op); break; - CASE_OP_32_64(deposit): + case INDEX_op_deposit: done = fold_deposit(&ctx, op); break; case INDEX_op_divs: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b88f411ece..961a39f446 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -915,7 +915,7 @@ void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, return; } if (TCG_TARGET_deposit_valid(TCG_TYPE_I32, ofs, len)) { - tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, arg1, arg2, ofs, len); + tcg_gen_op5ii_i32(INDEX_op_deposit, ret, arg1, arg2, ofs, len); return; } @@ -961,7 +961,7 @@ void tcg_gen_deposit_z_i32(TCGv_i32 ret, TCGv_i32 arg, tcg_gen_andi_i32(ret, arg, (1u << len) - 1); } else if (TCG_TARGET_deposit_valid(TCG_TYPE_I32, ofs, len)) { TCGv_i32 zero = tcg_constant_i32(0); - tcg_gen_op5ii_i32(INDEX_op_deposit_i32, ret, zero, arg, ofs, len); + tcg_gen_op5ii_i32(INDEX_op_deposit, ret, zero, arg, ofs, len); } else { /* * To help two-operand hosts we prefer to zero-extend first, @@ -2533,7 +2533,7 @@ void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, if (TCG_TARGET_REG_BITS == 64) { if (TCG_TARGET_deposit_valid(TCG_TYPE_I64, ofs, len)) { - tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, arg1, arg2, ofs, len); + tcg_gen_op5ii_i64(INDEX_op_deposit, ret, arg1, arg2, ofs, len); return; } } else { @@ -2594,7 +2594,7 @@ void tcg_gen_deposit_z_i64(TCGv_i64 ret, TCGv_i64 arg, } else if (TCG_TARGET_REG_BITS == 64 && TCG_TARGET_deposit_valid(TCG_TYPE_I64, ofs, len)) { TCGv_i64 zero = tcg_constant_i64(0); - tcg_gen_op5ii_i64(INDEX_op_deposit_i64, ret, zero, arg, ofs, len); + tcg_gen_op5ii_i64(INDEX_op_deposit, ret, zero, arg, ofs, len); } else { if (TCG_TARGET_REG_BITS == 32) { if (ofs >= 32) { diff --git a/tcg/tcg.c b/tcg/tcg.c index b9e9454654..6b49fd4acf 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1133,8 +1133,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_clz, TCGOutOpBinary, outop_clz), OUTOP(INDEX_op_ctpop, TCGOutOpUnary, outop_ctpop), OUTOP(INDEX_op_ctz, TCGOutOpBinary, outop_ctz), - OUTOP(INDEX_op_deposit_i32, TCGOutOpDeposit, outop_deposit), - OUTOP(INDEX_op_deposit_i64, TCGOutOpDeposit, outop_deposit), + OUTOP(INDEX_op_deposit, TCGOutOpDeposit, outop_deposit), OUTOP(INDEX_op_divs, TCGOutOpBinary, outop_divs), OUTOP(INDEX_op_divu, TCGOutOpBinary, outop_divu), OUTOP(INDEX_op_divs2, TCGOutOpDivRem, outop_divs2), @@ -2379,6 +2378,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add: case INDEX_op_and: case INDEX_op_brcond: + case INDEX_op_deposit: case INDEX_op_extract: case INDEX_op_mov: case INDEX_op_movcond: @@ -2397,7 +2397,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: - case INDEX_op_deposit_i32: return true; case INDEX_op_extract2_i32: @@ -2426,7 +2425,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: case INDEX_op_extrh_i64_i32: - case INDEX_op_deposit_i64: return TCG_TARGET_REG_BITS == 64; case INDEX_op_extract2_i64: @@ -5549,8 +5547,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: + case INDEX_op_deposit: { const TCGOutOpDeposit *out = &outop_deposit; diff --git a/tcg/tci.c b/tcg/tci.c index 595416a192..dc916eb112 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -655,8 +655,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = ror32(regs[r1], regs[r2] & 31); break; - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: + case INDEX_op_deposit: tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); regs[r0] = deposit_tr(regs[r1], pos, len, regs[r2]); break; @@ -1042,8 +1041,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), str_r(r1), str_r(r2)); break; - case INDEX_op_deposit_i32: - case INDEX_op_deposit_i64: + case INDEX_op_deposit: tci_args_rrrbb(insn, &r0, &r1, &r2, &pos, &len); info->fprintf_func(info->stream, "%-12s %s, %s, %s, %d, %d", op_name, str_r(r0), str_r(r1), str_r(r2), pos, len); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 566c2fb0d0..ef14e81609 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -622,7 +622,7 @@ static const TCGOutOpBinary outop_ctz = { static void tgen_deposit(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2, unsigned ofs, unsigned len) { - tcg_out_op_rrrbb(s, INDEX_op_deposit_i64, a0, a1, a2, ofs, len); + tcg_out_op_rrrbb(s, INDEX_op_deposit, a0, a1, a2, ofs, len); } static const TCGOutOpDeposit outop_deposit = { From c8f9f70047e17ce70e016bc59fe7857123f3cbd5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 21:30:10 -0800 Subject: [PATCH 0463/2760] tcg: Convert extract2 to TCGOutOpExtract2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-has.h | 2 -- tcg/aarch64/tcg-target.c.inc | 20 +++++++++-------- tcg/arm/tcg-target-has.h | 1 - tcg/arm/tcg-target.c.inc | 38 ++++++++++++-------------------- tcg/i386/tcg-target-has.h | 2 -- tcg/i386/tcg-target.c.inc | 25 ++++++++++++--------- tcg/loongarch64/tcg-target-has.h | 2 -- tcg/loongarch64/tcg-target.c.inc | 5 +++++ tcg/mips/tcg-target-has.h | 6 ----- tcg/mips/tcg-target.c.inc | 5 +++++ tcg/ppc/tcg-target-has.h | 2 -- tcg/ppc/tcg-target.c.inc | 4 ++++ tcg/riscv/tcg-target-has.h | 2 -- tcg/riscv/tcg-target.c.inc | 5 +++++ tcg/s390x/tcg-target-has.h | 2 -- tcg/s390x/tcg-target.c.inc | 4 ++++ tcg/sparc64/tcg-target-has.h | 2 -- tcg/sparc64/tcg-target.c.inc | 4 ++++ tcg/tcg-has.h | 1 - tcg/tcg-op.c | 12 +++++----- tcg/tcg.c | 24 ++++++++++++++++---- tcg/tci/tcg-target-has.h | 2 -- tcg/tci/tcg-target.c.inc | 4 ++++ 23 files changed, 97 insertions(+), 77 deletions(-) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 82d8cd5965..011a91c263 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,13 +13,11 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index dee4afcce1..bece494c55 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2634,6 +2634,17 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static void tgen_extract2(TCGContext *s, TCGType type, TCGReg a0, + TCGReg a1, TCGReg a2, unsigned shr) +{ + tcg_out_extr(s, type, a0, a2, a1, shr); +} + +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_O1_I2(r, rz, rz), + .out_rrr = tgen_extract2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2714,11 +2725,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; - case INDEX_op_extract2_i64: - case INDEX_op_extract2_i32: - tcg_out_extr(s, ext, a0, a2, a1, args[3]); - break; - case INDEX_op_add2_i32: tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, a2, args[3], (int32_t)args[4], args[5], const_args[4], @@ -3231,10 +3237,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(rz, rz, r); - case INDEX_op_extract2_i32: - case INDEX_op_extract2_i64: - return C_O1_I2(r, rz, rz); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index c85b5da1e5..0d6a785542 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,7 +24,6 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 2bf6bfe274..f366424af5 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2317,6 +2317,20 @@ static const TCGOutOpSetcond2 outop_setcond2 = { .out = tgen_setcond2, }; +static void tgen_extract2(TCGContext *s, TCGType type, TCGReg a0, + TCGReg a1, TCGReg a2, unsigned shr) +{ + /* We can do extract2 in 2 insns, vs the 3 required otherwise. */ + tgen_shli(s, TCG_TYPE_I32, TCG_REG_TMP, a2, 32 - shr); + tcg_out_dat_reg(s, COND_AL, ARITH_ORR, a0, TCG_REG_TMP, + a1, SHIFT_IMM_LSR(shr)); +} + +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_O1_I2(r, r, r), + .out_rrr = tgen_extract2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2411,28 +2425,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_extract2_i32: - /* ??? These optimization vs zero should be generic. */ - /* ??? But we can't substitute 2 for 1 in the opcode stream yet. */ - if (const_args[1]) { - if (const_args[2]) { - tcg_out_movi(s, TCG_TYPE_REG, args[0], 0); - } else { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, - args[2], SHIFT_IMM_LSL(32 - args[3])); - } - } else if (const_args[2]) { - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, - args[1], SHIFT_IMM_LSR(args[3])); - } else { - /* We can do extract2 in 2 insns, vs the 3 required otherwise. */ - tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, - args[2], SHIFT_IMM_LSL(32 - args[3])); - tcg_out_dat_reg(s, COND_AL, ARITH_ORR, args[0], TCG_REG_TMP, - args[1], SHIFT_IMM_LSR(args[3])); - } - break; - case INDEX_op_mb: tcg_out_mb(s, args[0]); break; @@ -2464,8 +2456,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_extract2_i32: - return C_O1_I2(r, rZ, rZ); case INDEX_op_add2_i32: return C_O2_I4(r, r, r, r, rIN, rIK); case INDEX_op_sub2_i32: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 6b91b23fe8..0328102c2a 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,14 +26,12 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 1 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_extract2_i64 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 1dd9741f45..2b2ad9ca95 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3261,6 +3261,21 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static void tgen_extract2(TCGContext *s, TCGType type, TCGReg a0, + TCGReg a1, TCGReg a2, unsigned shr) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + + /* Note that SHRD outputs to the r/m operand. */ + tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0); + tcg_out8(s, shr); +} + +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_O1_I2(r, 0, r), + .out_rrr = tgen_extract2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -3414,12 +3429,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #endif - OP_32_64(extract2): - /* Note that SHRD outputs to the r/m operand. */ - tcg_out_modrm(s, OPC_SHRD_Ib + rexw, a2, a0); - tcg_out8(s, args[3]); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -4008,10 +4017,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_extract2_i32: - case INDEX_op_extract2_i64: - return C_O1_I2(r, 0, r); - case INDEX_op_add2_i32: case INDEX_op_add2_i64: case INDEX_op_sub2_i32: diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 10090102f7..a1bd71db6a 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -10,13 +10,11 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 0b64efc078..eb2143703d 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1868,6 +1868,11 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 24b00f1eec..48a1e68fbe 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -51,13 +51,7 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions detected at runtime */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 - -#if TCG_TARGET_REG_BITS == 64 -#define TCG_TARGET_HAS_extract2_i64 0 -#endif - #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 0 diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index cd648ab1df..7fae1c51e9 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2273,6 +2273,11 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index bd9c3d92ed..033d58e095 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,14 +17,12 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #endif diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index fc92a4896d..a964239aab 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3495,6 +3495,10 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 88fadc2428..b2814f8ef9 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -10,12 +10,10 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 371e0c24c8..d74ac7587a 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2542,6 +2542,11 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 95407f61cf..4a2b71995d 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,13 +29,11 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index d72393315d..ff06834e6e 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1637,6 +1637,10 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tgen_gotoi(TCGContext *s, int cc, const tcg_insn_unit *dest) { ptrdiff_t off = tcg_pcrel_diff(s, dest) >> 1; diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index 2ced6f7c1c..b8760dd154 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,13 +14,11 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 741de260e9..4c7d916302 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1795,6 +1795,10 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tgen_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 21bef070fe..6125ac677c 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,7 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 /* Turn some undef macros into true macros. */ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 961a39f446..5f95350d5d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -921,7 +921,7 @@ void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, t1 = tcg_temp_ebb_new_i32(); - if (TCG_TARGET_HAS_extract2_i32) { + if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { if (ofs + len == 32) { tcg_gen_shli_i32(t1, arg1, len); tcg_gen_extract2_i32(ret, t1, arg2, len); @@ -1077,7 +1077,7 @@ void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah, tcg_gen_mov_i32(ret, ah); } else if (al == ah) { tcg_gen_rotri_i32(ret, al, ofs); - } else if (TCG_TARGET_HAS_extract2_i32) { + } else if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -1799,7 +1799,7 @@ static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, tcg_gen_movi_i32(TCGV_LOW(ret), 0); } } else if (right) { - if (TCG_TARGET_HAS_extract2_i32) { + if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { tcg_gen_extract2_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), c); } else { @@ -1813,7 +1813,7 @@ static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); } } else { - if (TCG_TARGET_HAS_extract2_i32) { + if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { tcg_gen_extract2_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c); } else { @@ -2553,7 +2553,7 @@ void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, t1 = tcg_temp_ebb_new_i64(); - if (TCG_TARGET_HAS_extract2_i64) { + if (tcg_op_supported(INDEX_op_extract2_i64, TCG_TYPE_I64, 0)) { if (ofs + len == 64) { tcg_gen_shli_i64(t1, arg1, len); tcg_gen_extract2_i64(ret, t1, arg2, len); @@ -2781,7 +2781,7 @@ void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah, tcg_gen_mov_i64(ret, ah); } else if (al == ah) { tcg_gen_rotri_i64(ret, al, ofs); - } else if (TCG_TARGET_HAS_extract2_i64) { + } else if (tcg_op_supported(INDEX_op_extract2_i64, TCG_TYPE_I64, 0)) { tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 6b49fd4acf..3fbbe3bd83 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1029,6 +1029,12 @@ typedef struct TCGOutOpExtract { unsigned ofs, unsigned len); } TCGOutOpExtract; +typedef struct TCGOutOpExtract2 { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, + TCGReg a2, unsigned shr); +} TCGOutOpExtract2; + typedef struct TCGOutOpMovcond { TCGOutOp base; void (*out)(TCGContext *s, TCGType type, TCGCond cond, @@ -1140,6 +1146,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), + OUTOP(INDEX_op_extract2_i32, TCGOutOpExtract2, outop_extract2), + OUTOP(INDEX_op_extract2_i64, TCGOutOpExtract2, outop_extract2), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -2399,8 +2407,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return true; - case INDEX_op_extract2_i32: - return TCG_TARGET_HAS_extract2_i32; case INDEX_op_add2_i32: return TCG_TARGET_HAS_add2_i32; case INDEX_op_sub2_i32: @@ -2427,8 +2433,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return TCG_TARGET_REG_BITS == 64; - case INDEX_op_extract2_i64: - return TCG_TARGET_HAS_extract2_i64; case INDEX_op_add2_i64: return TCG_TARGET_HAS_add2_i64; case INDEX_op_sub2_i64: @@ -5593,6 +5597,18 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_extract2_i32: + case INDEX_op_extract2_i64: + { + const TCGOutOpExtract2 *out = &outop_extract2; + + tcg_debug_assert(!const_args[1]); + tcg_debug_assert(!const_args[2]); + out->out_rrr(s, type, new_args[0], new_args[1], + new_args[2], new_args[3]); + } + break; + case INDEX_op_muls2: case INDEX_op_mulu2: { diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 90aa5c8bbb..4cb2b529ae 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -7,12 +7,10 @@ #ifndef TCG_TARGET_HAS_H #define TCG_TARGET_HAS_H -#define TCG_TARGET_HAS_extract2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_extract2_i64 0 #define TCG_TARGET_HAS_add2_i32 1 #define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_add2_i64 1 diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index ef14e81609..9a5ca9c778 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -447,6 +447,10 @@ static const TCGOutOpExtract outop_sextract = { .out_rr = tcg_out_sextract, }; +static const TCGOutOpExtract2 outop_extract2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_ext8s(TCGContext *s, TCGType type, TCGReg rd, TCGReg rs) { tcg_out_sextract(s, type, rd, rs, 0, 8); From 61d6a8767a5d4cd4fe5086ef98b53614ae099104 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 12 Jan 2025 21:40:43 -0800 Subject: [PATCH 0464/2760] tcg: Merge INDEX_op_extract2_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 4 ++-- include/tcg/tcg-opc.h | 5 +---- target/i386/tcg/emit.c.inc | 12 +----------- tcg/optimize.c | 10 +++++----- tcg/tcg-op.c | 16 ++++++++-------- tcg/tcg.c | 6 ++---- 6 files changed, 19 insertions(+), 34 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index aea8a897bd..9392d88069 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -476,9 +476,9 @@ Misc | | (using an arithmetic right shift) on TCG_TYPE_I32. - * - extract2_i32/i64 *dest*, *t1*, *t2*, *pos* + * - extract2 *dest*, *t1*, *t2*, *pos* - - | For N = {32,64}, extract an N-bit quantity from the concatenation + - | For TCG_TYPE_I{N}, extract an N-bit quantity from the concatenation of *t2*:*t1*, beginning at *pos*. The tcg_gen_extract2_{i32,i64} expander accepts 0 <= *pos* <= N as inputs. The backend code generator will not see either 0 or N as inputs for these opcodes. diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index c6848b3c63..1f995c54be 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -56,6 +56,7 @@ DEF(divu, 1, 2, 0, TCG_OPF_INT) DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(extract, 1, 1, 2, TCG_OPF_INT) +DEF(extract2, 1, 2, 1, TCG_OPF_INT) DEF(movcond, 1, 4, 1, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(muls2, 2, 2, 0, TCG_OPF_INT) @@ -90,8 +91,6 @@ DEF(ld_i32, 1, 1, 1, 0) DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) -/* shifts/rotates */ -DEF(extract2_i32, 1, 2, 1, 0) DEF(add2_i32, 2, 4, 0, 0) DEF(sub2_i32, 2, 4, 0, 0) @@ -110,8 +109,6 @@ DEF(st8_i64, 0, 2, 1, 0) DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) DEF(st_i64, 0, 2, 1, 0) -/* shifts/rotates */ -DEF(extract2_i64, 1, 2, 1, 0) /* size changing ops */ DEF(ext_i32_i64, 1, 1, 0, 0) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index ca6bc2ea82..e3166e70a5 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -19,16 +19,6 @@ * License along with this library; if not, see . */ -/* - * Sometimes, knowing what the backend has can produce better code. - * The exact opcode to check depends on 32- vs. 64-bit. - */ -#ifdef TARGET_X86_64 -#define INDEX_op_extract2_tl INDEX_op_extract2_i64 -#else -#define INDEX_op_extract2_tl INDEX_op_extract2_i32 -#endif - #define MMX_OFFSET(reg) \ ({ assert((reg) >= 0 && (reg) <= 7); \ offsetof(CPUX86State, fpregs[reg].mmx); }) @@ -3023,7 +3013,7 @@ static void gen_PMOVMSKB(DisasContext *s, X86DecodedInsn *decode) tcg_gen_ld8u_tl(s->T0, tcg_env, offsetof(CPUX86State, xmm_t0.ZMM_B(vec_len - 1))); while (vec_len > 8) { vec_len -= 8; - if (tcg_op_supported(INDEX_op_extract2_tl, TCG_TYPE_TL, 0)) { + if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_TL, 0)) { /* * Load the next byte of the result into the high byte of T. * TCG does a similar expansion of deposit to shl+extract2; by diff --git a/tcg/optimize.c b/tcg/optimize.c index acc566ed76..a728a4b2fa 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1873,12 +1873,12 @@ static bool fold_extract2(OptContext *ctx, TCGOp *op) uint64_t v2 = arg_info(op->args[2])->val; int shr = op->args[3]; - if (op->opc == INDEX_op_extract2_i64) { - v1 >>= shr; - v2 <<= 64 - shr; - } else { + if (ctx->type == TCG_TYPE_I32) { v1 = (uint32_t)v1 >> shr; v2 = (uint64_t)((int32_t)v2 << (32 - shr)); + } else { + v1 >>= shr; + v2 <<= 64 - shr; } return tcg_opt_gen_movi(ctx, op, op->args[0], v1 | v2); } @@ -2878,7 +2878,7 @@ void tcg_optimize(TCGContext *s) case INDEX_op_extract: done = fold_extract(&ctx, op); break; - CASE_OP_32_64(extract2): + case INDEX_op_extract2: done = fold_extract2(&ctx, op); break; case INDEX_op_ext_i32_i64: diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 5f95350d5d..edbb214f7c 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -921,7 +921,7 @@ void tcg_gen_deposit_i32(TCGv_i32 ret, TCGv_i32 arg1, TCGv_i32 arg2, t1 = tcg_temp_ebb_new_i32(); - if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) { if (ofs + len == 32) { tcg_gen_shli_i32(t1, arg1, len); tcg_gen_extract2_i32(ret, t1, arg2, len); @@ -1077,8 +1077,8 @@ void tcg_gen_extract2_i32(TCGv_i32 ret, TCGv_i32 al, TCGv_i32 ah, tcg_gen_mov_i32(ret, ah); } else if (al == ah) { tcg_gen_rotri_i32(ret, al, ofs); - } else if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { - tcg_gen_op4i_i32(INDEX_op_extract2_i32, ret, al, ah, ofs); + } else if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) { + tcg_gen_op4i_i32(INDEX_op_extract2, ret, al, ah, ofs); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); tcg_gen_shri_i32(t0, al, ofs); @@ -1799,7 +1799,7 @@ static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, tcg_gen_movi_i32(TCGV_LOW(ret), 0); } } else if (right) { - if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) { tcg_gen_extract2_i32(TCGV_LOW(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), c); } else { @@ -1813,7 +1813,7 @@ static inline void tcg_gen_shifti_i64(TCGv_i64 ret, TCGv_i64 arg1, tcg_gen_shri_i32(TCGV_HIGH(ret), TCGV_HIGH(arg1), c); } } else { - if (tcg_op_supported(INDEX_op_extract2_i32, TCG_TYPE_I32, 0)) { + if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I32, 0)) { tcg_gen_extract2_i32(TCGV_HIGH(ret), TCGV_LOW(arg1), TCGV_HIGH(arg1), 32 - c); } else { @@ -2553,7 +2553,7 @@ void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, TCGv_i64 arg2, t1 = tcg_temp_ebb_new_i64(); - if (tcg_op_supported(INDEX_op_extract2_i64, TCG_TYPE_I64, 0)) { + if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I64, 0)) { if (ofs + len == 64) { tcg_gen_shli_i64(t1, arg1, len); tcg_gen_extract2_i64(ret, t1, arg2, len); @@ -2781,8 +2781,8 @@ void tcg_gen_extract2_i64(TCGv_i64 ret, TCGv_i64 al, TCGv_i64 ah, tcg_gen_mov_i64(ret, ah); } else if (al == ah) { tcg_gen_rotri_i64(ret, al, ofs); - } else if (tcg_op_supported(INDEX_op_extract2_i64, TCG_TYPE_I64, 0)) { - tcg_gen_op4i_i64(INDEX_op_extract2_i64, ret, al, ah, ofs); + } else if (tcg_op_supported(INDEX_op_extract2, TCG_TYPE_I64, 0)) { + tcg_gen_op4i_i64(INDEX_op_extract2, ret, al, ah, ofs); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); tcg_gen_shri_i64(t0, al, ofs); diff --git a/tcg/tcg.c b/tcg/tcg.c index 3fbbe3bd83..037b5a4664 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1146,8 +1146,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_divu2, TCGOutOpDivRem, outop_divu2), OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), - OUTOP(INDEX_op_extract2_i32, TCGOutOpExtract2, outop_extract2), - OUTOP(INDEX_op_extract2_i64, TCGOutOpExtract2, outop_extract2), + OUTOP(INDEX_op_extract2, TCGOutOpExtract2, outop_extract2), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -5597,8 +5596,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_extract2_i32: - case INDEX_op_extract2_i64: + case INDEX_op_extract2: { const TCGOutOpExtract2 *out = &outop_extract2; From 3ff7e44ef35924f76dbe36510c54c27e72af9121 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 20:14:09 -0800 Subject: [PATCH 0465/2760] tcg: Expand fallback add2 with 32-bit operations No need to expand to i64 to perform the add. This is smaller on a loongarch64 host, e.g. bstrpick_d r28, r27, 31, 0 bstrpick_d r29, r24, 31, 0 add_d r28, r28, r29 addi_w r29, r28, 0 srai_d r28, r28, 32 --- add_w r28, r27, r24 sltu r29, r28, r24 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index edbb214f7c..8b1356c526 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1105,14 +1105,15 @@ void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, if (TCG_TARGET_HAS_add2_i32) { tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); } else { - TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - tcg_gen_concat_i32_i64(t0, al, ah); - tcg_gen_concat_i32_i64(t1, bl, bh); - tcg_gen_add_i64(t0, t0, t1); - tcg_gen_extr_i64_i32(rl, rh, t0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); + tcg_gen_add_i32(t0, al, bl); + tcg_gen_setcond_i32(TCG_COND_LTU, t1, t0, al); + tcg_gen_add_i32(rh, ah, bh); + tcg_gen_add_i32(rh, rh, t1); + tcg_gen_mov_i32(rl, t0); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); } } From 3db22914ced9bb3683bffa03729608be0c42f666 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 20:21:09 -0800 Subject: [PATCH 0466/2760] tcg: Expand fallback sub2 with 32-bit operations No need to expand to i64 to perform the subtract. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 8b1356c526..127338b994 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1123,14 +1123,15 @@ void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, if (TCG_TARGET_HAS_sub2_i32) { tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); } else { - TCGv_i64 t0 = tcg_temp_ebb_new_i64(); - TCGv_i64 t1 = tcg_temp_ebb_new_i64(); - tcg_gen_concat_i32_i64(t0, al, ah); - tcg_gen_concat_i32_i64(t1, bl, bh); - tcg_gen_sub_i64(t0, t0, t1); - tcg_gen_extr_i64_i32(rl, rh, t0); - tcg_temp_free_i64(t0); - tcg_temp_free_i64(t1); + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); + tcg_gen_sub_i32(t0, al, bl); + tcg_gen_setcond_i32(TCG_COND_LTU, t1, al, bl); + tcg_gen_sub_i32(rh, ah, bh); + tcg_gen_sub_i32(rh, rh, t1); + tcg_gen_mov_i32(rl, t0); + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); } } From 8dc1bdf79553594287b6c3f9185fe028307aedcb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 21:13:54 -0800 Subject: [PATCH 0467/2760] tcg: Do not default add2/sub2_i32 for 32-bit hosts Require TCG_TARGET_HAS_{add2,sub2}_i32 be defined, one way or another. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/arm/tcg-target-has.h | 2 ++ tcg/mips/tcg-target-has.h | 3 +++ tcg/ppc/tcg-target-has.h | 3 +++ tcg/tcg-has.h | 3 --- tcg/tci/tcg-target-has.h | 4 ++-- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 0d6a785542..3973df1f12 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,6 +24,8 @@ extern bool use_neon_instructions; #endif /* optional instructions */ +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 48a1e68fbe..9f6fa194b9 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -48,6 +48,9 @@ extern bool use_mips32r2_instructions; #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 +#else +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 #endif /* optional instructions detected at runtime */ diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 033d58e095..8d832ce99c 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -25,6 +25,9 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 +#else +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 6125ac677c..50e8d0cda4 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -14,9 +14,6 @@ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 -/* Turn some undef macros into true macros. */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 #endif #if !defined(TCG_TARGET_HAS_v64) \ diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 4cb2b529ae..6063f32f7b 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -8,11 +8,11 @@ #define TCG_TARGET_HAS_H #define TCG_TARGET_HAS_qemu_st8_i32 0 +#define TCG_TARGET_HAS_add2_i32 1 +#define TCG_TARGET_HAS_sub2_i32 1 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_add2_i64 1 #define TCG_TARGET_HAS_sub2_i64 1 #endif /* TCG_TARGET_REG_BITS == 64 */ From 52c49c79b820ceeff10c7c414f747f9bbb39f6c9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 21:16:40 -0800 Subject: [PATCH 0468/2760] tcg/mips: Drop support for add2/sub2 We now produce exactly the same code via generic expansion. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/mips/tcg-target-con-set.h | 1 - tcg/mips/tcg-target-con-str.h | 1 - tcg/mips/tcg-target-has.h | 7 ++-- tcg/mips/tcg-target.c.inc | 67 +---------------------------------- 4 files changed, 3 insertions(+), 73 deletions(-) diff --git a/tcg/mips/tcg-target-con-set.h b/tcg/mips/tcg-target-con-set.h index 4e09c9a400..5304691dc1 100644 --- a/tcg/mips/tcg-target-con-set.h +++ b/tcg/mips/tcg-target-con-set.h @@ -28,4 +28,3 @@ C_O1_I4(r, r, rz, rz, rz) C_O1_I4(r, r, r, rz, rz) C_O2_I1(r, r, r) C_O2_I2(r, r, r, r) -C_O2_I4(r, r, rz, rz, rN, rN) diff --git a/tcg/mips/tcg-target-con-str.h b/tcg/mips/tcg-target-con-str.h index dfe2b156df..db2b225e4a 100644 --- a/tcg/mips/tcg-target-con-str.h +++ b/tcg/mips/tcg-target-con-str.h @@ -17,5 +17,4 @@ REGS('r', ALL_GENERAL_REGS) CONST('I', TCG_CT_CONST_U16) CONST('J', TCG_CT_CONST_S16) CONST('K', TCG_CT_CONST_P2M1) -CONST('N', TCG_CT_CONST_N16) CONST('W', TCG_CT_CONST_WSZ) diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 9f6fa194b9..9d86906bf3 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,18 +39,15 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ - -#if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 + +#if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_add2_i64 0 #define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 -#else -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 #endif /* optional instructions detected at runtime */ diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 7fae1c51e9..e69781b871 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -187,8 +187,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, #define TCG_CT_CONST_U16 0x100 /* Unsigned 16-bit: 0 - 0xffff. */ #define TCG_CT_CONST_S16 0x200 /* Signed 16-bit: -32768 - 32767 */ #define TCG_CT_CONST_P2M1 0x400 /* Power of 2 minus 1. */ -#define TCG_CT_CONST_N16 0x800 /* "Negatable" 16-bit: -32767 - 32767 */ -#define TCG_CT_CONST_WSZ 0x1000 /* word size */ +#define TCG_CT_CONST_WSZ 0x800 /* word size */ #define ALL_GENERAL_REGS 0xffffffffu @@ -207,8 +206,6 @@ static bool tcg_target_const_match(int64_t val, int ct, return 1; } else if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) { return 1; - } else if ((ct & TCG_CT_CONST_N16) && val >= -32767 && val <= 32767) { - return 1; } else if ((ct & TCG_CT_CONST_P2M1) && use_mips32r2_instructions && is_p2m1(val)) { return 1; @@ -765,55 +762,6 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, return false; } -static void tcg_out_addsub2(TCGContext *s, TCGReg rl, TCGReg rh, TCGReg al, - TCGReg ah, TCGArg bl, TCGArg bh, bool cbl, - bool cbh, bool is_sub) -{ - TCGReg th = TCG_TMP1; - - /* If we have a negative constant such that negating it would - make the high part zero, we can (usually) eliminate one insn. */ - if (cbl && cbh && bh == -1 && bl != 0) { - bl = -bl; - bh = 0; - is_sub = !is_sub; - } - - /* By operating on the high part first, we get to use the final - carry operation to move back from the temporary. */ - if (!cbh) { - tcg_out_opc_reg(s, (is_sub ? OPC_SUBU : OPC_ADDU), th, ah, bh); - } else if (bh != 0 || ah == rl) { - tcg_out_opc_imm(s, OPC_ADDIU, th, ah, (is_sub ? -bh : bh)); - } else { - th = ah; - } - - /* Note that tcg optimization should eliminate the bl == 0 case. */ - if (is_sub) { - if (cbl) { - tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, al, bl); - tcg_out_opc_imm(s, OPC_ADDIU, rl, al, -bl); - } else { - tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, al, bl); - tcg_out_opc_reg(s, OPC_SUBU, rl, al, bl); - } - tcg_out_opc_reg(s, OPC_SUBU, rh, th, TCG_TMP0); - } else { - if (cbl) { - tcg_out_opc_imm(s, OPC_ADDIU, rl, al, bl); - tcg_out_opc_imm(s, OPC_SLTIU, TCG_TMP0, rl, bl); - } else if (rl == al && rl == bl) { - tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, al, TCG_TARGET_REG_BITS - 1); - tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl); - } else { - tcg_out_opc_reg(s, OPC_ADDU, rl, al, bl); - tcg_out_opc_reg(s, OPC_SLTU, TCG_TMP0, rl, (rl == bl ? al : bl)); - } - tcg_out_opc_reg(s, OPC_ADDU, rh, th, TCG_TMP0); - } -} - #define SETCOND_INV TCG_TARGET_NB_REGS #define SETCOND_NEZ (SETCOND_INV << 1) #define SETCOND_FLAGS (SETCOND_INV | SETCOND_NEZ) @@ -2370,15 +2318,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_add2_i32: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], false); - break; - case INDEX_op_sub2_i32: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], true); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -2420,10 +2359,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add2_i32: - case INDEX_op_sub2_i32: - return C_O2_I4(r, r, rz, rz, rN, rN); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_st_i32: From 0e08be0f5482af78f7ed703f665287964d1650f5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 21:24:25 -0800 Subject: [PATCH 0469/2760] tcg/riscv: Drop support for add2/sub2 We now produce exactly the same code via generic expansion. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/riscv/tcg-target-con-set.h | 1 - tcg/riscv/tcg-target-has.h | 6 +-- tcg/riscv/tcg-target.c.inc | 86 +--------------------------------- 3 files changed, 3 insertions(+), 90 deletions(-) diff --git a/tcg/riscv/tcg-target-con-set.h b/tcg/riscv/tcg-target-con-set.h index 5ff2c2db60..0fc26d3f98 100644 --- a/tcg/riscv/tcg-target-con-set.h +++ b/tcg/riscv/tcg-target-con-set.h @@ -18,7 +18,6 @@ C_O1_I2(r, r, ri) C_O1_I2(r, r, rI) C_N1_I2(r, r, rM) C_O1_I4(r, r, rI, rM, rM) -C_O2_I4(r, r, rz, rz, rM, rM) C_O0_I2(v, r) C_O1_I1(v, r) C_O1_I1(v, v) diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index b2814f8ef9..c95dc1921e 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -10,13 +10,11 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index d74ac7587a..dce46dcba6 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -401,7 +401,7 @@ static bool tcg_target_const_match(int64_t val, int ct, } /* * Sign extended from 12 bits, +/- matching: [-0x7ff, 0x7ff]. - * Used by addsub2 and movcond, which may need the negative value, + * Used by movcond, which may need the negative value, * and requires the modified constant to be representable. */ if ((ct & TCG_CT_CONST_M12) && val >= -0x7ff && val <= 0x7ff) { @@ -1073,67 +1073,6 @@ static bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, return false; } -static void tcg_out_addsub2(TCGContext *s, - TCGReg rl, TCGReg rh, - TCGReg al, TCGReg ah, - TCGArg bl, TCGArg bh, - bool cbl, bool cbh, bool is_sub, bool is32bit) -{ - const RISCVInsn opc_add = is32bit ? OPC_ADDW : OPC_ADD; - const RISCVInsn opc_addi = is32bit ? OPC_ADDIW : OPC_ADDI; - const RISCVInsn opc_sub = is32bit ? OPC_SUBW : OPC_SUB; - TCGReg th = TCG_REG_TMP1; - - /* If we have a negative constant such that negating it would - make the high part zero, we can (usually) eliminate one insn. */ - if (cbl && cbh && bh == -1 && bl != 0) { - bl = -bl; - bh = 0; - is_sub = !is_sub; - } - - /* By operating on the high part first, we get to use the final - carry operation to move back from the temporary. */ - if (!cbh) { - tcg_out_opc_reg(s, (is_sub ? opc_sub : opc_add), th, ah, bh); - } else if (bh != 0 || ah == rl) { - tcg_out_opc_imm(s, opc_addi, th, ah, (is_sub ? -bh : bh)); - } else { - th = ah; - } - - /* Note that tcg optimization should eliminate the bl == 0 case. */ - if (is_sub) { - if (cbl) { - tcg_out_opc_imm(s, OPC_SLTIU, TCG_REG_TMP0, al, bl); - tcg_out_opc_imm(s, opc_addi, rl, al, -bl); - } else { - tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_TMP0, al, bl); - tcg_out_opc_reg(s, opc_sub, rl, al, bl); - } - tcg_out_opc_reg(s, opc_sub, rh, th, TCG_REG_TMP0); - } else { - if (cbl) { - tcg_out_opc_imm(s, opc_addi, rl, al, bl); - tcg_out_opc_imm(s, OPC_SLTIU, TCG_REG_TMP0, rl, bl); - } else if (al == bl) { - /* - * If the input regs overlap, this is a simple doubling - * and carry-out is the input msb. This special case is - * required when the output reg overlaps the input, - * but we might as well use it always. - */ - tcg_out_opc_imm(s, OPC_SLTI, TCG_REG_TMP0, al, 0); - tcg_out_opc_reg(s, opc_add, rl, al, al); - } else { - tcg_out_opc_reg(s, opc_add, rl, al, bl); - tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_TMP0, - rl, (rl == bl ? al : bl)); - } - tcg_out_opc_reg(s, opc_add, rh, th, TCG_REG_TMP0); - } -} - static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, TCGReg dst, TCGReg src) { @@ -2608,23 +2547,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, OPC_SD, a0, a1, a2); break; - case INDEX_op_add2_i32: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], false, true); - break; - case INDEX_op_add2_i64: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], false, false); - break; - case INDEX_op_sub2_i32: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], true, true); - break; - case INDEX_op_sub2_i64: - tcg_out_addsub2(s, a0, a1, a2, args[3], args[4], args[5], - const_args[4], const_args[5], true, false); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -2897,12 +2819,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - return C_O2_I4(r, r, rz, rz, rM, rM); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); From 7d10d8e076201e968d57f1c2f5ffd8c88ae1eec9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 13:04:15 -0800 Subject: [PATCH 0470/2760] tcg: Move i into each for loop in liveness_pass_1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use per-loop variables instead of one 'i' for the function. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index 037b5a4664..e2ca02eddf 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3924,10 +3924,9 @@ liveness_pass_1(TCGContext *s) int nb_temps = s->nb_temps; TCGOp *op, *op_prev; TCGRegSet *prefs; - int i; prefs = tcg_malloc(sizeof(TCGRegSet) * nb_temps); - for (i = 0; i < nb_temps; ++i) { + for (int i = 0; i < nb_temps; ++i) { s->temps[i].state_ptr = prefs + i; } @@ -3954,7 +3953,7 @@ liveness_pass_1(TCGContext *s) /* pure functions can be removed if their result is unused */ if (call_flags & TCG_CALL_NO_SIDE_EFFECTS) { - for (i = 0; i < nb_oargs; i++) { + for (int i = 0; i < nb_oargs; i++) { ts = arg_temp(op->args[i]); if (ts->state != TS_DEAD) { goto do_not_remove_call; @@ -3965,7 +3964,7 @@ liveness_pass_1(TCGContext *s) do_not_remove_call: /* Output args are dead. */ - for (i = 0; i < nb_oargs; i++) { + for (int i = 0; i < nb_oargs; i++) { ts = arg_temp(op->args[i]); if (ts->state & TS_DEAD) { arg_life |= DEAD_ARG << i; @@ -3988,7 +3987,7 @@ liveness_pass_1(TCGContext *s) } /* Record arguments that die in this helper. */ - for (i = nb_oargs; i < nb_iargs + nb_oargs; i++) { + for (int i = nb_oargs; i < nb_iargs + nb_oargs; i++) { ts = arg_temp(op->args[i]); if (ts->state & TS_DEAD) { arg_life |= DEAD_ARG << i; @@ -4008,7 +4007,7 @@ liveness_pass_1(TCGContext *s) * order so that if a temp is used more than once, the stack * reset to max happens before the register reset to 0. */ - for (i = nb_iargs - 1; i >= 0; i--) { + for (int i = nb_iargs - 1; i >= 0; i--) { const TCGCallArgumentLoc *loc = &info->in[i]; ts = arg_temp(op->args[nb_oargs + i]); @@ -4036,7 +4035,7 @@ liveness_pass_1(TCGContext *s) * If a temp is used once, this produces a single set bit; * if a temp is used multiple times, this produces a set. */ - for (i = 0; i < nb_iargs; i++) { + for (int i = 0; i < nb_iargs; i++) { const TCGCallArgumentLoc *loc = &info->in[i]; ts = arg_temp(op->args[nb_oargs + i]); @@ -4135,7 +4134,7 @@ liveness_pass_1(TCGContext *s) its outputs are dead. We assume that nb_oargs == 0 implies side effects */ if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { - for (i = 0; i < nb_oargs; i++) { + for (int i = 0; i < nb_oargs; i++) { if (arg_temp(op->args[i])->state != TS_DEAD) { goto do_not_remove; } @@ -4149,7 +4148,7 @@ liveness_pass_1(TCGContext *s) break; do_not_remove: - for (i = 0; i < nb_oargs; i++) { + for (int i = 0; i < nb_oargs; i++) { ts = arg_temp(op->args[i]); /* Remember the preference of the uses that followed. */ @@ -4183,7 +4182,7 @@ liveness_pass_1(TCGContext *s) } /* Record arguments that die in this opcode. */ - for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { + for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { ts = arg_temp(op->args[i]); if (ts->state & TS_DEAD) { arg_life |= DEAD_ARG << i; @@ -4191,7 +4190,7 @@ liveness_pass_1(TCGContext *s) } /* Input arguments are live for preceding opcodes. */ - for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { + for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { ts = arg_temp(op->args[i]); if (ts->state & TS_DEAD) { /* For operands that were dead, initially allow @@ -4215,7 +4214,7 @@ liveness_pass_1(TCGContext *s) default: args_ct = opcode_args_ct(op); - for (i = nb_oargs; i < nb_oargs + nb_iargs; i++) { + for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { const TCGArgConstraint *ct = &args_ct[i]; TCGRegSet set, *pset; From 3e3689df4e05eb76b64a9e45247d87f9dad03177 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 13:12:35 -0800 Subject: [PATCH 0471/2760] tcg: Sink def, nb_iargs, nb_oargs loads in liveness_pass_1 Sink the sets of the def, nb_iargs, nb_oargs variables to the default and do_not_remove labels. They're not really needed beforehand, and it avoids preceding code from having to keep them up-to-date. Note that def had *not* been kept up-to-date; thankfully only def->flags had been used and those bits were constant between opcode changes. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tcg/tcg.c b/tcg/tcg.c index e2ca02eddf..2849bba480 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -4071,8 +4071,6 @@ liveness_pass_1(TCGContext *s) case INDEX_op_sub2_i64: opc_new = INDEX_op_sub; do_addsub2: - nb_iargs = 4; - nb_oargs = 2; /* Test if the high part of the operation is dead, but not the low part. The result can be optimized to a simple add or sub. This happens often for x86_64 guest when the @@ -4087,8 +4085,6 @@ liveness_pass_1(TCGContext *s) op->args[1] = op->args[2]; op->args[2] = op->args[4]; /* Fall through and mark the single-word operation live. */ - nb_iargs = 2; - nb_oargs = 1; } goto do_not_remove; @@ -4100,8 +4096,6 @@ liveness_pass_1(TCGContext *s) opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh; do_mul2: - nb_iargs = 2; - nb_oargs = 2; if (arg_temp(op->args[1])->state == TS_DEAD) { if (arg_temp(op->args[0])->state == TS_DEAD) { /* Both parts of the operation are dead. */ @@ -4122,19 +4116,15 @@ liveness_pass_1(TCGContext *s) goto do_not_remove; } /* Mark the single-word operation live. */ - nb_oargs = 1; goto do_not_remove; default: - /* XXX: optimize by hardcoding common cases (e.g. triadic ops) */ - nb_iargs = def->nb_iargs; - nb_oargs = def->nb_oargs; - /* Test if the operation can be removed because all its outputs are dead. We assume that nb_oargs == 0 implies side effects */ - if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && nb_oargs != 0) { - for (int i = 0; i < nb_oargs; i++) { + def = &tcg_op_defs[opc]; + if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && def->nb_oargs != 0) { + for (int i = def->nb_oargs - 1; i >= 0; i--) { if (arg_temp(op->args[i])->state != TS_DEAD) { goto do_not_remove; } @@ -4148,6 +4138,10 @@ liveness_pass_1(TCGContext *s) break; do_not_remove: + def = &tcg_op_defs[opc]; + nb_iargs = def->nb_iargs; + nb_oargs = def->nb_oargs; + for (int i = 0; i < nb_oargs; i++) { ts = arg_temp(op->args[i]); From 76f42780292c16a0d2f36cbbfbaf57495cd4d5e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 13:58:39 -0800 Subject: [PATCH 0472/2760] tcg: Add add/sub with carry opcodes and infrastructure Liveness needs to track carry-live state in order to determine if the (hidden) output of the opcode is used. Code generation needs to track carry-live state in order to avoid clobbering cpu flags when loading constants. So far, output routines and backends are unchanged. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 61 +++++++++++++++++ include/tcg/tcg-opc.h | 10 +++ include/tcg/tcg.h | 13 +++- tcg/optimize.c | 11 +++ tcg/tcg.c | 150 ++++++++++++++++++++++++++++++++++++++--- 5 files changed, 235 insertions(+), 10 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 9392d88069..93bcc70639 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -593,6 +593,67 @@ Multiword arithmetic support .. list-table:: + * - addco *t0*, *t1*, *t2* + + - | Compute *t0* = *t1* + *t2* and in addition output to the + carry bit provided by the host architecture. + + * - addci *t0, *t1*, *t2* + + - | Compute *t0* = *t1* + *t2* + *C*, where *C* is the + input carry bit provided by the host architecture. + The output carry bit need not be computed. + + * - addcio *t0, *t1*, *t2* + + - | Compute *t0* = *t1* + *t2* + *C*, where *C* is the + input carry bit provided by the host architecture, + and also compute the output carry bit. + + * - addc1o *t0, *t1*, *t2* + + - | Compute *t0* = *t1* + *t2* + 1, and in addition output to the + carry bit provided by the host architecture. This is akin to + *addcio* with a fixed carry-in value of 1. + | This is intended to be used by the optimization pass, + intermediate to complete folding of the addition chain. + In some cases complete folding is not possible and this + opcode will remain until output. If this happens, the + code generator will use ``tcg_out_set_carry`` and then + the output routine for *addcio*. + + * - subbo *t0*, *t1*, *t2* + + - | Compute *t0* = *t1* - *t2* and in addition output to the + borrow bit provided by the host architecture. + | Depending on the host architecture, the carry bit may or may not be + identical to the borrow bit. Thus the addc\* and subb\* + opcodes must not be mixed. + + * - subbi *t0, *t1*, *t2* + + - | Compute *t0* = *t1* - *t2* - *B*, where *B* is the + input borrow bit provided by the host architecture. + The output borrow bit need not be computed. + + * - subbio *t0, *t1*, *t2* + + - | Compute *t0* = *t1* - *t2* - *B*, where *B* is the + input borrow bit provided by the host architecture, + and also compute the output borrow bit. + + * - subb1o *t0, *t1*, *t2* + + - | Compute *t0* = *t1* - *t2* - 1, and in addition output to the + borrow bit provided by the host architecture. This is akin to + *subbio* with a fixed borrow-in value of 1. + | This is intended to be used by the optimization pass, + intermediate to complete folding of the subtraction chain. + In some cases complete folding is not possible and this + opcode will remain until output. If this happens, the + code generator will use ``tcg_out_set_borrow`` and then + the output routine for *subbio*. + * - add2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* sub2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 1f995c54be..9cc20cd62c 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -82,6 +82,16 @@ DEF(shr, 1, 2, 0, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) +DEF(addco, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) +DEF(addc1o, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) +DEF(addci, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN) +DEF(addcio, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN | TCG_OPF_CARRY_OUT) + +DEF(subbo, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) +DEF(subb1o, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) +DEF(subbi, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN) +DEF(subbio, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN | TCG_OPF_CARRY_OUT) + /* load/store */ DEF(ld8u_i32, 1, 1, 1, 0) DEF(ld8s_i32, 1, 1, 1, 0) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index c6b50b5226..aa300a2f8b 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -418,6 +418,11 @@ struct TCGContext { MemOp riscv_cur_vsew; TCGType riscv_cur_type; #endif + /* + * During the tcg_reg_alloc_op loop, we are within a sequence of + * carry-using opcodes like addco+addci. + */ + bool carry_live; GHashTable *const_table[TCG_TYPE_COUNT]; TCGTempSet free_temps[TCG_TYPE_COUNT]; @@ -749,13 +754,17 @@ enum { /* Instruction operands are vectors. */ TCG_OPF_VECTOR = 0x40, /* Instruction is a conditional branch. */ - TCG_OPF_COND_BRANCH = 0x80 + TCG_OPF_COND_BRANCH = 0x80, + /* Instruction produces carry out. */ + TCG_OPF_CARRY_OUT = 0x100, + /* Instruction consumes carry in. */ + TCG_OPF_CARRY_IN = 0x200, }; typedef struct TCGOpDef { const char *name; uint8_t nb_oargs, nb_iargs, nb_cargs, nb_args; - uint8_t flags; + uint16_t flags; } TCGOpDef; extern const TCGOpDef tcg_op_defs[]; diff --git a/tcg/optimize.c b/tcg/optimize.c index a728a4b2fa..8b00833f97 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1226,6 +1226,12 @@ static bool fold_add_vec(OptContext *ctx, TCGOp *op) return finish_folding(ctx, op); } +static bool fold_add_carry(OptContext *ctx, TCGOp *op) +{ + fold_commutative(ctx, op); + return finish_folding(ctx, op); +} + static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) { bool a_const = arg_is_const(op->args[2]) && arg_is_const(op->args[3]); @@ -2829,6 +2835,11 @@ void tcg_optimize(TCGContext *s) case INDEX_op_add_vec: done = fold_add_vec(&ctx, op); break; + case INDEX_op_addci: + case INDEX_op_addco: + case INDEX_op_addcio: + done = fold_add_carry(&ctx, op); + break; CASE_OP_32_64(add2): done = fold_add2(&ctx, op); break; diff --git a/tcg/tcg.c b/tcg/tcg.c index 2849bba480..f04ad0afcf 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -3914,6 +3914,17 @@ liveness_pass_0(TCGContext *s) } } +static void assert_carry_dead(TCGContext *s) +{ + /* + * Carry operations can be separated by a few insns like mov, + * load or store, but they should always be "close", and + * carry-out operations should always be paired with carry-in. + * At various boundaries, carry must have been consumed. + */ + tcg_debug_assert(!s->carry_live); +} + /* Liveness analysis : update the opc_arg_life array to tell if a given input arguments is dead. Instructions updating dead temporaries are removed. */ @@ -3933,17 +3944,19 @@ liveness_pass_1(TCGContext *s) /* ??? Should be redundant with the exit_tb that ends the TB. */ la_func_end(s, nb_globals, nb_temps); + s->carry_live = false; QTAILQ_FOREACH_REVERSE_SAFE(op, &s->ops, link, op_prev) { int nb_iargs, nb_oargs; TCGOpcode opc_new, opc_new2; TCGLifeData arg_life = 0; TCGTemp *ts; TCGOpcode opc = op->opc; - const TCGOpDef *def = &tcg_op_defs[opc]; + const TCGOpDef *def; const TCGArgConstraint *args_ct; switch (opc) { case INDEX_op_call: + assert_carry_dead(s); { const TCGHelperInfo *info = tcg_call_info(op); int call_flags = tcg_call_flags(op); @@ -4055,6 +4068,7 @@ liveness_pass_1(TCGContext *s) } break; case INDEX_op_insn_start: + assert_carry_dead(s); break; case INDEX_op_discard: /* mark the temporary as dead */ @@ -4071,6 +4085,7 @@ liveness_pass_1(TCGContext *s) case INDEX_op_sub2_i64: opc_new = INDEX_op_sub; do_addsub2: + assert_carry_dead(s); /* Test if the high part of the operation is dead, but not the low part. The result can be optimized to a simple add or sub. This happens often for x86_64 guest when the @@ -4096,6 +4111,7 @@ liveness_pass_1(TCGContext *s) opc_new = INDEX_op_mul; opc_new2 = INDEX_op_muluh; do_mul2: + assert_carry_dead(s); if (arg_temp(op->args[1])->state == TS_DEAD) { if (arg_temp(op->args[0])->state == TS_DEAD) { /* Both parts of the operation are dead. */ @@ -4118,10 +4134,89 @@ liveness_pass_1(TCGContext *s) /* Mark the single-word operation live. */ goto do_not_remove; + case INDEX_op_addco: + if (s->carry_live) { + goto do_not_remove; + } + op->opc = opc = INDEX_op_add; + goto do_default; + + case INDEX_op_addcio: + if (s->carry_live) { + goto do_not_remove; + } + op->opc = opc = INDEX_op_addci; + goto do_default; + + case INDEX_op_subbo: + if (s->carry_live) { + goto do_not_remove; + } + /* Lower to sub, but this may also require canonicalization. */ + op->opc = opc = INDEX_op_sub; + ts = arg_temp(op->args[2]); + if (ts->kind == TEMP_CONST) { + ts = tcg_constant_internal(ts->type, -ts->val); + if (ts->state_ptr == NULL) { + tcg_debug_assert(temp_idx(ts) == nb_temps); + nb_temps++; + ts->state_ptr = tcg_malloc(sizeof(TCGRegSet)); + ts->state = TS_DEAD; + la_reset_pref(ts); + } + op->args[2] = temp_arg(ts); + op->opc = opc = INDEX_op_add; + } + goto do_default; + + case INDEX_op_subbio: + if (s->carry_live) { + goto do_not_remove; + } + op->opc = opc = INDEX_op_subbi; + goto do_default; + + case INDEX_op_addc1o: + if (s->carry_live) { + goto do_not_remove; + } + /* Lower to add, add +1. */ + op_prev = tcg_op_insert_before(s, op, INDEX_op_add, + TCGOP_TYPE(op), 3); + op_prev->args[0] = op->args[0]; + op_prev->args[1] = op->args[1]; + op_prev->args[2] = op->args[2]; + op->opc = opc = INDEX_op_add; + op->args[1] = op->args[0]; + ts = arg_temp(op->args[0]); + ts = tcg_constant_internal(ts->type, 1); + op->args[2] = temp_arg(ts); + goto do_default; + + case INDEX_op_subb1o: + if (s->carry_live) { + goto do_not_remove; + } + /* Lower to sub, add -1. */ + op_prev = tcg_op_insert_before(s, op, INDEX_op_sub, + TCGOP_TYPE(op), 3); + op_prev->args[0] = op->args[0]; + op_prev->args[1] = op->args[1]; + op_prev->args[2] = op->args[2]; + op->opc = opc = INDEX_op_add; + op->args[1] = op->args[0]; + ts = arg_temp(op->args[0]); + ts = tcg_constant_internal(ts->type, -1); + op->args[2] = temp_arg(ts); + goto do_default; + default: - /* Test if the operation can be removed because all - its outputs are dead. We assume that nb_oargs == 0 - implies side effects */ + do_default: + /* + * Test if the operation can be removed because all + * its outputs are dead. We assume that nb_oargs == 0 + * implies side effects. + */ def = &tcg_op_defs[opc]; if (!(def->flags & TCG_OPF_SIDE_EFFECTS) && def->nb_oargs != 0) { for (int i = def->nb_oargs - 1; i >= 0; i--) { @@ -4163,12 +4258,16 @@ liveness_pass_1(TCGContext *s) /* If end of basic block, update. */ if (def->flags & TCG_OPF_BB_EXIT) { + assert_carry_dead(s); la_func_end(s, nb_globals, nb_temps); } else if (def->flags & TCG_OPF_COND_BRANCH) { + assert_carry_dead(s); la_bb_sync(s, nb_globals, nb_temps); } else if (def->flags & TCG_OPF_BB_END) { + assert_carry_dead(s); la_bb_end(s, nb_globals, nb_temps); } else if (def->flags & TCG_OPF_SIDE_EFFECTS) { + assert_carry_dead(s); la_global_sync(s, nb_globals); if (def->flags & TCG_OPF_CALL_CLOBBER) { la_cross_call(s, nb_temps); @@ -4182,6 +4281,9 @@ liveness_pass_1(TCGContext *s) arg_life |= DEAD_ARG << i; } } + if (def->flags & TCG_OPF_CARRY_OUT) { + s->carry_live = false; + } /* Input arguments are live for preceding opcodes. */ for (int i = nb_oargs; i < nb_oargs + nb_iargs; i++) { @@ -4193,6 +4295,9 @@ liveness_pass_1(TCGContext *s) ts->state &= ~TS_DEAD; } } + if (def->flags & TCG_OPF_CARRY_IN) { + s->carry_live = true; + } /* Incorporate constraints for this operand. */ switch (opc) { @@ -4232,6 +4337,7 @@ liveness_pass_1(TCGContext *s) } op->life = arg_life; } + assert_carry_dead(s); } /* Liveness analysis: Convert indirect regs to direct temporaries. */ @@ -4820,9 +4926,8 @@ static void sync_globals(TCGContext *s, TCGRegSet allocated_regs) all globals are stored at their canonical location. */ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) { - int i; - - for (i = s->nb_globals; i < s->nb_temps; i++) { + assert_carry_dead(s); + for (int i = s->nb_globals; i < s->nb_temps; i++) { TCGTemp *ts = &s->temps[i]; switch (ts->kind) { @@ -4853,6 +4958,7 @@ static void tcg_reg_alloc_bb_end(TCGContext *s, TCGRegSet allocated_regs) */ static void tcg_reg_alloc_cbranch(TCGContext *s, TCGRegSet allocated_regs) { + assert_carry_dead(s); sync_globals(s, allocated_regs); for (int i = s->nb_globals; i < s->nb_temps; i++) { @@ -5124,6 +5230,10 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) int const_args[TCG_MAX_OP_ARGS]; TCGCond op_cond; + if (def->flags & TCG_OPF_CARRY_IN) { + tcg_debug_assert(s->carry_live); + } + nb_oargs = def->nb_oargs; nb_iargs = def->nb_iargs; @@ -5380,6 +5490,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) tcg_reg_alloc_bb_end(s, i_allocated_regs); } else { if (def->flags & TCG_OPF_CALL_CLOBBER) { + assert_carry_dead(s); /* XXX: permit generic clobber register list ? */ for (i = 0; i < TCG_TARGET_NB_REGS; i++) { if (tcg_regset_test_reg(tcg_target_call_clobber_regs, i)) { @@ -5497,7 +5608,8 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_sub: { - const TCGOutOpSubtract *out = &outop_sub; + const TCGOutOpSubtract *out = + container_of(all_outop[op->opc], TCGOutOpSubtract, base); /* * Constants should never appear in the second source operand. @@ -5512,6 +5624,16 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_addco: + case INDEX_op_subbo: + case INDEX_op_addci: + case INDEX_op_subbi: + case INDEX_op_addcio: + case INDEX_op_subbio: + case INDEX_op_addc1o: + case INDEX_op_subb1o: + g_assert_not_reached(); + case INDEX_op_bswap64: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: @@ -5700,6 +5822,13 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; } + if (def->flags & TCG_OPF_CARRY_IN) { + s->carry_live = false; + } + if (def->flags & TCG_OPF_CARRY_OUT) { + s->carry_live = true; + } + /* move the outputs in the correct register if needed */ for(i = 0; i < nb_oargs; i++) { ts = arg_temp(op->args[i]); @@ -6702,6 +6831,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) tcg_out_tb_start(s); num_insns = -1; + s->carry_live = false; QTAILQ_FOREACH(op, &s->ops, link) { TCGOpcode opc = op->opc; @@ -6730,6 +6860,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) tcg_reg_alloc_dup(s, op); break; case INDEX_op_insn_start: + assert_carry_dead(s); if (num_insns >= 0) { size_t off = tcg_current_code_size(s); s->gen_insn_end_off[num_insns] = off; @@ -6750,6 +6881,7 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) tcg_out_label(s, arg_label(op->args[0])); break; case INDEX_op_call: + assert_carry_dead(s); tcg_reg_alloc_call(s, op); break; case INDEX_op_exit_tb: @@ -6786,6 +6918,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) return -2; } } + assert_carry_dead(s); + tcg_debug_assert(num_insns + 1 == s->gen_tb->icount); s->gen_insn_end_off[num_insns] = tcg_current_code_size(s); From ee60315210058c9b3d0869b2046eeb254ba33f3a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 23:27:53 -0800 Subject: [PATCH 0473/2760] tcg: Add TCGOutOp structures for add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/arm/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/i386/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/loongarch64/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/mips/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/ppc/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/riscv/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/s390x/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/sparc64/tcg-target.c.inc | 34 ++++++++++++++++++ tcg/tcg.c | 61 +++++++++++++++++++++++++++----- tcg/tci/tcg-target.c.inc | 34 ++++++++++++++++++ 11 files changed, 393 insertions(+), 8 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index bece494c55..87f8c98ed7 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2078,6 +2078,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2421,6 +2438,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index f366424af5..aa0397520d 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1826,6 +1826,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2135,6 +2152,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rir = tgen_subfi, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 2b2ad9ca95..04e31cae12 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2629,6 +2629,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3054,6 +3071,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index eb2143703d..4f640764ef 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1338,6 +1338,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tcg_out_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1727,6 +1744,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index e69781b871..0c268cef42 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1593,6 +1593,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2044,6 +2061,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index a964239aab..5b04655f3b 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2863,6 +2863,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -3267,6 +3284,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rir = tgen_subfi, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index dce46dcba6..707ebb8f6d 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1947,6 +1947,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2333,6 +2350,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index ff06834e6e..a30afb455e 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2248,6 +2248,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -2766,6 +2783,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 4c7d916302..12f0dbd23d 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1381,6 +1381,23 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -1717,6 +1734,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { diff --git a/tcg/tcg.c b/tcg/tcg.c index f04ad0afcf..3b9f519ef6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -133,6 +133,8 @@ static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); static void tcg_out_goto_tb(TCGContext *s, int which); +static void tcg_out_set_carry(TCGContext *s); +static void tcg_out_set_borrow(TCGContext *s); static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]); @@ -978,6 +980,18 @@ typedef struct TCGOutOp { TCGConstraintSetIndex (*dynamic_constraint)(TCGType type, unsigned flags); } TCGOutOp; +typedef struct TCGOutOpAddSubCarry { + TCGOutOp base; + void (*out_rrr)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2); + void (*out_rri)(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2); + void (*out_rir)(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2); + void (*out_rii)(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2); +} TCGOutOpAddSubCarry; + typedef struct TCGOutOpBinary { TCGOutOp base; void (*out_rrr)(TCGContext *s, TCGType type, @@ -1131,6 +1145,11 @@ static const TCGOutOpUnary outop_extrl_i64_i32 = { /* Register allocation descriptions for every TCGOpcode. */ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_add, TCGOutOpBinary, outop_add), + OUTOP(INDEX_op_addci, TCGOutOpAddSubCarry, outop_addci), + OUTOP(INDEX_op_addcio, TCGOutOpBinary, outop_addcio), + OUTOP(INDEX_op_addco, TCGOutOpBinary, outop_addco), + /* addc1o is implemented with set_carry + addcio */ + OUTOP(INDEX_op_addc1o, TCGOutOpBinary, outop_addcio), OUTOP(INDEX_op_and, TCGOutOpBinary, outop_and), OUTOP(INDEX_op_andc, TCGOutOpBinary, outop_andc), OUTOP(INDEX_op_brcond, TCGOutOpBrcond, outop_brcond), @@ -1170,6 +1189,11 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), + OUTOP(INDEX_op_subbi, TCGOutOpAddSubCarry, outop_subbi), + OUTOP(INDEX_op_subbio, TCGOutOpAddSubCarry, outop_subbio), + OUTOP(INDEX_op_subbo, TCGOutOpAddSubCarry, outop_subbo), + /* subb1o is implemented with set_borrow + subbio */ + OUTOP(INDEX_op_subb1o, TCGOutOpAddSubCarry, outop_subbio), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), #if TCG_TARGET_REG_BITS == 32 @@ -5569,7 +5593,12 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) /* emit instruction */ TCGType type = TCGOP_TYPE(op); switch (op->opc) { + case INDEX_op_addc1o: + tcg_out_set_carry(s); + /* fall through */ case INDEX_op_add: + case INDEX_op_addcio: + case INDEX_op_addco: case INDEX_op_and: case INDEX_op_andc: case INDEX_op_clz: @@ -5608,8 +5637,7 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) case INDEX_op_sub: { - const TCGOutOpSubtract *out = - container_of(all_outop[op->opc], TCGOutOpSubtract, base); + const TCGOutOpSubtract *out = &outop_sub; /* * Constants should never appear in the second source operand. @@ -5624,15 +5652,32 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_addco: - case INDEX_op_subbo: + case INDEX_op_subb1o: + tcg_out_set_borrow(s); + /* fall through */ case INDEX_op_addci: case INDEX_op_subbi: - case INDEX_op_addcio: case INDEX_op_subbio: - case INDEX_op_addc1o: - case INDEX_op_subb1o: - g_assert_not_reached(); + case INDEX_op_subbo: + { + const TCGOutOpAddSubCarry *out = + container_of(all_outop[op->opc], TCGOutOpAddSubCarry, base); + + if (const_args[2]) { + if (const_args[1]) { + out->out_rii(s, type, new_args[0], + new_args[1], new_args[2]); + } else { + out->out_rri(s, type, new_args[0], + new_args[1], new_args[2]); + } + } else if (const_args[1]) { + out->out_rir(s, type, new_args[0], new_args[1], new_args[2]); + } else { + out->out_rrr(s, type, new_args[0], new_args[1], new_args[2]); + } + } + break; case INDEX_op_bswap64: case INDEX_op_ext_i32_i64: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 9a5ca9c778..bba96d7a19 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -573,6 +573,23 @@ static const TCGOutOpBinary outop_add = { .out_rrr = tgen_add, }; +static const TCGOutOpBinary outop_addco = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_addci = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_carry(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_and(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { @@ -893,6 +910,23 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static const TCGOutOpAddSubCarry outop_subbo = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbi = { + .base.static_constraint = C_NotImplemented, +}; + +static const TCGOutOpAddSubCarry outop_subbio = { + .base.static_constraint = C_NotImplemented, +}; + +static void tcg_out_set_borrow(TCGContext *s) +{ + g_assert_not_reached(); +} + static void tgen_xor(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, TCGReg a2) { From aeb3514bd06b278dd026c90e8f71ca5b32762ab9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 18:28:15 -0800 Subject: [PATCH 0474/2760] tcg/optimize: Handle add/sub with carry opcodes Propagate known carry when possible, and simplify the opcodes to not require carry-in when known. The result will be cleaned up further by the subsequent liveness analysis pass. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/optimize.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 3 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index 8b00833f97..cfcd0ab7f9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -66,6 +66,7 @@ typedef struct OptContext { /* In flight values from optimization. */ TCGType type; + int carry_state; /* -1 = non-constant, {0,1} = constant carry-in */ } OptContext; static inline TempOptInfo *ts_info(TCGTemp *ts) @@ -1203,8 +1204,10 @@ static bool fold_xx_to_x(OptContext *ctx, TCGOp *op) * 3) those that produce information about the result value. */ +static bool fold_addco(OptContext *ctx, TCGOp *op); static bool fold_or(OptContext *ctx, TCGOp *op); static bool fold_orc(OptContext *ctx, TCGOp *op); +static bool fold_subbo(OptContext *ctx, TCGOp *op); static bool fold_xor(OptContext *ctx, TCGOp *op); static bool fold_add(OptContext *ctx, TCGOp *op) @@ -1226,9 +1229,167 @@ static bool fold_add_vec(OptContext *ctx, TCGOp *op) return finish_folding(ctx, op); } -static bool fold_add_carry(OptContext *ctx, TCGOp *op) +static void squash_prev_carryout(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t2; + + op = QTAILQ_PREV(op, link); + switch (op->opc) { + case INDEX_op_addco: + op->opc = INDEX_op_add; + fold_add(ctx, op); + break; + case INDEX_op_addcio: + op->opc = INDEX_op_addci; + break; + case INDEX_op_addc1o: + op->opc = INDEX_op_add; + t2 = arg_info(op->args[2]); + if (ti_is_const(t2)) { + op->args[2] = arg_new_constant(ctx, ti_const_val(t2) + 1); + /* Perform other constant folding, if needed. */ + fold_add(ctx, op); + } else { + TCGArg ret = op->args[0]; + op = opt_insert_after(ctx, op, INDEX_op_add, 3); + op->args[0] = ret; + op->args[1] = ret; + op->args[2] = arg_new_constant(ctx, 1); + } + break; + default: + g_assert_not_reached(); + } +} + +static bool fold_addci(OptContext *ctx, TCGOp *op) { fold_commutative(ctx, op); + + if (ctx->carry_state < 0) { + return finish_folding(ctx, op); + } + + squash_prev_carryout(ctx, op); + op->opc = INDEX_op_add; + + if (ctx->carry_state > 0) { + TempOptInfo *t2 = arg_info(op->args[2]); + + /* + * Propagate the known carry-in into a constant, if possible. + * Otherwise emit a second add +1. + */ + if (ti_is_const(t2)) { + op->args[2] = arg_new_constant(ctx, ti_const_val(t2) + 1); + } else { + TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_add, 3); + + op2->args[0] = op->args[0]; + op2->args[1] = op->args[1]; + op2->args[2] = op->args[2]; + fold_add(ctx, op2); + + op->args[1] = op->args[0]; + op->args[2] = arg_new_constant(ctx, 1); + } + } + + ctx->carry_state = -1; + return fold_add(ctx, op); +} + +static bool fold_addcio(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t1, *t2; + int carry_out = -1; + uint64_t sum, max; + + fold_commutative(ctx, op); + t1 = arg_info(op->args[1]); + t2 = arg_info(op->args[2]); + + /* + * The z_mask value is >= the maximum value that can be represented + * with the known zero bits. So adding the z_mask values will not + * overflow if and only if the true values cannot overflow. + */ + if (!uadd64_overflow(t1->z_mask, t2->z_mask, &sum) && + !uadd64_overflow(sum, ctx->carry_state != 0, &sum)) { + carry_out = 0; + } + + if (ctx->carry_state < 0) { + ctx->carry_state = carry_out; + return finish_folding(ctx, op); + } + + squash_prev_carryout(ctx, op); + if (ctx->carry_state == 0) { + goto do_addco; + } + + /* Propagate the known carry-in into a constant, if possible. */ + max = ctx->type == TCG_TYPE_I32 ? UINT32_MAX : UINT64_MAX; + if (ti_is_const(t2)) { + uint64_t v = ti_const_val(t2) & max; + if (v < max) { + op->args[2] = arg_new_constant(ctx, v + 1); + goto do_addco; + } + /* max + known carry in produces known carry out. */ + carry_out = 1; + } + if (ti_is_const(t1)) { + uint64_t v = ti_const_val(t1) & max; + if (v < max) { + op->args[1] = arg_new_constant(ctx, v + 1); + goto do_addco; + } + carry_out = 1; + } + + /* Adjust the opcode to remember the known carry-in. */ + op->opc = INDEX_op_addc1o; + ctx->carry_state = carry_out; + return finish_folding(ctx, op); + + do_addco: + op->opc = INDEX_op_addco; + return fold_addco(ctx, op); +} + +static bool fold_addco(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t1, *t2; + int carry_out = -1; + uint64_t ign; + + fold_commutative(ctx, op); + t1 = arg_info(op->args[1]); + t2 = arg_info(op->args[2]); + + if (ti_is_const(t2)) { + uint64_t v2 = ti_const_val(t2); + + if (ti_is_const(t1)) { + uint64_t v1 = ti_const_val(t1); + /* Given sign-extension of z_mask for I32, we need not truncate. */ + carry_out = uadd64_overflow(v1, v2, &ign); + } else if (v2 == 0) { + carry_out = 0; + } + } else { + /* + * The z_mask value is >= the maximum value that can be represented + * with the known zero bits. So adding the z_mask values will not + * overflow if and only if the true values cannot overflow. + */ + if (!uadd64_overflow(t1->z_mask, t2->z_mask, &ign)) { + carry_out = 0; + } + } + ctx->carry_state = carry_out; return finish_folding(ctx, op); } @@ -2649,6 +2810,145 @@ static bool fold_sub2(OptContext *ctx, TCGOp *op) return fold_addsub2(ctx, op, false); } +static void squash_prev_borrowout(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t2; + + op = QTAILQ_PREV(op, link); + switch (op->opc) { + case INDEX_op_subbo: + op->opc = INDEX_op_sub; + fold_sub(ctx, op); + break; + case INDEX_op_subbio: + op->opc = INDEX_op_subbi; + break; + case INDEX_op_subb1o: + t2 = arg_info(op->args[2]); + if (ti_is_const(t2)) { + op->opc = INDEX_op_add; + op->args[2] = arg_new_constant(ctx, -(ti_const_val(t2) + 1)); + /* Perform other constant folding, if needed. */ + fold_add(ctx, op); + } else { + TCGArg ret = op->args[0]; + op->opc = INDEX_op_sub; + op = opt_insert_after(ctx, op, INDEX_op_add, 3); + op->args[0] = ret; + op->args[1] = ret; + op->args[2] = arg_new_constant(ctx, -1); + } + break; + default: + g_assert_not_reached(); + } +} + +static bool fold_subbi(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t2; + int borrow_in = ctx->carry_state; + + if (borrow_in < 0) { + return finish_folding(ctx, op); + } + ctx->carry_state = -1; + + squash_prev_borrowout(ctx, op); + if (borrow_in == 0) { + op->opc = INDEX_op_sub; + return fold_sub(ctx, op); + } + + /* + * Propagate the known carry-in into any constant, then negate to + * transform from sub to add. If there is no constant, emit a + * separate add -1. + */ + t2 = arg_info(op->args[2]); + if (ti_is_const(t2)) { + op->args[2] = arg_new_constant(ctx, -(ti_const_val(t2) + 1)); + } else { + TCGOp *op2 = opt_insert_before(ctx, op, INDEX_op_sub, 3); + + op2->args[0] = op->args[0]; + op2->args[1] = op->args[1]; + op2->args[2] = op->args[2]; + fold_sub(ctx, op2); + + op->args[1] = op->args[0]; + op->args[2] = arg_new_constant(ctx, -1); + } + op->opc = INDEX_op_add; + return fold_add(ctx, op); +} + +static bool fold_subbio(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t1, *t2; + int borrow_out = -1; + + if (ctx->carry_state < 0) { + return finish_folding(ctx, op); + } + + squash_prev_borrowout(ctx, op); + if (ctx->carry_state == 0) { + goto do_subbo; + } + + t1 = arg_info(op->args[1]); + t2 = arg_info(op->args[2]); + + /* Propagate the known borrow-in into a constant, if possible. */ + if (ti_is_const(t2)) { + uint64_t max = ctx->type == TCG_TYPE_I32 ? UINT32_MAX : UINT64_MAX; + uint64_t v = ti_const_val(t2) & max; + + if (v < max) { + op->args[2] = arg_new_constant(ctx, v + 1); + goto do_subbo; + } + /* subtracting max + 1 produces known borrow out. */ + borrow_out = 1; + } + if (ti_is_const(t1)) { + uint64_t v = ti_const_val(t1); + if (v != 0) { + op->args[2] = arg_new_constant(ctx, v - 1); + goto do_subbo; + } + } + + /* Adjust the opcode to remember the known carry-in. */ + op->opc = INDEX_op_subb1o; + ctx->carry_state = borrow_out; + return finish_folding(ctx, op); + + do_subbo: + op->opc = INDEX_op_subbo; + return fold_subbo(ctx, op); +} + +static bool fold_subbo(OptContext *ctx, TCGOp *op) +{ + TempOptInfo *t1 = arg_info(op->args[1]); + TempOptInfo *t2 = arg_info(op->args[2]); + int borrow_out = -1; + + if (ti_is_const(t2)) { + uint64_t v2 = ti_const_val(t2); + if (v2 == 0) { + borrow_out = 0; + } else if (ti_is_const(t1)) { + uint64_t v1 = ti_const_val(t1); + borrow_out = v1 < v2; + } + } + ctx->carry_state = borrow_out; + return finish_folding(ctx, op); +} + static bool fold_tcg_ld(OptContext *ctx, TCGOp *op) { uint64_t z_mask = -1, s_mask = 0; @@ -2836,9 +3136,13 @@ void tcg_optimize(TCGContext *s) done = fold_add_vec(&ctx, op); break; case INDEX_op_addci: - case INDEX_op_addco: + done = fold_addci(&ctx, op); + break; case INDEX_op_addcio: - done = fold_add_carry(&ctx, op); + done = fold_addcio(&ctx, op); + break; + case INDEX_op_addco: + done = fold_addco(&ctx, op); break; CASE_OP_32_64(add2): done = fold_add2(&ctx, op); @@ -3020,6 +3324,15 @@ void tcg_optimize(TCGContext *s) case INDEX_op_sub: done = fold_sub(&ctx, op); break; + case INDEX_op_subbi: + done = fold_subbi(&ctx, op); + break; + case INDEX_op_subbio: + done = fold_subbio(&ctx, op); + break; + case INDEX_op_subbo: + done = fold_subbo(&ctx, op); + break; case INDEX_op_sub_vec: done = fold_sub_vec(&ctx, op); break; From e2f5ee36afb3b5306c99f40044534ae7d2580114 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 23:08:24 -0800 Subject: [PATCH 0475/2760] tcg/optimize: With two const operands, prefer 0 in arg1 For most binary operands, two const operands fold. However, the add/sub carry opcodes have a third input. Prefer "reg, zero, const" since many risc hosts have a zero register that can fit a "reg, reg, const" insn format. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/optimize.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tcg/optimize.c b/tcg/optimize.c index cfcd0ab7f9..95ec3b426d 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -737,12 +737,18 @@ static int do_constant_folding_cond(TCGType type, TCGArg x, #define NO_DEST temp_arg(NULL) +static int pref_commutative(TempOptInfo *ti) +{ + /* Slight preference for non-zero constants second. */ + return !ti_is_const(ti) ? 0 : ti_const_val(ti) ? 3 : 2; +} + static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) { TCGArg a1 = *p1, a2 = *p2; int sum = 0; - sum += arg_is_const(a1); - sum -= arg_is_const(a2); + sum += pref_commutative(arg_info(a1)); + sum -= pref_commutative(arg_info(a2)); /* Prefer the constant in second argument, and then the form op a, a, b, which is better handled on non-RISC hosts. */ @@ -757,10 +763,10 @@ static bool swap_commutative(TCGArg dest, TCGArg *p1, TCGArg *p2) static bool swap_commutative2(TCGArg *p1, TCGArg *p2) { int sum = 0; - sum += arg_is_const(p1[0]); - sum += arg_is_const(p1[1]); - sum -= arg_is_const(p2[0]); - sum -= arg_is_const(p2[1]); + sum += pref_commutative(arg_info(p1[0])); + sum += pref_commutative(arg_info(p1[1])); + sum -= pref_commutative(arg_info(p2[0])); + sum -= pref_commutative(arg_info(p2[1])); if (sum > 0) { TCGArg t; t = p1[0], p1[0] = p2[0], p2[0] = t; From c4d2e3d736197bb2d82bd37de0de1819222d9768 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 13 Jan 2025 23:29:42 -0800 Subject: [PATCH 0476/2760] tcg: Use add carry opcodes to expand add2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 127338b994..f17ec658fb 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1102,7 +1102,13 @@ void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, TCGv_i32 c1, void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) { - if (TCG_TARGET_HAS_add2_i32) { + if (tcg_op_supported(INDEX_op_addci, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + tcg_gen_op3_i32(INDEX_op_addco, t0, al, bl); + tcg_gen_op3_i32(INDEX_op_addci, rh, ah, bh); + tcg_gen_mov_i32(rl, t0); + tcg_temp_free_i32(t0); + } else if (TCG_TARGET_HAS_add2_i32) { tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2822,7 +2828,26 @@ void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, TCGv_i64 c1, void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) { - if (TCG_TARGET_HAS_add2_i64) { + if (tcg_op_supported(INDEX_op_addci, TCG_TYPE_REG, 0)) { + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + + if (TCG_TARGET_REG_BITS == 32) { + tcg_gen_op3_i32(INDEX_op_addco, TCGV_LOW(t0), + TCGV_LOW(al), TCGV_LOW(bl)); + tcg_gen_op3_i32(INDEX_op_addcio, TCGV_HIGH(t0), + TCGV_HIGH(al), TCGV_HIGH(bl)); + tcg_gen_op3_i32(INDEX_op_addcio, TCGV_LOW(rh), + TCGV_LOW(ah), TCGV_LOW(bh)); + tcg_gen_op3_i32(INDEX_op_addci, TCGV_HIGH(rh), + TCGV_HIGH(ah), TCGV_HIGH(bh)); + } else { + tcg_gen_op3_i64(INDEX_op_addco, t0, al, bl); + tcg_gen_op3_i64(INDEX_op_addci, rh, ah, bh); + } + + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + } else if (TCG_TARGET_HAS_add2_i64) { tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); From 7a89deae635ceaf687973dd95e4714af27a3f9d2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 14 Jan 2025 18:58:05 -0800 Subject: [PATCH 0477/2760] tcg: Use sub carry opcodes to expand sub2 Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index f17ec658fb..447b0ebacd 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1126,7 +1126,13 @@ void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) { - if (TCG_TARGET_HAS_sub2_i32) { + if (tcg_op_supported(INDEX_op_subbi, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + tcg_gen_op3_i32(INDEX_op_subbo, t0, al, bl); + tcg_gen_op3_i32(INDEX_op_subbi, rh, ah, bh); + tcg_gen_mov_i32(rl, t0); + tcg_temp_free_i32(t0); + } else if (TCG_TARGET_HAS_sub2_i32) { tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); @@ -2865,7 +2871,26 @@ void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) { - if (TCG_TARGET_HAS_sub2_i64) { + if (tcg_op_supported(INDEX_op_subbi, TCG_TYPE_REG, 0)) { + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + + if (TCG_TARGET_REG_BITS == 32) { + tcg_gen_op3_i32(INDEX_op_subbo, TCGV_LOW(t0), + TCGV_LOW(al), TCGV_LOW(bl)); + tcg_gen_op3_i32(INDEX_op_subbio, TCGV_HIGH(t0), + TCGV_HIGH(al), TCGV_HIGH(bl)); + tcg_gen_op3_i32(INDEX_op_subbio, TCGV_LOW(rh), + TCGV_LOW(ah), TCGV_LOW(bh)); + tcg_gen_op3_i32(INDEX_op_subbi, TCGV_HIGH(rh), + TCGV_HIGH(ah), TCGV_HIGH(bh)); + } else { + tcg_gen_op3_i64(INDEX_op_subbo, t0, al, bl); + tcg_gen_op3_i64(INDEX_op_subbi, rh, ah, bh); + } + + tcg_gen_mov_i64(rl, t0); + tcg_temp_free_i64(t0); + } else if (TCG_TARGET_HAS_sub2_i64) { tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); From 1f049cc5fda405c46de94f9328f0e3f84c0c993b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Jan 2025 22:05:48 -0800 Subject: [PATCH 0478/2760] tcg/i386: Honor carry_live in tcg_out_movi Do not clobber flags if they're live. Required in order to perform register allocation on add/sub carry opcodes. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/i386/tcg-target.c.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 04e31cae12..8e0ccbc722 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1092,7 +1092,7 @@ static void tcg_out_movi_int(TCGContext *s, TCGType type, { tcg_target_long diff; - if (arg == 0) { + if (arg == 0 && !s->carry_live) { tgen_arithr(s, ARITH_XOR, ret, ret); return; } From e37e98b711975752d592e7b2daf11d320d0a8daf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Jan 2025 22:24:56 -0800 Subject: [PATCH 0479/2760] tcg/i386: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/i386/tcg-target-con-set.h | 1 - tcg/i386/tcg-target-has.h | 8 +-- tcg/i386/tcg-target.c.inc | 117 +++++++++++++++++++++------------- 3 files changed, 76 insertions(+), 50 deletions(-) diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h index 0ae9775944..85c93836bb 100644 --- a/tcg/i386/tcg-target-con-set.h +++ b/tcg/i386/tcg-target-con-set.h @@ -57,4 +57,3 @@ C_O2_I1(r, r, L) C_O2_I2(a, d, a, r) C_O2_I2(r, r, L, L) C_O2_I3(a, d, 0, 1, r) -C_N1_O1_I4(r, r, 0, 1, re, re) diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 0328102c2a..a984a6af2e 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,14 +26,14 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else #define TCG_TARGET_HAS_qemu_st8_i32 1 diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 8e0ccbc722..44f9afc0d6 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -424,6 +424,7 @@ static bool tcg_target_const_match(int64_t val, int ct, #define OPC_SHLX (0xf7 | P_EXT38 | P_DATA16) #define OPC_SHRX (0xf7 | P_EXT38 | P_SIMDF2) #define OPC_SHRD_Ib (0xac | P_EXT) +#define OPC_STC (0xf9) #define OPC_TESTB (0x84) #define OPC_TESTL (0x85) #define OPC_TZCNT (0xbc | P_EXT | P_SIMDF3) @@ -2629,21 +2630,55 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_ADD + rexw, a0, a2); +} + +static void tgen_addco_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_ADD + rexw, a0, a2, true); +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_addco, + .out_rri = tgen_addco_imm, +}; + +static void tgen_addcio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_ADC + rexw, a0, a2); +} + +static void tgen_addcio_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_ADC + rexw, a0, a2, true); +} + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_addcio, + .out_rri = tgen_addcio_imm, }; static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, -}; - -static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_addcio, + .out_rri = tgen_addcio_imm, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out8(s, OPC_STC); } static void tgen_and(TCGContext *s, TCGType type, @@ -3060,7 +3095,7 @@ static const TCGOutOpBinary outop_shr = { }; static void tgen_sub(TCGContext *s, TCGType type, - TCGReg a0, TCGReg a1, TCGReg a2) + TCGReg a0, TCGReg a1, TCGReg a2) { int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; tgen_arithr(s, ARITH_SUB + rexw, a0, a2); @@ -3071,21 +3106,44 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_SUB + rexw, a0, a2, 1); +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_sub, + .out_rri = tgen_subbo_rri, }; -static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, -}; +static void tgen_subbio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithr(s, ARITH_SBB + rexw, a0, a2); +} + +static void tgen_subbio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tgen_arithi(s, ARITH_SBB + rexw, a0, a2, 1); +} static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, re), + .out_rrr = tgen_subbio_rrr, + .out_rri = tgen_subbio_rri, }; +#define outop_subbi outop_subbio + static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out8(s, OPC_STC); } static void tgen_xor(TCGContext *s, TCGType type, @@ -3421,31 +3479,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I128); break; - OP_32_64(add2): - if (const_args[4]) { - tgen_arithi(s, ARITH_ADD + rexw, a0, args[4], 1); - } else { - tgen_arithr(s, ARITH_ADD + rexw, a0, args[4]); - } - if (const_args[5]) { - tgen_arithi(s, ARITH_ADC + rexw, a1, args[5], 1); - } else { - tgen_arithr(s, ARITH_ADC + rexw, a1, args[5]); - } - break; - OP_32_64(sub2): - if (const_args[4]) { - tgen_arithi(s, ARITH_SUB + rexw, a0, args[4], 1); - } else { - tgen_arithr(s, ARITH_SUB + rexw, a0, args[4]); - } - if (const_args[5]) { - tgen_arithi(s, ARITH_SBB + rexw, a1, args[5], 1); - } else { - tgen_arithr(s, ARITH_SBB + rexw, a1, args[5]); - } - break; - #if TCG_TARGET_REG_BITS == 64 case INDEX_op_ld32s_i64: tcg_out_modrm_offset(s, OPC_MOVSLQ, a0, a1, a2); @@ -4051,12 +4084,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(re, r); - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - return C_N1_O1_I4(r, r, 0, 1, re, re); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, L); From 0ad6d64b7be6287f8c07c72f8462ef5635b1e2da Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 17 Jan 2025 22:39:14 -0800 Subject: [PATCH 0480/2760] tcg/i386: Special case addci r, 0, 0 Using addci with two zeros as input in order to capture the value of the carry-in bit is common. Special case this with sbb+neg so that we do not have to load 0 into a register first. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/i386/tcg-target-con-set.h | 1 + tcg/i386/tcg-target.c.inc | 46 ++++++++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/tcg/i386/tcg-target-con-set.h b/tcg/i386/tcg-target-con-set.h index 85c93836bb..458d69c3c0 100644 --- a/tcg/i386/tcg-target-con-set.h +++ b/tcg/i386/tcg-target-con-set.h @@ -45,6 +45,7 @@ C_O1_I2(r, L, L) C_O1_I2(r, r, r) C_O1_I2(r, r, re) C_O1_I2(r, r, ri) +C_O1_I2(r, rO, re) C_O1_I2(x, x, x) C_N1_I2(r, r, r) C_N1_I2(r, r, rW) diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 44f9afc0d6..da05f13b21 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2670,10 +2670,50 @@ static const TCGOutOpBinary outop_addcio = { .out_rri = tgen_addcio_imm, }; +static void tgen_addci_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + /* Because "0O" is not a valid constraint, we must match ourselves. */ + if (a0 == a2) { + tgen_addcio(s, type, a0, a0, a1); + } else { + tcg_out_mov(s, type, a0, a1); + tgen_addcio(s, type, a0, a0, a2); + } +} + +static void tgen_addci_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + tgen_addcio_imm(s, type, a0, a0, a2); +} + +static void tgen_addci_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tgen_addci_rri(s, type, a0, a2, a1); +} + +static void tgen_addci_rii(TCGContext *s, TCGType type, TCGReg a0, + tcg_target_long a1, tcg_target_long a2) +{ + if (a2 == 0) { + /* Implement 0 + 0 + C with -(x - x - c). */ + tgen_arithr(s, ARITH_SBB, a0, a0); + tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_NEG, a0); + } else { + tcg_out_movi(s, type, a0, a2); + tgen_addcio_imm(s, type, a0, a0, a1); + } +} + static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_O1_I2(r, 0, re), - .out_rrr = tgen_addcio, - .out_rri = tgen_addcio_imm, + .base.static_constraint = C_O1_I2(r, rO, re), + .out_rrr = tgen_addci_rrr, + .out_rri = tgen_addci_rri, + .out_rir = tgen_addci_rir, + .out_rii = tgen_addci_rii, }; static void tcg_out_set_carry(TCGContext *s) From db3feb02b82d388d85a0c0a14d62f1a625f626a4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:19:51 -0800 Subject: [PATCH 0481/2760] tcg: Add tcg_gen_addcio_{i32,i64,tl} Create a function for performing an add with carry-in and producing carry out. The carry-out result is boolean. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/tcg/tcg-op-common.h | 4 ++ include/tcg/tcg-op.h | 2 + tcg/tcg-op.c | 95 +++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index 009e2778c5..b439bdb385 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -135,6 +135,8 @@ void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh); void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh); +void tcg_gen_addcio_i32(TCGv_i32 r, TCGv_i32 co, + TCGv_i32 a, TCGv_i32 b, TCGv_i32 ci); void tcg_gen_mulu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_muls2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2); void tcg_gen_mulsu2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 arg1, TCGv_i32 arg2); @@ -238,6 +240,8 @@ void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh); void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh); +void tcg_gen_addcio_i64(TCGv_i64 r, TCGv_i64 co, + TCGv_i64 a, TCGv_i64 b, TCGv_i64 ci); void tcg_gen_mulu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_muls2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2); void tcg_gen_mulsu2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 arg1, TCGv_i64 arg2); diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index cded92a447..59d19755e6 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -253,6 +253,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_movcond_tl tcg_gen_movcond_i64 #define tcg_gen_add2_tl tcg_gen_add2_i64 #define tcg_gen_sub2_tl tcg_gen_sub2_i64 +#define tcg_gen_addcio_tl tcg_gen_addcio_i64 #define tcg_gen_mulu2_tl tcg_gen_mulu2_i64 #define tcg_gen_muls2_tl tcg_gen_muls2_i64 #define tcg_gen_mulsu2_tl tcg_gen_mulsu2_i64 @@ -371,6 +372,7 @@ DEF_ATOMIC2(tcg_gen_atomic_umax_fetch, i64) #define tcg_gen_movcond_tl tcg_gen_movcond_i32 #define tcg_gen_add2_tl tcg_gen_add2_i32 #define tcg_gen_sub2_tl tcg_gen_sub2_i32 +#define tcg_gen_addcio_tl tcg_gen_addcio_i32 #define tcg_gen_mulu2_tl tcg_gen_mulu2_i32 #define tcg_gen_muls2_tl tcg_gen_muls2_i32 #define tcg_gen_mulsu2_tl tcg_gen_mulsu2_i32 diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 447b0ebacd..b0a29278ab 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1123,6 +1123,33 @@ void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, } } +void tcg_gen_addcio_i32(TCGv_i32 r, TCGv_i32 co, + TCGv_i32 a, TCGv_i32 b, TCGv_i32 ci) +{ + if (tcg_op_supported(INDEX_op_addci, TCG_TYPE_I32, 0)) { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 zero = tcg_constant_i32(0); + TCGv_i32 mone = tcg_constant_i32(-1); + + tcg_gen_op3_i32(INDEX_op_addco, t0, ci, mone); + tcg_gen_op3_i32(INDEX_op_addcio, r, a, b); + tcg_gen_op3_i32(INDEX_op_addci, co, zero, zero); + tcg_temp_free_i32(t0); + } else { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 t1 = tcg_temp_ebb_new_i32(); + + tcg_gen_add_i32(t0, a, b); + tcg_gen_setcond_i32(TCG_COND_LTU, t1, t0, a); + tcg_gen_add_i32(r, t0, ci); + tcg_gen_setcond_i32(TCG_COND_LTU, t0, r, t0); + tcg_gen_or_i32(co, t0, t1); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(t1); + } +} + void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, TCGv_i32 ah, TCGv_i32 bl, TCGv_i32 bh) { @@ -2868,6 +2895,74 @@ void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, } } +void tcg_gen_addcio_i64(TCGv_i64 r, TCGv_i64 co, + TCGv_i64 a, TCGv_i64 b, TCGv_i64 ci) +{ + if (TCG_TARGET_REG_BITS == 64) { + if (tcg_op_supported(INDEX_op_addci, TCG_TYPE_I64, 0)) { + TCGv_i64 discard = tcg_temp_ebb_new_i64(); + TCGv_i64 zero = tcg_constant_i64(0); + TCGv_i64 mone = tcg_constant_i64(-1); + + tcg_gen_op3_i64(INDEX_op_addco, discard, ci, mone); + tcg_gen_op3_i64(INDEX_op_addcio, r, a, b); + tcg_gen_op3_i64(INDEX_op_addci, co, zero, zero); + tcg_temp_free_i64(discard); + } else { + TCGv_i64 t0 = tcg_temp_ebb_new_i64(); + TCGv_i64 t1 = tcg_temp_ebb_new_i64(); + + tcg_gen_add_i64(t0, a, b); + tcg_gen_setcond_i64(TCG_COND_LTU, t1, t0, a); + tcg_gen_add_i64(r, t0, ci); + tcg_gen_setcond_i64(TCG_COND_LTU, t0, r, t0); + tcg_gen_or_i64(co, t0, t1); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); + } + } else { + if (tcg_op_supported(INDEX_op_addci, TCG_TYPE_I32, 0)) { + TCGv_i32 discard = tcg_temp_ebb_new_i32(); + TCGv_i32 zero = tcg_constant_i32(0); + TCGv_i32 mone = tcg_constant_i32(-1); + + tcg_gen_op3_i32(INDEX_op_addco, discard, TCGV_LOW(ci), mone); + tcg_gen_op3_i32(INDEX_op_addcio, discard, TCGV_HIGH(ci), mone); + tcg_gen_op3_i32(INDEX_op_addcio, TCGV_LOW(r), + TCGV_LOW(a), TCGV_LOW(b)); + tcg_gen_op3_i32(INDEX_op_addcio, TCGV_HIGH(r), + TCGV_HIGH(a), TCGV_HIGH(b)); + tcg_gen_op3_i32(INDEX_op_addci, TCGV_LOW(co), zero, zero); + tcg_temp_free_i32(discard); + } else { + TCGv_i32 t0 = tcg_temp_ebb_new_i32(); + TCGv_i32 c0 = tcg_temp_ebb_new_i32(); + TCGv_i32 c1 = tcg_temp_ebb_new_i32(); + + tcg_gen_or_i32(c1, TCGV_LOW(ci), TCGV_HIGH(ci)); + tcg_gen_setcondi_i32(TCG_COND_NE, c1, c1, 0); + + tcg_gen_add_i32(t0, TCGV_LOW(a), TCGV_LOW(b)); + tcg_gen_setcond_i32(TCG_COND_LTU, c0, t0, TCGV_LOW(a)); + tcg_gen_add_i32(TCGV_LOW(r), t0, c1); + tcg_gen_setcond_i32(TCG_COND_LTU, c1, TCGV_LOW(r), c1); + tcg_gen_or_i32(c1, c1, c0); + + tcg_gen_add_i32(t0, TCGV_HIGH(a), TCGV_HIGH(b)); + tcg_gen_setcond_i32(TCG_COND_LTU, c0, t0, TCGV_HIGH(a)); + tcg_gen_add_i32(TCGV_HIGH(r), t0, c1); + tcg_gen_setcond_i32(TCG_COND_LTU, c1, TCGV_HIGH(r), c1); + tcg_gen_or_i32(TCGV_LOW(co), c0, c1); + + tcg_temp_free_i32(t0); + tcg_temp_free_i32(c0); + tcg_temp_free_i32(c1); + } + tcg_gen_movi_i32(TCGV_HIGH(co), 0); + } +} + void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, TCGv_i64 ah, TCGv_i64 bl, TCGv_i64 bh) { From eea0f7ea5170b47aa2cd6f6ad077e48702aad6f3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:27:41 -0800 Subject: [PATCH 0482/2760] target/arm: Use tcg_gen_addcio_* for ADCS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/arm/tcg/translate-a64.c | 8 ++------ target/arm/tcg/translate.c | 17 +++-------------- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index e076d4aa05..d9305f9d26 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -1076,11 +1076,9 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) TCGv_i64 cf_64 = tcg_temp_new_i64(); TCGv_i64 vf_64 = tcg_temp_new_i64(); TCGv_i64 tmp = tcg_temp_new_i64(); - TCGv_i64 zero = tcg_constant_i64(0); tcg_gen_extu_i32_i64(cf_64, cpu_CF); - tcg_gen_add2_i64(result, cf_64, t0, zero, cf_64, zero); - tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, zero); + tcg_gen_addcio_i64(result, cf_64, t0, t1, cf_64); tcg_gen_extrl_i64_i32(cpu_CF, cf_64); gen_set_NZ64(result); @@ -1094,12 +1092,10 @@ static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1) TCGv_i32 t0_32 = tcg_temp_new_i32(); TCGv_i32 t1_32 = tcg_temp_new_i32(); TCGv_i32 tmp = tcg_temp_new_i32(); - TCGv_i32 zero = tcg_constant_i32(0); tcg_gen_extrl_i64_i32(t0_32, t0); tcg_gen_extrl_i64_i32(t1_32, t1); - tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, zero, cpu_CF, zero); - tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, zero); + tcg_gen_addcio_i32(cpu_NF, cpu_CF, t0_32, t1_32, cpu_CF); tcg_gen_mov_i32(cpu_ZF, cpu_NF); tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32); diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index 273b860d57..88df9c482a 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -494,20 +494,9 @@ static void gen_add_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) static void gen_adc_CC(TCGv_i32 dest, TCGv_i32 t0, TCGv_i32 t1) { TCGv_i32 tmp = tcg_temp_new_i32(); - if (tcg_op_supported(INDEX_op_add2_i32, TCG_TYPE_I32, 0)) { - tcg_gen_movi_i32(tmp, 0); - tcg_gen_add2_i32(cpu_NF, cpu_CF, t0, tmp, cpu_CF, tmp); - tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1, tmp); - } else { - TCGv_i64 q0 = tcg_temp_new_i64(); - TCGv_i64 q1 = tcg_temp_new_i64(); - tcg_gen_extu_i32_i64(q0, t0); - tcg_gen_extu_i32_i64(q1, t1); - tcg_gen_add_i64(q0, q0, q1); - tcg_gen_extu_i32_i64(q1, cpu_CF); - tcg_gen_add_i64(q0, q0, q1); - tcg_gen_extr_i64_i32(cpu_NF, cpu_CF, q0); - } + + tcg_gen_addcio_i32(cpu_NF, cpu_CF, t0, t1, cpu_CF); + tcg_gen_mov_i32(cpu_ZF, cpu_NF); tcg_gen_xor_i32(cpu_VF, cpu_NF, t0); tcg_gen_xor_i32(tmp, t0, t1); From 14e9ff8514bcae95d45dc8603f1ef33ad2f1dce1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:35:49 -0800 Subject: [PATCH 0483/2760] target/hppa: Use tcg_gen_addcio_i64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use this in do_add, do_sub, and do_ds, all of which need add with carry-in and carry-out. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/hppa/translate.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 14f3833322..88a7d339eb 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -1209,10 +1209,10 @@ static void do_add(DisasContext *ctx, unsigned rt, TCGv_i64 orig_in1, cb_msb = tcg_temp_new_i64(); cb = tcg_temp_new_i64(); - tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); if (is_c) { - tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, - get_psw_carry(ctx, d), ctx->zero); + tcg_gen_addcio_i64(dest, cb_msb, in1, in2, get_psw_carry(ctx, d)); + } else { + tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); } tcg_gen_xor_i64(cb, in1, in2); tcg_gen_xor_i64(cb, cb, dest); @@ -1308,9 +1308,7 @@ static void do_sub(DisasContext *ctx, unsigned rt, TCGv_i64 in1, if (is_b) { /* DEST,C = IN1 + ~IN2 + C. */ tcg_gen_not_i64(cb, in2); - tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, - get_psw_carry(ctx, d), ctx->zero); - tcg_gen_add2_i64(dest, cb_msb, dest, cb_msb, cb, ctx->zero); + tcg_gen_addcio_i64(dest, cb_msb, in1, cb, get_psw_carry(ctx, d)); tcg_gen_xor_i64(cb, cb, in1); tcg_gen_xor_i64(cb, cb, dest); } else { @@ -3008,9 +3006,7 @@ static bool trans_ds(DisasContext *ctx, arg_rrr_cf *a) tcg_gen_xor_i64(add2, in2, addc); tcg_gen_andi_i64(addc, addc, 1); - tcg_gen_add2_i64(dest, cpu_psw_cb_msb, add1, ctx->zero, add2, ctx->zero); - tcg_gen_add2_i64(dest, cpu_psw_cb_msb, dest, cpu_psw_cb_msb, - addc, ctx->zero); + tcg_gen_addcio_i64(dest, cpu_psw_cb_msb, add1, add2, addc); /* Write back the result register. */ save_gpr(ctx, a->t, dest); @@ -3553,8 +3549,7 @@ static bool do_addb(DisasContext *ctx, unsigned r, TCGv_i64 in1, TCGv_i64 cb = tcg_temp_new_i64(); TCGv_i64 cb_msb = tcg_temp_new_i64(); - tcg_gen_movi_i64(cb_msb, 0); - tcg_gen_add2_i64(dest, cb_msb, in1, cb_msb, in2, cb_msb); + tcg_gen_add2_i64(dest, cb_msb, in1, ctx->zero, in2, ctx->zero); tcg_gen_xor_i64(cb, in1, in2); tcg_gen_xor_i64(cb, cb, dest); cb_cond = get_carry(ctx, d, cb, cb_msb); From fcfbd8f4a9c3cbc09376230093d28e14acf7854b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:47:53 -0800 Subject: [PATCH 0484/2760] target/microblaze: Use tcg_gen_addcio_i32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use this in gen_addc and gen_rsubc, both of which need add with carry-in and carry-out. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 7dcad6cf0d..23f1037236 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -311,11 +311,7 @@ static void gen_add(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) /* Input and output carry. */ static void gen_addc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { - TCGv_i32 zero = tcg_constant_i32(0); - TCGv_i32 tmp = tcg_temp_new_i32(); - - tcg_gen_add2_i32(tmp, cpu_msr_c, ina, zero, cpu_msr_c, zero); - tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); + tcg_gen_addcio_i32(out, cpu_msr_c, ina, inb, cpu_msr_c); } /* Input carry, but no output carry. */ @@ -544,12 +540,10 @@ static void gen_rsub(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) /* Input and output carry. */ static void gen_rsubc(TCGv_i32 out, TCGv_i32 ina, TCGv_i32 inb) { - TCGv_i32 zero = tcg_constant_i32(0); TCGv_i32 tmp = tcg_temp_new_i32(); tcg_gen_not_i32(tmp, ina); - tcg_gen_add2_i32(tmp, cpu_msr_c, tmp, zero, cpu_msr_c, zero); - tcg_gen_add2_i32(out, cpu_msr_c, tmp, cpu_msr_c, inb, zero); + tcg_gen_addcio_i32(out, cpu_msr_c, tmp, inb, cpu_msr_c); } /* No input or output carry. */ From 02b9d791be10ea9e4c8fdfe4cfdc2a6a0de7e810 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:50:50 -0800 Subject: [PATCH 0485/2760] target/openrisc: Use tcg_gen_addcio_* for ADDC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/openrisc/translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index d4ce60188b..baadea4448 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -221,8 +221,7 @@ static void gen_addc(DisasContext *dc, TCGv dest, TCGv srca, TCGv srcb) TCGv t0 = tcg_temp_new(); TCGv res = tcg_temp_new(); - tcg_gen_add2_tl(res, cpu_sr_cy, srca, dc->zero, cpu_sr_cy, dc->zero); - tcg_gen_add2_tl(res, cpu_sr_cy, res, cpu_sr_cy, srcb, dc->zero); + tcg_gen_addcio_tl(res, cpu_sr_cy, srca, srcb, cpu_sr_cy); tcg_gen_xor_tl(cpu_sr_ov, srca, srcb); tcg_gen_xor_tl(t0, res, srcb); tcg_gen_andc_tl(cpu_sr_ov, t0, cpu_sr_ov); From 3a6ec7d71a4e268a6be319cf2efa780091d42d30 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:55:11 -0800 Subject: [PATCH 0486/2760] target/ppc: Use tcg_gen_addcio_tl for ADD and SUBF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tested-by: Nicholas Piggin Reviewed-by: Nicholas Piggin Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/ppc/translate.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/target/ppc/translate.c b/target/ppc/translate.c index fea2f2ce23..62dd008e36 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -1746,11 +1746,10 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_mov_tl(ca32, ca); } } else { - TCGv zero = tcg_constant_tl(0); if (add_ca) { - tcg_gen_add2_tl(t0, ca, arg1, zero, ca, zero); - tcg_gen_add2_tl(t0, ca, t0, ca, arg2, zero); + tcg_gen_addcio_tl(t0, ca, arg1, arg2, ca); } else { + TCGv zero = tcg_constant_tl(0); tcg_gen_add2_tl(t0, ca, arg1, zero, arg2, zero); } gen_op_arith_compute_ca32(ctx, t0, arg1, arg2, ca32, 0); @@ -1949,11 +1948,9 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, tcg_gen_mov_tl(cpu_ca32, cpu_ca); } } else if (add_ca) { - TCGv zero, inv1 = tcg_temp_new(); + TCGv inv1 = tcg_temp_new(); tcg_gen_not_tl(inv1, arg1); - zero = tcg_constant_tl(0); - tcg_gen_add2_tl(t0, cpu_ca, arg2, zero, cpu_ca, zero); - tcg_gen_add2_tl(t0, cpu_ca, t0, cpu_ca, inv1, zero); + tcg_gen_addcio_tl(t0, cpu_ca, arg2, inv1, cpu_ca); gen_op_arith_compute_ca32(ctx, t0, inv1, arg2, cpu_ca32, 0); } else { tcg_gen_setcond_tl(TCG_COND_GEU, cpu_ca, arg2, arg1); From 206c23e4720cd2b7668197887d1694bd346e979e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 01:59:12 -0800 Subject: [PATCH 0487/2760] target/s390x: Use tcg_gen_addcio_i64 for op_addc64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/s390x/tcg/translate.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index 00073c5560..a714f9c0c2 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -1250,11 +1250,7 @@ static DisasJumpType op_addc32(DisasContext *s, DisasOps *o) static DisasJumpType op_addc64(DisasContext *s, DisasOps *o) { compute_carry(s); - - TCGv_i64 zero = tcg_constant_i64(0); - tcg_gen_add2_i64(o->out, cc_src, o->in1, zero, cc_src, zero); - tcg_gen_add2_i64(o->out, cc_src, o->out, cc_src, o->in2, zero); - + tcg_gen_addcio_i64(o->out, cc_src, o->in1, o->in2, cc_src); return DISAS_NEXT; } From 68188214d5b5dc80acc9143f6bdca25fc06f6e2b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 02:03:03 -0800 Subject: [PATCH 0488/2760] target/sh4: Use tcg_gen_addcio_i32 for addc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/sh4/translate.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 712a57fb54..712117be22 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -695,14 +695,8 @@ static void _decode_opc(DisasContext * ctx) tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4)); return; case 0x300e: /* addc Rm,Rn */ - { - TCGv t0, t1; - t0 = tcg_constant_tl(0); - t1 = tcg_temp_new(); - tcg_gen_add2_i32(t1, cpu_sr_t, cpu_sr_t, t0, REG(B7_4), t0); - tcg_gen_add2_i32(REG(B11_8), cpu_sr_t, - REG(B11_8), t0, t1, cpu_sr_t); - } + tcg_gen_addcio_i32(REG(B11_8), cpu_sr_t, + REG(B11_8), REG(B7_4), cpu_sr_t); return; case 0x300f: /* addv Rm,Rn */ { From 6ed4d97ff7fbd2ef3d0d3f1f06d89560955873b8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 02:05:19 -0800 Subject: [PATCH 0489/2760] target/sparc: Use tcg_gen_addcio_tl for gen_op_addcc_int Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/sparc/translate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/sparc/translate.c b/target/sparc/translate.c index adebddf27b..63dd90447b 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -396,8 +396,7 @@ static void gen_op_addcc_int(TCGv dst, TCGv src1, TCGv src2, TCGv cin) TCGv z = tcg_constant_tl(0); if (cin) { - tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, cin, z); - tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, cpu_cc_N, cpu_cc_C, src2, z); + tcg_gen_addcio_tl(cpu_cc_N, cpu_cc_C, src1, src2, cin); } else { tcg_gen_add2_tl(cpu_cc_N, cpu_cc_C, src1, z, src2, z); } From 867878c112a0c8bbf7590a948ea291f1f1d61209 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 02:08:55 -0800 Subject: [PATCH 0490/2760] target/tricore: Use tcg_gen_addcio_i32 for gen_addc_CC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/tricore/translate.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target/tricore/translate.c b/target/tricore/translate.c index ede0c92c1e..ba36c9fcc8 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -1346,15 +1346,11 @@ static inline void gen_addi_CC(TCGv ret, TCGv r1, int32_t con) static inline void gen_addc_CC(TCGv ret, TCGv r1, TCGv r2) { - TCGv carry = tcg_temp_new_i32(); - TCGv t0 = tcg_temp_new_i32(); + TCGv t0 = tcg_temp_new_i32(); TCGv result = tcg_temp_new_i32(); - tcg_gen_movi_tl(t0, 0); - tcg_gen_setcondi_tl(TCG_COND_NE, carry, cpu_PSW_C, 0); /* Addition, carry and set C/V/SV bits */ - tcg_gen_add2_i32(result, cpu_PSW_C, r1, t0, carry, t0); - tcg_gen_add2_i32(result, cpu_PSW_C, result, cpu_PSW_C, r2, t0); + tcg_gen_addcio_i32(result, cpu_PSW_C, r1, r2, cpu_PSW_C); /* calc V bit */ tcg_gen_xor_tl(cpu_PSW_V, result, r1); tcg_gen_xor_tl(t0, r1, r2); From 75351891b85f5fe4bd3c1e281d0d9d2dae097e6a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Jan 2025 02:41:58 -0800 Subject: [PATCH 0491/2760] tcg/aarch64: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target-con-set.h | 3 +- tcg/aarch64/tcg-target-has.h | 8 +- tcg/aarch64/tcg-target.c.inc | 227 ++++++++++++++++++++----------- 3 files changed, 150 insertions(+), 88 deletions(-) diff --git a/tcg/aarch64/tcg-target-con-set.h b/tcg/aarch64/tcg-target-con-set.h index 2eda499cd3..d0622e65fb 100644 --- a/tcg/aarch64/tcg-target-con-set.h +++ b/tcg/aarch64/tcg-target-con-set.h @@ -24,6 +24,8 @@ C_O1_I2(r, r, rAL) C_O1_I2(r, r, rC) C_O1_I2(r, r, ri) C_O1_I2(r, r, rL) +C_O1_I2(r, rZ, rA) +C_O1_I2(r, rz, rMZ) C_O1_I2(r, rz, rz) C_O1_I2(r, rZ, rZ) C_O1_I2(w, 0, w) @@ -34,4 +36,3 @@ C_O1_I2(w, w, wZ) C_O1_I3(w, w, w, w) C_O1_I4(r, r, rC, rz, rz) C_O2_I1(r, r, r) -C_O2_I4(r, r, rz, rz, rA, rMZ) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 011a91c263..695effd77c 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,13 +13,13 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 87f8c98ed7..75cf490fd2 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -508,7 +508,9 @@ typedef enum { /* Add/subtract with carry instructions. */ I3503_ADC = 0x1a000000, + I3503_ADCS = 0x3a000000, I3503_SBC = 0x5a000000, + I3503_SBCS = 0x7a000000, /* Conditional select instructions. */ I3506_CSEL = 0x1a800000, @@ -1573,56 +1575,6 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) tcg_out_mov(s, TCG_TYPE_I32, rd, rn); } -static void tcg_out_addsub2(TCGContext *s, TCGType ext, TCGReg rl, - TCGReg rh, TCGReg al, TCGReg ah, - tcg_target_long bl, tcg_target_long bh, - bool const_bl, bool const_bh, bool sub) -{ - TCGReg orig_rl = rl; - AArch64Insn insn; - - if (rl == ah || (!const_bh && rl == bh)) { - rl = TCG_REG_TMP0; - } - - if (const_bl) { - if (bl < 0) { - bl = -bl; - insn = sub ? I3401_ADDSI : I3401_SUBSI; - } else { - insn = sub ? I3401_SUBSI : I3401_ADDSI; - } - - if (unlikely(al == TCG_REG_XZR)) { - /* ??? We want to allow al to be zero for the benefit of - negation via subtraction. However, that leaves open the - possibility of adding 0+const in the low part, and the - immediate add instructions encode XSP not XZR. Don't try - anything more elaborate here than loading another zero. */ - al = TCG_REG_TMP0; - tcg_out_movi(s, ext, al, 0); - } - tcg_out_insn_3401(s, insn, ext, rl, al, bl); - } else { - tcg_out_insn_3502(s, sub ? I3502_SUBS : I3502_ADDS, ext, rl, al, bl); - } - - insn = I3503_ADC; - if (const_bh) { - /* Note that the only two constants we support are 0 and -1, and - that SBC = rn + ~rm + c, so adc -1 is sbc 0, and vice-versa. */ - if ((bh != 0) ^ sub) { - insn = I3503_SBC; - } - bh = TCG_REG_XZR; - } else if (sub) { - insn = I3503_SBC; - } - tcg_out_insn_3503(s, insn, ext, rh, ah, bh); - - tcg_out_mov(s, ext, orig_rl, rl); -} - static inline void tcg_out_mb(TCGContext *s, TCGArg a0) { static const uint32_t sync[] = { @@ -2078,21 +2030,81 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3502, ADDS, type, a0, a1, a2); +} + +static void tgen_addco_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 >= 0) { + tcg_out_insn(s, 3401, ADDSI, type, a0, a1, a2); + } else { + tcg_out_insn(s, 3401, SUBSI, type, a0, a1, -a2); + } +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rA), + .out_rrr = tgen_addco, + .out_rri = tgen_addco_imm, }; +static void tgen_addci_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3503, ADC, type, a0, a1, a2); +} + +static void tgen_addci_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* + * Note that the only two constants we support are 0 and -1, and + * that SBC = rn + ~rm + c, so adc -1 is sbc 0, and vice-versa. + */ + if (a2) { + tcg_out_insn(s, 3503, SBC, type, a0, a1, TCG_REG_XZR); + } else { + tcg_out_insn(s, 3503, ADC, type, a0, a1, TCG_REG_XZR); + } +} + static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rMZ), + .out_rrr = tgen_addci_rrr, + .out_rri = tgen_addci_rri, }; +static void tgen_addcio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3503, ADCS, type, a0, a1, a2); +} + +static void tgen_addcio_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + /* Use SBCS w/0 for ADCS w/-1 -- see above. */ + if (a2) { + tcg_out_insn(s, 3503, SBCS, type, a0, a1, TCG_REG_XZR); + } else { + tcg_out_insn(s, 3503, ADCS, type, a0, a1, TCG_REG_XZR); + } +} + static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rMZ), + .out_rrr = tgen_addcio, + .out_rri = tgen_addcio_imm, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out_insn(s, 3502, SUBS, TCG_TYPE_I32, + TCG_REG_XZR, TCG_REG_XZR, TCG_REG_XZR); } static void tgen_and(TCGContext *s, TCGType type, @@ -2438,21 +2450,95 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static void tgen_subbo_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3502, SUBS, type, a0, a1, a2); +} + +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 >= 0) { + tcg_out_insn(s, 3401, SUBSI, type, a0, a1, a2); + } else { + tcg_out_insn(s, 3401, ADDSI, type, a0, a1, -a2); + } +} + +static void tgen_subbo_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tgen_subbo_rrr(s, type, a0, TCG_REG_XZR, a2); +} + +static void tgen_subbo_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + if (a2 == 0) { + tgen_subbo_rrr(s, type, a0, TCG_REG_XZR, TCG_REG_XZR); + return; + } + + /* + * We want to allow a1 to be zero for the benefit of negation via + * subtraction. However, that leaves open the possibility of + * adding 0 +/- const, and the immediate add/sub instructions + * encode XSP not XZR. Since we have 0 - non-zero, borrow is + * always set. + */ + tcg_out_movi(s, type, a0, -a2); + tcg_out_set_borrow(s); +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rZ, rA), + .out_rrr = tgen_subbo_rrr, + .out_rri = tgen_subbo_rri, + .out_rir = tgen_subbo_rir, + .out_rii = tgen_subbo_rii, }; +static void tgen_subbi_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3503, SBC, type, a0, a1, a2); +} + +static void tgen_subbi_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_addci_rri(s, type, a0, a1, ~a2); +} + static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rMZ), + .out_rrr = tgen_subbi_rrr, + .out_rri = tgen_subbi_rri, }; +static void tgen_subbio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_insn(s, 3503, SBCS, type, a0, a1, a2); +} + +static void tgen_subbio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_addcio_imm(s, type, a0, a1, ~a2); +} + static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rMZ), + .out_rrr = tgen_subbio_rrr, + .out_rri = tgen_subbio_rri, }; static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out_insn(s, 3502, ADDS, TCG_TYPE_I32, + TCG_REG_XZR, TCG_REG_XZR, TCG_REG_XZR); } static void tgen_xor(TCGContext *s, TCGType type, @@ -2759,25 +2845,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; - case INDEX_op_add2_i32: - tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, a2, args[3], - (int32_t)args[4], args[5], const_args[4], - const_args[5], false); - break; - case INDEX_op_add2_i64: - tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, a2, args[3], args[4], - args[5], const_args[4], const_args[5], false); - break; - case INDEX_op_sub2_i32: - tcg_out_addsub2(s, TCG_TYPE_I32, a0, a1, a2, args[3], - (int32_t)args[4], args[5], const_args[4], - const_args[5], true); - break; - case INDEX_op_sub2_i64: - tcg_out_addsub2(s, TCG_TYPE_I64, a0, a1, a2, args[3], args[4], - args[5], const_args[4], const_args[5], true); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -3271,12 +3338,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(rz, rz, r); - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - return C_O2_I4(r, r, rz, rz, rA, rMZ); - case INDEX_op_add_vec: case INDEX_op_sub_vec: case INDEX_op_mul_vec: From b15c0d11a28e6be7156b6920a7a5b2179112b1fa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 15 Jan 2025 23:35:53 +0000 Subject: [PATCH 0492/2760] tcg/arm: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/arm/tcg-target-con-set.h | 4 +- tcg/arm/tcg-target-has.h | 4 +- tcg/arm/tcg-target.c.inc | 212 ++++++++++++++++++++++++++--------- 3 files changed, 161 insertions(+), 59 deletions(-) diff --git a/tcg/arm/tcg-target-con-set.h b/tcg/arm/tcg-target-con-set.h index f46a8444fb..16b1193228 100644 --- a/tcg/arm/tcg-target-con-set.h +++ b/tcg/arm/tcg-target-con-set.h @@ -31,6 +31,8 @@ C_O1_I2(r, r, rIK) C_O1_I2(r, r, rIN) C_O1_I2(r, r, ri) C_O1_I2(r, rI, r) +C_O1_I2(r, rI, rIK) +C_O1_I2(r, rI, rIN) C_O1_I2(r, rZ, rZ) C_O1_I2(w, 0, w) C_O1_I2(w, w, w) @@ -43,5 +45,3 @@ C_O1_I4(r, r, rIN, rIK, 0) C_O2_I1(e, p, q) C_O2_I2(e, p, q, q) C_O2_I2(r, r, r, r) -C_O2_I4(r, r, r, r, rIN, rIK) -C_O2_I4(r, r, rI, rI, rIN, rIK) diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 3973df1f12..f4bd15c68a 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,8 +24,8 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index aa0397520d..3c9042ebfa 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -178,6 +178,8 @@ typedef enum { INSN_DMB_ISH = 0xf57ff05b, INSN_DMB_MCR = 0xee070fba, + INSN_MSRI_CPSR = 0x0360f000, + /* Architected nop introduced in v6k. */ /* ??? This is an MSR (imm) 0,0,0 insn. Anyone know if this also Just So Happened to do nothing on pre-v6k so that we @@ -1826,21 +1828,74 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_ADD | TO_CPSR, + a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_addco_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IN(s, COND_AL, ARITH_ADD | TO_CPSR, ARITH_SUB | TO_CPSR, + a0, a1, a2); +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rIN), + .out_rrr = tgen_addco, + .out_rri = tgen_addco_imm, }; +static void tgen_addci(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_ADC, a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_addci_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IK(s, COND_AL, ARITH_ADC, ARITH_SBC, a0, a1, a2); +} + static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rIK), + .out_rrr = tgen_addci, + .out_rri = tgen_addci_imm, }; +static void tgen_addcio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_ADC | TO_CPSR, + a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_addcio_imm(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IK(s, COND_AL, ARITH_ADC | TO_CPSR, ARITH_SBC | TO_CPSR, + a0, a1, a2); +} + static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rIK), + .out_rrr = tgen_addcio, + .out_rri = tgen_addcio_imm, }; +/* Set C to @c; NZVQ all set to 0. */ +static void tcg_out_movi_apsr_c(TCGContext *s, bool c) +{ + int imm12 = encode_imm_nofail(c << 29); + tcg_out32(s, (COND_AL << 28) | INSN_MSRI_CPSR | 0x80000 | imm12); +} + static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out_movi_apsr_c(s, 1); } static void tgen_and(TCGContext *s, TCGType type, @@ -2152,21 +2207,115 @@ static const TCGOutOpSubtract outop_sub = { .out_rir = tgen_subfi, }; +static void tgen_subbo_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_SUB | TO_CPSR, + a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IN(s, COND_AL, ARITH_SUB | TO_CPSR, ARITH_ADD | TO_CPSR, + a0, a1, a2); +} + +static void tgen_subbo_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_RSB | TO_CPSR, + a0, a2, encode_imm_nofail(a1)); +} + +static void tgen_subbo_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, a2); + tgen_subbo_rir(s, TCG_TYPE_I32, a0, a1, TCG_REG_TMP); +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rI, rIN), + .out_rrr = tgen_subbo_rrr, + .out_rri = tgen_subbo_rri, + .out_rir = tgen_subbo_rir, + .out_rii = tgen_subbo_rii, }; +static void tgen_subbi_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_SBC, + a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_subbi_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IK(s, COND_AL, ARITH_SBC, ARITH_ADC, a0, a1, a2); +} + +static void tgen_subbi_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_RSC, a0, a2, encode_imm_nofail(a1)); +} + +static void tgen_subbi_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, a2); + tgen_subbi_rir(s, TCG_TYPE_I32, a0, a1, TCG_REG_TMP); +} + static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rI, rIK), + .out_rrr = tgen_subbi_rrr, + .out_rri = tgen_subbi_rri, + .out_rir = tgen_subbi_rir, + .out_rii = tgen_subbi_rii, }; +static void tgen_subbio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_dat_reg(s, COND_AL, ARITH_SBC | TO_CPSR, + a0, a1, a2, SHIFT_IMM_LSL(0)); +} + +static void tgen_subbio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_dat_IK(s, COND_AL, ARITH_SBC | TO_CPSR, ARITH_ADC | TO_CPSR, + a0, a1, a2); +} + +static void tgen_subbio_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_out_dat_imm(s, COND_AL, ARITH_RSC | TO_CPSR, + a0, a2, encode_imm_nofail(a1)); +} + +static void tgen_subbio_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, a2); + tgen_subbio_rir(s, TCG_TYPE_I32, a0, a1, TCG_REG_TMP); +} + static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rI, rIK), + .out_rrr = tgen_subbio_rrr, + .out_rri = tgen_subbio_rri, + .out_rir = tgen_subbio_rir, + .out_rii = tgen_subbio_rii, }; static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out_movi_apsr_c(s, 0); /* borrow = !carry */ } static void tgen_xor(TCGContext *s, TCGType type, @@ -2369,8 +2518,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2, a3, a4, a5; - switch (opc) { case INDEX_op_goto_ptr: tcg_out_b_reg(s, COND_AL, args[0]); @@ -2404,47 +2551,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); break; - case INDEX_op_add2_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - a3 = args[3], a4 = args[4], a5 = args[5]; - if (a0 == a3 || (a0 == a5 && !const_args[5])) { - a0 = TCG_REG_TMP; - } - tcg_out_dat_rIN(s, COND_AL, ARITH_ADD | TO_CPSR, ARITH_SUB | TO_CPSR, - a0, a2, a4, const_args[4]); - tcg_out_dat_rIK(s, COND_AL, ARITH_ADC, ARITH_SBC, - a1, a3, a5, const_args[5]); - tcg_out_mov_reg(s, COND_AL, args[0], a0); - break; - case INDEX_op_sub2_i32: - a0 = args[0], a1 = args[1], a2 = args[2]; - a3 = args[3], a4 = args[4], a5 = args[5]; - if ((a0 == a3 && !const_args[3]) || (a0 == a5 && !const_args[5])) { - a0 = TCG_REG_TMP; - } - if (const_args[2]) { - if (const_args[4]) { - tcg_out_movi32(s, COND_AL, a0, a4); - a4 = a0; - } - tcg_out_dat_rI(s, COND_AL, ARITH_RSB | TO_CPSR, a0, a4, a2, 1); - } else { - tcg_out_dat_rIN(s, COND_AL, ARITH_SUB | TO_CPSR, - ARITH_ADD | TO_CPSR, a0, a2, a4, const_args[4]); - } - if (const_args[3]) { - if (const_args[5]) { - tcg_out_movi32(s, COND_AL, a1, a5); - a5 = a1; - } - tcg_out_dat_rI(s, COND_AL, ARITH_RSC, a1, a5, a3, 1); - } else { - tcg_out_dat_rIK(s, COND_AL, ARITH_SBC, ARITH_ADC, - a1, a3, a5, const_args[5]); - } - tcg_out_mov_reg(s, COND_AL, args[0], a0); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -2490,10 +2596,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return C_O0_I2(r, r); - case INDEX_op_add2_i32: - return C_O2_I4(r, r, r, r, rIN, rIK); - case INDEX_op_sub2_i32: - return C_O2_I4(r, r, rI, rI, rIN, rIK); case INDEX_op_qemu_ld_i32: return C_O1_I1(r, q); case INDEX_op_qemu_ld_i64: From 2329da9605b0f1b7bd59f58afb5ab2154d0af137 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 00:38:13 +0000 Subject: [PATCH 0493/2760] tcg/ppc: Implement add/sub carry opcodes Tested-by: Nicholas Piggin Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/ppc/tcg-target-con-set.h | 5 +- tcg/ppc/tcg-target-con-str.h | 1 + tcg/ppc/tcg-target-has.h | 11 +- tcg/ppc/tcg-target.c.inc | 227 ++++++++++++++++++++++------------- 4 files changed, 154 insertions(+), 90 deletions(-) diff --git a/tcg/ppc/tcg-target-con-set.h b/tcg/ppc/tcg-target-con-set.h index 14cd217287..da7a383bff 100644 --- a/tcg/ppc/tcg-target-con-set.h +++ b/tcg/ppc/tcg-target-con-set.h @@ -29,7 +29,10 @@ C_O1_I2(r, r, rC) C_O1_I2(r, r, rI) C_O1_I2(r, r, rT) C_O1_I2(r, r, rU) +C_O1_I2(r, r, rZM) C_O1_I2(r, r, rZW) +C_O1_I2(r, rI, rN) +C_O1_I2(r, rZM, rZM) C_O1_I2(v, v, v) C_O1_I3(v, v, v, v) C_O1_I4(v, v, v, vZM, v) @@ -38,5 +41,3 @@ C_O1_I4(r, r, r, rU, rC) C_O2_I1(r, r, r) C_N1O1_I1(o, m, r) C_O2_I2(r, r, r, r) -C_O2_I4(r, r, rI, rZM, r, r) -C_O2_I4(r, r, r, r, rI, rZM) diff --git a/tcg/ppc/tcg-target-con-str.h b/tcg/ppc/tcg-target-con-str.h index 16b687216e..faf92da47f 100644 --- a/tcg/ppc/tcg-target-con-str.h +++ b/tcg/ppc/tcg-target-con-str.h @@ -19,6 +19,7 @@ REGS('v', ALL_VECTOR_REGS) CONST('C', TCG_CT_CONST_CMP) CONST('I', TCG_CT_CONST_S16) CONST('M', TCG_CT_CONST_MONE) +CONST('N', TCG_CT_CONST_N16) CONST('T', TCG_CT_CONST_S32) CONST('U', TCG_CT_CONST_U32) CONST('W', TCG_CT_CONST_WSZ) diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 8d832ce99c..4dda668706 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -18,16 +18,13 @@ /* optional instructions */ #define TCG_TARGET_HAS_qemu_st8_i32 0 - -#if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_add2_i32 0 #define TCG_TARGET_HAS_sub2_i32 0 + +#if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 -#else -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 5b04655f3b..91df9610ec 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -89,14 +89,15 @@ /* Shorthand for size of a register. */ #define SZR (TCG_TARGET_REG_BITS / 8) -#define TCG_CT_CONST_S16 0x100 -#define TCG_CT_CONST_U16 0x200 -#define TCG_CT_CONST_S32 0x400 -#define TCG_CT_CONST_U32 0x800 -#define TCG_CT_CONST_ZERO 0x1000 -#define TCG_CT_CONST_MONE 0x2000 -#define TCG_CT_CONST_WSZ 0x4000 -#define TCG_CT_CONST_CMP 0x8000 +#define TCG_CT_CONST_S16 0x00100 +#define TCG_CT_CONST_U16 0x00200 +#define TCG_CT_CONST_N16 0x00400 +#define TCG_CT_CONST_S32 0x00800 +#define TCG_CT_CONST_U32 0x01000 +#define TCG_CT_CONST_ZERO 0x02000 +#define TCG_CT_CONST_MONE 0x04000 +#define TCG_CT_CONST_WSZ 0x08000 +#define TCG_CT_CONST_CMP 0x10000 #define ALL_GENERAL_REGS 0xffffffffu #define ALL_VECTOR_REGS 0xffffffff00000000ull @@ -342,6 +343,9 @@ static bool tcg_target_const_match(int64_t sval, int ct, if ((ct & TCG_CT_CONST_U16) && uval == (uint16_t)uval) { return 1; } + if ((ct & TCG_CT_CONST_N16) && -sval == (int16_t)-sval) { + return 1; + } if ((ct & TCG_CT_CONST_S32) && sval == (int32_t)sval) { return 1; } @@ -2863,21 +2867,69 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, ADDC | TAB(a0, a1, a2)); +} + +static void tgen_addco_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out32(s, ADDIC | TAI(a0, a1, a2)); +} + +static TCGConstraintSetIndex cset_addco(TCGType type, unsigned flags) +{ + /* + * Note that the CA bit is defined based on the word size of the + * environment. So in 64-bit mode it's always carry-out of bit 63. + * The fallback code using deposit works just as well for TCG_TYPE_I32. + */ + return type == TCG_TYPE_REG ? C_O1_I2(r, r, rI) : C_NotImplemented; +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addco, + .out_rrr = tgen_addco_rrr, + .out_rri = tgen_addco_rri, +}; + +static void tgen_addcio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, ADDE | TAB(a0, a1, a2)); +} + +static void tgen_addcio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out32(s, (a2 ? ADDME : ADDZE) | RT(a0) | RA(a1)); +} + +static TCGConstraintSetIndex cset_addcio(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_REG ? C_O1_I2(r, r, rZM) : C_NotImplemented; +} + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addcio, + .out_rrr = tgen_addcio_rrr, + .out_rri = tgen_addcio_rri, }; static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, -}; - -static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addcio, + .out_rrr = tgen_addcio_rrr, + .out_rri = tgen_addcio_rri, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out32(s, SUBFC | TAB(TCG_REG_R0, TCG_REG_R0, TCG_REG_R0)); } static void tgen_and(TCGContext *s, TCGType type, @@ -3284,21 +3336,94 @@ static const TCGOutOpSubtract outop_sub = { .out_rir = tgen_subfi, }; +static void tgen_subbo_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, SUBFC | TAB(a0, a2, a1)); +} + +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (a2 == 0) { + tcg_out_movi(s, type, TCG_REG_R0, 0); + tgen_subbo_rrr(s, type, a0, a1, TCG_REG_R0); + } else { + tgen_addco_rri(s, type, a0, a1, -a2); + } +} + +/* The underlying insn for subfi is subfic. */ +#define tgen_subbo_rir tgen_subfi + +static void tgen_subbo_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + tcg_out_movi(s, type, TCG_REG_R0, a2); + tgen_subbo_rir(s, type, a0, a1, TCG_REG_R0); +} + +static TCGConstraintSetIndex cset_subbo(TCGType type, unsigned flags) +{ + /* Recall that the CA bit is defined based on the host word size. */ + return type == TCG_TYPE_REG ? C_O1_I2(r, rI, rN) : C_NotImplemented; +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_subbo, + .out_rrr = tgen_subbo_rrr, + .out_rri = tgen_subbo_rri, + .out_rir = tgen_subbo_rir, + .out_rii = tgen_subbo_rii, }; -static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, -}; +static void tgen_subbio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out32(s, SUBFE | TAB(a0, a2, a1)); +} + +static void tgen_subbio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tgen_addcio_rri(s, type, a0, a1, ~a2); +} + +static void tgen_subbio_rir(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, TCGReg a2) +{ + tcg_debug_assert(a1 == 0 || a1 == -1); + tcg_out32(s, (a1 ? SUBFME : SUBFZE) | RT(a0) | RA(a2)); +} + +static void tgen_subbio_rii(TCGContext *s, TCGType type, + TCGReg a0, tcg_target_long a1, tcg_target_long a2) +{ + tcg_out_movi(s, type, TCG_REG_R0, a2); + tgen_subbio_rir(s, type, a0, a1, TCG_REG_R0); +} + +static TCGConstraintSetIndex cset_subbio(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_REG ? C_O1_I2(r, rZM, rZM) : C_NotImplemented; +} static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_subbio, + .out_rrr = tgen_subbio_rrr, + .out_rri = tgen_subbio_rri, + .out_rir = tgen_subbio_rir, + .out_rii = tgen_subbio_rii, }; +#define outop_subbi outop_subbio + static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + /* borrow = !carry */ + tcg_out32(s, ADDIC | TAI(TCG_REG_R0, TCG_REG_R0, 0)); } static void tgen_xor(TCGContext *s, TCGType type, @@ -3538,8 +3663,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1; - switch (opc) { case INDEX_op_goto_ptr: tcg_out32(s, MTSPR | RS(args[0]) | CTR); @@ -3635,57 +3758,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; -#if TCG_TARGET_REG_BITS == 64 - case INDEX_op_add2_i64: -#else - case INDEX_op_add2_i32: -#endif - /* Note that the CA bit is defined based on the word size of the - environment. So in 64-bit mode it's always carry-out of bit 63. - The fallback code using deposit works just as well for 32-bit. */ - a0 = args[0], a1 = args[1]; - if (a0 == args[3] || (!const_args[5] && a0 == args[5])) { - a0 = TCG_REG_R0; - } - if (const_args[4]) { - tcg_out32(s, ADDIC | TAI(a0, args[2], args[4])); - } else { - tcg_out32(s, ADDC | TAB(a0, args[2], args[4])); - } - if (const_args[5]) { - tcg_out32(s, (args[5] ? ADDME : ADDZE) | RT(a1) | RA(args[3])); - } else { - tcg_out32(s, ADDE | TAB(a1, args[3], args[5])); - } - if (a0 != args[0]) { - tcg_out_mov(s, TCG_TYPE_REG, args[0], a0); - } - break; - -#if TCG_TARGET_REG_BITS == 64 - case INDEX_op_sub2_i64: -#else - case INDEX_op_sub2_i32: -#endif - a0 = args[0], a1 = args[1]; - if (a0 == args[5] || (!const_args[3] && a0 == args[3])) { - a0 = TCG_REG_R0; - } - if (const_args[2]) { - tcg_out32(s, SUBFIC | TAI(a0, args[4], args[2])); - } else { - tcg_out32(s, SUBFC | TAB(a0, args[4], args[2])); - } - if (const_args[3]) { - tcg_out32(s, (args[3] ? SUBFME : SUBFZE) | RT(a1) | RA(args[5])); - } else { - tcg_out32(s, SUBFE | TAB(a1, args[5], args[3])); - } - if (a0 != args[0]) { - tcg_out_mov(s, TCG_TYPE_REG, args[0], a0); - } - break; - case INDEX_op_mb: tcg_out_mb(s, args[0]); break; @@ -4331,13 +4403,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_add2_i64: - case INDEX_op_add2_i32: - return C_O2_I4(r, r, r, r, rI, rZM); - case INDEX_op_sub2_i64: - case INDEX_op_sub2_i32: - return C_O2_I4(r, r, rI, rZM, r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i64: From 1b6e25e300e78cf8d8581245c2f8339c5b423d30 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 13:26:43 -0800 Subject: [PATCH 0494/2760] tcg/s390x: Honor carry_live in tcg_out_movi Do not clobber flags if they're live. Required in order to perform register allocation on add/sub carry opcodes. LA and AGHI are the same size, so use LA unconditionally. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target.c.inc | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index a30afb455e..e262876614 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -951,25 +951,32 @@ static void tcg_out_movi(TCGContext *s, TCGType type, if (pc_off == (int32_t)pc_off) { tcg_out_insn(s, RIL, LARL, ret, pc_off); if (sval & 1) { - tcg_out_insn(s, RI, AGHI, ret, 1); + tcg_out_insn(s, RX, LA, ret, ret, TCG_REG_NONE, 1); } return; } - /* Otherwise, load it by parts. */ - i = is_const_p16((uint32_t)uval); - if (i >= 0) { - tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16)); - } else { - tcg_out_insn(s, RIL, LLILF, ret, uval); - } - uval >>= 32; - i = is_const_p16(uval); - if (i >= 0) { - tcg_out_insn_RI(s, oi_insns[i + 2], ret, uval >> (i * 16)); - } else { - tcg_out_insn(s, RIL, OIHF, ret, uval); + if (!s->carry_live) { + /* Load by parts, at most 2 instructions. */ + i = is_const_p16((uint32_t)uval); + if (i >= 0) { + tcg_out_insn_RI(s, li_insns[i], ret, uval >> (i * 16)); + } else { + tcg_out_insn(s, RIL, LLILF, ret, uval); + } + uval >>= 32; + i = is_const_p16(uval); + if (i >= 0) { + tcg_out_insn_RI(s, oi_insns[i + 2], ret, uval >> (i * 16)); + } else { + tcg_out_insn(s, RIL, OIHF, ret, uval); + } + return; } + + /* Otherwise, stuff it in the constant pool. */ + tcg_out_insn(s, RIL, LGRL, ret, 0); + new_pool_label(s, sval, R_390_PC32DBL, s->code_ptr - 2, 2); } /* Emit a load/store type instruction. Inputs are: From 19b9fc2a39c733f585388918e4e093f08e2c33eb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 18 Jan 2025 14:01:12 -0800 Subject: [PATCH 0495/2760] tcg/s390x: Add TCG_CT_CONST_N32 We were using S32 | U32 for add2/sub2. But the ALGFI and SLGFI insns that implement this both have uint32_t immediates. This makes the composite range balanced and enables use of -0xffffffff ... -0x80000001. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target-con-set.h | 2 +- tcg/s390x/tcg-target-con-str.h | 1 + tcg/s390x/tcg-target.c.inc | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index 78f06e3e52..f5d3878070 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -44,4 +44,4 @@ C_O2_I2(o, m, 0, r) C_O2_I2(o, m, r, r) C_O2_I3(o, m, 0, 1, r) C_N1_O1_I4(r, r, 0, 1, ri, r) -C_N1_O1_I4(r, r, 0, 1, rJU, r) +C_N1_O1_I4(r, r, 0, 1, rUV, r) diff --git a/tcg/s390x/tcg-target-con-str.h b/tcg/s390x/tcg-target-con-str.h index 3e574e0662..636a38a168 100644 --- a/tcg/s390x/tcg-target-con-str.h +++ b/tcg/s390x/tcg-target-con-str.h @@ -24,4 +24,5 @@ CONST('M', TCG_CT_CONST_M1) CONST('N', TCG_CT_CONST_INV) CONST('R', TCG_CT_CONST_INVRISBG) CONST('U', TCG_CT_CONST_U32) +CONST('V', TCG_CT_CONST_N32) CONST('Z', TCG_CT_CONST_ZERO) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e262876614..9b28083945 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -43,6 +43,7 @@ #define TCG_CT_CONST_INVRISBG (1 << 14) #define TCG_CT_CONST_CMP (1 << 15) #define TCG_CT_CONST_M1 (1 << 16) +#define TCG_CT_CONST_N32 (1 << 17) #define ALL_GENERAL_REGS MAKE_64BIT_MASK(0, 16) #define ALL_VECTOR_REGS MAKE_64BIT_MASK(32, 32) @@ -613,7 +614,10 @@ static bool tcg_target_const_match(int64_t val, int ct, if ((ct & TCG_CT_CONST_S32) && val == (int32_t)val) { return true; } - if ((ct & TCG_CT_CONST_U32) && val == (uint32_t)val) { + if ((ct & TCG_CT_CONST_U32) && uval <= UINT32_MAX) { + return true; + } + if ((ct & TCG_CT_CONST_N32) && -uval <= UINT32_MAX) { return true; } if ((ct & TCG_CT_CONST_S16) && val == (int16_t)val) { @@ -3548,7 +3552,7 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_add2_i64: case INDEX_op_sub2_i64: - return C_N1_O1_I4(r, r, 0, 1, rJU, r); + return C_N1_O1_I4(r, r, 0, 1, rUV, r); case INDEX_op_st_vec: return C_O0_I2(v, r); From cda7f93fa2fbf52e0fc70e4078caf8e7f7d3bd6f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Jan 2025 09:31:26 -0800 Subject: [PATCH 0496/2760] tcg/s390x: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target-con-set.h | 4 +- tcg/s390x/tcg-target-has.h | 8 +- tcg/s390x/tcg-target.c.inc | 153 +++++++++++++++++++-------------- 3 files changed, 96 insertions(+), 69 deletions(-) diff --git a/tcg/s390x/tcg-target-con-set.h b/tcg/s390x/tcg-target-con-set.h index f5d3878070..f67fd7898e 100644 --- a/tcg/s390x/tcg-target-con-set.h +++ b/tcg/s390x/tcg-target-con-set.h @@ -22,6 +22,7 @@ C_O1_I1(r, r) C_O1_I1(v, r) C_O1_I1(v, v) C_O1_I1(v, vr) +C_O1_I2(r, 0, r) C_O1_I2(r, 0, ri) C_O1_I2(r, 0, rI) C_O1_I2(r, 0, rJ) @@ -32,6 +33,7 @@ C_O1_I2(r, r, rI) C_O1_I2(r, r, rJ) C_O1_I2(r, r, rK) C_O1_I2(r, r, rNKR) +C_O1_I2(r, r, rUV) C_O1_I2(r, rZ, r) C_O1_I2(v, v, r) C_O1_I2(v, v, v) @@ -43,5 +45,3 @@ C_O2_I1(o, m, r) C_O2_I2(o, m, 0, r) C_O2_I2(o, m, r, r) C_O2_I3(o, m, 0, 1, r) -C_N1_O1_I4(r, r, 0, 1, ri, r) -C_N1_O1_I4(r, r, 0, 1, rUV, r) diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 4a2b71995d..17e61130cd 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,13 +29,13 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 1 diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 9b28083945..67179de848 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -173,6 +173,8 @@ typedef enum S390Opcode { RRE_SLBGR = 0xb989, RRE_XGR = 0xb982, + RRFa_ALRK = 0xb9fa, + RRFa_ALGRK = 0xb9ea, RRFa_MGRK = 0xb9ec, RRFa_MSRKC = 0xb9fd, RRFa_MSGRKC = 0xb9ed, @@ -2259,21 +2261,60 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, ALGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, ALR, a0, a2); + } else { + tcg_out_insn(s, RRFa, ALRK, a0, a1, a2); + } +} + +static void tgen_addco_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, ALFI, a0, a2); + } else if (a2 >= 0) { + tcg_out_insn(s, RIL, ALGFI, a0, a2); + } else { + tcg_out_insn(s, RIL, SLGFI, a0, -a2); + } +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rUV), + .out_rrr = tgen_addco_rrr, + .out_rri = tgen_addco_rri, +}; + +static void tgen_addcio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRE, ALCR, a0, a2); + } else { + tcg_out_insn(s, RRE, ALCGR, a0, a2); + } +} + +static const TCGOutOpBinary outop_addcio = { + .base.static_constraint = C_O1_I2(r, 0, r), + .out_rrr = tgen_addcio, }; static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, -}; - -static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, r), + .out_rrr = tgen_addcio, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out_insn(s, RR, SLR, TCG_REG_R0, TCG_REG_R0); /* cc = 2 */ } static void tgen_and(TCGContext *s, TCGType type, @@ -2794,21 +2835,57 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static void tgen_subbo_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_insn(s, RRFa, SLGRK, a0, a1, a2); + } else if (a0 == a1) { + tcg_out_insn(s, RR, SLR, a0, a2); + } else { + tcg_out_insn(s, RRFa, SLRK, a0, a1, a2); + } +} + +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_mov(s, type, a0, a1); + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIL, SLFI, a0, a2); + } else if (a2 >= 0) { + tcg_out_insn(s, RIL, SLGFI, a0, a2); + } else { + tcg_out_insn(s, RIL, ALGFI, a0, -a2); + } +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rUV), + .out_rrr = tgen_subbo_rrr, + .out_rri = tgen_subbo_rri, }; -static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, -}; +static void tgen_subbio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RRE, SLBR, a0, a2); + } else { + tcg_out_insn(s, RRE, SLBGR, a0, a2); + } +} static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, 0, r), + .out_rrr = tgen_subbio, }; +#define outop_subbi outop_subbio + static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out_insn(s, RR, CLR, TCG_REG_R0, TCG_REG_R0); /* cc = 0 */ } static void tgen_xor(TCGContext *s, TCGType type, @@ -2967,23 +3044,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_add2_i32: - if (const_args[4]) { - tcg_out_insn(s, RIL, ALFI, args[0], args[4]); - } else { - tcg_out_insn(s, RR, ALR, args[0], args[4]); - } - tcg_out_insn(s, RRE, ALCR, args[1], args[5]); - break; - case INDEX_op_sub2_i32: - if (const_args[4]) { - tcg_out_insn(s, RIL, SLFI, args[0], args[4]); - } else { - tcg_out_insn(s, RR, SLR, args[0], args[4]); - } - tcg_out_insn(s, RRE, SLBR, args[1], args[5]); - break; - case INDEX_op_br: tgen_branch(s, S390_CC_ALWAYS, arg_label(args[0])); break; @@ -3027,31 +3087,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_add2_i64: - if (const_args[4]) { - if ((int64_t)args[4] >= 0) { - tcg_out_insn(s, RIL, ALGFI, args[0], args[4]); - } else { - tcg_out_insn(s, RIL, SLGFI, args[0], -args[4]); - } - } else { - tcg_out_insn(s, RRE, ALGR, args[0], args[4]); - } - tcg_out_insn(s, RRE, ALCGR, args[1], args[5]); - break; - case INDEX_op_sub2_i64: - if (const_args[4]) { - if ((int64_t)args[4] >= 0) { - tcg_out_insn(s, RIL, SLGFI, args[0], args[4]); - } else { - tcg_out_insn(s, RIL, ALGFI, args[0], -args[4]); - } - } else { - tcg_out_insn(s, RRE, SLGR, args[0], args[4]); - } - tcg_out_insn(s, RRE, SLBGR, args[1], args[5]); - break; - case INDEX_op_mb: /* The host memory model is quite strong, we simply need to serialize the instruction stream. */ @@ -3546,14 +3581,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(o, m, r); - case INDEX_op_add2_i32: - case INDEX_op_sub2_i32: - return C_N1_O1_I4(r, r, 0, 1, ri, r); - - case INDEX_op_add2_i64: - case INDEX_op_sub2_i64: - return C_N1_O1_I4(r, r, 0, 1, rUV, r); - case INDEX_op_st_vec: return C_O0_I2(v, r); case INDEX_op_ld_vec: From 41dd55c79c0a1b1a4bf573821b81d97e6d4c159a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 19 Jan 2025 10:01:18 -0800 Subject: [PATCH 0497/2760] tcg/s390x: Use ADD LOGICAL WITH SIGNED IMMEDIATE Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/s390x/tcg-target.c.inc | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 67179de848..09c7ca5b44 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -135,6 +135,9 @@ typedef enum S390Opcode { RIEc_CLGIJ = 0xec7d, RIEc_CLIJ = 0xec7f, + RIEd_ALHSIK = 0xecda, + RIEd_ALGHSIK = 0xecdb, + RIEf_RISBG = 0xec55, RIEg_LOCGHI = 0xec46, @@ -682,8 +685,16 @@ static void tcg_out_insn_RI(TCGContext *s, S390Opcode op, TCGReg r1, int i2) tcg_out32(s, (op << 16) | (r1 << 20) | (i2 & 0xffff)); } +static void tcg_out_insn_RIEd(TCGContext *s, S390Opcode op, + TCGReg r1, TCGReg r3, int i2) +{ + tcg_out16(s, (op & 0xff00) | (r1 << 4) | r3); + tcg_out16(s, i2); + tcg_out16(s, op & 0xff); +} + static void tcg_out_insn_RIEg(TCGContext *s, S390Opcode op, TCGReg r1, - int i2, int m3) + int i2, int m3) { tcg_out16(s, (op & 0xff00) | (r1 << 4) | m3); tcg_out32(s, (i2 << 16) | (op & 0xff)); @@ -2276,6 +2287,15 @@ static void tgen_addco_rrr(TCGContext *s, TCGType type, static void tgen_addco_rri(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1, tcg_target_long a2) { + if (a2 == (int16_t)a2) { + if (type == TCG_TYPE_I32) { + tcg_out_insn(s, RIEd, ALHSIK, a0, a1, a2); + } else { + tcg_out_insn(s, RIEd, ALGHSIK, a0, a1, a2); + } + return; + } + tcg_out_mov(s, type, a0, a1); if (type == TCG_TYPE_I32) { tcg_out_insn(s, RIL, ALFI, a0, a2); From 809069eaa3d803092adaa06cec770d78db44211d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 16:34:47 -0800 Subject: [PATCH 0498/2760] tcg/sparc64: Hoist tcg_cond_to_bcond lookup out of tcg_out_movcc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the sparc COND_* value not the tcg TCG_COND_* value. This makes the usage within add2/sub2 clearer. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 12f0dbd23d..3f97261626 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -652,11 +652,10 @@ static void tcg_out_brcond_i32(TCGContext *s, TCGCond cond, TCGReg arg1, tcg_out_nop(s); } -static void tcg_out_movcc(TCGContext *s, TCGCond cond, int cc, TCGReg ret, +static void tcg_out_movcc(TCGContext *s, int scond, int cc, TCGReg ret, int32_t v1, int v1const) { - tcg_out32(s, ARITH_MOVCC | cc | INSN_RD(ret) - | INSN_RS1(tcg_cond_to_bcond[cond]) + tcg_out32(s, ARITH_MOVCC | cc | INSN_RD(ret) | INSN_RS1(scond) | (v1const ? INSN_IMM11(v1) : INSN_RS2(v1))); } @@ -665,7 +664,7 @@ static void tcg_out_movcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, int32_t v1, int v1const) { tcg_out_cmp(s, cond, c1, c2, c2const); - tcg_out_movcc(s, cond, MOVCC_ICC, ret, v1, v1const); + tcg_out_movcc(s, tcg_cond_to_bcond[cond], MOVCC_ICC, ret, v1, v1const); } static void tcg_out_brcond_i64(TCGContext *s, TCGCond cond, TCGReg arg1, @@ -709,7 +708,7 @@ static void tcg_out_movcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, tcg_out_movr(s, rcond, ret, c1, v1, v1const); } else { tcg_out_cmp(s, cond, c1, c2, c2const); - tcg_out_movcc(s, cond, MOVCC_XCC, ret, v1, v1const); + tcg_out_movcc(s, tcg_cond_to_bcond[cond], MOVCC_XCC, ret, v1, v1const); } } @@ -763,7 +762,8 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, default: tcg_out_cmp(s, cond, c1, c2, c2const); tcg_out_movi_s13(s, ret, 0); - tcg_out_movcc(s, cond, MOVCC_ICC, ret, neg ? -1 : 1, 1); + tcg_out_movcc(s, tcg_cond_to_bcond[cond], + MOVCC_ICC, ret, neg ? -1 : 1, 1); return; } @@ -818,7 +818,8 @@ static void tcg_out_setcond_i64(TCGContext *s, TCGCond cond, TCGReg ret, } else { tcg_out_cmp(s, cond, c1, c2, c2const); tcg_out_movi_s13(s, ret, 0); - tcg_out_movcc(s, cond, MOVCC_XCC, ret, neg ? -1 : 1, 1); + tcg_out_movcc(s, tcg_cond_to_bcond[cond], + MOVCC_XCC, ret, neg ? -1 : 1, 1); } } @@ -956,10 +957,10 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh, if (rh == ah) { tcg_out_arithi(s, TCG_REG_T2, ah, 1, is_sub ? ARITH_SUB : ARITH_ADD); - tcg_out_movcc(s, TCG_COND_LTU, MOVCC_XCC, rh, TCG_REG_T2, 0); + tcg_out_movcc(s, COND_CS, MOVCC_XCC, rh, TCG_REG_T2, 0); } else { tcg_out_arithi(s, rh, ah, 1, is_sub ? ARITH_SUB : ARITH_ADD); - tcg_out_movcc(s, TCG_COND_GEU, MOVCC_XCC, rh, ah, 0); + tcg_out_movcc(s, COND_CC, MOVCC_XCC, rh, ah, 0); } } else { /* @@ -974,7 +975,7 @@ static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh, is_sub ? ARITH_SUB : ARITH_ADD); } /* ... smoosh T2 back to original BH if carry is clear ... */ - tcg_out_movcc(s, TCG_COND_GEU, MOVCC_XCC, TCG_REG_T2, bh, bhconst); + tcg_out_movcc(s, COND_CC, MOVCC_XCC, TCG_REG_T2, bh, bhconst); /* ... and finally perform the arithmetic with the new operand. */ tcg_out_arith(s, rh, ah, TCG_REG_T2, is_sub ? ARITH_SUB : ARITH_ADD); } From 9dd1ea33b238d8b661b7541ebdb122b7cae6fd19 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 18:48:06 -0800 Subject: [PATCH 0499/2760] tcg/sparc64: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target-con-set.h | 3 +- tcg/sparc64/tcg-target-has.h | 8 +- tcg/sparc64/tcg-target.c.inc | 300 ++++++++++++++++++++----------- 3 files changed, 201 insertions(+), 110 deletions(-) diff --git a/tcg/sparc64/tcg-target-con-set.h b/tcg/sparc64/tcg-target-con-set.h index 8cec396173..1a57adc0e8 100644 --- a/tcg/sparc64/tcg-target-con-set.h +++ b/tcg/sparc64/tcg-target-con-set.h @@ -15,6 +15,7 @@ C_O0_I2(r, rJ) C_O1_I1(r, r) C_O1_I2(r, r, r) C_O1_I2(r, r, rJ) +C_O1_I2(r, rz, rJ) +C_O1_I2(r, rz, rz) C_O1_I4(r, r, rJ, rI, 0) C_O2_I2(r, r, r, r) -C_O2_I4(r, r, rz, rz, rJ, rJ) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index b8760dd154..caf7679595 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,13 +14,13 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 3f97261626..c2251a6927 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -199,7 +199,9 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) #define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) #define ARITH_ADDC (INSN_OP(2) | INSN_OP3(0x08)) +#define ARITH_ADDCCC (INSN_OP(2) | INSN_OP3(0x18)) #define ARITH_SUBC (INSN_OP(2) | INSN_OP3(0x0c)) +#define ARITH_SUBCCC (INSN_OP(2) | INSN_OP3(0x1c)) #define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) #define ARITH_SMUL (INSN_OP(2) | INSN_OP3(0x0b)) #define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) @@ -211,6 +213,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define ARITH_MOVR (INSN_OP(2) | INSN_OP3(0x2f)) #define ARITH_ADDXC (INSN_OP(2) | INSN_OP3(0x36) | INSN_OPF(0x11)) +#define ARITH_ADDXCCC (INSN_OP(2) | INSN_OP3(0x36) | INSN_OPF(0x13)) #define ARITH_UMULXHI (INSN_OP(2) | INSN_OP3(0x36) | INSN_OPF(0x16)) #define SHIFT_SLL (INSN_OP(2) | INSN_OP3(0x25)) @@ -223,6 +226,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define RDY (INSN_OP(2) | INSN_OP3(0x28) | INSN_RS1(0)) #define WRY (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(0)) +#define WRCCR (INSN_OP(2) | INSN_OP3(0x30) | INSN_RD(2)) #define JMPL (INSN_OP(2) | INSN_OP3(0x38)) #define RETURN (INSN_OP(2) | INSN_OP3(0x39)) #define SAVE (INSN_OP(2) | INSN_OP3(0x3c)) @@ -366,7 +370,7 @@ static void tcg_out_arithi(TCGContext *s, TCGReg rd, TCGReg rs1, } static void tcg_out_arithc(TCGContext *s, TCGReg rd, TCGReg rs1, - int32_t val2, int val2const, int op) + int32_t val2, int val2const, int op) { tcg_out32(s, op | INSN_RD(rd) | INSN_RS1(rs1) | (val2const ? INSN_IMM13(val2) : INSN_RS2(val2))); @@ -733,7 +737,7 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, } c1 = TCG_REG_G0, c2const = 0; cond = (cond == TCG_COND_EQ ? TCG_COND_GEU : TCG_COND_LTU); - break; + break; case TCG_COND_TSTEQ: case TCG_COND_TSTNE: @@ -742,7 +746,7 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGReg ret, c1 = TCG_REG_G0; c2 = TCG_REG_T1, c2const = 0; cond = (cond == TCG_COND_TSTEQ ? TCG_COND_GEU : TCG_COND_LTU); - break; + break; case TCG_COND_GTU: case TCG_COND_LEU: @@ -915,74 +919,6 @@ static const TCGOutOpMovcond outop_movcond = { .out = tgen_movcond, }; -static void tcg_out_addsub2_i32(TCGContext *s, TCGReg rl, TCGReg rh, - TCGReg al, TCGReg ah, int32_t bl, int blconst, - int32_t bh, int bhconst, int opl, int oph) -{ - TCGReg tmp = TCG_REG_T1; - - /* Note that the low parts are fully consumed before tmp is set. */ - if (rl != ah && (bhconst || rl != bh)) { - tmp = rl; - } - - tcg_out_arithc(s, tmp, al, bl, blconst, opl); - tcg_out_arithc(s, rh, ah, bh, bhconst, oph); - tcg_out_mov(s, TCG_TYPE_I32, rl, tmp); -} - -static void tcg_out_addsub2_i64(TCGContext *s, TCGReg rl, TCGReg rh, - TCGReg al, TCGReg ah, int32_t bl, int blconst, - int32_t bh, int bhconst, bool is_sub) -{ - TCGReg tmp = TCG_REG_T1; - - /* Note that the low parts are fully consumed before tmp is set. */ - if (rl != ah && (bhconst || rl != bh)) { - tmp = rl; - } - - tcg_out_arithc(s, tmp, al, bl, blconst, is_sub ? ARITH_SUBCC : ARITH_ADDCC); - - if (use_vis3_instructions && !is_sub) { - /* Note that ADDXC doesn't accept immediates. */ - if (bhconst && bh != 0) { - tcg_out_movi_s13(s, TCG_REG_T2, bh); - bh = TCG_REG_T2; - } - tcg_out_arith(s, rh, ah, bh, ARITH_ADDXC); - } else if (bh == TCG_REG_G0) { - /* If we have a zero, we can perform the operation in two insns, - with the arithmetic first, and a conditional move into place. */ - if (rh == ah) { - tcg_out_arithi(s, TCG_REG_T2, ah, 1, - is_sub ? ARITH_SUB : ARITH_ADD); - tcg_out_movcc(s, COND_CS, MOVCC_XCC, rh, TCG_REG_T2, 0); - } else { - tcg_out_arithi(s, rh, ah, 1, is_sub ? ARITH_SUB : ARITH_ADD); - tcg_out_movcc(s, COND_CC, MOVCC_XCC, rh, ah, 0); - } - } else { - /* - * Otherwise adjust BH as if there is carry into T2. - * Note that constant BH is constrained to 11 bits for the MOVCC, - * so the adjustment fits 12 bits. - */ - if (bhconst) { - tcg_out_movi_s13(s, TCG_REG_T2, bh + (is_sub ? -1 : 1)); - } else { - tcg_out_arithi(s, TCG_REG_T2, bh, 1, - is_sub ? ARITH_SUB : ARITH_ADD); - } - /* ... smoosh T2 back to original BH if carry is clear ... */ - tcg_out_movcc(s, COND_CC, MOVCC_XCC, TCG_REG_T2, bh, bhconst); - /* ... and finally perform the arithmetic with the new operand. */ - tcg_out_arith(s, rh, ah, TCG_REG_T2, is_sub ? ARITH_SUB : ARITH_ADD); - } - - tcg_out_mov(s, TCG_TYPE_I64, rl, tmp); -} - static void tcg_out_jmpl_const(TCGContext *s, const tcg_insn_unit *dest, bool in_prologue, bool tail_call) { @@ -1382,21 +1318,132 @@ static const TCGOutOpBinary outop_add = { .out_rri = tgen_addi, }; +static void tgen_addco_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_ADDCC); +} + +static void tgen_addco_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_ADDCC); +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, r, rJ), + .out_rrr = tgen_addco_rrr, + .out_rri = tgen_addco_rri, }; +static void tgen_addci_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_arith(s, a0, a1, a2, ARITH_ADDC); + } else if (use_vis3_instructions) { + tcg_out_arith(s, a0, a1, a2, ARITH_ADDXC); + } else { + tcg_out_arith(s, TCG_REG_T1, a1, a2, ARITH_ADD); /* for CC */ + tcg_out_arithi(s, a0, TCG_REG_T1, 1, ARITH_ADD); /* for CS */ + /* Select the correct result based on actual carry value. */ + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, TCG_REG_T1, false); + } +} + +static void tgen_addci_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_arithi(s, a0, a1, a2, ARITH_ADDC); + return; + } + /* !use_vis3_instructions */ + if (a2 != 0) { + tcg_out_arithi(s, TCG_REG_T1, a1, a2, ARITH_ADD); /* for CC */ + tcg_out_arithi(s, a0, TCG_REG_T1, 1, ARITH_ADD); /* for CS */ + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, TCG_REG_T1, false); + } else if (a0 == a1) { + tcg_out_arithi(s, TCG_REG_T1, a1, 1, ARITH_ADD); + tcg_out_movcc(s, COND_CS, MOVCC_XCC, a0, TCG_REG_T1, false); + } else { + tcg_out_arithi(s, a0, a1, 1, ARITH_ADD); + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, a1, false); + } +} + +static TCGConstraintSetIndex cset_addci(TCGType type, unsigned flags) +{ + if (use_vis3_instructions && type == TCG_TYPE_I64) { + /* Note that ADDXC doesn't accept immediates. */ + return C_O1_I2(r, rz, rz); + } + return C_O1_I2(r, rz, rJ); +} + static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addci, + .out_rrr = tgen_addci_rrr, + .out_rri = tgen_addci_rri, }; +/* Copy %xcc.c to %icc.c */ +static void tcg_out_dup_xcc_c(TCGContext *s) +{ + if (use_vis3_instructions) { + tcg_out_arith(s, TCG_REG_T1, TCG_REG_G0, TCG_REG_G0, ARITH_ADDXC); + } else { + tcg_out_movi_s13(s, TCG_REG_T1, 0); + tcg_out_movcc(s, COND_CS, MOVCC_XCC, TCG_REG_T1, 1, true); + } + /* Write carry-in into %icc via {0,1} + -1. */ + tcg_out_arithi(s, TCG_REG_G0, TCG_REG_T1, -1, ARITH_ADDCC); +} + +static void tgen_addcio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + if (use_vis3_instructions) { + tcg_out_arith(s, a0, a1, a2, ARITH_ADDXCCC); + return; + } + tcg_out_dup_xcc_c(s); + } + tcg_out_arith(s, a0, a1, a2, ARITH_ADDCCC); +} + +static void tgen_addcio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type != TCG_TYPE_I32) { + /* !use_vis3_instructions */ + tcg_out_dup_xcc_c(s); + } + tcg_out_arithi(s, a0, a1, a2, ARITH_ADDCCC); +} + +static TCGConstraintSetIndex cset_addcio(TCGType type, unsigned flags) +{ + if (use_vis3_instructions && type == TCG_TYPE_I64) { + /* Note that ADDXCCC doesn't accept immediates. */ + return C_O1_I2(r, rz, rz); + } + return C_O1_I2(r, rz, rJ); +} + static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addcio, + .out_rrr = tgen_addcio_rrr, + .out_rri = tgen_addcio_rri, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + /* 0x11 -> xcc = nzvC, icc = nzvC */ + tcg_out_arithi(s, 0, TCG_REG_G0, 0x11, WRCCR); } static void tgen_and(TCGContext *s, TCGType type, @@ -1735,21 +1782,90 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static void tgen_subbo_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_arith(s, a0, a1, a2, ARITH_SUBCC); +} + +static void tgen_subbo_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + tcg_out_arithi(s, a0, a1, a2, ARITH_SUBCC); +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rJ), + .out_rrr = tgen_subbo_rrr, + .out_rri = tgen_subbo_rri, }; +static void tgen_subbi_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + /* TODO: OSA 2015 added SUBXC */ + if (type == TCG_TYPE_I32) { + tcg_out_arith(s, a0, a1, a2, ARITH_SUBC); + } else { + tcg_out_arith(s, TCG_REG_T1, a1, a2, ARITH_SUB); /* for CC */ + tcg_out_arithi(s, a0, TCG_REG_T1, 1, ARITH_SUB); /* for CS */ + /* Select the correct result based on actual borrow value. */ + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, TCG_REG_T1, false); + } +} + +static void tgen_subbi_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type == TCG_TYPE_I32) { + tcg_out_arithi(s, a0, a1, a2, ARITH_SUBC); + } else if (a2 != 0) { + tcg_out_arithi(s, TCG_REG_T1, a1, a2, ARITH_SUB); /* for CC */ + tcg_out_arithi(s, a0, TCG_REG_T1, 1, ARITH_SUB); /* for CS */ + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, TCG_REG_T1, false); + } else if (a0 == a1) { + tcg_out_arithi(s, TCG_REG_T1, a1, 1, ARITH_SUB); + tcg_out_movcc(s, COND_CS, MOVCC_XCC, a0, TCG_REG_T1, false); + } else { + tcg_out_arithi(s, a0, a1, 1, ARITH_SUB); + tcg_out_movcc(s, COND_CC, MOVCC_XCC, a0, a1, false); + } +} + static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rJ), + .out_rrr = tgen_subbi_rrr, + .out_rri = tgen_subbi_rri, }; +static void tgen_subbio_rrr(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + if (type != TCG_TYPE_I32) { + /* TODO: OSA 2015 added SUBXCCC */ + tcg_out_dup_xcc_c(s); + } + tcg_out_arith(s, a0, a1, a2, ARITH_SUBCCC); +} + +static void tgen_subbio_rri(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, tcg_target_long a2) +{ + if (type != TCG_TYPE_I32) { + tcg_out_dup_xcc_c(s); + } + tcg_out_arithi(s, a0, a1, a2, ARITH_SUBCCC); +} + static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_O1_I2(r, rz, rJ), + .out_rrr = tgen_subbio_rrr, + .out_rri = tgen_subbio_rri, }; static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out_set_carry(s); /* borrow == carry */ } static void tgen_xor(TCGContext *s, TCGType type, @@ -1886,17 +2002,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STW); break; - case INDEX_op_add2_i32: - tcg_out_addsub2_i32(s, args[0], args[1], args[2], args[3], - args[4], const_args[4], args[5], const_args[5], - ARITH_ADDCC, ARITH_ADDC); - break; - case INDEX_op_sub2_i32: - tcg_out_addsub2_i32(s, args[0], args[1], args[2], args[3], - args[4], const_args[4], args[5], const_args[5], - ARITH_SUBCC, ARITH_SUBC); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -1920,15 +2025,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STX); break; - case INDEX_op_add2_i64: - tcg_out_addsub2_i64(s, args[0], args[1], args[2], args[3], args[4], - const_args[4], args[5], const_args[5], false); - break; - case INDEX_op_sub2_i64: - tcg_out_addsub2_i64(s, args[0], args[1], args[2], args[3], args[4], - const_args[4], args[5], const_args[5], true); - break; - case INDEX_op_mb: tcg_out_mb(s, a0); break; @@ -1975,12 +2071,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - return C_O2_I4(r, r, rz, rz, rJ, rJ); - default: return C_NotImplemented; } From 4b0ee858be252ed272a758e5b6f894717e911d51 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 19:46:04 -0800 Subject: [PATCH 0500/2760] tcg/tci: Implement add/sub carry opcodes Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tci.c | 120 +++++++++++++++++------------------ tcg/tci/tcg-target-has.h | 8 +-- tcg/tci/tcg-target-opc.h.inc | 1 + tcg/tci/tcg-target.c.inc | 97 +++++++++++++++++----------- 4 files changed, 125 insertions(+), 101 deletions(-) diff --git a/tcg/tci.c b/tcg/tci.c index dc916eb112..a18478a07a 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -179,17 +179,6 @@ static void tci_args_rrrrrc(uint32_t insn, TCGReg *r0, TCGReg *r1, *c5 = extract32(insn, 28, 4); } -static void tci_args_rrrrrr(uint32_t insn, TCGReg *r0, TCGReg *r1, - TCGReg *r2, TCGReg *r3, TCGReg *r4, TCGReg *r5) -{ - *r0 = extract32(insn, 8, 4); - *r1 = extract32(insn, 12, 4); - *r2 = extract32(insn, 16, 4); - *r3 = extract32(insn, 20, 4); - *r4 = extract32(insn, 24, 4); - *r5 = extract32(insn, 28, 4); -} - static bool tci_compare32(uint32_t u0, uint32_t u1, TCGCond condition) { bool result = false; @@ -361,6 +350,7 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tcg_target_ulong regs[TCG_TARGET_NB_REGS]; uint64_t stack[(TCG_STATIC_CALL_ARGS_SIZE + TCG_STATIC_FRAME_SIZE) / sizeof(uint64_t)]; + bool carry = false; regs[TCG_AREG0] = (tcg_target_ulong)env; regs[TCG_REG_CALL_STACK] = (uintptr_t)stack; @@ -369,13 +359,12 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, for (;;) { uint32_t insn; TCGOpcode opc; - TCGReg r0, r1, r2, r3, r4, r5; + TCGReg r0, r1, r2, r3, r4; tcg_target_ulong t1; TCGCond condition; uint8_t pos, len; uint32_t tmp32; uint64_t tmp64, taddr; - uint64_t T1, T2; MemOpIdx oi; int32_t ofs; void *ptr; @@ -444,9 +433,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, #if TCG_TARGET_REG_BITS == 32 case INDEX_op_setcond2_i32: tci_args_rrrrrc(insn, &r0, &r1, &r2, &r3, &r4, &condition); - T1 = tci_uint64(regs[r2], regs[r1]); - T2 = tci_uint64(regs[r4], regs[r3]); - regs[r0] = tci_compare64(T1, T2, condition); + regs[r0] = tci_compare64(tci_uint64(regs[r2], regs[r1]), + tci_uint64(regs[r4], regs[r3]), + condition); break; #elif TCG_TARGET_REG_BITS == 64 case INDEX_op_setcond: @@ -471,6 +460,9 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rl(insn, tb_ptr, &r0, &ptr); regs[r0] = *(tcg_target_ulong *)ptr; break; + case INDEX_op_tci_setcarry: + carry = true; + break; /* Load/store operations (32 bit). */ @@ -575,6 +567,46 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rr(insn, &r0, &r1); regs[r0] = ctpop_tr(regs[r1]); break; + case INDEX_op_addco: + tci_args_rrr(insn, &r0, &r1, &r2); + t1 = regs[r1] + regs[r2]; + carry = t1 < regs[r1]; + regs[r0] = t1; + break; + case INDEX_op_addci: + tci_args_rrr(insn, &r0, &r1, &r2); + regs[r0] = regs[r1] + regs[r2] + carry; + break; + case INDEX_op_addcio: + tci_args_rrr(insn, &r0, &r1, &r2); + if (carry) { + t1 = regs[r1] + regs[r2] + 1; + carry = t1 <= regs[r1]; + } else { + t1 = regs[r1] + regs[r2]; + carry = t1 < regs[r1]; + } + regs[r0] = t1; + break; + case INDEX_op_subbo: + tci_args_rrr(insn, &r0, &r1, &r2); + carry = regs[r1] < regs[r2]; + regs[r0] = regs[r1] - regs[r2]; + break; + case INDEX_op_subbi: + tci_args_rrr(insn, &r0, &r1, &r2); + regs[r0] = regs[r1] - regs[r2] - carry; + break; + case INDEX_op_subbio: + tci_args_rrr(insn, &r0, &r1, &r2); + if (carry) { + carry = regs[r1] <= regs[r2]; + regs[r0] = regs[r1] - regs[r2] - 1; + } else { + carry = regs[r1] < regs[r2]; + regs[r0] = regs[r1] - regs[r2]; + } + break; case INDEX_op_muls2: tci_args_rrrr(insn, &r0, &r1, &r2, &r3); #if TCG_TARGET_REG_BITS == 32 @@ -673,22 +705,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tb_ptr = ptr; } break; -#if TCG_TARGET_REG_BITS == 32 || TCG_TARGET_HAS_add2_i32 - case INDEX_op_add2_i32: - tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); - T1 = tci_uint64(regs[r3], regs[r2]); - T2 = tci_uint64(regs[r5], regs[r4]); - tci_write_reg64(regs, r1, r0, T1 + T2); - break; -#endif -#if TCG_TARGET_REG_BITS == 32 || TCG_TARGET_HAS_sub2_i32 - case INDEX_op_sub2_i32: - tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); - T1 = tci_uint64(regs[r3], regs[r2]); - T2 = tci_uint64(regs[r5], regs[r4]); - tci_write_reg64(regs, r1, r0, T1 - T2); - break; -#endif case INDEX_op_bswap16: tci_args_rr(insn, &r0, &r1); regs[r0] = bswap16(regs[r1]); @@ -742,24 +758,6 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tci_args_rrr(insn, &r0, &r1, &r2); regs[r0] = regs[r1] ? ctz64(regs[r1]) : regs[r2]; break; -#if TCG_TARGET_HAS_add2_i64 - case INDEX_op_add2_i64: - tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); - T1 = regs[r2] + regs[r4]; - T2 = regs[r3] + regs[r5] + (T1 < regs[r2]); - regs[r0] = T1; - regs[r1] = T2; - break; -#endif -#if TCG_TARGET_HAS_add2_i64 - case INDEX_op_sub2_i64: - tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); - T1 = regs[r2] - regs[r4]; - T2 = regs[r3] - regs[r5] - (regs[r2] < regs[r4]); - regs[r0] = T1; - regs[r1] = T2; - break; -#endif /* Shift/rotate operations (64 bit). */ @@ -908,7 +906,7 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) const char *op_name; uint32_t insn; TCGOpcode op; - TCGReg r0, r1, r2, r3, r4, r5; + TCGReg r0, r1, r2, r3, r4; tcg_target_ulong i1; int32_t s2; TCGCond c; @@ -968,6 +966,10 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) op_name, str_r(r0), ptr); break; + case INDEX_op_tci_setcarry: + info->fprintf_func(info->stream, "%-12s", op_name); + break; + case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: @@ -1007,6 +1009,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) break; case INDEX_op_add: + case INDEX_op_addci: + case INDEX_op_addcio: + case INDEX_op_addco: case INDEX_op_and: case INDEX_op_andc: case INDEX_op_clz: @@ -1027,6 +1032,9 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_shl: case INDEX_op_shr: case INDEX_op_sub: + case INDEX_op_subbi: + case INDEX_op_subbio: + case INDEX_op_subbo: case INDEX_op_xor: case INDEX_op_tci_ctz32: case INDEX_op_tci_clz32: @@ -1071,16 +1079,6 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) str_r(r2), str_r(r3)); break; - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - tci_args_rrrrrr(insn, &r0, &r1, &r2, &r3, &r4, &r5); - info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s, %s, %s", - op_name, str_r(r0), str_r(r1), str_r(r2), - str_r(r3), str_r(r4), str_r(r5)); - break; - case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: if (TCG_TARGET_REG_BITS == 32) { diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 6063f32f7b..310d45ba62 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -8,13 +8,13 @@ #define TCG_TARGET_HAS_H #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i32 1 -#define TCG_TARGET_HAS_sub2_i32 1 +#define TCG_TARGET_HAS_add2_i32 0 +#define TCG_TARGET_HAS_sub2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 1 -#define TCG_TARGET_HAS_sub2_i64 1 +#define TCG_TARGET_HAS_add2_i64 0 +#define TCG_TARGET_HAS_sub2_i64 0 #endif /* TCG_TARGET_REG_BITS == 64 */ #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/tci/tcg-target-opc.h.inc b/tcg/tci/tcg-target-opc.h.inc index 672d9b7323..4eb32ed736 100644 --- a/tcg/tci/tcg-target-opc.h.inc +++ b/tcg/tci/tcg-target-opc.h.inc @@ -2,6 +2,7 @@ /* These opcodes for use between the tci generator and interpreter. */ DEF(tci_movi, 1, 0, 1, TCG_OPF_NOT_PRESENT) DEF(tci_movl, 1, 0, 1, TCG_OPF_NOT_PRESENT) +DEF(tci_setcarry, 0, 0, 0, TCG_OPF_NOT_PRESENT) DEF(tci_clz32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_ctz32, 1, 2, 0, TCG_OPF_NOT_PRESENT) DEF(tci_divs32, 1, 2, 0, TCG_OPF_NOT_PRESENT) diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index bba96d7a19..35c0c91f3e 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -66,12 +66,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i64: return C_O0_I2(r, r); - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - return C_O2_I4(r, r, r, r, r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i64: @@ -346,22 +340,6 @@ static void tcg_out_op_rrrrrc(TCGContext *s, TCGOpcode op, tcg_out32(s, insn); } -static void tcg_out_op_rrrrrr(TCGContext *s, TCGOpcode op, - TCGReg r0, TCGReg r1, TCGReg r2, - TCGReg r3, TCGReg r4, TCGReg r5) -{ - tcg_insn_unit insn = 0; - - insn = deposit32(insn, 0, 8, op); - insn = deposit32(insn, 8, 4, r0); - insn = deposit32(insn, 12, 4, r1); - insn = deposit32(insn, 16, 4, r2); - insn = deposit32(insn, 20, 4, r3); - insn = deposit32(insn, 24, 4, r4); - insn = deposit32(insn, 28, 4, r5); - tcg_out32(s, insn); -} - static void tcg_out_ldst(TCGContext *s, TCGOpcode op, TCGReg val, TCGReg base, intptr_t offset) { @@ -573,21 +551,50 @@ static const TCGOutOpBinary outop_add = { .out_rrr = tgen_add, }; +static TCGConstraintSetIndex cset_addsubcarry(TCGType type, unsigned flags) +{ + return type == TCG_TYPE_REG ? C_O1_I2(r, r, r) : C_NotImplemented; +} + +static void tgen_addco(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_addco, a0, a1, a2); +} + static const TCGOutOpBinary outop_addco = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_addco, }; +static void tgen_addci(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_addci, a0, a1, a2); +} + static const TCGOutOpAddSubCarry outop_addci = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_addci, }; +static void tgen_addcio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_addcio, a0, a1, a2); +} + static const TCGOutOpBinary outop_addcio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_addcio, }; static void tcg_out_set_carry(TCGContext *s) { - g_assert_not_reached(); + tcg_out_op_v(s, INDEX_op_tci_setcarry); } static void tgen_and(TCGContext *s, TCGType type, @@ -910,21 +917,45 @@ static const TCGOutOpSubtract outop_sub = { .out_rrr = tgen_sub, }; +static void tgen_subbo(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_subbo, a0, a1, a2); +} + static const TCGOutOpAddSubCarry outop_subbo = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_subbo, }; +static void tgen_subbi(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_subbi, a0, a1, a2); +} + static const TCGOutOpAddSubCarry outop_subbi = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_subbi, }; +static void tgen_subbio(TCGContext *s, TCGType type, + TCGReg a0, TCGReg a1, TCGReg a2) +{ + tcg_out_op_rrr(s, INDEX_op_subbio, a0, a1, a2); +} + static const TCGOutOpAddSubCarry outop_subbio = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_addsubcarry, + .out_rrr = tgen_subbio, }; static void tcg_out_set_borrow(TCGContext *s) { - g_assert_not_reached(); + tcg_out_op_v(s, INDEX_op_tci_setcarry); /* borrow == carry */ } static void tgen_xor(TCGContext *s, TCGType type, @@ -1129,12 +1160,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, opc, args[0], args[1], args[2]); break; - CASE_32_64(add2) - CASE_32_64(sub2) - tcg_out_op_rrrrrr(s, opc, args[0], args[1], args[2], - args[3], args[4], args[5]); - break; - case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: if (TCG_TARGET_REG_BITS == 32) { From f2b1708e8080ab1beb0a2bf52a79a51e8de335cb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 20:15:31 -0800 Subject: [PATCH 0501/2760] tcg: Remove add2/sub2 opcodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All uses have been replaced by add/sub carry opcodes. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 14 ++--- include/tcg/tcg-opc.h | 5 -- tcg/aarch64/tcg-target-has.h | 5 -- tcg/arm/tcg-target-has.h | 4 -- tcg/i386/tcg-target-has.h | 5 -- tcg/loongarch64/tcg-target-has.h | 4 -- tcg/mips/tcg-target-has.h | 5 -- tcg/optimize.c | 87 -------------------------------- tcg/ppc/tcg-target-has.h | 4 -- tcg/riscv/tcg-target-has.h | 5 -- tcg/s390x/tcg-target-has.h | 7 --- tcg/sparc64/tcg-target-has.h | 7 --- tcg/tcg-has.h | 2 - tcg/tcg-op.c | 26 ---------- tcg/tcg.c | 36 ------------- tcg/tci/tcg-target-has.h | 4 -- 16 files changed, 3 insertions(+), 217 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index 93bcc70639..a7147407de 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -654,14 +654,6 @@ Multiword arithmetic support code generator will use ``tcg_out_set_borrow`` and then the output routine for *subbio*. - * - add2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* - - sub2_i32/i64 *t0_low*, *t0_high*, *t1_low*, *t1_high*, *t2_low*, *t2_high* - - - | Similar to add/sub, except that the double-word inputs *t1* and *t2* are - formed from two single-word arguments, and the double-word output *t0* - is returned in two single-word outputs. - * - mulu2 *t0_low*, *t0_high*, *t1*, *t2* - | Similar to mul, except two unsigned inputs *t1* and *t2* yielding the full @@ -952,9 +944,9 @@ Assumptions The target word size (``TCG_TARGET_REG_BITS``) is expected to be 32 bit or 64 bit. It is expected that the pointer has the same size as the word. -On a 32 bit target, all 64 bit operations are converted to 32 bits. A -few specific operations must be implemented to allow it (see add2_i32, -sub2_i32, brcond2_i32). +On a 32 bit target, all 64 bit operations are converted to 32 bits. +A few specific operations must be implemented to allow it +(see brcond2_i32, setcond2_i32). On a 64 bit target, the values are transferred between 32 and 64-bit registers using the following ops: diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 9cc20cd62c..30ba15723a 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -102,8 +102,6 @@ DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) -DEF(add2_i32, 2, 4, 0, 0) -DEF(sub2_i32, 2, 4, 0, 0) DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) @@ -126,9 +124,6 @@ DEF(extu_i32_i64, 1, 1, 0, 0) DEF(extrl_i64_i32, 1, 1, 0, 0) DEF(extrh_i64_i32, 1, 1, 0, 0) -DEF(add2_i64, 2, 4, 0, 0) -DEF(sub2_i64, 2, 4, 0, 0) - #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) /* There are tcg_ctx->insn_start_words here, not just one. */ diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index 695effd77c..b155e37639 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -13,14 +13,9 @@ #define have_lse2 (cpuinfo & CPUINFO_LSE2) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 - /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, * which requires writable pages. We must defer to the helper for user-only, diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index f4bd15c68a..187269e5bd 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,12 +24,8 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 - #define TCG_TARGET_HAS_qemu_ldst_i128 0 - #define TCG_TARGET_HAS_tst 1 #define TCG_TARGET_HAS_v64 use_neon_instructions diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index a984a6af2e..628e736de7 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -26,14 +26,9 @@ #define have_avx512vbmi2 ((cpuinfo & CPUINFO_AVX512VBMI2) && have_avx512vl) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 - #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 #else #define TCG_TARGET_HAS_qemu_st8_i32 1 diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index a1bd71db6a..9c118bd1f6 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -10,14 +10,10 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 /* 64-bit operations */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_qemu_ldst_i128 (cpuinfo & CPUINFO_LSX) diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index 9d86906bf3..d8f9f7beef 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -39,13 +39,8 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 - #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #define TCG_TARGET_HAS_ext32s_i64 1 #define TCG_TARGET_HAS_ext32u_i64 1 #endif diff --git a/tcg/optimize.c b/tcg/optimize.c index 95ec3b426d..52e194aaa9 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -1399,82 +1399,6 @@ static bool fold_addco(OptContext *ctx, TCGOp *op) return finish_folding(ctx, op); } -static bool fold_addsub2(OptContext *ctx, TCGOp *op, bool add) -{ - bool a_const = arg_is_const(op->args[2]) && arg_is_const(op->args[3]); - bool b_const = arg_is_const(op->args[4]) && arg_is_const(op->args[5]); - - if (a_const && b_const) { - uint64_t al = arg_info(op->args[2])->val; - uint64_t ah = arg_info(op->args[3])->val; - uint64_t bl = arg_info(op->args[4])->val; - uint64_t bh = arg_info(op->args[5])->val; - TCGArg rl, rh; - TCGOp *op2; - - if (ctx->type == TCG_TYPE_I32) { - uint64_t a = deposit64(al, 32, 32, ah); - uint64_t b = deposit64(bl, 32, 32, bh); - - if (add) { - a += b; - } else { - a -= b; - } - - al = sextract64(a, 0, 32); - ah = sextract64(a, 32, 32); - } else { - Int128 a = int128_make128(al, ah); - Int128 b = int128_make128(bl, bh); - - if (add) { - a = int128_add(a, b); - } else { - a = int128_sub(a, b); - } - - al = int128_getlo(a); - ah = int128_gethi(a); - } - - rl = op->args[0]; - rh = op->args[1]; - - /* The proper opcode is supplied by tcg_opt_gen_mov. */ - op2 = opt_insert_before(ctx, op, 0, 2); - - tcg_opt_gen_movi(ctx, op, rl, al); - tcg_opt_gen_movi(ctx, op2, rh, ah); - return true; - } - - /* Fold sub2 r,x,i to add2 r,x,-i */ - if (!add && b_const) { - uint64_t bl = arg_info(op->args[4])->val; - uint64_t bh = arg_info(op->args[5])->val; - - /* Negate the two parts without assembling and disassembling. */ - bl = -bl; - bh = ~bh + !bl; - - op->opc = (ctx->type == TCG_TYPE_I32 - ? INDEX_op_add2_i32 : INDEX_op_add2_i64); - op->args[4] = arg_new_constant(ctx, bl); - op->args[5] = arg_new_constant(ctx, bh); - } - return finish_folding(ctx, op); -} - -static bool fold_add2(OptContext *ctx, TCGOp *op) -{ - /* Note that the high and low parts may be independently swapped. */ - swap_commutative(op->args[0], &op->args[2], &op->args[4]); - swap_commutative(op->args[1], &op->args[3], &op->args[5]); - - return fold_addsub2(ctx, op, true); -} - static bool fold_and(OptContext *ctx, TCGOp *op) { uint64_t z1, z2, z_mask, s_mask; @@ -2811,11 +2735,6 @@ static bool fold_sub(OptContext *ctx, TCGOp *op) return finish_folding(ctx, op); } -static bool fold_sub2(OptContext *ctx, TCGOp *op) -{ - return fold_addsub2(ctx, op, false); -} - static void squash_prev_borrowout(OptContext *ctx, TCGOp *op) { TempOptInfo *t2; @@ -3150,9 +3069,6 @@ void tcg_optimize(TCGContext *s) case INDEX_op_addco: done = fold_addco(&ctx, op); break; - CASE_OP_32_64(add2): - done = fold_add2(&ctx, op); - break; case INDEX_op_and: case INDEX_op_and_vec: done = fold_and(&ctx, op); @@ -3342,9 +3258,6 @@ void tcg_optimize(TCGContext *s) case INDEX_op_sub_vec: done = fold_sub_vec(&ctx, op); break; - CASE_OP_32_64(sub2): - done = fold_sub2(&ctx, op); - break; case INDEX_op_xor: case INDEX_op_xor_vec: done = fold_xor(&ctx, op); diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index 4dda668706..b978c91a62 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -18,13 +18,9 @@ /* optional instructions */ #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index c95dc1921e..8cd099546f 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -11,13 +11,8 @@ /* optional instructions */ #define TCG_TARGET_HAS_qemu_st8_i32 0 - #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 - #define TCG_TARGET_HAS_qemu_ldst_i128 0 - #define TCG_TARGET_HAS_tst 0 /* vector instructions */ diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index 17e61130cd..c04cc4e377 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -29,16 +29,9 @@ extern uint64_t s390_facilities[3]; ((s390_facilities[FACILITY_##X / 64] >> (63 - FACILITY_##X % 64)) & 1) /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 - -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 - #define TCG_TARGET_HAS_qemu_ldst_i128 1 - #define TCG_TARGET_HAS_tst 1 #define TCG_TARGET_HAS_v64 HAVE_FACILITY(VECTOR) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index caf7679595..d9f5ef3fc9 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,16 +14,9 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #define TCG_TARGET_HAS_qemu_st8_i32 0 - #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 - #define TCG_TARGET_HAS_qemu_ldst_i128 0 - #define TCG_TARGET_HAS_tst 1 #define TCG_TARGET_extract_valid(type, ofs, len) \ diff --git a/tcg/tcg-has.h b/tcg/tcg-has.h index 50e8d0cda4..2fc0e50d20 100644 --- a/tcg/tcg-has.h +++ b/tcg/tcg-has.h @@ -12,8 +12,6 @@ #if TCG_TARGET_REG_BITS == 32 /* Turn some undef macros into false macros. */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #endif #if !defined(TCG_TARGET_HAS_v64) \ diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b0a29278ab..b0139ce05d 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -249,24 +249,6 @@ static void DNI tcg_gen_op5ii_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2, tcgv_i64_arg(a3), a4, a5); } -static void DNI tcg_gen_op6_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2, - TCGv_i32 a3, TCGv_i32 a4, - TCGv_i32 a5, TCGv_i32 a6) -{ - tcg_gen_op6(opc, TCG_TYPE_I32, tcgv_i32_arg(a1), tcgv_i32_arg(a2), - tcgv_i32_arg(a3), tcgv_i32_arg(a4), tcgv_i32_arg(a5), - tcgv_i32_arg(a6)); -} - -static void DNI tcg_gen_op6_i64(TCGOpcode opc, TCGv_i64 a1, TCGv_i64 a2, - TCGv_i64 a3, TCGv_i64 a4, - TCGv_i64 a5, TCGv_i64 a6) -{ - tcg_gen_op6(opc, TCG_TYPE_I64, tcgv_i64_arg(a1), tcgv_i64_arg(a2), - tcgv_i64_arg(a3), tcgv_i64_arg(a4), tcgv_i64_arg(a5), - tcgv_i64_arg(a6)); -} - static void DNI tcg_gen_op6i_i32(TCGOpcode opc, TCGv_i32 a1, TCGv_i32 a2, TCGv_i32 a3, TCGv_i32 a4, TCGv_i32 a5, TCGArg a6) @@ -1108,8 +1090,6 @@ void tcg_gen_add2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, tcg_gen_op3_i32(INDEX_op_addci, rh, ah, bh); tcg_gen_mov_i32(rl, t0); tcg_temp_free_i32(t0); - } else if (TCG_TARGET_HAS_add2_i32) { - tcg_gen_op6_i32(INDEX_op_add2_i32, rl, rh, al, ah, bl, bh); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); @@ -1159,8 +1139,6 @@ void tcg_gen_sub2_i32(TCGv_i32 rl, TCGv_i32 rh, TCGv_i32 al, tcg_gen_op3_i32(INDEX_op_subbi, rh, ah, bh); tcg_gen_mov_i32(rl, t0); tcg_temp_free_i32(t0); - } else if (TCG_TARGET_HAS_sub2_i32) { - tcg_gen_op6_i32(INDEX_op_sub2_i32, rl, rh, al, ah, bl, bh); } else { TCGv_i32 t0 = tcg_temp_ebb_new_i32(); TCGv_i32 t1 = tcg_temp_ebb_new_i32(); @@ -2880,8 +2858,6 @@ void tcg_gen_add2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, tcg_gen_mov_i64(rl, t0); tcg_temp_free_i64(t0); - } else if (TCG_TARGET_HAS_add2_i64) { - tcg_gen_op6_i64(INDEX_op_add2_i64, rl, rh, al, ah, bl, bh); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); @@ -2985,8 +2961,6 @@ void tcg_gen_sub2_i64(TCGv_i64 rl, TCGv_i64 rh, TCGv_i64 al, tcg_gen_mov_i64(rl, t0); tcg_temp_free_i64(t0); - } else if (TCG_TARGET_HAS_sub2_i64) { - tcg_gen_op6_i64(INDEX_op_sub2_i64, rl, rh, al, ah, bl, bh); } else { TCGv_i64 t0 = tcg_temp_ebb_new_i64(); TCGv_i64 t1 = tcg_temp_ebb_new_i64(); diff --git a/tcg/tcg.c b/tcg/tcg.c index 3b9f519ef6..5a498b48b6 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2430,11 +2430,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_st_i32: return true; - case INDEX_op_add2_i32: - return TCG_TARGET_HAS_add2_i32; - case INDEX_op_sub2_i32: - return TCG_TARGET_HAS_sub2_i32; - case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; @@ -2456,11 +2451,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_extrh_i64_i32: return TCG_TARGET_REG_BITS == 64; - case INDEX_op_add2_i64: - return TCG_TARGET_HAS_add2_i64; - case INDEX_op_sub2_i64: - return TCG_TARGET_HAS_sub2_i64; - case INDEX_op_mov_vec: case INDEX_op_dup_vec: case INDEX_op_dupm_vec: @@ -4101,32 +4091,6 @@ liveness_pass_1(TCGContext *s) la_reset_pref(ts); break; - case INDEX_op_add2_i32: - case INDEX_op_add2_i64: - opc_new = INDEX_op_add; - goto do_addsub2; - case INDEX_op_sub2_i32: - case INDEX_op_sub2_i64: - opc_new = INDEX_op_sub; - do_addsub2: - assert_carry_dead(s); - /* Test if the high part of the operation is dead, but not - the low part. The result can be optimized to a simple - add or sub. This happens often for x86_64 guest when the - cpu mode is set to 32 bit. */ - if (arg_temp(op->args[1])->state == TS_DEAD) { - if (arg_temp(op->args[0])->state == TS_DEAD) { - goto do_remove; - } - /* Replace the opcode and adjust the args in place, - leaving 3 unused args at the end. */ - op->opc = opc = opc_new; - op->args[1] = op->args[2]; - op->args[2] = op->args[4]; - /* Fall through and mark the single-word operation live. */ - } - goto do_not_remove; - case INDEX_op_muls2: opc_new = INDEX_op_mul; opc_new2 = INDEX_op_mulsh; diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 310d45ba62..497e8152b7 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -8,13 +8,9 @@ #define TCG_TARGET_HAS_H #define TCG_TARGET_HAS_qemu_st8_i32 0 -#define TCG_TARGET_HAS_add2_i32 0 -#define TCG_TARGET_HAS_sub2_i32 0 #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_add2_i64 0 -#define TCG_TARGET_HAS_sub2_i64 0 #endif /* TCG_TARGET_REG_BITS == 64 */ #define TCG_TARGET_HAS_qemu_ldst_i128 0 From e038696c9293f34dc7ccd4adac2c2f221a65a8e3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 20:47:42 -0800 Subject: [PATCH 0502/2760] tcg: Formalize tcg_out_mb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most tcg backends already have a function for this; the rest can split one out from tcg_out_op. Call it directly from tcg_gen_code. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 6 +----- tcg/arm/tcg-target.c.inc | 6 +----- tcg/i386/tcg-target.c.inc | 5 +---- tcg/loongarch64/tcg-target.c.inc | 6 +----- tcg/mips/tcg-target.c.inc | 5 +---- tcg/ppc/tcg-target.c.inc | 6 +----- tcg/riscv/tcg-target.c.inc | 6 +----- tcg/s390x/tcg-target.c.inc | 20 +++++++++++--------- tcg/sparc64/tcg-target.c.inc | 6 +----- tcg/tcg.c | 4 ++++ tcg/tci/tcg-target.c.inc | 9 +++++---- 11 files changed, 28 insertions(+), 51 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 75cf490fd2..d2babd9bab 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1575,7 +1575,7 @@ static void tcg_out_extrl_i64_i32(TCGContext *s, TCGReg rd, TCGReg rn) tcg_out_mov(s, TCG_TYPE_I32, rd, rn); } -static inline void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { static const uint32_t sync[] = { [0 ... TCG_MO_ALL] = DMB_ISH | DMB_LD | DMB_ST, @@ -2845,10 +2845,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 3c9042ebfa..131901dabc 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1203,7 +1203,7 @@ static void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l) } } -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { if (use_armv7_instructions) { tcg_out32(s, INSN_DMB_ISH); @@ -2565,10 +2565,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_mb: - tcg_out_mb(s, args[0]); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index da05f13b21..bf84f9f455 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1168,7 +1168,7 @@ static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val) } } -static inline void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { /* Given the strength of x86 memory ordering, we only need care for store-load ordering. Experimentally, "lock orl $0,0(%esp)" is @@ -3536,9 +3536,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #endif - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 4f640764ef..1ad577ad8d 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -301,7 +301,7 @@ static bool patch_reloc(tcg_insn_unit *code_ptr, int type, * TCG intrinsics */ -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { /* Baseline LoongArch only has the full barrier, unfortunately. */ tcg_out_opc_dbar(s, 0); @@ -1917,10 +1917,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; - case INDEX_op_goto_ptr: tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); break; diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 0c268cef42..b0da661561 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1491,7 +1491,7 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, } } -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { static const MIPSInsn sync[] = { /* Note that SYNC_MB is a slightly weaker than SYNC 0, @@ -2352,9 +2352,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 91df9610ec..ae18c84ae6 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2208,7 +2208,7 @@ static const TCGOutOpBrcond2 outop_brcond2 = { .out = tgen_brcond2, }; -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { uint32_t insn; @@ -3758,10 +3758,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_mb: - tcg_out_mb(s, args[0]); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 707ebb8f6d..df271752b7 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1582,7 +1582,7 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *arg, tcg_out_call_int(s, arg, false); } -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { tcg_insn_unit insn = OPC_FENCE; @@ -2594,10 +2594,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); break; - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 09c7ca5b44..020d8ba73f 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3008,6 +3008,17 @@ static const TCGOutOpUnary outop_not = { .out_rr = tgen_not, }; +static void tcg_out_mb(TCGContext *s, unsigned a0) +{ + /* + * The host memory model is quite strong, we simply need to + * serialize the instruction stream. + */ + if (a0 & TCG_MO_ST_LD) { + /* fast-bcr-serialization facility (45) is present */ + tcg_out_insn(s, RR, BCR, 14, 0); + } +} # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ @@ -3107,15 +3118,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); break; - case INDEX_op_mb: - /* The host memory model is quite strong, we simply need to - serialize the instruction stream. */ - if (args[0] & TCG_MO_ST_LD) { - /* fast-bcr-serialization facility (45) is present */ - tcg_out_insn(s, RR, BCR, 14, 0); - } - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index c2251a6927..7754627a5d 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -949,7 +949,7 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *dest, tcg_out_nop(s); } -static void tcg_out_mb(TCGContext *s, TCGArg a0) +static void tcg_out_mb(TCGContext *s, unsigned a0) { /* Note that the TCG memory order constants mirror the Sparc MEMBAR. */ tcg_out32(s, MEMBAR | (a0 & TCG_MO_ALL)); @@ -2025,10 +2025,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_ldst(s, a0, a1, a2, STX); break; - case INDEX_op_mb: - tcg_out_mb(s, a0); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ diff --git a/tcg/tcg.c b/tcg/tcg.c index 5a498b48b6..e7478bef77 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -133,6 +133,7 @@ static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); static void tcg_out_goto_tb(TCGContext *s, int which); +static void tcg_out_mb(TCGContext *s, unsigned bar); static void tcg_out_set_carry(TCGContext *s); static void tcg_out_set_borrow(TCGContext *s); static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, @@ -6899,6 +6900,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) case INDEX_op_goto_tb: tcg_out_goto_tb(s, op->args[0]); break; + case INDEX_op_mb: + tcg_out_mb(s, op->args[0]); + break; case INDEX_op_dup2_vec: if (tcg_reg_alloc_dup2(s, op)) { break; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 35c0c91f3e..64d4ac07cd 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -1131,6 +1131,11 @@ static const TCGOutOpSetcond2 outop_setcond2 = { .out = tgen_setcond2, }; +static void tcg_out_mb(TCGContext *s, unsigned a0) +{ + tcg_out_op_v(s, INDEX_op_mb); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1178,10 +1183,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, } break; - case INDEX_op_mb: - tcg_out_op_v(s, opc); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ From 3752a5a5ba33448fe40556d781e8096b5b9dd916 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 21:17:07 -0800 Subject: [PATCH 0503/2760] tcg: Formalize tcg_out_br Split these functions out from tcg_out_op. Call it directly from tcg_gen_code. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 6 +----- tcg/arm/tcg-target.c.inc | 8 +++++--- tcg/i386/tcg-target.c.inc | 8 +++++--- tcg/loongarch64/tcg-target.c.inc | 12 ++++++------ tcg/mips/tcg-target.c.inc | 10 +++++----- tcg/ppc/tcg-target.c.inc | 26 ++++++++++++-------------- tcg/riscv/tcg-target.c.inc | 11 ++++++----- tcg/s390x/tcg-target.c.inc | 9 +++++---- tcg/sparc64/tcg-target.c.inc | 10 ++++++---- tcg/tcg.c | 4 ++++ tcg/tci/tcg-target.c.inc | 9 +++++---- 11 files changed, 60 insertions(+), 53 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index d2babd9bab..fceb6e2796 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1407,7 +1407,7 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target, tcg_out_call_int(s, target); } -static inline void tcg_out_goto_label(TCGContext *s, TCGLabel *l) +static void tcg_out_br(TCGContext *s, TCGLabel *l) { if (!l->has_value) { tcg_out_reloc(s, s->code_ptr, R_AARCH64_JUMP26, l, 0); @@ -2779,10 +2779,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, tcg_out_insn(s, 3207, BR, a0); break; - case INDEX_op_br: - tcg_out_goto_label(s, arg_label(a0)); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_ldst(s, I3312_LDRB, a0, a1, a2, 0); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 131901dabc..327b01d377 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1203,6 +1203,11 @@ static void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l) } } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_goto_label(s, COND_AL, l); +} + static void tcg_out_mb(TCGContext *s, unsigned a0) { if (use_armv7_instructions) { @@ -2522,9 +2527,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, case INDEX_op_goto_ptr: tcg_out_b_reg(s, COND_AL, args[0]); break; - case INDEX_op_br: - tcg_out_goto_label(s, COND_AL, arg_label(args[0])); - break; case INDEX_op_ld8u_i32: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index bf84f9f455..f89982378b 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -1546,6 +1546,11 @@ static void tcg_out_jxx(TCGContext *s, int opc, TCGLabel *l, bool small) } } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_jxx(s, JCC_JMP, l, 0); +} + static int tcg_out_cmp(TCGContext *s, TCGCond cond, TCGArg arg1, TCGArg arg2, int const_arg2, int rexw) { @@ -3436,9 +3441,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, /* jmp to the given host address (could be epilogue) */ tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0); break; - case INDEX_op_br: - tcg_out_jxx(s, JCC_JMP, arg_label(a0), 0); - break; OP_32_64(ld8u): /* Note that we can ignore REXW for the zero-extend to 64-bit. */ tcg_out_modrm_offset(s, OPC_MOVZBL, a0, a1, a2); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 1ad577ad8d..cbdc42c157 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -756,6 +756,12 @@ static const TCGOutOpMovcond outop_movcond = { * Branch helpers */ +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SD10K16, l, 0); + tcg_out_opc_b(s, 0); +} + static const struct { LoongArchInsn op; bool swap; @@ -1921,12 +1927,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); break; - case INDEX_op_br: - tcg_out_reloc(s, s->code_ptr, R_LOONGARCH_BR_SD10K16, arg_label(a0), - 0); - tcg_out_opc_b(s, 0); - break; - case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index b0da661561..f4d6ee10b9 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -921,6 +921,11 @@ static const TCGOutOpBrcond outop_brcond = { .out_rr = tgen_brcond, }; +void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tgen_brcond(s, TCG_TYPE_I32, TCG_COND_EQ, TCG_REG_ZERO, TCG_REG_ZERO, l); +} + static int tcg_out_setcond2_int(TCGContext *s, TCGCond cond, TCGReg ret, TCGReg al, TCGReg ah, TCGReg bl, TCGReg bh) { @@ -2281,11 +2286,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_nop(s); } break; - case INDEX_op_br: - tgen_brcond(s, TCG_TYPE_I32, TCG_COND_EQ, - TCG_REG_ZERO, TCG_REG_ZERO, arg_label(a0)); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: i1 = OPC_LBU; diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index ae18c84ae6..d88ec8d690 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -1990,6 +1990,18 @@ static const TCGOutOpSetcond outop_negsetcond = { .out_rri = tgen_negsetcondi, }; +void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + uint32_t insn = B; + + if (l->has_value) { + insn |= reloc_pc24_val(tcg_splitwx_to_rx(s->code_ptr), l->u.value_ptr); + } else { + tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0); + } + tcg_out32(s, insn); +} + static void tcg_out_bc(TCGContext *s, TCGCond cond, int bd) { tcg_out32(s, tcg_to_bc[cond] | bd); @@ -3669,20 +3681,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0)); tcg_out32(s, BCCTR | BO_ALWAYS); break; - case INDEX_op_br: - { - TCGLabel *l = arg_label(args[0]); - uint32_t insn = B; - - if (l->has_value) { - insn |= reloc_pc24_val(tcg_splitwx_to_rx(s->code_ptr), - l->u.value_ptr); - } else { - tcg_out_reloc(s, s->code_ptr, R_PPC_REL24, l, 0); - } - tcg_out32(s, insn); - } - break; case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]); diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index df271752b7..5d8d8213cb 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1107,6 +1107,12 @@ static void tcg_out_dupi_vec(TCGContext *s, TCGType type, unsigned vece, tcg_out_dup_vec(s, type, vece, dst, TCG_REG_TMP0); } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_reloc(s, s->code_ptr, R_RISCV_JAL, l, 0); + tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, 0); +} + static const struct { RISCVInsn op; bool swap; @@ -2533,11 +2539,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0); break; - case INDEX_op_br: - tcg_out_reloc(s, s->code_ptr, R_RISCV_JAL, arg_label(a0), 0); - tcg_out_opc_jump(s, OPC_JAL, TCG_REG_ZERO, 0); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_ldst(s, OPC_LBU, a0, a1, a2); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 020d8ba73f..cdc61de4f8 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -1689,6 +1689,11 @@ static void tgen_branch(TCGContext *s, int cc, TCGLabel *l) } } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tgen_branch(s, S390_CC_ALWAYS, l); +} + static void tgen_compare_branch(TCGContext *s, S390Opcode opc, int cc, TCGReg r1, TCGReg r2, TCGLabel *l) { @@ -3075,10 +3080,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; - case INDEX_op_br: - tgen_branch(s, S390_CC_ALWAYS, arg_label(args[0])); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I32); break; diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 7754627a5d..0cc7567786 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -641,6 +641,12 @@ static void tcg_out_bpcc(TCGContext *s, int scond, int flags, TCGLabel *l) tcg_out_bpcc0(s, scond, flags, off19); } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_bpcc(s, COND_A, BPCC_PT, l); + tcg_out_nop(s); +} + static void tcg_out_cmp(TCGContext *s, TCGCond cond, TCGReg c1, int32_t c2, int c2const) { @@ -1966,10 +1972,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); tcg_out_mov_delay(s, TCG_REG_TB, a0); break; - case INDEX_op_br: - tcg_out_bpcc(s, COND_A, BPCC_PT, arg_label(a0)); - tcg_out_nop(s); - break; #define OP_32_64(x) \ glue(glue(case INDEX_op_, x), _i32): \ diff --git a/tcg/tcg.c b/tcg/tcg.c index e7478bef77..fbb1a43efc 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -134,6 +134,7 @@ static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); static void tcg_out_goto_tb(TCGContext *s, int which); static void tcg_out_mb(TCGContext *s, unsigned bar); +static void tcg_out_br(TCGContext *s, TCGLabel *l); static void tcg_out_set_carry(TCGContext *s); static void tcg_out_set_borrow(TCGContext *s); static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, @@ -6900,6 +6901,9 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) case INDEX_op_goto_tb: tcg_out_goto_tb(s, op->args[0]); break; + case INDEX_op_br: + tcg_out_br(s, arg_label(op->args[0])); + break; case INDEX_op_mb: tcg_out_mb(s, op->args[0]); break; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 64d4ac07cd..55a1a74fb6 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -1136,6 +1136,11 @@ static void tcg_out_mb(TCGContext *s, unsigned a0) tcg_out_op_v(s, INDEX_op_mb); } +static void tcg_out_br(TCGContext *s, TCGLabel *l) +{ + tcg_out_op_l(s, INDEX_op_br, l); +} + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1145,10 +1150,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_op_r(s, opc, args[0]); break; - case INDEX_op_br: - tcg_out_op_l(s, opc, arg_label(args[0])); - break; - CASE_32_64(ld8u) CASE_32_64(ld8s) CASE_32_64(ld16u) From fee03fdde32c3d5b26429b7e691f78d1ee03d631 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 20 Jan 2025 21:57:32 -0800 Subject: [PATCH 0504/2760] tcg: Formalize tcg_out_goto_ptr Split these functions out from tcg_out_op. Define outop_goto_ptr generically. Call tcg_out_goto_ptr from tcg_reg_alloc_op. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 12 +++++------- tcg/arm/tcg-target.c.inc | 12 +++++------- tcg/i386/tcg-target.c.inc | 13 ++++++------- tcg/loongarch64/tcg-target.c.inc | 12 +++++------- tcg/mips/tcg-target.c.inc | 22 ++++++++++------------ tcg/ppc/tcg-target.c.inc | 15 +++++++-------- tcg/riscv/tcg-target.c.inc | 12 +++++------- tcg/s390x/tcg-target.c.inc | 15 +++++---------- tcg/sparc64/tcg-target.c.inc | 14 ++++++-------- tcg/tcg.c | 12 ++++++++++++ tcg/tci/tcg-target.c.inc | 12 +++++------- 11 files changed, 71 insertions(+), 80 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index fceb6e2796..2678e1f176 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1986,6 +1986,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) tcg_out_bti(s, BTI_J); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_insn(s, 3207, BR, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -2775,10 +2780,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_insn(s, 3207, BR, a0); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_ldst(s, I3312_LDRB, a0, a1, a2, 0); @@ -3293,9 +3294,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 327b01d377..64be0a7e6d 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1795,6 +1795,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_b_reg(s, COND_AL, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -2524,10 +2529,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_b_reg(s, COND_AL, args[0]); - break; - case INDEX_op_ld8u_i32: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); break; @@ -2579,9 +2580,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index f89982378b..5ea4a44264 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2593,6 +2593,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + /* Jump to the given host address (could be epilogue) */ + tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -3437,10 +3443,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; switch (opc) { - case INDEX_op_goto_ptr: - /* jmp to the given host address (could be epilogue) */ - tcg_out_modrm(s, OPC_GRP5, EXT5_JMPN_Ev, a0); - break; OP_32_64(ld8u): /* Note that we can ignore REXW for the zero-extend to 64-bit. */ tcg_out_modrm_offset(s, OPC_MOVZBL, a0, a1, a2); @@ -4093,9 +4095,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index cbdc42c157..d89c27c67f 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1307,6 +1307,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -1923,10 +1928,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_opc_jirl(s, TCG_REG_ZERO, a0, 0); - break; - case INDEX_op_ld8s_i32: case INDEX_op_ld8s_i64: tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); @@ -2491,9 +2492,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_st8_i32: case INDEX_op_st8_i64: case INDEX_op_st16_i32: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index f4d6ee10b9..9455a0a17b 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1571,6 +1571,16 @@ static void tcg_out_goto_tb(TCGContext *s, int which) } } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_opc_reg(s, OPC_JR, 0, a0, 0); + if (TCG_TARGET_REG_BITS == 64) { + tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0); + } else { + tcg_out_nop(s); + } +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -2277,15 +2287,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_goto_ptr: - /* jmp to the given host address (could be epilogue) */ - tcg_out_opc_reg(s, OPC_JR, 0, a0, 0); - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_TB, a0); - } else { - tcg_out_nop(s); - } - break; case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: i1 = OPC_LBU; @@ -2364,9 +2365,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index d88ec8d690..a2a5b1e570 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2843,6 +2843,13 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out32(s, MTSPR | RS(a0) | CTR); + tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0)); + tcg_out32(s, BCCTR | BO_ALWAYS); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -3676,11 +3683,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_goto_ptr: - tcg_out32(s, MTSPR | RS(args[0]) | CTR); - tcg_out32(s, ADDI | TAI(TCG_REG_R3, 0, 0)); - tcg_out32(s, BCCTR | BO_ALWAYS); - break; case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]); @@ -4371,9 +4373,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 5d8d8213cb..c1bfd93569 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1915,6 +1915,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -2535,10 +2540,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_opc_imm(s, OPC_JALR, TCG_REG_ZERO, a0, 0); - break; - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: tcg_out_ldst(s, OPC_LBU, a0, a1, a2); @@ -2824,9 +2825,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index cdc61de4f8..2b2e00c609 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2213,6 +2213,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -3033,14 +3038,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0; - switch (opc) { - case INDEX_op_goto_ptr: - a0 = args[0]; - tcg_out_insn(s, RR, BCR, S390_CC_ALWAYS, a0); - break; - OP_32_64(ld8u): /* ??? LLC (RXY format) is only present with the extended-immediate facility, whereas LLGC is always present. */ @@ -3567,9 +3565,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 0cc7567786..208b96487e 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1300,6 +1300,12 @@ static void tcg_out_goto_tb(TCGContext *s, int which) } } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); + tcg_out_mov_delay(s, TCG_REG_TB, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -1968,11 +1974,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_arithi(s, TCG_REG_G0, a0, 0, JMPL); - tcg_out_mov_delay(s, TCG_REG_TB, a0); - break; - #define OP_32_64(x) \ glue(glue(case INDEX_op_, x), _i32): \ glue(glue(case INDEX_op_, x), _i64) @@ -2039,9 +2040,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8u_i64: case INDEX_op_ld8s_i32: diff --git a/tcg/tcg.c b/tcg/tcg.c index fbb1a43efc..5ab4f5e752 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -133,6 +133,7 @@ static void tcg_out_addi_ptr(TCGContext *s, TCGReg, TCGReg, tcg_target_long); static bool tcg_out_xchg(TCGContext *s, TCGType type, TCGReg r1, TCGReg r2); static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg); static void tcg_out_goto_tb(TCGContext *s, int which); +static void tcg_out_goto_ptr(TCGContext *s, TCGReg dest); static void tcg_out_mb(TCGContext *s, unsigned bar); static void tcg_out_br(TCGContext *s, TCGLabel *l); static void tcg_out_set_carry(TCGContext *s); @@ -1137,6 +1138,10 @@ static const TCGOutOpUnary outop_extrl_i64_i32 = { }; #endif +static const TCGOutOp outop_goto_ptr = { + .static_constraint = C_O0_I1(r), +}; + /* * Register V as the TCGOutOp for O. * This verifies that V is of type T, otherwise give a nice compiler error. @@ -1198,6 +1203,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_subb1o, TCGOutOpAddSubCarry, outop_subbio), OUTOP(INDEX_op_xor, TCGOutOpBinary, outop_xor), + [INDEX_op_goto_ptr] = &outop_goto_ptr, + #if TCG_TARGET_REG_BITS == 32 OUTOP(INDEX_op_brcond2_i32, TCGOutOpBrcond2, outop_brcond2), OUTOP(INDEX_op_setcond2_i32, TCGOutOpSetcond2, outop_setcond2), @@ -5823,6 +5830,11 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) g_assert_not_reached(); #endif + case INDEX_op_goto_ptr: + tcg_debug_assert(!const_args[0]); + tcg_out_goto_ptr(s, new_args[0]); + break; + default: if (def->flags & TCG_OPF_VECTOR) { tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 55a1a74fb6..d9cd62ed3d 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -40,9 +40,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_goto_ptr: - return C_O0_I1(r); - case INDEX_op_ld8u_i32: case INDEX_op_ld8s_i32: case INDEX_op_ld16u_i32: @@ -534,6 +531,11 @@ static void tcg_out_goto_tb(TCGContext *s, int which) set_jmp_reset_offset(s, which); } +static void tcg_out_goto_ptr(TCGContext *s, TCGReg a0) +{ + tcg_out_op_r(s, INDEX_op_goto_ptr, a0); +} + void tb_target_set_jmp_target(const TranslationBlock *tb, int n, uintptr_t jmp_rx, uintptr_t jmp_rw) { @@ -1146,10 +1148,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_goto_ptr: - tcg_out_op_r(s, opc, args[0]); - break; - CASE_32_64(ld8u) CASE_32_64(ld8s) CASE_32_64(ld16u) From 0de5c9d1f56332554c48152f535b47a1a0c2af7b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Jan 2025 20:44:42 -0800 Subject: [PATCH 0505/2760] tcg: Convert ld to TCGOutOpLoad Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 113 ++++++++++++++++----------- tcg/arm/tcg-target.c.inc | 126 ++++++++++++++++--------------- tcg/i386/tcg-target.c.inc | 112 ++++++++++++++++----------- tcg/loongarch64/tcg-target.c.inc | 104 +++++++++++++++---------- tcg/mips/tcg-target.c.inc | 108 ++++++++++++++++---------- tcg/ppc/tcg-target.c.inc | 110 +++++++++++++++++---------- tcg/riscv/tcg-target.c.inc | 107 ++++++++++++++++---------- tcg/s390x/tcg-target.c.inc | 122 +++++++++++++++++------------- tcg/sparc64/tcg-target.c.inc | 101 ++++++++++++++++--------- tcg/tcg.c | 46 +++++++++++ tcg/tci/tcg-target.c.inc | 91 ++++++++++++++++------ 11 files changed, 721 insertions(+), 419 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 2678e1f176..903a95ad7e 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2770,6 +2770,74 @@ static const TCGOutOpExtract2 outop_extract2 = { .out_rrr = tgen_extract2, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_LDRB, dest, base, offset, 0); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + AArch64Insn insn = type == TCG_TYPE_I32 ? I3312_LDRSBW : I3312_LDRSBX; + tcg_out_ldst(s, insn, dest, base, offset, 0); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_LDRH, dest, base, offset, 1); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + AArch64Insn insn = type == TCG_TYPE_I32 ? I3312_LDRSHW : I3312_LDRSHX; + tcg_out_ldst(s, insn, dest, base, offset, 1); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_LDRW, dest, base, offset, 2); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_LDRSWX, dest, base, offset, 2); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2780,37 +2848,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - tcg_out_ldst(s, I3312_LDRB, a0, a1, a2, 0); - break; - case INDEX_op_ld8s_i32: - tcg_out_ldst(s, I3312_LDRSBW, a0, a1, a2, 0); - break; - case INDEX_op_ld8s_i64: - tcg_out_ldst(s, I3312_LDRSBX, a0, a1, a2, 0); - break; - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - tcg_out_ldst(s, I3312_LDRH, a0, a1, a2, 1); - break; - case INDEX_op_ld16s_i32: - tcg_out_ldst(s, I3312_LDRSHW, a0, a1, a2, 1); - break; - case INDEX_op_ld16s_i64: - tcg_out_ldst(s, I3312_LDRSHX, a0, a1, a2, 1); - break; - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - tcg_out_ldst(s, I3312_LDRW, a0, a1, a2, 2); - break; - case INDEX_op_ld32s_i64: - tcg_out_ldst(s, I3312_LDRSWX, a0, a1, a2, 2); - break; - case INDEX_op_ld_i64: - tcg_out_ldst(s, I3312_LDRX, a0, a1, a2, 3); - break; - case INDEX_op_st8_i32: case INDEX_op_st8_i64: tcg_out_ldst(s, I3312_STRB, a0, a1, a2, 0); @@ -3294,20 +3331,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 64be0a7e6d..2079dd3bdc 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1084,26 +1084,6 @@ static void tcg_out_st32(TCGContext *s, ARMCond cond, tcg_out_st32_12(s, cond, rd, rn, offset); } -static void tcg_out_ld16u(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xff || offset < -0xff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_ld16u_8(s, cond, rd, rn, offset); -} - -static void tcg_out_ld16s(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xff || offset < -0xff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_ld16s_8(s, cond, rd, rn, offset); -} - static void tcg_out_st16(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn, int32_t offset) { @@ -1114,26 +1094,6 @@ static void tcg_out_st16(TCGContext *s, ARMCond cond, tcg_out_st16_8(s, cond, rd, rn, offset); } -static void tcg_out_ld8u(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xfff || offset < -0xfff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_ld8_12(s, cond, rd, rn, offset); -} - -static void tcg_out_ld8s(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xff || offset < -0xff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_ld8s_8(s, cond, rd, rn, offset); -} - static void tcg_out_st8(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn, int32_t offset) { @@ -2524,26 +2484,75 @@ static const TCGOutOpExtract2 outop_extract2 = { .out_rrr = tgen_extract2, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_ld8_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_ld8_12(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_ld8s_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_ld8s_8(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_ld16u_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_ld16u_8(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_ld16s_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_ld16s_8(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_ld8u_i32: - tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_ld8s_i32: - tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_ld16u_i32: - tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_ld16s_i32: - tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_ld_i32: - tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]); - break; case INDEX_op_st8_i32: tcg_out_st8(s, COND_AL, args[0], args[1], args[2]); break; @@ -2580,13 +2589,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 5ea4a44264..d16ddcb940 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3419,13 +3419,81 @@ static const TCGOutOpExtract2 outop_extract2 = { .out_rrr = tgen_extract2, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVZBL, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVZWL, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + int rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; + tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +#if TCG_TARGET_REG_BITS == 64 +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVL_GvEv, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVSLQ, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; +#endif static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; - int rexw; #if TCG_TARGET_REG_BITS == 64 # define OP_32_64(x) \ @@ -3440,30 +3508,8 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a0 = args[0]; a1 = args[1]; a2 = args[2]; - rexw = type == TCG_TYPE_I32 ? 0 : P_REXW; switch (opc) { - OP_32_64(ld8u): - /* Note that we can ignore REXW for the zero-extend to 64-bit. */ - tcg_out_modrm_offset(s, OPC_MOVZBL, a0, a1, a2); - break; - OP_32_64(ld8s): - tcg_out_modrm_offset(s, OPC_MOVSBL + rexw, a0, a1, a2); - break; - OP_32_64(ld16u): - /* Note that we can ignore REXW for the zero-extend to 64-bit. */ - tcg_out_modrm_offset(s, OPC_MOVZWL, a0, a1, a2); - break; - OP_32_64(ld16s): - tcg_out_modrm_offset(s, OPC_MOVSWL + rexw, a0, a1, a2); - break; -#if TCG_TARGET_REG_BITS == 64 - case INDEX_op_ld32u_i64: -#endif - case INDEX_op_ld_i32: - tcg_out_ld(s, TCG_TYPE_I32, a0, a1, a2); - break; - OP_32_64(st8): if (const_args[0]) { tcg_out_modrm_offset(s, OPC_MOVB_EvIz, 0, a1, a2); @@ -3524,12 +3570,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; #if TCG_TARGET_REG_BITS == 64 - case INDEX_op_ld32s_i64: - tcg_out_modrm_offset(s, OPC_MOVSLQ, a0, a1, a2); - break; - case INDEX_op_ld_i64: - tcg_out_ld(s, TCG_TYPE_I64, a0, a1, a2); - break; case INDEX_op_st_i64: if (const_args[0]) { tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_REXW, 0, a1, a2); @@ -4095,20 +4135,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st8_i64: return C_O0_I2(qi, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index d89c27c67f..66555b8982 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1917,6 +1917,71 @@ static const TCGOutOpExtract2 outop_extract2 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_BU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_B, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_HU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_H, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_WU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LD_W, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -1928,33 +1993,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - tcg_out_ldst(s, OPC_LD_B, a0, a1, a2); - break; - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - tcg_out_ldst(s, OPC_LD_BU, a0, a1, a2); - break; - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - tcg_out_ldst(s, OPC_LD_H, a0, a1, a2); - break; - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - tcg_out_ldst(s, OPC_LD_HU, a0, a1, a2); - break; - case INDEX_op_ld_i32: - case INDEX_op_ld32s_i64: - tcg_out_ldst(s, OPC_LD_W, a0, a1, a2); - break; - case INDEX_op_ld32u_i64: - tcg_out_ldst(s, OPC_LD_WU, a0, a1, a2); - break; - case INDEX_op_ld_i64: - tcg_out_ldst(s, OPC_LD_D, a0, a1, a2); - break; - case INDEX_op_st8_i32: case INDEX_op_st8_i64: tcg_out_ldst(s, OPC_ST_B, a0, a1, a2); @@ -2509,18 +2547,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i128: return C_O0_I3(r, r, r); - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 9455a0a17b..21ed11b78d 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2274,6 +2274,74 @@ static const TCGOutOpExtract2 outop_extract2 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LBU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LB, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LHU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LH, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +#if TCG_TARGET_REG_BITS == 64 +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LWU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LW, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; +#endif + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2287,32 +2355,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - i1 = OPC_LBU; - goto do_ldst; - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - i1 = OPC_LB; - goto do_ldst; - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - i1 = OPC_LHU; - goto do_ldst; - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - i1 = OPC_LH; - goto do_ldst; - case INDEX_op_ld_i32: - case INDEX_op_ld32s_i64: - i1 = OPC_LW; - goto do_ldst; - case INDEX_op_ld32u_i64: - i1 = OPC_LWU; - goto do_ldst; - case INDEX_op_ld_i64: - i1 = OPC_LD; - goto do_ldst; case INDEX_op_st8_i32: case INDEX_op_st8_i64: i1 = OPC_SB; @@ -2365,20 +2407,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index a2a5b1e570..275c5a90a5 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3677,39 +3677,81 @@ static const TCGOutOpExtract2 outop_extract2 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, LBZ, LBZX, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tgen_ld8u(s, type, dest, base, offset); + tcg_out_ext8s(s, type, dest, dest); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, LHZ, LHZX, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, LHA, LHAX, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +#if TCG_TARGET_REG_BITS == 64 +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, LWZ, LWZX, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, LWA, LWAX, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; +#endif + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]); - break; - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - tcg_out_mem_long(s, LBZ, LBZX, args[0], args[1], args[2]); - tcg_out_ext8s(s, TCG_TYPE_REG, args[0], args[0]); - break; - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - tcg_out_mem_long(s, LHZ, LHZX, args[0], args[1], args[2]); - break; - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - tcg_out_mem_long(s, LHA, LHAX, args[0], args[1], args[2]); - break; - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - tcg_out_mem_long(s, LWZ, LWZX, args[0], args[1], args[2]); - break; - case INDEX_op_ld32s_i64: - tcg_out_mem_long(s, LWA, LWAX, args[0], args[1], args[2]); - break; - case INDEX_op_ld_i64: - tcg_out_mem_long(s, LD, LDX, args[0], args[1], args[2]); - break; case INDEX_op_st8_i32: case INDEX_op_st8_i64: tcg_out_mem_long(s, STB, STBX, args[0], args[1], args[2]); @@ -4373,20 +4415,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index c1bfd93569..5b987c930f 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2530,6 +2530,72 @@ static const TCGOutOpExtract2 outop_extract2 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LBU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LB, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LHU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LH, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LWU, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_LW, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2540,33 +2606,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - tcg_out_ldst(s, OPC_LBU, a0, a1, a2); - break; - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - tcg_out_ldst(s, OPC_LB, a0, a1, a2); - break; - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - tcg_out_ldst(s, OPC_LHU, a0, a1, a2); - break; - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - tcg_out_ldst(s, OPC_LH, a0, a1, a2); - break; - case INDEX_op_ld32u_i64: - tcg_out_ldst(s, OPC_LWU, a0, a1, a2); - break; - case INDEX_op_ld_i32: - case INDEX_op_ld32s_i64: - tcg_out_ldst(s, OPC_LW, a0, a1, a2); - break; - case INDEX_op_ld_i64: - tcg_out_ldst(s, OPC_LD, a0, a1, a2); - break; - case INDEX_op_st8_i32: case INDEX_op_st8_i64: tcg_out_ldst(s, OPC_SB, a0, a1, a2); @@ -2825,20 +2864,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 2b2e00c609..fe7665b21d 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3030,6 +3030,76 @@ static void tcg_out_mb(TCGContext *s, unsigned a0) } } +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, 0, RXY_LLGC, dest, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, 0, RXY_LGB, dest, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, 0, RXY_LLGH, dest, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + if (type == TCG_TYPE_I32) { + tcg_out_mem(s, RX_LH, RXY_LHY, dest, base, TCG_REG_NONE, offset); + } else { + tcg_out_mem(s, 0, RXY_LGH, dest, base, TCG_REG_NONE, offset); + } +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, 0, RXY_LLGF, dest, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, 0, RXY_LGF, dest, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; + # define OP_32_64(x) \ case glue(glue(INDEX_op_,x),_i32): \ case glue(glue(INDEX_op_,x),_i64) @@ -3039,31 +3109,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - OP_32_64(ld8u): - /* ??? LLC (RXY format) is only present with the extended-immediate - facility, whereas LLGC is always present. */ - tcg_out_mem(s, 0, RXY_LLGC, args[0], args[1], TCG_REG_NONE, args[2]); - break; - - OP_32_64(ld8s): - /* ??? LB is no smaller than LGB, so no point to using it. */ - tcg_out_mem(s, 0, RXY_LGB, args[0], args[1], TCG_REG_NONE, args[2]); - break; - - OP_32_64(ld16u): - /* ??? LLH (RXY format) is only present with the extended-immediate - facility, whereas LLGH is always present. */ - tcg_out_mem(s, 0, RXY_LLGH, args[0], args[1], TCG_REG_NONE, args[2]); - break; - - case INDEX_op_ld16s_i32: - tcg_out_mem(s, RX_LH, RXY_LHY, args[0], args[1], TCG_REG_NONE, args[2]); - break; - - case INDEX_op_ld_i32: - tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]); - break; - OP_32_64(st8): tcg_out_mem(s, RX_STC, RXY_STCY, args[0], args[1], TCG_REG_NONE, args[2]); @@ -3097,19 +3142,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_ld16s_i64: - tcg_out_mem(s, 0, RXY_LGH, args[0], args[1], TCG_REG_NONE, args[2]); - break; - case INDEX_op_ld32u_i64: - tcg_out_mem(s, 0, RXY_LLGF, args[0], args[1], TCG_REG_NONE, args[2]); - break; - case INDEX_op_ld32s_i64: - tcg_out_mem(s, 0, RXY_LGF, args[0], args[1], TCG_REG_NONE, args[2]); - break; - case INDEX_op_ld_i64: - tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]); - break; - case INDEX_op_st32_i64: tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); break; @@ -3565,20 +3597,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st8_i64: case INDEX_op_st16_i32: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 208b96487e..59a737dde4 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1962,6 +1962,73 @@ static const TCGOutOpExtract2 outop_extract2 = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDUB); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDSB); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDUH); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDSH); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDUW); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, dest, base, offset, LDSW); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1978,22 +2045,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, glue(glue(case INDEX_op_, x), _i32): \ glue(glue(case INDEX_op_, x), _i64) - OP_32_64(ld8u): - tcg_out_ldst(s, a0, a1, a2, LDUB); - break; - OP_32_64(ld8s): - tcg_out_ldst(s, a0, a1, a2, LDSB); - break; - OP_32_64(ld16u): - tcg_out_ldst(s, a0, a1, a2, LDUH); - break; - OP_32_64(ld16s): - tcg_out_ldst(s, a0, a1, a2, LDSH); - break; - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - tcg_out_ldst(s, a0, a1, a2, LDUW); - break; OP_32_64(st8): tcg_out_ldst(s, a0, a1, a2, STB); break; @@ -2018,12 +2069,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); break; - case INDEX_op_ld32s_i64: - tcg_out_ldst(s, a0, a1, a2, LDSW); - break; - case INDEX_op_ld_i64: - tcg_out_ldst(s, a0, a1, a2, LDX); - break; case INDEX_op_st_i64: tcg_out_ldst(s, a0, a1, a2, STX); break; @@ -2040,18 +2085,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/tcg.c b/tcg/tcg.c index 5ab4f5e752..4cff888b7e 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1052,6 +1052,12 @@ typedef struct TCGOutOpExtract2 { TCGReg a2, unsigned shr); } TCGOutOpExtract2; +typedef struct TCGOutOpLoad { + TCGOutOp base; + void (*out)(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, intptr_t offset); +} TCGOutOpLoad; + typedef struct TCGOutOpMovcond { TCGOutOp base; void (*out)(TCGContext *s, TCGType type, TCGCond cond, @@ -1142,6 +1148,11 @@ static const TCGOutOp outop_goto_ptr = { .static_constraint = C_O0_I1(r), }; +static const TCGOutOpLoad outop_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tcg_out_ld, +}; + /* * Register V as the TCGOutOp for O. * This verifies that V is of type T, otherwise give a nice compiler error. @@ -1173,6 +1184,16 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), OUTOP(INDEX_op_extract2, TCGOutOpExtract2, outop_extract2), + OUTOP(INDEX_op_ld8u_i32, TCGOutOpLoad, outop_ld8u), + OUTOP(INDEX_op_ld8u_i64, TCGOutOpLoad, outop_ld8u), + OUTOP(INDEX_op_ld8s_i32, TCGOutOpLoad, outop_ld8s), + OUTOP(INDEX_op_ld8s_i64, TCGOutOpLoad, outop_ld8s), + OUTOP(INDEX_op_ld16u_i32, TCGOutOpLoad, outop_ld16u), + OUTOP(INDEX_op_ld16u_i64, TCGOutOpLoad, outop_ld16u), + OUTOP(INDEX_op_ld16s_i32, TCGOutOpLoad, outop_ld16s), + OUTOP(INDEX_op_ld16s_i64, TCGOutOpLoad, outop_ld16s), + OUTOP(INDEX_op_ld_i32, TCGOutOpLoad, outop_ld), + OUTOP(INDEX_op_ld_i64, TCGOutOpLoad, outop_ld), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -1214,6 +1235,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64), OUTOP(INDEX_op_extrl_i64_i32, TCGOutOpUnary, outop_extrl_i64_i32), OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), + OUTOP(INDEX_op_ld32u_i64, TCGOutOpLoad, outop_ld32u), + OUTOP(INDEX_op_ld32s_i64, TCGOutOpLoad, outop_ld32s), #endif }; @@ -5740,6 +5763,29 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_ld32u_i64: + case INDEX_op_ld32s_i64: + tcg_debug_assert(type == TCG_TYPE_I64); + /* fall through */ + case INDEX_op_ld8u_i32: + case INDEX_op_ld8u_i64: + case INDEX_op_ld8s_i32: + case INDEX_op_ld8s_i64: + case INDEX_op_ld16u_i32: + case INDEX_op_ld16u_i64: + case INDEX_op_ld16s_i32: + case INDEX_op_ld16s_i64: + case INDEX_op_ld_i32: + case INDEX_op_ld_i64: + { + const TCGOutOpLoad *out = + container_of(all_outop[op->opc], TCGOutOpLoad, base); + + tcg_debug_assert(!const_args[1]); + out->out(s, type, new_args[0], new_args[1], new_args[2]); + } + break; + case INDEX_op_muls2: case INDEX_op_mulu2: { diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d9cd62ed3d..2dcd561b77 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -40,20 +40,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: - return C_O1_I1(r, r); - case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: @@ -1143,19 +1129,80 @@ static void tcg_out_br(TCGContext *s, TCGLabel *l) tcg_out_op_l(s, INDEX_op_br, l); } +static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld8u_i32, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8u, +}; + +static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld8s_i32, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld8s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld8s, +}; + +static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld16u_i32, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16u, +}; + +static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld16s_i32, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld16s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld16s, +}; + +#if TCG_TARGET_REG_BITS == 64 +static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld32u_i64, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32u = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32u, +}; + +static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_ld32s_i64, dest, base, offset); +} + +static const TCGOutOpLoad outop_ld32s = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_ld32s, +}; +#endif + + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - CASE_32_64(ld8u) - CASE_32_64(ld8s) - CASE_32_64(ld16u) - CASE_32_64(ld16s) - case INDEX_op_ld_i32: - CASE_64(ld32u) - CASE_64(ld32s) - CASE_64(ld) CASE_32_64(st8) CASE_32_64(st16) case INDEX_op_st_i32: From e996804d40c10572550a1d3ca936a5dfb29ca0fc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 21 Jan 2025 21:47:16 -0800 Subject: [PATCH 0506/2760] tcg: Merge INDEX_op_ld*_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/tcg/tcg-opc.h | 19 +++++------- tcg/optimize.c | 27 ++++++++--------- tcg/tcg-op.c | 24 +++++++-------- tcg/tcg.c | 64 ++++++++++++++-------------------------- tcg/tci.c | 43 +++++++++++---------------- tcg/tci/tcg-target.c.inc | 28 +++++++----------- 6 files changed, 83 insertions(+), 122 deletions(-) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 30ba15723a..6e8fcefaef 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -57,6 +57,13 @@ DEF(divu2, 2, 3, 0, TCG_OPF_INT) DEF(eqv, 1, 2, 0, TCG_OPF_INT) DEF(extract, 1, 1, 2, TCG_OPF_INT) DEF(extract2, 1, 2, 1, TCG_OPF_INT) +DEF(ld8u, 1, 1, 1, TCG_OPF_INT) +DEF(ld8s, 1, 1, 1, TCG_OPF_INT) +DEF(ld16u, 1, 1, 1, TCG_OPF_INT) +DEF(ld16s, 1, 1, 1, TCG_OPF_INT) +DEF(ld32u, 1, 1, 1, TCG_OPF_INT) +DEF(ld32s, 1, 1, 1, TCG_OPF_INT) +DEF(ld, 1, 1, 1, TCG_OPF_INT) DEF(movcond, 1, 4, 1, TCG_OPF_INT) DEF(mul, 1, 2, 0, TCG_OPF_INT) DEF(muls2, 2, 2, 0, TCG_OPF_INT) @@ -93,11 +100,6 @@ DEF(subbi, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN) DEF(subbio, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN | TCG_OPF_CARRY_OUT) /* load/store */ -DEF(ld8u_i32, 1, 1, 1, 0) -DEF(ld8s_i32, 1, 1, 1, 0) -DEF(ld16u_i32, 1, 1, 1, 0) -DEF(ld16s_i32, 1, 1, 1, 0) -DEF(ld_i32, 1, 1, 1, 0) DEF(st8_i32, 0, 2, 1, 0) DEF(st16_i32, 0, 2, 1, 0) DEF(st_i32, 0, 2, 1, 0) @@ -106,13 +108,6 @@ DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) /* load/store */ -DEF(ld8u_i64, 1, 1, 1, 0) -DEF(ld8s_i64, 1, 1, 1, 0) -DEF(ld16u_i64, 1, 1, 1, 0) -DEF(ld16s_i64, 1, 1, 1, 0) -DEF(ld32u_i64, 1, 1, 1, 0) -DEF(ld32s_i64, 1, 1, 1, 0) -DEF(ld_i64, 1, 1, 1, 0) DEF(st8_i64, 0, 2, 1, 0) DEF(st16_i64, 0, 2, 1, 0) DEF(st32_i64, 0, 2, 1, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index 52e194aaa9..d928a38e14 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -2880,22 +2880,22 @@ static bool fold_tcg_ld(OptContext *ctx, TCGOp *op) /* We can't do any folding with a load, but we can record bits. */ switch (op->opc) { - CASE_OP_32_64(ld8s): + case INDEX_op_ld8s: s_mask = INT8_MIN; break; - CASE_OP_32_64(ld8u): + case INDEX_op_ld8u: z_mask = MAKE_64BIT_MASK(0, 8); break; - CASE_OP_32_64(ld16s): + case INDEX_op_ld16s: s_mask = INT16_MIN; break; - CASE_OP_32_64(ld16u): + case INDEX_op_ld16u: z_mask = MAKE_64BIT_MASK(0, 16); break; - case INDEX_op_ld32s_i64: + case INDEX_op_ld32s: s_mask = INT32_MIN; break; - case INDEX_op_ld32u_i64: + case INDEX_op_ld32u: z_mask = MAKE_64BIT_MASK(0, 32); break; default: @@ -3126,16 +3126,15 @@ void tcg_optimize(TCGContext *s) case INDEX_op_extrh_i64_i32: done = fold_extu(&ctx, op); break; - CASE_OP_32_64(ld8s): - CASE_OP_32_64(ld8u): - CASE_OP_32_64(ld16s): - CASE_OP_32_64(ld16u): - case INDEX_op_ld32s_i64: - case INDEX_op_ld32u_i64: + case INDEX_op_ld8s: + case INDEX_op_ld8u: + case INDEX_op_ld16s: + case INDEX_op_ld16u: + case INDEX_op_ld32s: + case INDEX_op_ld32u: done = fold_tcg_ld(&ctx, op); break; - case INDEX_op_ld_i32: - case INDEX_op_ld_i64: + case INDEX_op_ld: case INDEX_op_ld_vec: done = fold_tcg_ld_memcopy(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index b0139ce05d..680f752cf9 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1379,27 +1379,27 @@ void tcg_gen_abs_i32(TCGv_i32 ret, TCGv_i32 a) void tcg_gen_ld8u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_ld8u_i32, ret, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_ld8u, ret, arg2, offset); } void tcg_gen_ld8s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_ld8s_i32, ret, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_ld8s, ret, arg2, offset); } void tcg_gen_ld16u_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_ld16u_i32, ret, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_ld16u, ret, arg2, offset); } void tcg_gen_ld16s_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_ld16s_i32, ret, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_ld16s, ret, arg2, offset); } void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_ld_i32, ret, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_ld, ret, arg2, offset); } void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) @@ -1463,7 +1463,7 @@ void tcg_gen_movi_i64(TCGv_i64 ret, int64_t arg) void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld8u_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld8u, ret, arg2, offset); } else { tcg_gen_ld8u_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); @@ -1473,7 +1473,7 @@ void tcg_gen_ld8u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld8s_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld8s, ret, arg2, offset); } else { tcg_gen_ld8s_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); @@ -1483,7 +1483,7 @@ void tcg_gen_ld8s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld16u_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld16u, ret, arg2, offset); } else { tcg_gen_ld16u_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); @@ -1493,7 +1493,7 @@ void tcg_gen_ld16u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld16s_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld16s, ret, arg2, offset); } else { tcg_gen_ld16s_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); @@ -1503,7 +1503,7 @@ void tcg_gen_ld16s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld32u_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld32u, ret, arg2, offset); } else { tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_movi_i32(TCGV_HIGH(ret), 0); @@ -1513,7 +1513,7 @@ void tcg_gen_ld32u_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_ld32s_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld32s_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld32s, ret, arg2, offset); } else { tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset); tcg_gen_sari_i32(TCGV_HIGH(ret), TCGV_LOW(ret), 31); @@ -1527,7 +1527,7 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) * they cannot be the same temporary -- no chance of overlap. */ if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_ld_i64, ret, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_ld, ret, arg2, offset); } else if (HOST_BIG_ENDIAN) { tcg_gen_ld_i32(TCGV_HIGH(ret), arg2, offset); tcg_gen_ld_i32(TCGV_LOW(ret), arg2, offset + 4); diff --git a/tcg/tcg.c b/tcg/tcg.c index 4cff888b7e..a9d62d9e17 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1184,16 +1184,11 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_eqv, TCGOutOpBinary, outop_eqv), OUTOP(INDEX_op_extract, TCGOutOpExtract, outop_extract), OUTOP(INDEX_op_extract2, TCGOutOpExtract2, outop_extract2), - OUTOP(INDEX_op_ld8u_i32, TCGOutOpLoad, outop_ld8u), - OUTOP(INDEX_op_ld8u_i64, TCGOutOpLoad, outop_ld8u), - OUTOP(INDEX_op_ld8s_i32, TCGOutOpLoad, outop_ld8s), - OUTOP(INDEX_op_ld8s_i64, TCGOutOpLoad, outop_ld8s), - OUTOP(INDEX_op_ld16u_i32, TCGOutOpLoad, outop_ld16u), - OUTOP(INDEX_op_ld16u_i64, TCGOutOpLoad, outop_ld16u), - OUTOP(INDEX_op_ld16s_i32, TCGOutOpLoad, outop_ld16s), - OUTOP(INDEX_op_ld16s_i64, TCGOutOpLoad, outop_ld16s), - OUTOP(INDEX_op_ld_i32, TCGOutOpLoad, outop_ld), - OUTOP(INDEX_op_ld_i64, TCGOutOpLoad, outop_ld), + OUTOP(INDEX_op_ld8u, TCGOutOpLoad, outop_ld8u), + OUTOP(INDEX_op_ld8s, TCGOutOpLoad, outop_ld8s), + OUTOP(INDEX_op_ld16u, TCGOutOpLoad, outop_ld16u), + OUTOP(INDEX_op_ld16s, TCGOutOpLoad, outop_ld16s), + OUTOP(INDEX_op_ld, TCGOutOpLoad, outop_ld), OUTOP(INDEX_op_movcond, TCGOutOpMovcond, outop_movcond), OUTOP(INDEX_op_mul, TCGOutOpBinary, outop_mul), OUTOP(INDEX_op_muls2, TCGOutOpMul2, outop_muls2), @@ -1235,8 +1230,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extu_i32_i64, TCGOutOpUnary, outop_extu_i32_i64), OUTOP(INDEX_op_extrl_i64_i32, TCGOutOpUnary, outop_extrl_i64_i32), OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), - OUTOP(INDEX_op_ld32u_i64, TCGOutOpLoad, outop_ld32u), - OUTOP(INDEX_op_ld32s_i64, TCGOutOpLoad, outop_ld32s), + OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u), + OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s), #endif }; @@ -2443,6 +2438,11 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_brcond: case INDEX_op_deposit: case INDEX_op_extract: + case INDEX_op_ld8u: + case INDEX_op_ld8s: + case INDEX_op_ld16u: + case INDEX_op_ld16s: + case INDEX_op_ld: case INDEX_op_mov: case INDEX_op_movcond: case INDEX_op_negsetcond: @@ -2452,11 +2452,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_xor: return has_type; - case INDEX_op_ld8u_i32: - case INDEX_op_ld8s_i32: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16s_i32: - case INDEX_op_ld_i32: case INDEX_op_st8_i32: case INDEX_op_st16_i32: case INDEX_op_st_i32: @@ -2466,13 +2461,8 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i64: + case INDEX_op_ld32u: + case INDEX_op_ld32s: case INDEX_op_st8_i64: case INDEX_op_st16_i64: case INDEX_op_st32_i64: @@ -4428,10 +4418,7 @@ liveness_pass_2(TCGContext *s) arg_ts = arg_temp(op->args[i]); dir_ts = arg_ts->state_ptr; if (dir_ts && arg_ts->state == TS_DEAD) { - TCGOpcode lopc = (arg_ts->type == TCG_TYPE_I32 - ? INDEX_op_ld_i32 - : INDEX_op_ld_i64); - TCGOp *lop = tcg_op_insert_before(s, op, lopc, + TCGOp *lop = tcg_op_insert_before(s, op, INDEX_op_ld, arg_ts->type, 3); lop->args[0] = temp_arg(dir_ts); @@ -5763,20 +5750,13 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - tcg_debug_assert(type == TCG_TYPE_I64); - /* fall through */ - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld_i64: + case INDEX_op_ld8u: + case INDEX_op_ld8s: + case INDEX_op_ld16u: + case INDEX_op_ld16s: + case INDEX_op_ld32u: + case INDEX_op_ld32s: + case INDEX_op_ld: { const TCGOutOpLoad *out = container_of(all_outop[op->opc], TCGOutOpLoad, base); diff --git a/tcg/tci.c b/tcg/tci.c index a18478a07a..890ccbe85b 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -466,31 +466,30 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, /* Load/store operations (32 bit). */ - CASE_32_64(ld8u) + case INDEX_op_ld8u: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); regs[r0] = *(uint8_t *)ptr; break; - CASE_32_64(ld8s) + case INDEX_op_ld8s: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); regs[r0] = *(int8_t *)ptr; break; - CASE_32_64(ld16u) + case INDEX_op_ld16u: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); regs[r0] = *(uint16_t *)ptr; break; - CASE_32_64(ld16s) + case INDEX_op_ld16s: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); regs[r0] = *(int16_t *)ptr; break; - case INDEX_op_ld_i32: - CASE_64(ld32u) + case INDEX_op_ld: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); - regs[r0] = *(uint32_t *)ptr; + regs[r0] = *(tcg_target_ulong *)ptr; break; CASE_32_64(st8) tci_args_rrs(insn, &r0, &r1, &ofs); @@ -716,16 +715,16 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, #if TCG_TARGET_REG_BITS == 64 /* Load/store operations (64 bit). */ - case INDEX_op_ld32s_i64: + case INDEX_op_ld32u: + tci_args_rrs(insn, &r0, &r1, &ofs); + ptr = (void *)(regs[r1] + ofs); + regs[r0] = *(uint32_t *)ptr; + break; + case INDEX_op_ld32s: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); regs[r0] = *(int32_t *)ptr; break; - case INDEX_op_ld_i64: - tci_args_rrs(insn, &r0, &r1, &ofs); - ptr = (void *)(regs[r1] + ofs); - regs[r0] = *(uint64_t *)ptr; - break; case INDEX_op_st_i64: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); @@ -970,18 +969,12 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) info->fprintf_func(info->stream, "%-12s", op_name); break; - case INDEX_op_ld8u_i32: - case INDEX_op_ld8u_i64: - case INDEX_op_ld8s_i32: - case INDEX_op_ld8s_i64: - case INDEX_op_ld16u_i32: - case INDEX_op_ld16u_i64: - case INDEX_op_ld16s_i32: - case INDEX_op_ld16s_i64: - case INDEX_op_ld32u_i64: - case INDEX_op_ld32s_i64: - case INDEX_op_ld_i32: - case INDEX_op_ld_i64: + case INDEX_op_ld8u: + case INDEX_op_ld8s: + case INDEX_op_ld16u: + case INDEX_op_ld16s: + case INDEX_op_ld32u: + case INDEX_op_ld: case INDEX_op_st8_i32: case INDEX_op_st8_i64: case INDEX_op_st16_i32: diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 2dcd561b77..d549dc90f5 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -339,18 +339,12 @@ static void tcg_out_ldst(TCGContext *s, TCGOpcode op, TCGReg val, static void tcg_out_ld(TCGContext *s, TCGType type, TCGReg val, TCGReg base, intptr_t offset) { - switch (type) { - case TCG_TYPE_I32: - tcg_out_ldst(s, INDEX_op_ld_i32, val, base, offset); - break; -#if TCG_TARGET_REG_BITS == 64 - case TCG_TYPE_I64: - tcg_out_ldst(s, INDEX_op_ld_i64, val, base, offset); - break; -#endif - default: - g_assert_not_reached(); + TCGOpcode op = INDEX_op_ld; + + if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { + op = INDEX_op_ld32u; } + tcg_out_ldst(s, op, val, base, offset); } static bool tcg_out_mov(TCGContext *s, TCGType type, TCGReg ret, TCGReg arg) @@ -1132,7 +1126,7 @@ static void tcg_out_br(TCGContext *s, TCGLabel *l) static void tgen_ld8u(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld8u_i32, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld8u, dest, base, offset); } static const TCGOutOpLoad outop_ld8u = { @@ -1143,7 +1137,7 @@ static const TCGOutOpLoad outop_ld8u = { static void tgen_ld8s(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld8s_i32, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld8s, dest, base, offset); } static const TCGOutOpLoad outop_ld8s = { @@ -1154,7 +1148,7 @@ static const TCGOutOpLoad outop_ld8s = { static void tgen_ld16u(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld16u_i32, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld16u, dest, base, offset); } static const TCGOutOpLoad outop_ld16u = { @@ -1165,7 +1159,7 @@ static const TCGOutOpLoad outop_ld16u = { static void tgen_ld16s(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld16s_i32, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld16s, dest, base, offset); } static const TCGOutOpLoad outop_ld16s = { @@ -1177,7 +1171,7 @@ static const TCGOutOpLoad outop_ld16s = { static void tgen_ld32u(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld32u_i64, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld32u, dest, base, offset); } static const TCGOutOpLoad outop_ld32u = { @@ -1188,7 +1182,7 @@ static const TCGOutOpLoad outop_ld32u = { static void tgen_ld32s(TCGContext *s, TCGType type, TCGReg dest, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_ld32s_i64, dest, base, offset); + tcg_out_ldst(s, INDEX_op_ld32s, dest, base, offset); } static const TCGOutOpLoad outop_ld32s = { From 4a686aa9d9dcf8805de654ae09788c4e264c1439 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Jan 2025 12:49:41 -0800 Subject: [PATCH 0507/2760] tcg: Convert st to TCGOutOpStore Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 52 +++++++------- tcg/arm/tcg-target.c.inc | 72 +++++++++---------- tcg/i386/tcg-target.c.inc | 114 ++++++++++++++----------------- tcg/loongarch64/tcg-target.c.inc | 50 +++++++------- tcg/mips/tcg-target.c.inc | 55 ++++++++------- tcg/ppc/tcg-target.c.inc | 52 +++++++------- tcg/riscv/tcg-target.c.inc | 52 +++++++------- tcg/s390x/tcg-target.c.inc | 60 ++++++++-------- tcg/sparc64/tcg-target.c.inc | 53 +++++++------- tcg/tcg.c | 37 ++++++++++ tcg/tci/tcg-target.c.inc | 56 ++++++++------- 11 files changed, 341 insertions(+), 312 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 903a95ad7e..39a44507d1 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2838,6 +2838,33 @@ static const TCGOutOpLoad outop_ld32s = { .out = tgen_ld32s, }; +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_STRB, data, base, offset, 0); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st8_r, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, I3312_STRH, data, base, offset, 1); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st16_r, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -2848,22 +2875,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - tcg_out_ldst(s, I3312_STRB, a0, a1, a2, 0); - break; - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - tcg_out_ldst(s, I3312_STRH, a0, a1, a2, 1); - break; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - tcg_out_ldst(s, I3312_STRW, a0, a1, a2, 2); - break; - case INDEX_op_st_i64: - tcg_out_ldst(s, I3312_STRX, a0, a1, a2, 3); - break; - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: tcg_out_qemu_ld(s, a0, a1, a2, ext); @@ -3331,15 +3342,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(rz, r); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 2079dd3bdc..5b34f61ca1 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1084,26 +1084,6 @@ static void tcg_out_st32(TCGContext *s, ARMCond cond, tcg_out_st32_12(s, cond, rd, rn, offset); } -static void tcg_out_st16(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xff || offset < -0xff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_st16_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_st16_8(s, cond, rd, rn, offset); -} - -static void tcg_out_st8(TCGContext *s, ARMCond cond, - TCGReg rd, TCGReg rn, int32_t offset) -{ - if (offset > 0xfff || offset < -0xfff) { - tcg_out_movi32(s, cond, TCG_REG_TMP, offset); - tcg_out_st8_r(s, cond, rd, rn, TCG_REG_TMP); - } else - tcg_out_st8_12(s, cond, rd, rn, offset); -} - /* * The _goto case is normally between TBs within the same code buffer, and * with the code buffer limited to 16MB we wouldn't need the long case. @@ -2548,21 +2528,48 @@ static const TCGOutOpLoad outop_ld16s = { .out = tgen_ld16s, }; +static void tgen_st8(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xfff || offset < -0xfff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_st8_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_st8_12(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st8, +}; + +static void tgen_st16(TCGContext *s, TCGType type, TCGReg rd, + TCGReg rn, ptrdiff_t offset) +{ + if (offset > 0xff || offset < -0xff) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, offset); + tcg_out_st16_r(s, COND_AL, rd, rn, TCG_REG_TMP); + } else { + tcg_out_st16_8(s, COND_AL, rd, rn, offset); + } +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st16, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_st8_i32: - tcg_out_st8(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_st16_i32: - tcg_out_st16(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_st_i32: - tcg_out_st32(s, COND_AL, args[0], args[1], args[2]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -2589,11 +2596,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - return C_O0_I2(r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, q); case INDEX_op_qemu_ld_i64: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index d16ddcb940..52285bcd54 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3489,55 +3489,69 @@ static const TCGOutOpLoad outop_ld32s = { }; #endif +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, data, base, offset); +} + +static void tgen_st8_i(TCGContext *s, TCGType type, tcg_target_long data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVB_EvIz, 0, base, offset); + tcg_out8(s, data); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(qi, r), + .out_r = tgen_st8_r, + .out_i = tgen_st8_i, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, data, base, offset); +} + +static void tgen_st16_i(TCGContext *s, TCGType type, tcg_target_long data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16, 0, base, offset); + tcg_out16(s, data); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(ri, r), + .out_r = tgen_st16_r, + .out_i = tgen_st16_i, +}; + +static void tgen_st_i(TCGContext *s, TCGType type, tcg_target_long data, + TCGReg base, ptrdiff_t offset) +{ + bool ok = tcg_out_sti(s, type, data, base, offset); + tcg_debug_assert(ok); +} + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(re, r), + .out_r = tcg_out_st, + .out_i = tgen_st_i, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { TCGArg a0, a1, a2; -#if TCG_TARGET_REG_BITS == 64 -# define OP_32_64(x) \ - case glue(glue(INDEX_op_, x), _i64): \ - case glue(glue(INDEX_op_, x), _i32) -#else -# define OP_32_64(x) \ - case glue(glue(INDEX_op_, x), _i32) -#endif - /* Hoist the loads of the most common arguments. */ a0 = args[0]; a1 = args[1]; a2 = args[2]; switch (opc) { - OP_32_64(st8): - if (const_args[0]) { - tcg_out_modrm_offset(s, OPC_MOVB_EvIz, 0, a1, a2); - tcg_out8(s, a0); - } else { - tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, a0, a1, a2); - } - break; - OP_32_64(st16): - if (const_args[0]) { - tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16, 0, a1, a2); - tcg_out16(s, a0); - } else { - tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, a0, a1, a2); - } - break; -#if TCG_TARGET_REG_BITS == 64 - case INDEX_op_st32_i64: -#endif - case INDEX_op_st_i32: - if (const_args[0]) { - tcg_out_modrm_offset(s, OPC_MOVL_EvIz, 0, a1, a2); - tcg_out32(s, a0); - } else { - tcg_out_st(s, TCG_TYPE_I32, a0, a1, a2); - } - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I32); break; @@ -3569,25 +3583,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I128); break; -#if TCG_TARGET_REG_BITS == 64 - case INDEX_op_st_i64: - if (const_args[0]) { - tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_REXW, 0, a1, a2); - tcg_out32(s, a0); - } else { - tcg_out_st(s, TCG_TYPE_I64, a0, a1, a2); - } - break; -#endif - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ default: g_assert_not_reached(); } - -#undef OP_32_64 } static int const umin_insn[4] = { @@ -4135,19 +4136,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - return C_O0_I2(qi, r); - - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - return C_O0_I2(ri, r); - - case INDEX_op_st_i64: - return C_O0_I2(re, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, L); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 66555b8982..73a1196d8b 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1983,6 +1983,33 @@ static const TCGOutOpLoad outop_ld32s = { .out = tgen_ld32s, }; +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_ST_B, data, base, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st8_r, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_ST_H, data, base, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st16_r, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) @@ -1993,22 +2020,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - tcg_out_ldst(s, OPC_ST_B, a0, a1, a2); - break; - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - tcg_out_ldst(s, OPC_ST_H, a0, a1, a2); - break; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - tcg_out_ldst(s, OPC_ST_W, a0, a1, a2); - break; - case INDEX_op_st_i64: - tcg_out_ldst(s, OPC_ST_D, a0, a1, a2); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -2530,13 +2541,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i32: - case INDEX_op_st_i64: case INDEX_op_qemu_st_i32: case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 21ed11b78d..5e41729d88 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2342,12 +2342,38 @@ static const TCGOutOpLoad outop_ld32s = { }; #endif +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_SB, data, base, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st8_r, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_SH, data, base, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st16_r, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - MIPSInsn i1; TCGArg a0, a1, a2; a0 = args[0]; @@ -2355,24 +2381,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - i1 = OPC_SB; - goto do_ldst; - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - i1 = OPC_SH; - goto do_ldst; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - i1 = OPC_SW; - goto do_ldst; - case INDEX_op_st_i64: - i1 = OPC_SD; - do_ldst: - tcg_out_ldst(s, i1, a0, a1, a2); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32); break; @@ -2407,15 +2415,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(rz, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_st_i32: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 275c5a90a5..9cf24831df 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3746,28 +3746,39 @@ static const TCGOutOpLoad outop_ld32s = { }; #endif +static void tgen_st8(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, STB, STBX, data, base, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st8, +}; + +static void tgen_st16(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem_long(s, STH, STHX, data, base, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st16, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - tcg_out_mem_long(s, STB, STBX, args[0], args[1], args[2]); - break; - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - tcg_out_mem_long(s, STH, STHX, args[0], args[1], args[2]); - break; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - tcg_out_mem_long(s, STW, STWX, args[0], args[1], args[2]); - break; - case INDEX_op_st_i64: - tcg_out_mem_long(s, STD, STDX, args[0], args[1], args[2]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -4415,15 +4426,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i64: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 5b987c930f..bcfdb6c545 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2596,6 +2596,33 @@ static const TCGOutOpLoad outop_ld32s = { .out = tgen_ld32s, }; +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_SB, data, base, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st8_r, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, OPC_SH, data, base, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st16_r, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2606,22 +2633,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - tcg_out_ldst(s, OPC_SB, a0, a1, a2); - break; - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - tcg_out_ldst(s, OPC_SH, a0, a1, a2); - break; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - tcg_out_ldst(s, OPC_SW, a0, a1, a2); - break; - case INDEX_op_st_i64: - tcg_out_ldst(s, OPC_SD, a0, a1, a2); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -2864,15 +2875,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(rz, r); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index fe7665b21d..e266c19829 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3100,29 +3100,39 @@ static const TCGOutOpLoad outop_ld32s = { .out = tgen_ld32s, }; -# define OP_32_64(x) \ - case glue(glue(INDEX_op_,x),_i32): \ - case glue(glue(INDEX_op_,x),_i64) +static void tgen_st8(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, RX_STC, RXY_STCY, data, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st8, +}; + +static void tgen_st16(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_mem(s, RX_STH, RXY_STHY, data, base, TCG_REG_NONE, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st16, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - OP_32_64(st8): - tcg_out_mem(s, RX_STC, RXY_STCY, args[0], args[1], - TCG_REG_NONE, args[2]); - break; - - OP_32_64(st16): - tcg_out_mem(s, RX_STH, RXY_STHY, args[0], args[1], - TCG_REG_NONE, args[2]); - break; - - case INDEX_op_st_i32: - tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I32); break; @@ -3142,13 +3152,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; - case INDEX_op_st32_i64: - tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); - break; - case INDEX_op_st_i64: - tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ @@ -3597,15 +3600,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(r, r); - case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 59a737dde4..a0efeee98c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -2028,6 +2028,33 @@ static const TCGOutOpLoad outop_ld32s = { .out = tgen_ld32s, }; +static void tgen_st8_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, data, base, offset, STB); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st8_r, +}; + +static void tgen_st16_r(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, data, base, offset, STH); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tgen_st16_r, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], @@ -2041,21 +2068,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { -#define OP_32_64(x) \ - glue(glue(case INDEX_op_, x), _i32): \ - glue(glue(case INDEX_op_, x), _i64) - - OP_32_64(st8): - tcg_out_ldst(s, a0, a1, a2, STB); - break; - OP_32_64(st16): - tcg_out_ldst(s, a0, a1, a2, STH); - break; - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - tcg_out_ldst(s, a0, a1, a2, STW); - break; - case INDEX_op_qemu_ld_i32: tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); break; @@ -2069,10 +2081,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); break; - case INDEX_op_st_i64: - tcg_out_ldst(s, a0, a1, a2, STX); - break; - case INDEX_op_call: /* Always emitted via tcg_out_call. */ case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ @@ -2089,13 +2097,6 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_ld_i64: return C_O1_I1(r, r); - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - case INDEX_op_st_i32: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: case INDEX_op_qemu_st_i32: case INDEX_op_qemu_st_i64: return C_O0_I2(rz, r); diff --git a/tcg/tcg.c b/tcg/tcg.c index a9d62d9e17..28791c6567 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1090,6 +1090,14 @@ typedef struct TCGOutOpSetcond2 { TCGArg bl, bool const_bl, TCGArg bh, bool const_bh); } TCGOutOpSetcond2; +typedef struct TCGOutOpStore { + TCGOutOp base; + void (*out_r)(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, intptr_t offset); + void (*out_i)(TCGContext *s, TCGType type, tcg_target_long data, + TCGReg base, intptr_t offset); +} TCGOutOpStore; + typedef struct TCGOutOpSubtract { TCGOutOp base; void (*out_rrr)(TCGContext *s, TCGType type, @@ -1211,6 +1219,12 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_sextract, TCGOutOpExtract, outop_sextract), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), + OUTOP(INDEX_op_st_i32, TCGOutOpStore, outop_st), + OUTOP(INDEX_op_st_i64, TCGOutOpStore, outop_st), + OUTOP(INDEX_op_st8_i32, TCGOutOpStore, outop_st8), + OUTOP(INDEX_op_st8_i64, TCGOutOpStore, outop_st8), + OUTOP(INDEX_op_st16_i32, TCGOutOpStore, outop_st16), + OUTOP(INDEX_op_st16_i64, TCGOutOpStore, outop_st16), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_subbi, TCGOutOpAddSubCarry, outop_subbi), OUTOP(INDEX_op_subbio, TCGOutOpAddSubCarry, outop_subbio), @@ -1232,6 +1246,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u), OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s), + OUTOP(INDEX_op_st32_i64, TCGOutOpStore, outop_st), #endif }; @@ -5779,6 +5794,28 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_st32_i64: + /* Use tcg_op_st w/ I32. */ + type = TCG_TYPE_I32; + /* fall through */ + case INDEX_op_st_i32: + case INDEX_op_st_i64: + case INDEX_op_st8_i32: + case INDEX_op_st8_i64: + case INDEX_op_st16_i32: + case INDEX_op_st16_i64: + { + const TCGOutOpStore *out = + container_of(all_outop[op->opc], TCGOutOpStore, base); + + if (const_args[0]) { + out->out_i(s, type, new_args[0], new_args[1], new_args[2]); + } else { + out->out_r(s, type, new_args[0], new_args[1], new_args[2]); + } + } + break; + case INDEX_op_brcond: { const TCGOutOpBrcond *out = &outop_brcond; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index d549dc90f5..be9270a861 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -40,15 +40,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: - return C_O0_I2(r, r); - case INDEX_op_qemu_ld_i32: return C_O1_I1(r, r); case INDEX_op_qemu_ld_i64: @@ -487,18 +478,6 @@ static void tcg_out_call(TCGContext *s, const tcg_insn_unit *func, tcg_out32(s, insn); } -#if TCG_TARGET_REG_BITS == 64 -# define CASE_32_64(x) \ - case glue(glue(INDEX_op_, x), _i64): \ - case glue(glue(INDEX_op_, x), _i32): -# define CASE_64(x) \ - case glue(glue(INDEX_op_, x), _i64): -#else -# define CASE_32_64(x) \ - case glue(glue(INDEX_op_, x), _i32): -# define CASE_64(x) -#endif - static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) { tcg_out_op_p(s, INDEX_op_exit_tb, (void *)arg); @@ -1191,20 +1170,39 @@ static const TCGOutOpLoad outop_ld32s = { }; #endif +static void tgen_st8(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_st8_i32, data, base, offset); +} + +static const TCGOutOpStore outop_st8 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st8, +}; + +static void tgen_st16(TCGContext *s, TCGType type, TCGReg data, + TCGReg base, ptrdiff_t offset) +{ + tcg_out_ldst(s, INDEX_op_st16_i32, data, base, offset); +} + +static const TCGOutOpStore outop_st16 = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tgen_st16, +}; + +static const TCGOutOpStore outop_st = { + .base.static_constraint = C_O0_I2(r, r), + .out_r = tcg_out_st, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - CASE_32_64(st8) - CASE_32_64(st16) - case INDEX_op_st_i32: - CASE_64(st32) - CASE_64(st) - tcg_out_ldst(s, opc, args[0], args[1], args[2]); - break; - case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: if (TCG_TARGET_REG_BITS == 32) { From a28f151d61604feae1d6c75b79e67d1c6c6a8b18 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 Jan 2025 13:28:55 -0800 Subject: [PATCH 0508/2760] tcg: Merge INDEX_op_st*_{i32,i64} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/tcg/tcg-opc.h | 15 ++++---------- tcg/optimize.c | 28 +++++++------------------ tcg/tcg-op.c | 14 ++++++------- tcg/tcg.c | 45 +++++++++++++--------------------------- tcg/tci.c | 36 +++++++++----------------------- tcg/tci/tcg-target.c.inc | 20 +++++++----------- 6 files changed, 50 insertions(+), 108 deletions(-) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 6e8fcefaef..a22433d8b5 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -86,6 +86,10 @@ DEF(setcond, 1, 2, 1, TCG_OPF_INT) DEF(sextract, 1, 1, 2, TCG_OPF_INT) DEF(shl, 1, 2, 0, TCG_OPF_INT) DEF(shr, 1, 2, 0, TCG_OPF_INT) +DEF(st8, 0, 2, 1, TCG_OPF_INT) +DEF(st16, 0, 2, 1, TCG_OPF_INT) +DEF(st32, 0, 2, 1, TCG_OPF_INT) +DEF(st, 0, 2, 1, TCG_OPF_INT) DEF(sub, 1, 2, 0, TCG_OPF_INT) DEF(xor, 1, 2, 0, TCG_OPF_INT) @@ -99,20 +103,9 @@ DEF(subb1o, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_OUT) DEF(subbi, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN) DEF(subbio, 1, 2, 0, TCG_OPF_INT | TCG_OPF_CARRY_IN | TCG_OPF_CARRY_OUT) -/* load/store */ -DEF(st8_i32, 0, 2, 1, 0) -DEF(st16_i32, 0, 2, 1, 0) -DEF(st_i32, 0, 2, 1, 0) - DEF(brcond2_i32, 0, 4, 2, TCG_OPF_BB_END | TCG_OPF_COND_BRANCH) DEF(setcond2_i32, 1, 4, 1, 0) -/* load/store */ -DEF(st8_i64, 0, 2, 1, 0) -DEF(st16_i64, 0, 2, 1, 0) -DEF(st32_i64, 0, 2, 1, 0) -DEF(st_i64, 0, 2, 1, 0) - /* size changing ops */ DEF(ext_i32_i64, 1, 1, 0, 0) DEF(extu_i32_i64, 1, 1, 0, 0) diff --git a/tcg/optimize.c b/tcg/optimize.c index d928a38e14..cfb407c7fc 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -30,14 +30,6 @@ #include "tcg-internal.h" #include "tcg-has.h" -#define CASE_OP_32_64(x) \ - glue(glue(case INDEX_op_, x), _i32): \ - glue(glue(case INDEX_op_, x), _i64) - -#define CASE_OP_32_64_VEC(x) \ - glue(glue(case INDEX_op_, x), _i32): \ - glue(glue(case INDEX_op_, x), _i64): \ - glue(glue(case INDEX_op_, x), _vec) typedef struct MemCopyInfo { IntervalTreeNode itree; @@ -2938,19 +2930,16 @@ static bool fold_tcg_st(OptContext *ctx, TCGOp *op) } switch (op->opc) { - CASE_OP_32_64(st8): + case INDEX_op_st8: lm1 = 0; break; - CASE_OP_32_64(st16): + case INDEX_op_st16: lm1 = 1; break; - case INDEX_op_st32_i64: - case INDEX_op_st_i32: + case INDEX_op_st32: lm1 = 3; break; - case INDEX_op_st_i64: - lm1 = 7; - break; + case INDEX_op_st: case INDEX_op_st_vec: lm1 = tcg_type_size(ctx->type) - 1; break; @@ -3138,13 +3127,12 @@ void tcg_optimize(TCGContext *s) case INDEX_op_ld_vec: done = fold_tcg_ld_memcopy(&ctx, op); break; - CASE_OP_32_64(st8): - CASE_OP_32_64(st16): - case INDEX_op_st32_i64: + case INDEX_op_st8: + case INDEX_op_st16: + case INDEX_op_st32: done = fold_tcg_st(&ctx, op); break; - case INDEX_op_st_i32: - case INDEX_op_st_i64: + case INDEX_op_st: case INDEX_op_st_vec: done = fold_tcg_st_memcopy(&ctx, op); break; diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c index 680f752cf9..dfa5c38728 100644 --- a/tcg/tcg-op.c +++ b/tcg/tcg-op.c @@ -1404,17 +1404,17 @@ void tcg_gen_ld_i32(TCGv_i32 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_st8_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_st8_i32, arg1, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_st8, arg1, arg2, offset); } void tcg_gen_st16_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_st16_i32, arg1, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_st16, arg1, arg2, offset); } void tcg_gen_st_i32(TCGv_i32 arg1, TCGv_ptr arg2, tcg_target_long offset) { - tcg_gen_ldst_op_i32(INDEX_op_st_i32, arg1, arg2, offset); + tcg_gen_ldst_op_i32(INDEX_op_st, arg1, arg2, offset); } @@ -1540,7 +1540,7 @@ void tcg_gen_ld_i64(TCGv_i64 ret, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_st8_i64, arg1, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_st8, arg1, arg2, offset); } else { tcg_gen_st8_i32(TCGV_LOW(arg1), arg2, offset); } @@ -1549,7 +1549,7 @@ void tcg_gen_st8_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_st16_i64, arg1, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_st16, arg1, arg2, offset); } else { tcg_gen_st16_i32(TCGV_LOW(arg1), arg2, offset); } @@ -1558,7 +1558,7 @@ void tcg_gen_st16_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_st32_i64, arg1, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_st32, arg1, arg2, offset); } else { tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset); } @@ -1567,7 +1567,7 @@ void tcg_gen_st32_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) void tcg_gen_st_i64(TCGv_i64 arg1, TCGv_ptr arg2, tcg_target_long offset) { if (TCG_TARGET_REG_BITS == 64) { - tcg_gen_ldst_op_i64(INDEX_op_st_i64, arg1, arg2, offset); + tcg_gen_ldst_op_i64(INDEX_op_st, arg1, arg2, offset); } else if (HOST_BIG_ENDIAN) { tcg_gen_st_i32(TCGV_HIGH(arg1), arg2, offset); tcg_gen_st_i32(TCGV_LOW(arg1), arg2, offset + 4); diff --git a/tcg/tcg.c b/tcg/tcg.c index 28791c6567..44b6b8319f 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1219,12 +1219,9 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_sextract, TCGOutOpExtract, outop_sextract), OUTOP(INDEX_op_shl, TCGOutOpBinary, outop_shl), OUTOP(INDEX_op_shr, TCGOutOpBinary, outop_shr), - OUTOP(INDEX_op_st_i32, TCGOutOpStore, outop_st), - OUTOP(INDEX_op_st_i64, TCGOutOpStore, outop_st), - OUTOP(INDEX_op_st8_i32, TCGOutOpStore, outop_st8), - OUTOP(INDEX_op_st8_i64, TCGOutOpStore, outop_st8), - OUTOP(INDEX_op_st16_i32, TCGOutOpStore, outop_st16), - OUTOP(INDEX_op_st16_i64, TCGOutOpStore, outop_st16), + OUTOP(INDEX_op_st, TCGOutOpStore, outop_st), + OUTOP(INDEX_op_st8, TCGOutOpStore, outop_st8), + OUTOP(INDEX_op_st16, TCGOutOpStore, outop_st16), OUTOP(INDEX_op_sub, TCGOutOpSubtract, outop_sub), OUTOP(INDEX_op_subbi, TCGOutOpAddSubCarry, outop_subbi), OUTOP(INDEX_op_subbio, TCGOutOpAddSubCarry, outop_subbio), @@ -1246,7 +1243,7 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_extrh_i64_i32, TCGOutOpUnary, outop_extrh_i64_i32), OUTOP(INDEX_op_ld32u, TCGOutOpLoad, outop_ld32u), OUTOP(INDEX_op_ld32s, TCGOutOpLoad, outop_ld32s), - OUTOP(INDEX_op_st32_i64, TCGOutOpStore, outop_st), + OUTOP(INDEX_op_st32, TCGOutOpStore, outop_st), #endif }; @@ -2464,24 +2461,19 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_or: case INDEX_op_setcond: case INDEX_op_sextract: + case INDEX_op_st8: + case INDEX_op_st16: + case INDEX_op_st: case INDEX_op_xor: return has_type; - case INDEX_op_st8_i32: - case INDEX_op_st16_i32: - case INDEX_op_st_i32: - return true; - case INDEX_op_brcond2_i32: case INDEX_op_setcond2_i32: return TCG_TARGET_REG_BITS == 32; case INDEX_op_ld32u: case INDEX_op_ld32s: - case INDEX_op_st8_i64: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i64: + case INDEX_op_st32: case INDEX_op_ext_i32_i64: case INDEX_op_extu_i32_i64: case INDEX_op_extrl_i64_i32: @@ -4494,10 +4486,7 @@ liveness_pass_2(TCGContext *s) arg_ts->state = 0; if (NEED_SYNC_ARG(0)) { - TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 - ? INDEX_op_st_i32 - : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc, + TCGOp *sop = tcg_op_insert_after(s, op, INDEX_op_st, arg_ts->type, 3); TCGTemp *out_ts = dir_ts; @@ -4531,10 +4520,7 @@ liveness_pass_2(TCGContext *s) /* Sync outputs upon their last write. */ if (NEED_SYNC_ARG(i)) { - TCGOpcode sopc = (arg_ts->type == TCG_TYPE_I32 - ? INDEX_op_st_i32 - : INDEX_op_st_i64); - TCGOp *sop = tcg_op_insert_after(s, op, sopc, + TCGOp *sop = tcg_op_insert_after(s, op, INDEX_op_st, arg_ts->type, 3); sop->args[0] = temp_arg(dir_ts); @@ -5794,16 +5780,13 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; - case INDEX_op_st32_i64: + case INDEX_op_st32: /* Use tcg_op_st w/ I32. */ type = TCG_TYPE_I32; /* fall through */ - case INDEX_op_st_i32: - case INDEX_op_st_i64: - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: + case INDEX_op_st: + case INDEX_op_st8: + case INDEX_op_st16: { const TCGOutOpStore *out = container_of(all_outop[op->opc], TCGOutOpStore, base); diff --git a/tcg/tci.c b/tcg/tci.c index 890ccbe85b..b08288e7d3 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -325,18 +325,6 @@ static void tci_qemu_st(CPUArchState *env, uint64_t taddr, uint64_t val, } } -#if TCG_TARGET_REG_BITS == 64 -# define CASE_32_64(x) \ - case glue(glue(INDEX_op_, x), _i64): \ - case glue(glue(INDEX_op_, x), _i32): -# define CASE_64(x) \ - case glue(glue(INDEX_op_, x), _i64): -#else -# define CASE_32_64(x) \ - case glue(glue(INDEX_op_, x), _i32): -# define CASE_64(x) -#endif - /* Interpret pseudo code in tb. */ /* * Disable CFI checks. @@ -491,21 +479,20 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, ptr = (void *)(regs[r1] + ofs); regs[r0] = *(tcg_target_ulong *)ptr; break; - CASE_32_64(st8) + case INDEX_op_st8: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); *(uint8_t *)ptr = regs[r0]; break; - CASE_32_64(st16) + case INDEX_op_st16: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); *(uint16_t *)ptr = regs[r0]; break; - case INDEX_op_st_i32: - CASE_64(st32) + case INDEX_op_st: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); - *(uint32_t *)ptr = regs[r0]; + *(tcg_target_ulong *)ptr = regs[r0]; break; /* Arithmetic operations (mixed 32/64 bit). */ @@ -725,10 +712,10 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, ptr = (void *)(regs[r1] + ofs); regs[r0] = *(int32_t *)ptr; break; - case INDEX_op_st_i64: + case INDEX_op_st32: tci_args_rrs(insn, &r0, &r1, &ofs); ptr = (void *)(regs[r1] + ofs); - *(uint64_t *)ptr = regs[r0]; + *(uint32_t *)ptr = regs[r0]; break; /* Arithmetic operations (64 bit). */ @@ -975,13 +962,10 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) case INDEX_op_ld16s: case INDEX_op_ld32u: case INDEX_op_ld: - case INDEX_op_st8_i32: - case INDEX_op_st8_i64: - case INDEX_op_st16_i32: - case INDEX_op_st16_i64: - case INDEX_op_st32_i64: - case INDEX_op_st_i32: - case INDEX_op_st_i64: + case INDEX_op_st8: + case INDEX_op_st16: + case INDEX_op_st32: + case INDEX_op_st: tci_args_rrs(insn, &r0, &r1, &s2); info->fprintf_func(info->stream, "%-12s %s, %s, %d", op_name, str_r(r0), str_r(r1), s2); diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index be9270a861..1fb7575061 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -1173,7 +1173,7 @@ static const TCGOutOpLoad outop_ld32s = { static void tgen_st8(TCGContext *s, TCGType type, TCGReg data, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_st8_i32, data, base, offset); + tcg_out_ldst(s, INDEX_op_st8, data, base, offset); } static const TCGOutOpStore outop_st8 = { @@ -1184,7 +1184,7 @@ static const TCGOutOpStore outop_st8 = { static void tgen_st16(TCGContext *s, TCGType type, TCGReg data, TCGReg base, ptrdiff_t offset) { - tcg_out_ldst(s, INDEX_op_st16_i32, data, base, offset); + tcg_out_ldst(s, INDEX_op_st16, data, base, offset); } static const TCGOutOpStore outop_st16 = { @@ -1232,18 +1232,12 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, static void tcg_out_st(TCGContext *s, TCGType type, TCGReg val, TCGReg base, intptr_t offset) { - switch (type) { - case TCG_TYPE_I32: - tcg_out_ldst(s, INDEX_op_st_i32, val, base, offset); - break; -#if TCG_TARGET_REG_BITS == 64 - case TCG_TYPE_I64: - tcg_out_ldst(s, INDEX_op_st_i64, val, base, offset); - break; -#endif - default: - g_assert_not_reached(); + TCGOpcode op = INDEX_op_st; + + if (TCG_TARGET_REG_BITS == 64 && type == TCG_TYPE_I32) { + op = INDEX_op_st32; } + tcg_out_ldst(s, op, val, base, offset); } static inline bool tcg_out_sti(TCGContext *s, TCGType type, TCGArg val, From bf7ca5fb3032b95fd83dbb9883e904ee28baa229 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 23 Jan 2025 09:46:57 -0800 Subject: [PATCH 0509/2760] tcg: Stash MemOp size in TCGOP_FLAGS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will enable removing INDEX_op_qemu_st8_*_i32, by exposing the operand size to constraint selection. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/tcg-op-ldst.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index 3b073b4ce0..9e4626e51d 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -91,11 +91,15 @@ static MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) static void gen_ldst(TCGOpcode opc, TCGType type, TCGTemp *vl, TCGTemp *vh, TCGTemp *addr, MemOpIdx oi) { + TCGOp *op; + if (vh) { - tcg_gen_op4(opc, type, temp_arg(vl), temp_arg(vh), temp_arg(addr), oi); + op = tcg_gen_op4(opc, type, temp_arg(vl), temp_arg(vh), + temp_arg(addr), oi); } else { - tcg_gen_op3(opc, type, temp_arg(vl), temp_arg(addr), oi); + op = tcg_gen_op3(opc, type, temp_arg(vl), temp_arg(addr), oi); } + TCGOP_FLAGS(op) = get_memop(oi) & MO_SIZE; } static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 v, TCGTemp *addr, MemOpIdx oi) From 33aba058c8fcc9b1581b03a1fbac45d8d91baac6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 26 Jan 2025 17:34:19 -0800 Subject: [PATCH 0510/2760] tcg: Remove INDEX_op_qemu_st8_* MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The i386 backend can now check TCGOP_FLAGS to select the correct set of constraints. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- docs/devel/tcg-ops.rst | 6 ------ include/tcg/tcg-opc.h | 4 ---- tcg/aarch64/tcg-target-has.h | 1 - tcg/arm/tcg-target-has.h | 1 - tcg/i386/tcg-target-con-str.h | 2 +- tcg/i386/tcg-target-has.h | 3 --- tcg/i386/tcg-target.c.inc | 9 ++++----- tcg/loongarch64/tcg-target-has.h | 3 --- tcg/mips/tcg-target-has.h | 1 - tcg/optimize.c | 1 - tcg/ppc/tcg-target-has.h | 2 -- tcg/riscv/tcg-target-has.h | 1 - tcg/s390x/tcg-target-has.h | 1 - tcg/sparc64/tcg-target-has.h | 1 - tcg/tcg-op-ldst.c | 9 ++------- tcg/tcg.c | 4 ---- tcg/tci/tcg-target-has.h | 2 -- 17 files changed, 7 insertions(+), 44 deletions(-) diff --git a/docs/devel/tcg-ops.rst b/docs/devel/tcg-ops.rst index a7147407de..f26b837a30 100644 --- a/docs/devel/tcg-ops.rst +++ b/docs/devel/tcg-ops.rst @@ -744,8 +744,6 @@ QEMU specific operations qemu_st_i32/i64/i128 *t0*, *t1*, *flags*, *memidx* - qemu_st8_i32 *t0*, *t1*, *flags*, *memidx* - - | Load data at the guest address *t1* into *t0*, or store data in *t0* at guest address *t1*. The _i32/_i64/_i128 size applies to the size of the input/output register *t0* only. The address *t1* is always sized according to the guest, @@ -763,10 +761,6 @@ QEMU specific operations 64-bit memory access specified in *flags*. | | For qemu_ld/st_i128, these are only supported for a 64-bit host. - | - | For i386, qemu_st8_i32 is exactly like qemu_st_i32, except the size of - the memory operation is known to be 8-bit. This allows the backend to - provide a different set of register constraints. Host vector operations diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index a22433d8b5..0ce8332aab 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -133,10 +133,6 @@ DEF(qemu_ld_i64, DATA64_ARGS, 1, 1, DEF(qemu_st_i64, 0, DATA64_ARGS + 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -/* Only used by i386 to cope with stupid register constraints. */ -DEF(qemu_st8_i32, 0, 1 + 1, 1, - TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) - /* Only for 64-bit hosts at the moment. */ DEF(qemu_ld_i128, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) DEF(qemu_st_i128, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) diff --git a/tcg/aarch64/tcg-target-has.h b/tcg/aarch64/tcg-target-has.h index b155e37639..69e83efb69 100644 --- a/tcg/aarch64/tcg-target-has.h +++ b/tcg/aarch64/tcg-target-has.h @@ -14,7 +14,6 @@ /* optional instructions */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_qemu_st8_i32 0 /* * Without FEAT_LSE2, we must use LDXP+STXP to implement atomic 128-bit load, diff --git a/tcg/arm/tcg-target-has.h b/tcg/arm/tcg-target-has.h index 187269e5bd..3bbbde5d59 100644 --- a/tcg/arm/tcg-target-has.h +++ b/tcg/arm/tcg-target-has.h @@ -24,7 +24,6 @@ extern bool use_neon_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 1 diff --git a/tcg/i386/tcg-target-con-str.h b/tcg/i386/tcg-target-con-str.h index 52142ab121..dbedff1f54 100644 --- a/tcg/i386/tcg-target-con-str.h +++ b/tcg/i386/tcg-target-con-str.h @@ -20,7 +20,7 @@ REGS('r', ALL_GENERAL_REGS) REGS('x', ALL_VECTOR_REGS) REGS('q', ALL_BYTEL_REGS) /* regs that can be used as a byte operand */ REGS('L', ALL_GENERAL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_ld/st */ -REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st8_i32 data */ +REGS('s', ALL_BYTEL_REGS & ~SOFTMMU_RESERVE_REGS) /* qemu_st MO_8 data */ /* * Define constraint letters for constants: diff --git a/tcg/i386/tcg-target-has.h b/tcg/i386/tcg-target-has.h index 628e736de7..42647fabbd 100644 --- a/tcg/i386/tcg-target-has.h +++ b/tcg/i386/tcg-target-has.h @@ -29,9 +29,6 @@ #if TCG_TARGET_REG_BITS == 64 /* Keep 32-bit values zero-extended in a register. */ #define TCG_TARGET_HAS_extr_i64_i32 1 -#define TCG_TARGET_HAS_qemu_st8_i32 0 -#else -#define TCG_TARGET_HAS_qemu_st8_i32 1 #endif #define TCG_TARGET_HAS_qemu_ldst_i128 \ diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 52285bcd54..6c4c2ebd0e 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2457,7 +2457,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, switch (memop & MO_SIZE) { case MO_8: - /* This is handled with constraints on INDEX_op_qemu_st8_i32. */ + /* This is handled with constraints on INDEX_op_qemu_st_i32. */ tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || datalo < 4); tcg_out_modrm_sib_offset(s, OPC_MOVB_EvGv + P_REXB_R + h.seg, datalo, h.base, h.index, 0, h.ofs); @@ -3568,7 +3568,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, break; case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st8_i32: tcg_out_qemu_st(s, a0, -1, a1, a2, TCG_TYPE_I32); break; case INDEX_op_qemu_st_i64: @@ -4140,9 +4139,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) return C_O1_I1(r, L); case INDEX_op_qemu_st_i32: - return C_O0_I2(L, L); - case INDEX_op_qemu_st8_i32: - return C_O0_I2(s, L); + return (TCG_TARGET_REG_BITS == 32 && flags == MO_8 + ? C_O0_I2(s, L) + : C_O0_I2(L, L)); case INDEX_op_qemu_ld_i64: return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) : C_O2_I1(r, r, L); diff --git a/tcg/loongarch64/tcg-target-has.h b/tcg/loongarch64/tcg-target-has.h index 9c118bd1f6..32abc6f457 100644 --- a/tcg/loongarch64/tcg-target-has.h +++ b/tcg/loongarch64/tcg-target-has.h @@ -9,9 +9,6 @@ #include "host/cpuinfo.h" -/* optional instructions */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 - /* 64-bit operations */ #define TCG_TARGET_HAS_extr_i64_i32 1 diff --git a/tcg/mips/tcg-target-has.h b/tcg/mips/tcg-target-has.h index d8f9f7beef..b9eb338528 100644 --- a/tcg/mips/tcg-target-has.h +++ b/tcg/mips/tcg-target-has.h @@ -46,7 +46,6 @@ extern bool use_mips32r2_instructions; #endif /* optional instructions detected at runtime */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 0 diff --git a/tcg/optimize.c b/tcg/optimize.c index cfb407c7fc..4d2220664a 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -3192,7 +3192,6 @@ void tcg_optimize(TCGContext *s) case INDEX_op_qemu_ld_i128: done = fold_qemu_ld_2reg(&ctx, op); break; - case INDEX_op_qemu_st8_i32: case INDEX_op_qemu_st_i32: case INDEX_op_qemu_st_i64: case INDEX_op_qemu_st_i128: diff --git a/tcg/ppc/tcg-target-has.h b/tcg/ppc/tcg-target-has.h index b978c91a62..81ec5aece7 100644 --- a/tcg/ppc/tcg-target-has.h +++ b/tcg/ppc/tcg-target-has.h @@ -17,8 +17,6 @@ #define have_vsx (cpuinfo & CPUINFO_VSX) /* optional instructions */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 - #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 #endif diff --git a/tcg/riscv/tcg-target-has.h b/tcg/riscv/tcg-target-has.h index 8cd099546f..aef10c2d9d 100644 --- a/tcg/riscv/tcg-target-has.h +++ b/tcg/riscv/tcg-target-has.h @@ -10,7 +10,6 @@ #include "host/cpuinfo.h" /* optional instructions */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 1 #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 0 diff --git a/tcg/s390x/tcg-target-has.h b/tcg/s390x/tcg-target-has.h index c04cc4e377..0aeb5ba01a 100644 --- a/tcg/s390x/tcg-target-has.h +++ b/tcg/s390x/tcg-target-has.h @@ -30,7 +30,6 @@ extern uint64_t s390_facilities[3]; /* optional instructions */ #define TCG_TARGET_HAS_extr_i64_i32 0 -#define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 1 #define TCG_TARGET_HAS_tst 1 diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index d9f5ef3fc9..af6a949da3 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -14,7 +14,6 @@ extern bool use_vis3_instructions; #endif /* optional instructions */ -#define TCG_TARGET_HAS_qemu_st8_i32 0 #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 #define TCG_TARGET_HAS_tst 1 diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index 9e4626e51d..ac1af9f77c 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -270,7 +270,6 @@ static void tcg_gen_qemu_st_i32_int(TCGv_i32 val, TCGTemp *addr, { TCGv_i32 swap = NULL; MemOpIdx orig_oi, oi; - TCGOpcode opc; tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST); memop = tcg_canonicalize_memop(memop, 0, 1); @@ -293,12 +292,8 @@ static void tcg_gen_qemu_st_i32_int(TCGv_i32 val, TCGTemp *addr, oi = make_memop_idx(memop, idx); } - if (TCG_TARGET_HAS_qemu_st8_i32 && (memop & MO_SIZE) == MO_8) { - opc = INDEX_op_qemu_st8_i32; - } else { - opc = INDEX_op_qemu_st_i32; - } - gen_ldst(opc, TCG_TYPE_I32, tcgv_i32_temp(val), NULL, addr, oi); + gen_ldst(INDEX_op_qemu_st_i32, TCG_TYPE_I32, + tcgv_i32_temp(val), NULL, addr, oi); plugin_gen_mem_callbacks_i32(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W); if (swap) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 44b6b8319f..5c0cab205c 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2438,9 +2438,6 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_qemu_st_i64: return true; - case INDEX_op_qemu_st8_i32: - return TCG_TARGET_HAS_qemu_st8_i32; - case INDEX_op_qemu_ld_i128: case INDEX_op_qemu_st_i128: return TCG_TARGET_HAS_qemu_ldst_i128; @@ -3012,7 +3009,6 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) break; case INDEX_op_qemu_ld_i32: case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st8_i32: case INDEX_op_qemu_ld_i64: case INDEX_op_qemu_st_i64: case INDEX_op_qemu_ld_i128: diff --git a/tcg/tci/tcg-target-has.h b/tcg/tci/tcg-target-has.h index 497e8152b7..ab07ce1fcb 100644 --- a/tcg/tci/tcg-target-has.h +++ b/tcg/tci/tcg-target-has.h @@ -7,8 +7,6 @@ #ifndef TCG_TARGET_HAS_H #define TCG_TARGET_HAS_H -#define TCG_TARGET_HAS_qemu_st8_i32 0 - #if TCG_TARGET_REG_BITS == 64 #define TCG_TARGET_HAS_extr_i64_i32 0 #endif /* TCG_TARGET_REG_BITS == 64 */ From aae2456ac0b4eb91da7ee8a4b31052f2e8a77af8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 9 Feb 2025 12:55:15 -0800 Subject: [PATCH 0511/2760] tcg: Merge INDEX_op_{ld,st}_{i32,i64,i128} Merge into INDEX_op_{ld,st,ld2,st2}, where "2" indicates that two inputs or outputs are required. This simplifies the processing of i64/i128 depending on host word size. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/tcg/tcg-opc.h | 16 ++----- tcg/aarch64/tcg-target.c.inc | 20 ++++----- tcg/arm/tcg-target.c.inc | 16 +++---- tcg/i386/tcg-target.c.inc | 50 ++++++--------------- tcg/loongarch64/tcg-target.c.inc | 28 +++++------- tcg/mips/tcg-target.c.inc | 38 +++++++--------- tcg/optimize.c | 15 ++----- tcg/ppc/tcg-target.c.inc | 47 ++++++++------------ tcg/riscv/tcg-target.c.inc | 20 +++------ tcg/s390x/tcg-target.c.inc | 28 +++++------- tcg/sparc64/tcg-target.c.inc | 20 +++------ tcg/tcg-op-ldst.c | 75 +++++++++++++++++--------------- tcg/tcg.c | 28 +++++++----- tcg/tci.c | 69 ++++++++++++----------------- tcg/tci/tcg-target.c.inc | 36 ++++++--------- 15 files changed, 200 insertions(+), 306 deletions(-) diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 0ce8332aab..995b79383e 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -124,18 +124,10 @@ DEF(goto_ptr, 0, 1, 0, TCG_OPF_BB_EXIT | TCG_OPF_BB_END) DEF(plugin_cb, 0, 0, 1, TCG_OPF_NOT_PRESENT) DEF(plugin_mem_cb, 0, 1, 1, TCG_OPF_NOT_PRESENT) -DEF(qemu_ld_i32, 1, 1, 1, - TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -DEF(qemu_st_i32, 0, 1 + 1, 1, - TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -DEF(qemu_ld_i64, DATA64_ARGS, 1, 1, - TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -DEF(qemu_st_i64, 0, DATA64_ARGS + 1, 1, - TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) - -/* Only for 64-bit hosts at the moment. */ -DEF(qemu_ld_i128, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) -DEF(qemu_st_i128, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS) +DEF(qemu_ld, 1, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_INT) +DEF(qemu_st, 0, 2, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_INT) +DEF(qemu_ld2, 2, 1, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_INT) +DEF(qemu_st2, 0, 3, 1, TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS | TCG_OPF_INT) /* Host vector support. */ diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 39a44507d1..a48cb46799 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2875,18 +2875,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: tcg_out_qemu_ld(s, a0, a1, a2, ext); break; - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, a1, a2, ext); break; - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], true); break; - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; @@ -3342,15 +3340,13 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: return C_O2_I1(r, r, r); - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st: return C_O0_I2(rz, r); - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: return C_O0_I3(rz, rz, r); case INDEX_op_add_vec: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 5b34f61ca1..29fd82e9e0 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2570,17 +2570,17 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld2: tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st2: tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); break; @@ -2596,13 +2596,13 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: return C_O1_I1(r, q); - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld2: return C_O2_I1(e, p, q); - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return C_O0_I2(q, q); - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st2: return C_O0_I3(Q, p, q); case INDEX_op_st_vec: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 6c4c2ebd0e..cb66f6c27f 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2457,7 +2457,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, switch (memop & MO_SIZE) { case MO_8: - /* This is handled with constraints on INDEX_op_qemu_st_i32. */ + /* This is handled with constraints on INDEX_op_qemu_st. */ tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || datalo < 4); tcg_out_modrm_sib_offset(s, OPC_MOVB_EvGv + P_REXB_R + h.seg, datalo, h.base, h.index, 0, h.ofs); @@ -3552,34 +3552,18 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, a0, -1, a1, a2, type); break; - case INDEX_op_qemu_ld_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_ld(s, a0, -1, a1, a2, TCG_TYPE_I64); - } else { - tcg_out_qemu_ld(s, a0, a1, a2, args[3], TCG_TYPE_I64); - } - break; - case INDEX_op_qemu_ld_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); - tcg_out_qemu_ld(s, a0, a1, a2, args[3], TCG_TYPE_I128); + case INDEX_op_qemu_ld2: + tcg_out_qemu_ld(s, a0, a1, a2, args[3], type); break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, a0, -1, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, a0, -1, a1, a2, type); break; - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_st(s, a0, -1, a1, a2, TCG_TYPE_I64); - } else { - tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I64); - } - break; - case INDEX_op_qemu_st_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); - tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I128); + case INDEX_op_qemu_st2: + tcg_out_qemu_st(s, a0, a1, a2, args[3], type); break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -4135,25 +4119,17 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: return C_O1_I1(r, L); - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return (TCG_TARGET_REG_BITS == 32 && flags == MO_8 ? C_O0_I2(s, L) : C_O0_I2(L, L)); - case INDEX_op_qemu_ld_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, L) : C_O2_I1(r, r, L); - - case INDEX_op_qemu_st_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(L, L) : C_O0_I3(L, L, L); - - case INDEX_op_qemu_ld_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); + case INDEX_op_qemu_ld2: return C_O2_I1(r, r, L); - case INDEX_op_qemu_st_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); + case INDEX_op_qemu_st2: return C_O0_I3(L, L, L); case INDEX_op_ld_vec: diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index 73a1196d8b..e4a8b43578 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -2020,22 +2020,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, a0, a1, a2, type); break; - case INDEX_op_qemu_ld_i64: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I64); - break; - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: tcg_out_qemu_ldst_i128(s, a0, a1, a2, a3, true); break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, a0, a1, a2, type); break; - case INDEX_op_qemu_st_i64: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); - break; - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: tcg_out_qemu_ldst_i128(s, a0, a1, a2, a3, false); break; @@ -2541,18 +2535,16 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st: return C_O0_I2(rz, r); - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: return C_N2_I1(r, r, r); - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: return C_O0_I3(r, r, r); - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); case INDEX_op_ld_vec: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 5e41729d88..eaaf0f2024 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2381,26 +2381,20 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, a0, 0, a1, a2, type); break; - case INDEX_op_qemu_ld_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_ld(s, a0, 0, a1, a2, TCG_TYPE_I64); - } else { - tcg_out_qemu_ld(s, a0, a1, a2, args[3], TCG_TYPE_I64); - } + case INDEX_op_qemu_ld2: + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + tcg_out_qemu_ld(s, a0, a1, a2, args[3], type); break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, a0, 0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, a0, 0, a1, a2, type); break; - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_st(s, a0, 0, a1, a2, TCG_TYPE_I64); - } else { - tcg_out_qemu_st(s, a0, a1, a2, args[3], TCG_TYPE_I64); - } + case INDEX_op_qemu_st2: + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + tcg_out_qemu_st(s, a0, a1, a2, args[3], type); break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -2415,14 +2409,14 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return C_O0_I2(rz, r); - case INDEX_op_qemu_ld_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r); - case INDEX_op_qemu_st_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(rz, r) : C_O0_I3(rz, rz, r); + case INDEX_op_qemu_ld2: + return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O2_I1(r, r, r); + case INDEX_op_qemu_st2: + return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(rz, rz, r); default: return C_NotImplemented; diff --git a/tcg/optimize.c b/tcg/optimize.c index 4d2220664a..10a76c5461 100644 --- a/tcg/optimize.c +++ b/tcg/optimize.c @@ -3180,21 +3180,14 @@ void tcg_optimize(TCGContext *s) case INDEX_op_orc_vec: done = fold_orc(&ctx, op); break; - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: done = fold_qemu_ld_1reg(&ctx, op); break; - case INDEX_op_qemu_ld_i64: - if (TCG_TARGET_REG_BITS == 64) { - done = fold_qemu_ld_1reg(&ctx, op); - break; - } - QEMU_FALLTHROUGH; - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: done = fold_qemu_ld_2reg(&ctx, op); break; - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st: + case INDEX_op_qemu_st2: done = fold_qemu_st(&ctx, op); break; case INDEX_op_rems: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 9cf24831df..bb26769d53 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3779,35 +3779,27 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], type); break; - case INDEX_op_qemu_ld_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I64); - } else { + case INDEX_op_qemu_ld2: + if (TCG_TARGET_REG_BITS == 32) { tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); + break; } - break; - case INDEX_op_qemu_ld_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true); break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, args[0], -1, args[1], args[2], type); break; - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 64) { - tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I64); - } else { + case INDEX_op_qemu_st2: + if (TCG_TARGET_REG_BITS == 32) { tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); + break; } - break; - case INDEX_op_qemu_st_i128: - tcg_debug_assert(TCG_TARGET_REG_BITS == 64); tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; @@ -4426,20 +4418,17 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_ld_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r); + case INDEX_op_qemu_ld2: + return TCG_TARGET_REG_BITS == 64 + ? C_N1O1_I1(o, m, r) : C_O2_I1(r, r, r); - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return C_O0_I2(r, r); - case INDEX_op_qemu_st_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r); - - case INDEX_op_qemu_ld_i128: - return C_N1O1_I1(o, m, r); - case INDEX_op_qemu_st_i128: - return C_O0_I3(o, m, r); + case INDEX_op_qemu_st2: + return TCG_TARGET_REG_BITS == 64 + ? C_O0_I3(o, m, r) : C_O0_I3(r, r, r); case INDEX_op_add_vec: case INDEX_op_sub_vec: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index bcfdb6c545..89c7736f9a 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2633,17 +2633,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, a0, a1, a2, type); break; - case INDEX_op_qemu_ld_i64: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I64); - break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I32); - break; - case INDEX_op_qemu_st_i64: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, a0, a1, a2, type); break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -2875,11 +2869,9 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st: return C_O0_I2(rz, r); case INDEX_op_st_vec: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index e266c19829..652ce9023e 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3133,22 +3133,16 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, args[0], args[1], args[2], type); break; - case INDEX_op_qemu_ld_i64: - tcg_out_qemu_ld(s, args[0], args[1], args[2], TCG_TYPE_I64); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, args[0], args[1], args[2], type); break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, args[0], args[1], args[2], TCG_TYPE_I32); - break; - case INDEX_op_qemu_st_i64: - tcg_out_qemu_st(s, args[0], args[1], args[2], TCG_TYPE_I64); - break; - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true); break; - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; @@ -3600,15 +3594,13 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_st_i64: - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return C_O0_I2(r, r); - case INDEX_op_qemu_ld_i128: + case INDEX_op_qemu_ld2: return C_O2_I1(o, m, r); - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_st2: return C_O0_I3(o, m, r); case INDEX_op_st_vec: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index a0efeee98c..bf27b6b54b 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -2068,17 +2068,11 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld_i32: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I32); + case INDEX_op_qemu_ld: + tcg_out_qemu_ld(s, a0, a1, a2, type); break; - case INDEX_op_qemu_ld_i64: - tcg_out_qemu_ld(s, a0, a1, a2, TCG_TYPE_I64); - break; - case INDEX_op_qemu_st_i32: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I32); - break; - case INDEX_op_qemu_st_i64: - tcg_out_qemu_st(s, a0, a1, a2, TCG_TYPE_I64); + case INDEX_op_qemu_st: + tcg_out_qemu_st(s, a0, a1, a2, type); break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ @@ -2093,12 +2087,10 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_ld_i64: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_st_i64: + case INDEX_op_qemu_st: return C_O0_I2(rz, r); default: diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index ac1af9f77c..fa9e52277b 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -88,28 +88,40 @@ static MemOp tcg_canonicalize_memop(MemOp op, bool is64, bool st) return op; } -static void gen_ldst(TCGOpcode opc, TCGType type, TCGTemp *vl, TCGTemp *vh, - TCGTemp *addr, MemOpIdx oi) +static void gen_ldst1(TCGOpcode opc, TCGType type, TCGTemp *v, + TCGTemp *addr, MemOpIdx oi) { - TCGOp *op; - - if (vh) { - op = tcg_gen_op4(opc, type, temp_arg(vl), temp_arg(vh), - temp_arg(addr), oi); - } else { - op = tcg_gen_op3(opc, type, temp_arg(vl), temp_arg(addr), oi); - } + TCGOp *op = tcg_gen_op3(opc, type, temp_arg(v), temp_arg(addr), oi); TCGOP_FLAGS(op) = get_memop(oi) & MO_SIZE; } -static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 v, TCGTemp *addr, MemOpIdx oi) +static void gen_ldst2(TCGOpcode opc, TCGType type, TCGTemp *vl, TCGTemp *vh, + TCGTemp *addr, MemOpIdx oi) +{ + TCGOp *op = tcg_gen_op4(opc, type, temp_arg(vl), temp_arg(vh), + temp_arg(addr), oi); + TCGOP_FLAGS(op) = get_memop(oi) & MO_SIZE; +} + +static void gen_ld_i64(TCGv_i64 v, TCGTemp *addr, MemOpIdx oi) { if (TCG_TARGET_REG_BITS == 32) { - TCGTemp *vl = tcgv_i32_temp(TCGV_LOW(v)); - TCGTemp *vh = tcgv_i32_temp(TCGV_HIGH(v)); - gen_ldst(opc, TCG_TYPE_I64, vl, vh, addr, oi); + gen_ldst2(INDEX_op_qemu_ld2, TCG_TYPE_I64, + tcgv_i32_temp(TCGV_LOW(v)), tcgv_i32_temp(TCGV_HIGH(v)), + addr, oi); } else { - gen_ldst(opc, TCG_TYPE_I64, tcgv_i64_temp(v), NULL, addr, oi); + gen_ldst1(INDEX_op_qemu_ld, TCG_TYPE_I64, tcgv_i64_temp(v), addr, oi); + } +} + +static void gen_st_i64(TCGv_i64 v, TCGTemp *addr, MemOpIdx oi) +{ + if (TCG_TARGET_REG_BITS == 32) { + gen_ldst2(INDEX_op_qemu_st2, TCG_TYPE_I64, + tcgv_i32_temp(TCGV_LOW(v)), tcgv_i32_temp(TCGV_HIGH(v)), + addr, oi); + } else { + gen_ldst1(INDEX_op_qemu_st, TCG_TYPE_I64, tcgv_i64_temp(v), addr, oi); } } @@ -236,8 +248,7 @@ static void tcg_gen_qemu_ld_i32_int(TCGv_i32 val, TCGTemp *addr, } copy_addr = plugin_maybe_preserve_addr(addr); - gen_ldst(INDEX_op_qemu_ld_i32, TCG_TYPE_I32, - tcgv_i32_temp(val), NULL, addr, oi); + gen_ldst1(INDEX_op_qemu_ld, TCG_TYPE_I32, tcgv_i32_temp(val), addr, oi); plugin_gen_mem_callbacks_i32(val, copy_addr, addr, orig_oi, QEMU_PLUGIN_MEM_R); @@ -292,8 +303,7 @@ static void tcg_gen_qemu_st_i32_int(TCGv_i32 val, TCGTemp *addr, oi = make_memop_idx(memop, idx); } - gen_ldst(INDEX_op_qemu_st_i32, TCG_TYPE_I32, - tcgv_i32_temp(val), NULL, addr, oi); + gen_ldst1(INDEX_op_qemu_st, TCG_TYPE_I32, tcgv_i32_temp(val), addr, oi); plugin_gen_mem_callbacks_i32(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W); if (swap) { @@ -340,7 +350,7 @@ static void tcg_gen_qemu_ld_i64_int(TCGv_i64 val, TCGTemp *addr, } copy_addr = plugin_maybe_preserve_addr(addr); - gen_ldst_i64(INDEX_op_qemu_ld_i64, val, addr, oi); + gen_ld_i64(val, addr, oi); plugin_gen_mem_callbacks_i64(val, copy_addr, addr, orig_oi, QEMU_PLUGIN_MEM_R); @@ -407,7 +417,7 @@ static void tcg_gen_qemu_st_i64_int(TCGv_i64 val, TCGTemp *addr, oi = make_memop_idx(memop, idx); } - gen_ldst_i64(INDEX_op_qemu_st_i64, val, addr, oi); + gen_st_i64(val, addr, oi); plugin_gen_mem_callbacks_i64(val, NULL, addr, orig_oi, QEMU_PLUGIN_MEM_W); if (swap) { @@ -546,8 +556,8 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr, hi = TCGV128_HIGH(val); } - gen_ldst(INDEX_op_qemu_ld_i128, TCG_TYPE_I128, tcgv_i64_temp(lo), - tcgv_i64_temp(hi), addr, oi); + gen_ldst2(INDEX_op_qemu_ld2, TCG_TYPE_I128, tcgv_i64_temp(lo), + tcgv_i64_temp(hi), addr, oi); if (need_bswap) { tcg_gen_bswap64_i64(lo, lo); @@ -575,8 +585,7 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr, y = TCGV128_LOW(val); } - gen_ldst_i64(INDEX_op_qemu_ld_i64, x, addr, - make_memop_idx(mop[0], idx)); + gen_ld_i64(x, addr, make_memop_idx(mop[0], idx)); if (need_bswap) { tcg_gen_bswap64_i64(x, x); @@ -592,8 +601,7 @@ static void tcg_gen_qemu_ld_i128_int(TCGv_i128 val, TCGTemp *addr, addr_p8 = tcgv_i64_temp(t); } - gen_ldst_i64(INDEX_op_qemu_ld_i64, y, addr_p8, - make_memop_idx(mop[1], idx)); + gen_ld_i64(y, addr_p8, make_memop_idx(mop[1], idx)); tcg_temp_free_internal(addr_p8); if (need_bswap) { @@ -657,8 +665,8 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr, hi = TCGV128_HIGH(val); } - gen_ldst(INDEX_op_qemu_st_i128, TCG_TYPE_I128, - tcgv_i64_temp(lo), tcgv_i64_temp(hi), addr, oi); + gen_ldst2(INDEX_op_qemu_st2, TCG_TYPE_I128, + tcgv_i64_temp(lo), tcgv_i64_temp(hi), addr, oi); if (need_bswap) { tcg_temp_free_i64(lo); @@ -685,8 +693,7 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr, x = b; } - gen_ldst_i64(INDEX_op_qemu_st_i64, x, addr, - make_memop_idx(mop[0], idx)); + gen_st_i64(x, addr, make_memop_idx(mop[0], idx)); if (tcg_ctx->addr_type == TCG_TYPE_I32) { TCGv_i32 t = tcg_temp_ebb_new_i32(); @@ -700,12 +707,10 @@ static void tcg_gen_qemu_st_i128_int(TCGv_i128 val, TCGTemp *addr, if (b) { tcg_gen_bswap64_i64(b, y); - gen_ldst_i64(INDEX_op_qemu_st_i64, b, addr_p8, - make_memop_idx(mop[1], idx)); + gen_st_i64(b, addr_p8, make_memop_idx(mop[1], idx)); tcg_temp_free_i64(b); } else { - gen_ldst_i64(INDEX_op_qemu_st_i64, y, addr_p8, - make_memop_idx(mop[1], idx)); + gen_st_i64(y, addr_p8, make_memop_idx(mop[1], idx)); } tcg_temp_free_internal(addr_p8); } else { diff --git a/tcg/tcg.c b/tcg/tcg.c index 5c0cab205c..6c0866d446 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2432,14 +2432,20 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) case INDEX_op_exit_tb: case INDEX_op_goto_tb: case INDEX_op_goto_ptr: - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_ld_i64: - case INDEX_op_qemu_st_i64: return true; - case INDEX_op_qemu_ld_i128: - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_ld: + case INDEX_op_qemu_st: + tcg_debug_assert(type <= TCG_TYPE_REG); + return true; + + case INDEX_op_qemu_ld2: + case INDEX_op_qemu_st2: + if (TCG_TARGET_REG_BITS == 32) { + tcg_debug_assert(type == TCG_TYPE_I64); + return true; + } + tcg_debug_assert(type == TCG_TYPE_I128); return TCG_TARGET_HAS_qemu_ldst_i128; case INDEX_op_add: @@ -3007,12 +3013,10 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) } i = 1; break; - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_st_i32: - case INDEX_op_qemu_ld_i64: - case INDEX_op_qemu_st_i64: - case INDEX_op_qemu_ld_i128: - case INDEX_op_qemu_st_i128: + case INDEX_op_qemu_ld: + case INDEX_op_qemu_st: + case INDEX_op_qemu_ld2: + case INDEX_op_qemu_st2: { const char *s_al, *s_op, *s_at; MemOpIdx oi = op->args[k++]; diff --git a/tcg/tci.c b/tcg/tci.c index b08288e7d3..700e672616 100644 --- a/tcg/tci.c +++ b/tcg/tci.c @@ -789,46 +789,33 @@ uintptr_t QEMU_DISABLE_CFI tcg_qemu_tb_exec(CPUArchState *env, tb_ptr = ptr; break; - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: tci_args_rrm(insn, &r0, &r1, &oi); taddr = regs[r1]; regs[r0] = tci_qemu_ld(env, taddr, oi, tb_ptr); break; - case INDEX_op_qemu_ld_i64: - if (TCG_TARGET_REG_BITS == 64) { - tci_args_rrm(insn, &r0, &r1, &oi); - taddr = regs[r1]; - } else { - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - taddr = regs[r2]; - oi = regs[r3]; - } - tmp64 = tci_qemu_ld(env, taddr, oi, tb_ptr); - if (TCG_TARGET_REG_BITS == 32) { - tci_write_reg64(regs, r1, r0, tmp64); - } else { - regs[r0] = tmp64; - } - break; - - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: tci_args_rrm(insn, &r0, &r1, &oi); taddr = regs[r1]; tci_qemu_st(env, taddr, regs[r0], oi, tb_ptr); break; - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 64) { - tci_args_rrm(insn, &r0, &r1, &oi); - tmp64 = regs[r0]; - taddr = regs[r1]; - } else { - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - tmp64 = tci_uint64(regs[r1], regs[r0]); - taddr = regs[r2]; - oi = regs[r3]; - } + case INDEX_op_qemu_ld2: + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + tci_args_rrrr(insn, &r0, &r1, &r2, &r3); + taddr = regs[r2]; + oi = regs[r3]; + tmp64 = tci_qemu_ld(env, taddr, oi, tb_ptr); + tci_write_reg64(regs, r1, r0, tmp64); + break; + + case INDEX_op_qemu_st2: + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + tci_args_rrrr(insn, &r0, &r1, &r2, &r3); + tmp64 = tci_uint64(regs[r1], regs[r0]); + taddr = regs[r2]; + oi = regs[r3]; tci_qemu_st(env, taddr, tmp64, oi, tb_ptr); break; @@ -1056,23 +1043,21 @@ int print_insn_tci(bfd_vma addr, disassemble_info *info) str_r(r2), str_r(r3)); break; - case INDEX_op_qemu_ld_i64: - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 32) { - tci_args_rrrr(insn, &r0, &r1, &r2, &r3); - info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s", - op_name, str_r(r0), str_r(r1), - str_r(r2), str_r(r3)); - break; - } - /* fall through */ - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_ld: + case INDEX_op_qemu_st: tci_args_rrm(insn, &r0, &r1, &oi); info->fprintf_func(info->stream, "%-12s %s, %s, %x", op_name, str_r(r0), str_r(r1), oi); break; + case INDEX_op_qemu_ld2: + case INDEX_op_qemu_st2: + tci_args_rrrr(insn, &r0, &r1, &r2, &r3); + info->fprintf_func(info->stream, "%-12s %s, %s, %s, %s", + op_name, str_r(r0), str_r(r1), + str_r(r2), str_r(r3)); + break; + case 0: /* tcg_out_nop_fill uses zeros */ if (insn == 0) { diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 1fb7575061..6b8f71f49e 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -40,14 +40,14 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld_i32: + case INDEX_op_qemu_ld: return C_O1_I1(r, r); - case INDEX_op_qemu_ld_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O1_I1(r, r) : C_O2_I1(r, r, r); - case INDEX_op_qemu_st_i32: + case INDEX_op_qemu_st: return C_O0_I2(r, r); - case INDEX_op_qemu_st_i64: - return TCG_TARGET_REG_BITS == 64 ? C_O0_I2(r, r) : C_O0_I3(r, r, r); + case INDEX_op_qemu_ld2: + return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O2_I1(r, r, r); + case INDEX_op_qemu_st2: + return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(r, r, r); default: return C_NotImplemented; @@ -1203,22 +1203,14 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld_i64: - case INDEX_op_qemu_st_i64: - if (TCG_TARGET_REG_BITS == 32) { - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, args[3]); - tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], TCG_REG_TMP); - break; - } - /* fall through */ - case INDEX_op_qemu_ld_i32: - case INDEX_op_qemu_st_i32: - if (TCG_TARGET_REG_BITS == 64 && s->addr_type == TCG_TYPE_I32) { - tcg_out_ext32u(s, TCG_REG_TMP, args[1]); - tcg_out_op_rrm(s, opc, args[0], TCG_REG_TMP, args[2]); - } else { - tcg_out_op_rrm(s, opc, args[0], args[1], args[2]); - } + case INDEX_op_qemu_ld: + case INDEX_op_qemu_st: + tcg_out_op_rrm(s, opc, args[0], args[1], args[2]); + break; + case INDEX_op_qemu_ld2: + case INDEX_op_qemu_st2: + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, args[3]); + tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], TCG_REG_TMP); break; case INDEX_op_call: /* Always emitted via tcg_out_call. */ From 3bedb9d3e2855606f2b4982ce07f8ae399957c3d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 11 Feb 2025 13:41:42 -0800 Subject: [PATCH 0512/2760] tcg: Convert qemu_ld{2} to TCGOutOpLoad{2} Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 30 +++++++++------ tcg/arm/tcg-target.c.inc | 63 +++++++++++++++++++++++--------- tcg/i386/tcg-target.c.inc | 47 ++++++++++++++++-------- tcg/loongarch64/tcg-target.c.inc | 37 ++++++++++--------- tcg/mips/tcg-target.c.inc | 57 +++++++++++++++++++++-------- tcg/ppc/tcg-target.c.inc | 45 ++++++++++++++--------- tcg/riscv/tcg-target.c.inc | 22 ++++++----- tcg/s390x/tcg-target.c.inc | 32 +++++++++------- tcg/sparc64/tcg-target.c.inc | 21 ++++++----- tcg/tcg.c | 32 +++++++++++++++- tcg/tci/tcg-target.c.inc | 30 ++++++++++++--- 11 files changed, 283 insertions(+), 133 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index a48cb46799..feda64afa3 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1806,8 +1806,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp memop, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType data_type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -1822,6 +1822,11 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, } } +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType data_type) { @@ -1940,6 +1945,17 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, } } +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, true); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_O2_I1(r, r, r), + .out = tgen_qemu_ld2, +}; + static const tcg_insn_unit *tb_ret_addr; static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) @@ -2875,15 +2891,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, a1, a2, ext); - break; case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, a1, a2, ext); break; - case INDEX_op_qemu_ld2: - tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], true); - break; case INDEX_op_qemu_st2: tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); break; @@ -3340,10 +3350,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); - case INDEX_op_qemu_ld2: - return C_O2_I1(r, r, r); case INDEX_op_qemu_st: return C_O0_I2(rz, r); case INDEX_op_qemu_st2: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 29fd82e9e0..681ecc3d7a 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1586,8 +1586,8 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp opc, TCGReg datalo, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { MemOp opc = get_memop(oi); TCGLabelQemuLdst *ldst; @@ -1595,7 +1595,41 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, ldst = prepare_host_addr(s, &h, addr, oi, true); if (ldst) { - ldst->type = data_type; + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = -1; + + /* + * This a conditional BL only to load a pointer within this + * opcode into LR for the slow path. We will not be using + * the value for a tail call. + */ + ldst->label_ptr[0] = s->code_ptr; + tcg_out_bl_imm(s, COND_NE, 0); + } + + tcg_out_qemu_ld_direct(s, opc, data, -1, h); + + if (ldst) { + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } +} + +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, q), + .out = tgen_qemu_ld, +}; + +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + MemOp opc = get_memop(oi); + TCGLabelQemuLdst *ldst; + HostAddress h; + + ldst = prepare_host_addr(s, &h, addr, oi, true); + if (ldst) { + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; @@ -1606,14 +1640,20 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, */ ldst->label_ptr[0] = s->code_ptr; tcg_out_bl_imm(s, COND_NE, 0); + } - tcg_out_qemu_ld_direct(s, opc, datalo, datahi, h); + tcg_out_qemu_ld_direct(s, opc, datalo, datahi, h); + + if (ldst) { ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); - } else { - tcg_out_qemu_ld_direct(s, opc, datalo, datahi, h); } } +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_O2_I1(e, p, q), + .out = tgen_qemu_ld2, +}; + static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, TCGReg datahi, HostAddress h) { @@ -2570,13 +2610,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); - break; - case INDEX_op_qemu_ld2: - tcg_out_qemu_ld(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); - break; - case INDEX_op_qemu_st: tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); break; @@ -2596,10 +2629,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, q); - case INDEX_op_qemu_ld2: - return C_O2_I1(e, p, q); case INDEX_op_qemu_st: return C_O0_I2(q, q); case INDEX_op_qemu_st2: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index cb66f6c27f..7ec06f57ee 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2422,23 +2422,50 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; ldst = prepare_host_addr(s, &h, addr, oi, true); - tcg_out_qemu_ld_direct(s, datalo, datahi, h, data_type, get_memop(oi)); + tcg_out_qemu_ld_direct(s, data, -1, h, type, get_memop(oi)); if (ldst) { - ldst->type = data_type; + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = -1; + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } +} + +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, L), + .out = tgen_qemu_ld, +}; + +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + TCGLabelQemuLdst *ldst; + HostAddress h; + + ldst = prepare_host_addr(s, &h, addr, oi, true); + tcg_out_qemu_ld_direct(s, datalo, datahi, h, type, get_memop(oi)); + + if (ldst) { + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_O2_I1(r, r, L), + .out = tgen_qemu_ld2, +}; + static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, HostAddress h, MemOp memop) { @@ -3552,13 +3579,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, -1, a1, a2, type); - break; - case INDEX_op_qemu_ld2: - tcg_out_qemu_ld(s, a0, a1, a2, args[3], type); - break; - case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, -1, a1, a2, type); break; @@ -4119,16 +4139,11 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, L); - case INDEX_op_qemu_st: return (TCG_TARGET_REG_BITS == 32 && flags == MO_8 ? C_O0_I2(s, L) : C_O0_I2(L, L)); - case INDEX_op_qemu_ld2: - return C_O2_I1(r, r, L); case INDEX_op_qemu_st2: return C_O0_I3(L, L, L); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e4a8b43578..e2f0b7f894 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1167,22 +1167,27 @@ static void tcg_out_qemu_ld_indexed(TCGContext *s, MemOp opc, TCGType type, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; ldst = prepare_host_addr(s, &h, addr_reg, oi, true); - tcg_out_qemu_ld_indexed(s, get_memop(oi), data_type, data_reg, h); + tcg_out_qemu_ld_indexed(s, get_memop(oi), type, data_reg, h); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + static void tcg_out_qemu_st_indexed(TCGContext *s, MemOp opc, TCGReg rd, HostAddress h) { @@ -1270,6 +1275,17 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg data_lo, TCGReg data_hi } } +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, true); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_N2_I1(r, r, r), + .out = tgen_qemu_ld2, +}; + /* * Entry-points */ @@ -2020,12 +2036,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a3 = args[3]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, a1, a2, type); - break; - case INDEX_op_qemu_ld2: - tcg_out_qemu_ldst_i128(s, a0, a1, a2, a3, true); - break; case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, a1, a2, type); break; @@ -2537,16 +2547,9 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) switch (op) { case INDEX_op_qemu_st: return C_O0_I2(rz, r); - - case INDEX_op_qemu_ld2: - return C_N2_I1(r, r, r); - case INDEX_op_qemu_st2: return C_O0_I3(r, r, r); - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: case INDEX_op_dup_vec: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index eaaf0f2024..14bffcd404 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1387,8 +1387,8 @@ static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { MemOp opc = get_memop(oi); TCGLabelQemuLdst *ldst; @@ -1397,19 +1397,56 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg datalo, TCGReg datahi, ldst = prepare_host_addr(s, &h, addr, oi, true); if (use_mips32r6_instructions || h.aa.align >= (opc & MO_SIZE)) { - tcg_out_qemu_ld_direct(s, datalo, datahi, h.base, opc, data_type); + tcg_out_qemu_ld_direct(s, data, 0, h.base, opc, type); } else { - tcg_out_qemu_ld_unalign(s, datalo, datahi, h.base, opc, data_type); + tcg_out_qemu_ld_unalign(s, data, 0, h.base, opc, type); } if (ldst) { - ldst->type = data_type; + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = 0; + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } +} + +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + MemOp opc = get_memop(oi); + TCGLabelQemuLdst *ldst; + HostAddress h; + + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + ldst = prepare_host_addr(s, &h, addr, oi, true); + + if (use_mips32r6_instructions || h.aa.align >= (opc & MO_SIZE)) { + tcg_out_qemu_ld_direct(s, datalo, datahi, h.base, opc, type); + } else { + tcg_out_qemu_ld_unalign(s, datalo, datahi, h.base, opc, type); + } + + if (ldst) { + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + /* Ensure that the mips32 code is compiled but discarded for mips64. */ + .base.static_constraint = + TCG_TARGET_REG_BITS == 32 ? C_O2_I1(r, r, r) : C_NotImplemented, + .out = + TCG_TARGET_REG_BITS == 32 ? tgen_qemu_ld2 : NULL, +}; + static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg lo, TCGReg hi, TCGReg base, MemOp opc) { @@ -2381,14 +2418,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, 0, a1, a2, type); - break; - case INDEX_op_qemu_ld2: - tcg_debug_assert(TCG_TARGET_REG_BITS == 32); - tcg_out_qemu_ld(s, a0, a1, a2, args[3], type); - break; - case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, 0, a1, a2, type); break; @@ -2409,8 +2438,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); case INDEX_op_qemu_st: return C_O0_I2(rz, r); case INDEX_op_qemu_ld2: diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index bb26769d53..e4e6b7b2d9 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2695,6 +2695,33 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, } } +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) +{ + tcg_out_qemu_ld(s, data, -1, addr, oi, type); +} + +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + if (TCG_TARGET_REG_BITS == 32) { + tcg_out_qemu_ld(s, datalo, datahi, addr, oi, type); + } else { + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr, oi, true); + } +} + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = + TCG_TARGET_REG_BITS == 64 ? C_N1O1_I1(o, m, r) : C_O2_I1(r, r, r), + .out = tgen_qemu_ld2, +}; + static void tcg_out_nop_fill(tcg_insn_unit *p, int count) { int i; @@ -3779,18 +3806,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, args[0], -1, args[1], args[2], type); - break; - case INDEX_op_qemu_ld2: - if (TCG_TARGET_REG_BITS == 32) { - tcg_out_qemu_ld(s, args[0], args[1], args[2], - args[3], TCG_TYPE_I64); - break; - } - tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true); - break; - case INDEX_op_qemu_st: tcg_out_qemu_st(s, args[0], -1, args[1], args[2], type); break; @@ -4418,12 +4433,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); - case INDEX_op_qemu_ld2: - return TCG_TARGET_REG_BITS == 64 - ? C_N1O1_I1(o, m, r) : C_O2_I1(r, r, r); - case INDEX_op_qemu_st: return C_O0_I2(r, r); case INDEX_op_qemu_st2: diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 89c7736f9a..94e6f04fa6 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1833,22 +1833,31 @@ static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg val, } } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; TCGReg base; ldst = prepare_host_addr(s, &base, addr_reg, oi, true); - tcg_out_qemu_ld_direct(s, data_reg, base, get_memop(oi), data_type); + tcg_out_qemu_ld_direct(s, data_reg, base, get_memop(oi), type); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg val, TCGReg base, MemOp opc) { @@ -2633,9 +2642,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, TCGArg a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, a1, a2, type); - break; case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, a1, a2, type); break; @@ -2869,8 +2875,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); case INDEX_op_qemu_st: return C_O0_I2(rz, r); diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 652ce9023e..bf99b765cf 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2081,8 +2081,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, return ldst; } -static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -2091,12 +2091,17 @@ static void tcg_out_qemu_ld(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, tcg_out_qemu_ld_direct(s, get_memop(oi), data_reg, h); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, MemOpIdx oi, TCGType data_type) { @@ -2187,6 +2192,17 @@ static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, } } +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, true); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_O2_I1(o, m, r), + .out = tgen_qemu_ld2, +}; + static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) { /* Reuse the zeroing that exists for goto_ptr. */ @@ -3133,15 +3149,9 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, args[0], args[1], args[2], type); - break; case INDEX_op_qemu_st: tcg_out_qemu_st(s, args[0], args[1], args[2], type); break; - case INDEX_op_qemu_ld2: - tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], true); - break; case INDEX_op_qemu_st2: tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); break; @@ -3594,12 +3604,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); case INDEX_op_qemu_st: return C_O0_I2(r, r); - case INDEX_op_qemu_ld2: - return C_O2_I1(o, m, r); case INDEX_op_qemu_st2: return C_O0_I3(o, m, r); diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index bf27b6b54b..4426168354 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1186,8 +1186,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, return ldst; } -static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { static const int ld_opc[(MO_SSIZE | MO_BSWAP) + 1] = { [MO_UB] = LDUB, @@ -1219,12 +1219,21 @@ static void tcg_out_qemu_ld(TCGContext *s, TCGReg data, TCGReg addr, ld_opc[get_memop(oi) & (MO_BSWAP | MO_SSIZE)]); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, MemOpIdx oi, TCGType data_type) { @@ -2068,9 +2077,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, a2 = args[2]; switch (opc) { - case INDEX_op_qemu_ld: - tcg_out_qemu_ld(s, a0, a1, a2, type); - break; case INDEX_op_qemu_st: tcg_out_qemu_st(s, a0, a1, a2, type); break; @@ -2087,9 +2093,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); - case INDEX_op_qemu_st: return C_O0_I2(rz, r); diff --git a/tcg/tcg.c b/tcg/tcg.c index 6c0866d446..f338deb019 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1071,6 +1071,18 @@ typedef struct TCGOutOpMul2 { TCGReg a0, TCGReg a1, TCGReg a2, TCGReg a3); } TCGOutOpMul2; +typedef struct TCGOutOpQemuLdSt { + TCGOutOp base; + void (*out)(TCGContext *s, TCGType type, TCGReg dest, + TCGReg addr, MemOpIdx oi); +} TCGOutOpQemuLdSt; + +typedef struct TCGOutOpQemuLdSt2 { + TCGOutOp base; + void (*out)(TCGContext *s, TCGType type, TCGReg dlo, TCGReg dhi, + TCGReg addr, MemOpIdx oi); +} TCGOutOpQemuLdSt2; + typedef struct TCGOutOpUnary { TCGOutOp base; void (*out_rr)(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1); @@ -1210,6 +1222,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_not, TCGOutOpUnary, outop_not), OUTOP(INDEX_op_or, TCGOutOpBinary, outop_or), OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), + OUTOP(INDEX_op_qemu_ld, TCGOutOpQemuLdSt, outop_qemu_ld), + OUTOP(INDEX_op_qemu_ld2, TCGOutOpQemuLdSt2, outop_qemu_ld2), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), @@ -2446,7 +2460,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return true; } tcg_debug_assert(type == TCG_TYPE_I128); - return TCG_TARGET_HAS_qemu_ldst_i128; + goto do_lookup; case INDEX_op_add: case INDEX_op_and: @@ -2558,6 +2572,7 @@ bool tcg_op_supported(TCGOpcode op, TCGType type, unsigned flags) return false; } + do_lookup: outop = all_outop[op]; tcg_debug_assert(outop != NULL); @@ -5799,6 +5814,21 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) } break; + case INDEX_op_qemu_ld: + { + const TCGOutOpQemuLdSt *out = &outop_qemu_ld; + out->out(s, type, new_args[0], new_args[1], new_args[2]); + } + break; + + case INDEX_op_qemu_ld2: + { + const TCGOutOpQemuLdSt2 *out = &outop_qemu_ld2; + out->out(s, type, new_args[0], new_args[1], + new_args[2], new_args[3]); + } + break; + case INDEX_op_brcond: { const TCGOutOpBrcond *out = &outop_brcond; diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 6b8f71f49e..f69e35e6ce 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -40,12 +40,8 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_ld: - return C_O1_I1(r, r); case INDEX_op_qemu_st: return C_O0_I2(r, r); - case INDEX_op_qemu_ld2: - return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O2_I1(r, r, r); case INDEX_op_qemu_st2: return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(r, r, r); @@ -1197,17 +1193,39 @@ static const TCGOutOpStore outop_st = { .out_r = tcg_out_st, }; +static void tgen_qemu_ld(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) +{ + tcg_out_op_rrm(s, INDEX_op_qemu_ld, data, addr, oi); +} + +static const TCGOutOpQemuLdSt outop_qemu_ld = { + .base.static_constraint = C_O1_I1(r, r), + .out = tgen_qemu_ld, +}; + +static void tgen_qemu_ld2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, oi); + tcg_out_op_rrrr(s, INDEX_op_qemu_ld2, datalo, datahi, addr, TCG_REG_TMP); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { + .base.static_constraint = + TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O2_I1(r, r, r), + .out = + TCG_TARGET_REG_BITS == 64 ? NULL : tgen_qemu_ld2, +}; static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { switch (opc) { - case INDEX_op_qemu_ld: case INDEX_op_qemu_st: tcg_out_op_rrm(s, opc, args[0], args[1], args[2]); break; - case INDEX_op_qemu_ld2: case INDEX_op_qemu_st2: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, args[3]); tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], TCG_REG_TMP); From 86fe5c2597ca165228ee9cd082886846de4c9ece Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 16 Feb 2025 14:02:00 -0800 Subject: [PATCH 0513/2760] tcg: Convert qemu_st{2} to TCGOutOpLdSt{2} Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 45 ++++++++----------- tcg/arm/tcg-target.c.inc | 61 ++++++++++++++++--------- tcg/i386/tcg-target.c.inc | 73 ++++++++++++++++-------------- tcg/loongarch64/tcg-target.c.inc | 47 +++++++++---------- tcg/mips/tcg-target.c.inc | 77 +++++++++++++++++--------------- tcg/ppc/tcg-target.c.inc | 47 +++++++++++-------- tcg/riscv/tcg-target.c.inc | 34 ++++++-------- tcg/s390x/tcg-target.c.inc | 42 +++++++++-------- tcg/sparc64/tcg-target.c.inc | 42 ++++++----------- tcg/tcg.c | 12 ++++- tcg/tci/tcg-target.c.inc | 51 +++++++++++---------- 11 files changed, 272 insertions(+), 259 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index feda64afa3..59e7992a5f 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1827,8 +1827,8 @@ static const TCGOutOpQemuLdSt outop_qemu_ld = { .out = tgen_qemu_ld, }; -static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType data_type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -1843,6 +1843,11 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, } } +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out = tgen_qemu_st, +}; + static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg addr_reg, MemOpIdx oi, bool is_ld) { @@ -1956,6 +1961,17 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { .out = tgen_qemu_ld2, }; +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, false); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_O0_I3(rz, rz, r), + .out = tgen_qemu_st2, +}; + static const tcg_insn_unit *tb_ret_addr; static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) @@ -2885,25 +2901,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - /* Hoist the loads of the most common arguments. */ - TCGArg a0 = args[0]; - TCGArg a1 = args[1]; - TCGArg a2 = args[2]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, a1, a2, ext); - break; - case INDEX_op_qemu_st2: - tcg_out_qemu_ldst_i128(s, a0, a1, a2, args[3], false); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, @@ -3350,11 +3348,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(rz, r); - case INDEX_op_qemu_st2: - return C_O0_I3(rz, rz, r); - case INDEX_op_add_vec: case INDEX_op_sub_vec: case INDEX_op_mul_vec: diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 681ecc3d7a..014a441420 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1711,8 +1711,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, MemOp opc, TCGReg datalo, } } -static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { MemOp opc = get_memop(oi); TCGLabelQemuLdst *ldst; @@ -1720,7 +1720,37 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, ldst = prepare_host_addr(s, &h, addr, oi, false); if (ldst) { - ldst->type = data_type; + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = -1; + + h.cond = COND_EQ; + tcg_out_qemu_st_direct(s, opc, data, -1, h); + + /* The conditional call is last, as we're going to return here. */ + ldst->label_ptr[0] = s->code_ptr; + tcg_out_bl_imm(s, COND_NE, 0); + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } else { + tcg_out_qemu_st_direct(s, opc, data, -1, h); + } +} + +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(q, q), + .out = tgen_qemu_st, +}; + +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + MemOp opc = get_memop(oi); + TCGLabelQemuLdst *ldst; + HostAddress h; + + ldst = prepare_host_addr(s, &h, addr, oi, false); + if (ldst) { + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; @@ -1736,6 +1766,11 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, } } +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_O0_I3(Q, p, q), + .out = tgen_qemu_st2, +}; + static void tcg_out_epilogue(TCGContext *s); static void tcg_out_exit_tb(TCGContext *s, uintptr_t arg) @@ -2609,31 +2644,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, args[0], -1, args[1], args[2], TCG_TYPE_I32); - break; - case INDEX_op_qemu_st2: - tcg_out_qemu_st(s, args[0], args[1], args[2], args[3], TCG_TYPE_I64); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(q, q); - case INDEX_op_qemu_st2: - return C_O0_I3(Q, p, q); - case INDEX_op_st_vec: return C_O0_I2(w, r); case INDEX_op_ld_vec: diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 7ec06f57ee..9f294f28ed 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2484,7 +2484,7 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, switch (memop & MO_SIZE) { case MO_8: - /* This is handled with constraints on INDEX_op_qemu_st. */ + /* This is handled with constraints in cset_qemu_st(). */ tcg_debug_assert(TCG_TARGET_REG_BITS == 64 || datalo < 4); tcg_out_modrm_sib_offset(s, OPC_MOVB_EvGv + P_REXB_R + h.seg, datalo, h.base, h.index, 0, h.ofs); @@ -2576,8 +2576,38 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg datalo, TCGReg datahi, } } -static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) +{ + TCGLabelQemuLdst *ldst; + HostAddress h; + + ldst = prepare_host_addr(s, &h, addr, oi, false); + tcg_out_qemu_st_direct(s, data, -1, h, get_memop(oi)); + + if (ldst) { + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = -1; + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } +} + +static TCGConstraintSetIndex cset_qemu_st(TCGType type, unsigned flags) +{ + return flags == MO_8 ? C_O0_I2(s, L) : C_O0_I2(L, L); +} + +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = + TCG_TARGET_REG_BITS == 32 ? C_Dynamic : C_O0_I2(L, L), + .base.dynamic_constraint = + TCG_TARGET_REG_BITS == 32 ? cset_qemu_st : NULL, + .out = tgen_qemu_st, +}; + +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -2586,13 +2616,18 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, tcg_out_qemu_st_direct(s, datalo, datahi, h, get_memop(oi)); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_O0_I3(L, L, L), + .out = tgen_qemu_st2, +}; + static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) { /* Reuse the zeroing that exists for goto_ptr. */ @@ -3571,27 +3606,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2; - - /* Hoist the loads of the most common arguments. */ - a0 = args[0]; - a1 = args[1]; - a2 = args[2]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, -1, a1, a2, type); - break; - case INDEX_op_qemu_st2: - tcg_out_qemu_st(s, a0, a1, a2, args[3], type); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static int const umin_insn[4] = { @@ -4139,14 +4154,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return (TCG_TARGET_REG_BITS == 32 && flags == MO_8 - ? C_O0_I2(s, L) - : C_O0_I2(L, L)); - - case INDEX_op_qemu_st2: - return C_O0_I3(L, L, L); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: return C_O1_I1(x, r); diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e2f0b7f894..c74ddee644 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1212,8 +1212,8 @@ static void tcg_out_qemu_st_indexed(TCGContext *s, MemOp opc, } } -static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -1222,12 +1222,17 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, tcg_out_qemu_st_indexed(s, get_memop(oi), data_reg, h); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out = tgen_qemu_st, +}; + static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg data_lo, TCGReg data_hi, TCGReg addr_reg, MemOpIdx oi, bool is_ld) { @@ -1286,6 +1291,17 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { .out = tgen_qemu_ld2, }; +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, false); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_O0_I3(r, r, r), + .out = tgen_qemu_st2, +}; + /* * Entry-points */ @@ -2030,25 +2046,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0 = args[0]; - TCGArg a1 = args[1]; - TCGArg a2 = args[2]; - TCGArg a3 = args[3]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, a1, a2, type); - break; - case INDEX_op_qemu_st2: - tcg_out_qemu_ldst_i128(s, a0, a1, a2, a3, false); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, @@ -2545,11 +2543,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(rz, r); - case INDEX_op_qemu_st2: - return C_O0_I3(r, r, r); - case INDEX_op_ld_vec: case INDEX_op_dupm_vec: case INDEX_op_dup_vec: diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 14bffcd404..1f12500344 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1510,8 +1510,8 @@ static void tcg_out_qemu_st_unalign(TCGContext *s, TCGReg lo, TCGReg hi, } } -static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, - TCGReg addr, MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { MemOp opc = get_memop(oi); TCGLabelQemuLdst *ldst; @@ -1519,6 +1519,35 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, ldst = prepare_host_addr(s, &h, addr, oi, false); + if (use_mips32r6_instructions || h.aa.align >= (opc & MO_SIZE)) { + tcg_out_qemu_st_direct(s, data, 0, h.base, opc); + } else { + tcg_out_qemu_st_unalign(s, data, 0, h.base, opc); + } + + if (ldst) { + ldst->type = type; + ldst->datalo_reg = data; + ldst->datahi_reg = 0; + ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); + } +} + +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out = tgen_qemu_st, +}; + +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + MemOp opc = get_memop(oi); + TCGLabelQemuLdst *ldst; + HostAddress h; + + tcg_debug_assert(TCG_TARGET_REG_BITS == 32); + ldst = prepare_host_addr(s, &h, addr, oi, false); + if (use_mips32r6_instructions || h.aa.align >= (opc & MO_SIZE)) { tcg_out_qemu_st_direct(s, datalo, datahi, h.base, opc); } else { @@ -1526,13 +1555,21 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg datalo, TCGReg datahi, } if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = datalo; ldst->datahi_reg = datahi; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + /* Ensure that the mips32 code is compiled but discarded for mips64. */ + .base.static_constraint = + TCG_TARGET_REG_BITS == 32 ? C_O0_I3(rz, rz, r) : C_NotImplemented, + .out = + TCG_TARGET_REG_BITS == 32 ? tgen_qemu_st2 : NULL, +}; + static void tcg_out_mb(TCGContext *s, unsigned a0) { static const MIPSInsn sync[] = { @@ -2411,43 +2448,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2; - - a0 = args[0]; - a1 = args[1]; - a2 = args[2]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, 0, a1, a2, type); - break; - case INDEX_op_qemu_st2: - tcg_debug_assert(TCG_TARGET_REG_BITS == 32); - tcg_out_qemu_st(s, a0, a1, a2, args[3], type); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { - switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(rz, r); - case INDEX_op_qemu_ld2: - return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O2_I1(r, r, r); - case INDEX_op_qemu_st2: - return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(rz, rz, r); - - default: - return C_NotImplemented; - } + return C_NotImplemented; } static const int tcg_target_callee_save_regs[] = { diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index e4e6b7b2d9..824cced94a 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2722,6 +2722,33 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { .out = tgen_qemu_ld2, }; +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) +{ + tcg_out_qemu_st(s, data, -1, addr, oi, type); +} + +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(r, r), + .out = tgen_qemu_st, +}; + +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + if (TCG_TARGET_REG_BITS == 32) { + tcg_out_qemu_st(s, datalo, datahi, addr, oi, type); + } else { + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr, oi, false); + } +} + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = + TCG_TARGET_REG_BITS == 64 ? C_O0_I3(o, m, r) : C_O0_I3(r, r, r), + .out = tgen_qemu_st2, +}; + static void tcg_out_nop_fill(tcg_insn_unit *p, int count) { int i; @@ -3805,25 +3832,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, args[0], -1, args[1], args[2], type); - break; - case INDEX_op_qemu_st2: - if (TCG_TARGET_REG_BITS == 32) { - tcg_out_qemu_st(s, args[0], args[1], args[2], - args[3], TCG_TYPE_I64); - break; - } - tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index 94e6f04fa6..eca1283742 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1882,8 +1882,8 @@ static void tcg_out_qemu_st_direct(TCGContext *s, TCGReg val, } } -static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; TCGReg base; @@ -1892,12 +1892,21 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data_reg, TCGReg addr_reg, tcg_out_qemu_st_direct(s, data_reg, base, get_memop(oi)); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out = tgen_qemu_st, +}; + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_NotImplemented, +}; + static const tcg_insn_unit *tb_ret_addr; static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) @@ -2637,21 +2646,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0 = args[0]; - TCGArg a1 = args[1]; - TCGArg a2 = args[2]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, a1, a2, type); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, @@ -2875,9 +2870,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(rz, r); - case INDEX_op_st_vec: return C_O0_I2(v, r); case INDEX_op_dup_vec: diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index bf99b765cf..a316c8de41 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2102,8 +2102,8 @@ static const TCGOutOpQemuLdSt outop_qemu_ld = { .out = tgen_qemu_ld, }; -static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data_reg, + TCGReg addr_reg, MemOpIdx oi) { TCGLabelQemuLdst *ldst; HostAddress h; @@ -2112,12 +2112,17 @@ static void tcg_out_qemu_st(TCGContext* s, TCGReg data_reg, TCGReg addr_reg, tcg_out_qemu_st_direct(s, get_memop(oi), data_reg, h); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data_reg; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(r, r), + .out = tgen_qemu_st, +}; + static void tcg_out_qemu_ldst_i128(TCGContext *s, TCGReg datalo, TCGReg datahi, TCGReg addr_reg, MemOpIdx oi, bool is_ld) { @@ -2203,6 +2208,17 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { .out = tgen_qemu_ld2, }; +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr_reg, MemOpIdx oi) +{ + tcg_out_qemu_ldst_i128(s, datalo, datahi, addr_reg, oi, false); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_O0_I3(o, m, r), + .out = tgen_qemu_st2, +}; + static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) { /* Reuse the zeroing that exists for goto_ptr. */ @@ -3148,20 +3164,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, args[0], args[1], args[2], type); - break; - case INDEX_op_qemu_st2: - tcg_out_qemu_ldst_i128(s, args[0], args[1], args[2], args[3], false); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, @@ -3604,11 +3607,6 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(r, r); - case INDEX_op_qemu_st2: - return C_O0_I3(o, m, r); - case INDEX_op_st_vec: return C_O0_I2(v, r); case INDEX_op_ld_vec: diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 4426168354..d1dd0fa33c 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1234,8 +1234,8 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { .base.static_constraint = C_NotImplemented, }; -static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, - MemOpIdx oi, TCGType data_type) +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) { static const int st_opc[(MO_SIZE | MO_BSWAP) + 1] = { [MO_UB] = STB, @@ -1258,12 +1258,21 @@ static void tcg_out_qemu_st(TCGContext *s, TCGReg data, TCGReg addr, st_opc[get_memop(oi) & (MO_BSWAP | MO_SIZE)]); if (ldst) { - ldst->type = data_type; + ldst->type = type; ldst->datalo_reg = data; ldst->raddr = tcg_splitwx_to_rx(s->code_ptr); } } +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(rz, r), + .out = tgen_qemu_st, +}; + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = C_NotImplemented, +}; + static void tcg_out_exit_tb(TCGContext *s, uintptr_t a0) { if (check_fit_ptr(a0, 13)) { @@ -2069,36 +2078,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - TCGArg a0, a1, a2; - - /* Hoist the loads of the most common arguments. */ - a0 = args[0]; - a1 = args[1]; - a2 = args[2]; - - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_qemu_st(s, a0, a1, a2, type); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { - switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(rz, r); - - default: - return C_NotImplemented; - } + return C_NotImplemented; } static void tcg_target_init(TCGContext *s) diff --git a/tcg/tcg.c b/tcg/tcg.c index f338deb019..302f7025e7 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1224,6 +1224,8 @@ static const TCGOutOp * const all_outop[NB_OPS] = { OUTOP(INDEX_op_orc, TCGOutOpBinary, outop_orc), OUTOP(INDEX_op_qemu_ld, TCGOutOpQemuLdSt, outop_qemu_ld), OUTOP(INDEX_op_qemu_ld2, TCGOutOpQemuLdSt2, outop_qemu_ld2), + OUTOP(INDEX_op_qemu_st, TCGOutOpQemuLdSt, outop_qemu_st), + OUTOP(INDEX_op_qemu_st2, TCGOutOpQemuLdSt2, outop_qemu_st2), OUTOP(INDEX_op_rems, TCGOutOpBinary, outop_rems), OUTOP(INDEX_op_remu, TCGOutOpBinary, outop_remu), OUTOP(INDEX_op_rotl, TCGOutOpBinary, outop_rotl), @@ -5815,15 +5817,21 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; case INDEX_op_qemu_ld: + case INDEX_op_qemu_st: { - const TCGOutOpQemuLdSt *out = &outop_qemu_ld; + const TCGOutOpQemuLdSt *out = + container_of(all_outop[op->opc], TCGOutOpQemuLdSt, base); + out->out(s, type, new_args[0], new_args[1], new_args[2]); } break; case INDEX_op_qemu_ld2: + case INDEX_op_qemu_st2: { - const TCGOutOpQemuLdSt2 *out = &outop_qemu_ld2; + const TCGOutOpQemuLdSt2 *out = + container_of(all_outop[op->opc], TCGOutOpQemuLdSt2, base); + out->out(s, type, new_args[0], new_args[1], new_args[2], new_args[3]); } diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index f69e35e6ce..50e205211d 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -39,15 +39,7 @@ static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { - switch (op) { - case INDEX_op_qemu_st: - return C_O0_I2(r, r); - case INDEX_op_qemu_st2: - return TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(r, r, r); - - default: - return C_NotImplemented; - } + return C_NotImplemented; } static const int tcg_target_reg_alloc_order[] = { @@ -1218,25 +1210,36 @@ static const TCGOutOpQemuLdSt2 outop_qemu_ld2 = { TCG_TARGET_REG_BITS == 64 ? NULL : tgen_qemu_ld2, }; +static void tgen_qemu_st(TCGContext *s, TCGType type, TCGReg data, + TCGReg addr, MemOpIdx oi) +{ + tcg_out_op_rrm(s, INDEX_op_qemu_st, data, addr, oi); +} + +static const TCGOutOpQemuLdSt outop_qemu_st = { + .base.static_constraint = C_O0_I2(r, r), + .out = tgen_qemu_st, +}; + +static void tgen_qemu_st2(TCGContext *s, TCGType type, TCGReg datalo, + TCGReg datahi, TCGReg addr, MemOpIdx oi) +{ + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, oi); + tcg_out_op_rrrr(s, INDEX_op_qemu_st2, datalo, datahi, addr, TCG_REG_TMP); +} + +static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { + .base.static_constraint = + TCG_TARGET_REG_BITS == 64 ? C_NotImplemented : C_O0_I3(r, r, r), + .out = + TCG_TARGET_REG_BITS == 64 ? NULL : tgen_qemu_st2, +}; + static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, const TCGArg args[TCG_MAX_OP_ARGS], const int const_args[TCG_MAX_OP_ARGS]) { - switch (opc) { - case INDEX_op_qemu_st: - tcg_out_op_rrm(s, opc, args[0], args[1], args[2]); - break; - case INDEX_op_qemu_st2: - tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_TMP, args[3]); - tcg_out_op_rrrr(s, opc, args[0], args[1], args[2], TCG_REG_TMP); - break; - - case INDEX_op_call: /* Always emitted via tcg_out_call. */ - case INDEX_op_exit_tb: /* Always emitted via tcg_out_exit_tb. */ - case INDEX_op_goto_tb: /* Always emitted via tcg_out_goto_tb. */ - default: - g_assert_not_reached(); - } + g_assert_not_reached(); } static void tcg_out_st(TCGContext *s, TCGType type, TCGReg val, TCGReg base, From eafecf08059953a2d1d06b6a6ded3c56916cbdd4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 16 Feb 2025 14:22:48 -0800 Subject: [PATCH 0514/2760] tcg: Remove tcg_out_op MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All integer opcodes are now converted to TCGOutOp. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- tcg/aarch64/tcg-target.c.inc | 7 ------- tcg/arm/tcg-target.c.inc | 7 ------- tcg/i386/tcg-target.c.inc | 7 ------- tcg/loongarch64/tcg-target.c.inc | 7 ------- tcg/mips/tcg-target.c.inc | 7 ------- tcg/ppc/tcg-target.c.inc | 7 ------- tcg/riscv/tcg-target.c.inc | 7 ------- tcg/s390x/tcg-target.c.inc | 7 ------- tcg/sparc64/tcg-target.c.inc | 7 ------- tcg/tcg.c | 12 +++--------- tcg/tci/tcg-target.c.inc | 7 ------- 11 files changed, 3 insertions(+), 79 deletions(-) diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 59e7992a5f..4cb647cb34 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -2897,13 +2897,6 @@ static const TCGOutOpStore outop_st = { .out_r = tcg_out_st, }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType ext, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, unsigned vece, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 014a441420..447e43583e 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -2640,13 +2640,6 @@ static const TCGOutOpStore outop_st = { .out_r = tcg_out_st, }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 9f294f28ed..09fce27b06 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -3602,13 +3602,6 @@ static const TCGOutOpStore outop_st = { .out_i = tgen_st_i, }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static int const umin_insn[4] = { OPC_PMINUB, OPC_PMINUW, OPC_PMINUD, OPC_VPMINUQ }; diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index c74ddee644..e5580d69a8 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -2042,13 +2042,6 @@ static const TCGOutOpStore outop_st = { .out_r = tcg_out_st, }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, TCGReg rd, TCGReg rs) { diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 1f12500344..2c0457e588 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -2444,13 +2444,6 @@ static const TCGOutOpStore outop_st = { }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 824cced94a..2e94778104 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -3828,13 +3828,6 @@ static const TCGOutOpStore outop_st = { }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - int tcg_can_emit_vec_op(TCGOpcode opc, TCGType type, unsigned vece) { switch (opc) { diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index eca1283742..f9417d15f7 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -2642,13 +2642,6 @@ static const TCGOutOpStore outop_st = { }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static void tcg_out_vec_op(TCGContext *s, TCGOpcode opc, unsigned vecl, unsigned vece, const TCGArg args[TCG_MAX_OP_ARGS], diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index a316c8de41..7ca0071f24 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -3160,13 +3160,6 @@ static const TCGOutOpStore outop_st = { }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, TCGReg dst, TCGReg src) { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index d1dd0fa33c..83167aa29d 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -2074,13 +2074,6 @@ static const TCGOutOpStore outop_st = { }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static TCGConstraintSetIndex tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) { diff --git a/tcg/tcg.c b/tcg/tcg.c index 302f7025e7..c4e866e9c3 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -138,9 +138,6 @@ static void tcg_out_mb(TCGContext *s, unsigned bar); static void tcg_out_br(TCGContext *s, TCGLabel *l); static void tcg_out_set_carry(TCGContext *s); static void tcg_out_set_borrow(TCGContext *s); -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]); #if TCG_TARGET_MAYBE_vec static bool tcg_out_dup_vec(TCGContext *s, TCGType type, unsigned vece, TCGReg dst, TCGReg src); @@ -5920,12 +5917,9 @@ static void tcg_reg_alloc_op(TCGContext *s, const TCGOp *op) break; default: - if (def->flags & TCG_OPF_VECTOR) { - tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, - TCGOP_VECE(op), new_args, const_args); - } else { - tcg_out_op(s, op->opc, type, new_args, const_args); - } + tcg_debug_assert(def->flags & TCG_OPF_VECTOR); + tcg_out_vec_op(s, op->opc, type - TCG_TYPE_V64, + TCGOP_VECE(op), new_args, const_args); break; } diff --git a/tcg/tci/tcg-target.c.inc b/tcg/tci/tcg-target.c.inc index 50e205211d..35c66a4836 100644 --- a/tcg/tci/tcg-target.c.inc +++ b/tcg/tci/tcg-target.c.inc @@ -1235,13 +1235,6 @@ static const TCGOutOpQemuLdSt2 outop_qemu_st2 = { TCG_TARGET_REG_BITS == 64 ? NULL : tgen_qemu_st2, }; -static void tcg_out_op(TCGContext *s, TCGOpcode opc, TCGType type, - const TCGArg args[TCG_MAX_OP_ARGS], - const int const_args[TCG_MAX_OP_ARGS]) -{ - g_assert_not_reached(); -} - static void tcg_out_st(TCGContext *s, TCGType type, TCGReg val, TCGReg base, intptr_t offset) { From 33b6c61cce2403193f9fc3a221f8a8656ba9cc37 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 11:59:58 -0700 Subject: [PATCH 0515/2760] tcg/sparc64: Unexport use_vis3_instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable is no longer used outside tcg-target.c.inc. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target-has.h | 6 ------ tcg/sparc64/tcg-target.c.inc | 6 ++++-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tcg/sparc64/tcg-target-has.h b/tcg/sparc64/tcg-target-has.h index af6a949da3..b29fd177f6 100644 --- a/tcg/sparc64/tcg-target-has.h +++ b/tcg/sparc64/tcg-target-has.h @@ -7,12 +7,6 @@ #ifndef TCG_TARGET_HAS_H #define TCG_TARGET_HAS_H -#if defined(__VIS__) && __VIS__ >= 0x300 -#define use_vis3_instructions 1 -#else -extern bool use_vis3_instructions; -#endif - /* optional instructions */ #define TCG_TARGET_HAS_extr_i64_i32 0 #define TCG_TARGET_HAS_qemu_ldst_i128 0 diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 83167aa29d..260dd461bd 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -274,8 +274,10 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE)) #define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE)) -#ifndef use_vis3_instructions -bool use_vis3_instructions; +#if defined(__VIS__) && __VIS__ >= 0x300 +#define use_vis3_instructions 1 +#else +static bool use_vis3_instructions; #endif static bool check_fit_i64(int64_t val, unsigned int bits) From 70ab4f4ed9bbe9bcfdb105681291b4695f151522 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 12:57:11 -0700 Subject: [PATCH 0516/2760] tcg/sparc64: Implement CTPOP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- tcg/sparc64/tcg-target.c.inc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 260dd461bd..9e004fb511 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -210,6 +210,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define ARITH_UDIVX (INSN_OP(2) | INSN_OP3(0x0d)) #define ARITH_SDIVX (INSN_OP(2) | INSN_OP3(0x2d)) #define ARITH_MOVCC (INSN_OP(2) | INSN_OP3(0x2c)) +#define ARITH_POPC (INSN_OP(2) | INSN_OP3(0x2e)) #define ARITH_MOVR (INSN_OP(2) | INSN_OP3(0x2f)) #define ARITH_ADDXC (INSN_OP(2) | INSN_OP3(0x36) | INSN_OPF(0x11)) @@ -274,6 +275,7 @@ static TCGReg tcg_target_call_oarg_reg(TCGCallReturnKind kind, int slot) #define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE)) #define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE)) +static bool use_popc_instructions; #if defined(__VIS__) && __VIS__ >= 0x300 #define use_vis3_instructions 1 #else @@ -1511,8 +1513,23 @@ static const TCGOutOpBinary outop_clz = { .base.static_constraint = C_NotImplemented, }; +static void tgen_ctpop(TCGContext *s, TCGType type, TCGReg a0, TCGReg a1) +{ + tcg_out_arith(s, a0, TCG_REG_G0, a1, ARITH_POPC); +} + +static TCGConstraintSetIndex cset_ctpop(TCGType type, unsigned flags) +{ + if (use_popc_instructions && type == TCG_TYPE_I64) { + return C_O1_I1(r, r); + } + return C_NotImplemented; +} + static const TCGOutOpUnary outop_ctpop = { - .base.static_constraint = C_NotImplemented, + .base.static_constraint = C_Dynamic, + .base.dynamic_constraint = cset_ctpop, + .out_rr = tgen_ctpop, }; static const TCGOutOpBinary outop_ctz = { @@ -2084,15 +2101,15 @@ tcg_target_op_def(TCGOpcode op, TCGType type, unsigned flags) static void tcg_target_init(TCGContext *s) { + unsigned long hwcap = qemu_getauxval(AT_HWCAP); + /* * Only probe for the platform and capabilities if we haven't already * determined maximum values at compile time. */ + use_popc_instructions = (hwcap & HWCAP_SPARC_POPC) != 0; #ifndef use_vis3_instructions - { - unsigned long hwcap = qemu_getauxval(AT_HWCAP); - use_vis3_instructions = (hwcap & HWCAP_SPARC_VIS3) != 0; - } + use_vis3_instructions = (hwcap & HWCAP_SPARC_VIS3) != 0; #endif tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS; From 71365ee433125026d9744a0a37142c81ff312b53 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 26 Oct 2024 18:30:05 +0200 Subject: [PATCH 0517/2760] block: get type of block allocation in commit_run bdrv_co_common_block_status_above not only returns whether the block is allocated, but also if it contains zeroes. Signed-off-by: Vincent Vanlaer Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20241026163010.2865002-2-libvirt-e6954efa@volkihar.be> Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/commit.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/block/commit.c b/block/commit.c index 5df3d05346..ba0ba59316 100644 --- a/block/commit.c +++ b/block/commit.c @@ -15,6 +15,8 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" #include "trace.h" +#include "block/block-common.h" +#include "block/coroutines.h" #include "block/block_int.h" #include "block/blockjob_int.h" #include "qapi/error.h" @@ -167,9 +169,13 @@ static int coroutine_fn commit_run(Job *job, Error **errp) break; } /* Copy if allocated above the base */ - ret = blk_co_is_allocated_above(s->top, s->base_overlay, true, - offset, COMMIT_BUFFER_SIZE, &n); - copy = (ret > 0); + WITH_GRAPH_RDLOCK_GUARD() { + ret = bdrv_co_common_block_status_above(blk_bs(s->top), + s->base_overlay, true, true, offset, COMMIT_BUFFER_SIZE, + &n, NULL, NULL, NULL); + } + + copy = (ret >= 0 && ret & BDRV_BLOCK_ALLOCATED); trace_commit_one_iteration(s, offset, n, ret); if (copy) { assert(n < SIZE_MAX); From 23743ab282af4fbb80fdc049bff2c93668c73c83 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 26 Oct 2024 18:30:06 +0200 Subject: [PATCH 0518/2760] block: move commit_run loop to separate function Signed-off-by: Vincent Vanlaer Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20241026163010.2865002-3-libvirt-e6954efa@volkihar.be> Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/commit.c | 87 +++++++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 36 deletions(-) diff --git a/block/commit.c b/block/commit.c index ba0ba59316..3ee0ade7df 100644 --- a/block/commit.c +++ b/block/commit.c @@ -128,6 +128,55 @@ static void commit_clean(Job *job) blk_unref(s->top); } +static int commit_iteration(CommitBlockJob *s, int64_t offset, + int64_t *n, void *buf) +{ + int ret = 0; + bool copy; + bool error_in_source = true; + + /* Copy if allocated above the base */ + WITH_GRAPH_RDLOCK_GUARD() { + ret = bdrv_co_common_block_status_above(blk_bs(s->top), + s->base_overlay, true, true, offset, COMMIT_BUFFER_SIZE, + n, NULL, NULL, NULL); + } + + copy = (ret >= 0 && ret & BDRV_BLOCK_ALLOCATED); + trace_commit_one_iteration(s, offset, *n, ret); + if (copy) { + assert(*n < SIZE_MAX); + + ret = blk_co_pread(s->top, offset, *n, buf, 0); + if (ret >= 0) { + ret = blk_co_pwrite(s->base, offset, *n, buf, 0); + if (ret < 0) { + error_in_source = false; + } + } + } + if (ret < 0) { + BlockErrorAction action = block_job_error_action(&s->common, + s->on_error, + error_in_source, + -ret); + if (action == BLOCK_ERROR_ACTION_REPORT) { + return ret; + } else { + *n = 0; + return 0; + } + } + /* Publish progress */ + job_progress_update(&s->common.job, *n); + + if (copy) { + block_job_ratelimit_processed_bytes(&s->common, *n); + } + + return 0; +} + static int coroutine_fn commit_run(Job *job, Error **errp) { CommitBlockJob *s = container_of(job, CommitBlockJob, common.job); @@ -158,9 +207,6 @@ static int coroutine_fn commit_run(Job *job, Error **errp) buf = blk_blockalign(s->top, COMMIT_BUFFER_SIZE); for (offset = 0; offset < len; offset += n) { - bool copy; - bool error_in_source = true; - /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that bdrv_drain_all() returns. */ @@ -168,42 +214,11 @@ static int coroutine_fn commit_run(Job *job, Error **errp) if (job_is_cancelled(&s->common.job)) { break; } - /* Copy if allocated above the base */ - WITH_GRAPH_RDLOCK_GUARD() { - ret = bdrv_co_common_block_status_above(blk_bs(s->top), - s->base_overlay, true, true, offset, COMMIT_BUFFER_SIZE, - &n, NULL, NULL, NULL); - } - copy = (ret >= 0 && ret & BDRV_BLOCK_ALLOCATED); - trace_commit_one_iteration(s, offset, n, ret); - if (copy) { - assert(n < SIZE_MAX); + ret = commit_iteration(s, offset, &n, buf); - ret = blk_co_pread(s->top, offset, n, buf, 0); - if (ret >= 0) { - ret = blk_co_pwrite(s->base, offset, n, buf, 0); - if (ret < 0) { - error_in_source = false; - } - } - } if (ret < 0) { - BlockErrorAction action = - block_job_error_action(&s->common, s->on_error, - error_in_source, -ret); - if (action == BLOCK_ERROR_ACTION_REPORT) { - return ret; - } else { - n = 0; - continue; - } - } - /* Publish progress */ - job_progress_update(&s->common.job, n); - - if (copy) { - block_job_ratelimit_processed_bytes(&s->common, n); + return ret; } } From 2e6a9f03ba1e8145cf71eced2b97611cfa754898 Mon Sep 17 00:00:00 2001 From: Gautam Gala Date: Wed, 23 Apr 2025 10:09:13 +0200 Subject: [PATCH 0519/2760] target/s390x: Introduce constant when checking if PV header couldn't be decrypted Introduce a named constant when checking the Set Secure Configuration parameters UV call return code for the case where no valid host key was found and therefore the PV header couldn't be decrypted (0x108). Reviewed-by: Steffen Eiden Reviewed-by: Janosch Frank Signed-off-by: Gautam Gala Message-ID: <20250423080915.1048123-2-ggala@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/kvm/pv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c index fe0a72c416..1947a3d669 100644 --- a/target/s390x/kvm/pv.c +++ b/target/s390x/kvm/pv.c @@ -147,6 +147,7 @@ bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) return true; } +#define UV_RC_SSC_INVAL_HOSTKEY 0x0108 int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, Error **errp) { int ret, pvrc; @@ -158,7 +159,7 @@ int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, Error **errp) ret = s390_pv_cmd_pvrc(KVM_PV_SET_SEC_PARMS, &args, &pvrc); if (ret) { error_setg(errp, "Failed to set secure execution parameters"); - if (pvrc == 0x108) { + if (pvrc == UV_RC_SSC_INVAL_HOSTKEY) { error_append_hint(errp, "Please check whether the image is " "correctly encrypted for this host\n"); } From e27cbd17dd5d46f92e2e9610e4ed12b525c548be Mon Sep 17 00:00:00 2001 From: Gautam Gala Date: Wed, 23 Apr 2025 10:09:14 +0200 Subject: [PATCH 0520/2760] target/s390x: Introduce function when exiting PV Replace an existing macro (s390_pv_cmd_exit) that looks like a function with an actual function. The function will be used when exiting PV instead of the macro. Reviewed-by: Steffen Eiden Reviewed-by: Janosch Frank Signed-off-by: Gautam Gala Reviewed-by: Thomas Huth Message-ID: <20250423080915.1048123-3-ggala@linux.ibm.com> Signed-off-by: Thomas Huth --- target/s390x/kvm/pv.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c index 1947a3d669..30b64f7f22 100644 --- a/target/s390x/kvm/pv.c +++ b/target/s390x/kvm/pv.c @@ -59,14 +59,12 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data, */ #define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data, NULL) #define s390_pv_cmd_pvrc(cmd, data, pvrc) __s390_pv_cmd(cmd, #cmd, data, pvrc) -#define s390_pv_cmd_exit(cmd, data) \ -{ \ - int rc; \ - \ - rc = __s390_pv_cmd(cmd, #cmd, data, NULL); \ - if (rc) { \ - exit(1); \ - } \ + +static void s390_pv_cmd_exit(uint32_t cmd, void *data) +{ + if (s390_pv_cmd(cmd, data)) { + exit(1); + } } int s390_pv_query_info(void) From 55a494e53e1f0c73ba5cfb1b072fed9035b7961b Mon Sep 17 00:00:00 2001 From: Gautam Gala Date: Wed, 23 Apr 2025 10:09:15 +0200 Subject: [PATCH 0521/2760] target/s390x: Return UVC cmd code, RC and RRC value when DIAG 308 Subcode 10 fails to enter secure mode Extend DIAG308 subcode 10 to return the UVC RC, RRC and command code in bit positions 32-47, 16-31, and 0-15 of register R1 + 1 if the function does not complete successfully (in addition to the previously returned diag response code in bit position 47-63). Reviewed-by: Janosch Frank Signed-off-by: Gautam Gala Reviewed-by: Steffen Eiden Message-ID: <20250423080915.1048123-4-ggala@linux.ibm.com> Signed-off-by: Thomas Huth --- hw/s390x/ipl.c | 11 ++++---- hw/s390x/ipl.h | 6 +++-- hw/s390x/s390-virtio-ccw.c | 14 ++++++----- target/s390x/kvm/pv.c | 51 +++++++++++++++++++++++++++----------- target/s390x/kvm/pv.h | 26 +++++++++++++------ 5 files changed, 73 insertions(+), 35 deletions(-) diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 716a6b7869..2f082396c7 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -26,7 +26,6 @@ #include "hw/s390x/vfio-ccw.h" #include "hw/s390x/css.h" #include "hw/s390x/ebcdic.h" -#include "target/s390x/kvm/pv.h" #include "hw/scsi/scsi.h" #include "hw/virtio/virtio-net.h" #include "ipl.h" @@ -676,7 +675,7 @@ static void s390_ipl_prepare_qipl(S390CPU *cpu) cpu_physical_memory_unmap(addr, len, 1, len); } -int s390_ipl_prepare_pv_header(Error **errp) +int s390_ipl_prepare_pv_header(struct S390PVResponse *pv_resp, Error **errp) { IplParameterBlock *ipib = s390_ipl_get_iplb_pv(); IPLBlockPV *ipib_pv = &ipib->pv; @@ -685,12 +684,13 @@ int s390_ipl_prepare_pv_header(Error **errp) cpu_physical_memory_read(ipib_pv->pv_header_addr, hdr, ipib_pv->pv_header_len); - rc = s390_pv_set_sec_parms((uintptr_t)hdr, ipib_pv->pv_header_len, errp); + rc = s390_pv_set_sec_parms((uintptr_t)hdr, ipib_pv->pv_header_len, + pv_resp, errp); g_free(hdr); return rc; } -int s390_ipl_pv_unpack(void) +int s390_ipl_pv_unpack(struct S390PVResponse *pv_resp) { IplParameterBlock *ipib = s390_ipl_get_iplb_pv(); IPLBlockPV *ipib_pv = &ipib->pv; @@ -699,7 +699,8 @@ int s390_ipl_pv_unpack(void) for (i = 0; i < ipib_pv->num_comp; i++) { rc = s390_pv_unpack(ipib_pv->components[i].addr, TARGET_PAGE_ALIGN(ipib_pv->components[i].size), - ipib_pv->components[i].tweak_pref); + ipib_pv->components[i].tweak_pref, + pv_resp); if (rc) { break; } diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h index cb55101f06..505cded490 100644 --- a/hw/s390x/ipl.h +++ b/hw/s390x/ipl.h @@ -20,6 +20,7 @@ #include "hw/qdev-core.h" #include "hw/s390x/ipl/qipl.h" #include "qom/object.h" +#include "target/s390x/kvm/pv.h" #define DIAG308_FLAGS_LP_VALID 0x80 #define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */ @@ -28,8 +29,9 @@ void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp); void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp); void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb); void s390_ipl_update_diag308(IplParameterBlock *iplb); -int s390_ipl_prepare_pv_header(Error **errp); -int s390_ipl_pv_unpack(void); +int s390_ipl_prepare_pv_header(struct S390PVResponse *pv_resp, + Error **errp); +int s390_ipl_pv_unpack(struct S390PVResponse *pv_resp); void s390_ipl_prepare_cpu(S390CPU *cpu); IplParameterBlock *s390_ipl_get_iplb(void); IplParameterBlock *s390_ipl_get_iplb_pv(void); diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 94edd42dd2..d5658afed9 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -365,7 +365,8 @@ static void s390_machine_unprotect(S390CcwMachineState *ms) ram_block_discard_disable(false); } -static int s390_machine_protect(S390CcwMachineState *ms) +static int s390_machine_protect(S390CcwMachineState *ms, + struct S390PVResponse *pv_resp) { Error *local_err = NULL; int rc; @@ -408,19 +409,19 @@ static int s390_machine_protect(S390CcwMachineState *ms) } /* Set SE header and unpack */ - rc = s390_ipl_prepare_pv_header(&local_err); + rc = s390_ipl_prepare_pv_header(pv_resp, &local_err); if (rc) { goto out_err; } /* Decrypt image */ - rc = s390_ipl_pv_unpack(); + rc = s390_ipl_pv_unpack(pv_resp); if (rc) { goto out_err; } /* Verify integrity */ - rc = s390_pv_verify(); + rc = s390_pv_verify(pv_resp); if (rc) { goto out_err; } @@ -452,6 +453,7 @@ static void s390_pv_prepare_reset(S390CcwMachineState *ms) static void s390_machine_reset(MachineState *machine, ResetType type) { S390CcwMachineState *ms = S390_CCW_MACHINE(machine); + struct S390PVResponse pv_resp; enum s390_reset reset_type; CPUState *cs, *t; S390CPU *cpu; @@ -540,8 +542,8 @@ static void s390_machine_reset(MachineState *machine, ResetType type) } run_on_cpu(cs, s390_do_cpu_reset, RUN_ON_CPU_NULL); - if (s390_machine_protect(ms)) { - s390_pv_inject_reset_error(cs); + if (s390_machine_protect(ms, &pv_resp)) { + s390_pv_inject_reset_error(cs, pv_resp); /* * Continue after the diag308 so the guest knows something * went wrong. diff --git a/target/s390x/kvm/pv.c b/target/s390x/kvm/pv.c index 30b64f7f22..2bc916a545 100644 --- a/target/s390x/kvm/pv.c +++ b/target/s390x/kvm/pv.c @@ -30,7 +30,7 @@ static struct kvm_s390_pv_info_vm info_vm; static struct kvm_s390_pv_info_dump info_dump; static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data, - int *pvrc) + struct S390PVResponse *pv_resp) { struct kvm_pv_cmd pv_cmd = { .cmd = cmd, @@ -47,8 +47,10 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data, "IOCTL rc: %d", cmd, cmdname, pv_cmd.rc, pv_cmd.rrc, rc); } - if (pvrc) { - *pvrc = pv_cmd.rc; + if (pv_resp) { + pv_resp->cmd = cmd; + pv_resp->rc = pv_cmd.rc; + pv_resp->rrc = pv_cmd.rrc; } return rc; } @@ -57,8 +59,9 @@ static int __s390_pv_cmd(uint32_t cmd, const char *cmdname, void *data, * This macro lets us pass the command as a string to the function so * we can print it on an error. */ -#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data, NULL) -#define s390_pv_cmd_pvrc(cmd, data, pvrc) __s390_pv_cmd(cmd, #cmd, data, pvrc) +#define s390_pv_cmd(cmd, data) __s390_pv_cmd(cmd, #cmd, data, NULL) +#define s390_pv_cmd_pv_resp(cmd, data, pv_resp) \ + __s390_pv_cmd(cmd, #cmd, data, pv_resp) static void s390_pv_cmd_exit(uint32_t cmd, void *data) { @@ -146,18 +149,19 @@ bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) } #define UV_RC_SSC_INVAL_HOSTKEY 0x0108 -int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, Error **errp) +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, + struct S390PVResponse *pv_resp, Error **errp) { - int ret, pvrc; + int ret; struct kvm_s390_pv_sec_parm args = { .origin = origin, .length = length, }; - ret = s390_pv_cmd_pvrc(KVM_PV_SET_SEC_PARMS, &args, &pvrc); + ret = s390_pv_cmd_pv_resp(KVM_PV_SET_SEC_PARMS, &args, pv_resp); if (ret) { error_setg(errp, "Failed to set secure execution parameters"); - if (pvrc == UV_RC_SSC_INVAL_HOSTKEY) { + if (pv_resp->rc == UV_RC_SSC_INVAL_HOSTKEY) { error_append_hint(errp, "Please check whether the image is " "correctly encrypted for this host\n"); } @@ -169,7 +173,8 @@ int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, Error **errp) /* * Called for each component in the SE type IPL parameter block 0. */ -int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) +int s390_pv_unpack(uint64_t addr, uint64_t size, + uint64_t tweak, struct S390PVResponse *pv_resp) { struct kvm_s390_pv_unp args = { .addr = addr, @@ -177,7 +182,7 @@ int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) .tweak = tweak, }; - return s390_pv_cmd(KVM_PV_UNPACK, &args); + return s390_pv_cmd_pv_resp(KVM_PV_UNPACK, &args, pv_resp); } void s390_pv_prep_reset(void) @@ -185,9 +190,9 @@ void s390_pv_prep_reset(void) s390_pv_cmd_exit(KVM_PV_PREP_RESET, NULL); } -int s390_pv_verify(void) +int s390_pv_verify(struct S390PVResponse *pv_resp) { - return s390_pv_cmd(KVM_PV_VERIFY, NULL); + return s390_pv_cmd_pv_resp(KVM_PV_VERIFY, NULL, pv_resp); } void s390_pv_unshare(void) @@ -195,13 +200,29 @@ void s390_pv_unshare(void) s390_pv_cmd_exit(KVM_PV_UNSHARE_ALL, NULL); } -void s390_pv_inject_reset_error(CPUState *cs) +void s390_pv_inject_reset_error(CPUState *cs, + struct S390PVResponse pv_resp) { int r1 = (cs->kvm_run->s390_sieic.ipa & 0x00f0) >> 4; CPUS390XState *env = &S390_CPU(cs)->env; + union { + struct { + uint16_t pv_cmd; + uint16_t pv_rrc; + uint16_t pv_rc; + uint16_t diag_rc; + }; + uint64_t regs; + } resp = { + .pv_cmd = pv_resp.cmd, + .pv_rrc = pv_resp.rrc, + .pv_rc = pv_resp.rc, + .diag_rc = DIAG_308_RC_INVAL_FOR_PV + }; + /* Report that we are unable to enter protected mode */ - env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; + env->regs[r1 + 1] = resp.regs; } uint64_t kvm_s390_pv_dmp_get_size_cpu(void) diff --git a/target/s390x/kvm/pv.h b/target/s390x/kvm/pv.h index 5e9c8bd351..94e885e933 100644 --- a/target/s390x/kvm/pv.h +++ b/target/s390x/kvm/pv.h @@ -16,6 +16,12 @@ #include "system/kvm.h" #include "hw/s390x/s390-virtio-ccw.h" +struct S390PVResponse { + uint16_t cmd; + uint16_t rrc; + uint16_t rc; +}; + #ifdef CONFIG_KVM #include "cpu.h" @@ -42,12 +48,15 @@ int s390_pv_query_info(void); int s390_pv_vm_enable(void); void s390_pv_vm_disable(void); bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms); -int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, Error **errp); -int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak); +int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, + struct S390PVResponse *pv_resp, Error **errp); +int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak, + struct S390PVResponse *pv_resp); void s390_pv_prep_reset(void); -int s390_pv_verify(void); +int s390_pv_verify(struct S390PVResponse *pv_resp); void s390_pv_unshare(void); -void s390_pv_inject_reset_error(CPUState *cs); +void s390_pv_inject_reset_error(CPUState *cs, + struct S390PVResponse pv_resp); uint64_t kvm_s390_pv_dmp_get_size_cpu(void); uint64_t kvm_s390_pv_dmp_get_size_mem_state(void); uint64_t kvm_s390_pv_dmp_get_size_completion_data(void); @@ -63,12 +72,15 @@ static inline int s390_pv_vm_enable(void) { return 0; } static inline void s390_pv_vm_disable(void) {} static inline bool s390_pv_vm_try_disable_async(S390CcwMachineState *ms) { return false; } static inline int s390_pv_set_sec_parms(uint64_t origin, uint64_t length, + struct S390PVResponse *pv_resp, Error **errp) { return 0; } -static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak) { return 0; } +static inline int s390_pv_unpack(uint64_t addr, uint64_t size, uint64_t tweak, + struct S390PVResponse *pv_resp) { return 0; } static inline void s390_pv_prep_reset(void) {} -static inline int s390_pv_verify(void) { return 0; } +static inline int s390_pv_verify(struct S390PVResponse *pv_resp) { return 0; } static inline void s390_pv_unshare(void) {} -static inline void s390_pv_inject_reset_error(CPUState *cs) {}; +static inline void s390_pv_inject_reset_error(CPUState *cs, + struct S390PVResponse pv_resp) {}; static inline uint64_t kvm_s390_pv_dmp_get_size_cpu(void) { return 0; } static inline uint64_t kvm_s390_pv_dmp_get_size_mem_state(void) { return 0; } static inline uint64_t kvm_s390_pv_dmp_get_size_completion_data(void) { return 0; } From 71a30d54e6ab1d5c102a8bee2c263414697402ea Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Tue, 29 Apr 2025 17:56:54 +0200 Subject: [PATCH 0522/2760] file-posix: Fix crash on discard_granularity == 0 Block devices that don't support discard have a discard_granularity of 0. Currently, this results in a division by zero when we try to make sure that it's a multiple of request_alignment. Only try to update bs->bl.pdiscard_alignment when we got a non-zero discard_granularity from sysfs. Fixes: f605796aae4 ('file-posix: probe discard alignment on Linux block devices') Signed-off-by: Kevin Wolf Reviewed-by: Stefan Hajnoczi Reviewed-by: Eric Blake Message-ID: <20250429155654.102735-1-kwolf@redhat.com> Signed-off-by: Stefan Hajnoczi --- block/file-posix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 0d6e12f880..0d85123d0f 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -1573,7 +1573,7 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp) int ret; ret = hdev_get_pdiscard_alignment(&st, &dalign); - if (ret == 0) { + if (ret == 0 && dalign != 0) { uint32_t ralign = bs->bl.request_alignment; /* Probably never happens, but handle it just in case */ From 6b1c744ec0d66d6d568f9a156282153fc11a21cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 25 Apr 2025 13:17:12 +0100 Subject: [PATCH 0523/2760] meson/configure: add 'valgrind' option & --{en, dis}able-valgrind flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently valgrind debugging support for coroutine stacks is enabled unconditionally when valgrind/valgrind.h is found. There is no way to disable valgrind support if valgrind.h is present in the build env. This is bad for distros, as an dependency far down the chain may cause valgrind.h to become installed, inadvertently enabling QEMU's valgrind debugging support. It also means if a distro wants valgrind support there is no way to mandate this. The solution is to add a 'valgrind' build feature to meson and thus configure script. Signed-off-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Message-ID: <20250425121713.1913424-1-berrange@redhat.com> Signed-off-by: Thomas Huth --- meson.build | 13 ++++++++++++- meson_options.txt | 2 ++ scripts/meson-buildoptions.sh | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 8ae70dbe45..ccd6c71577 100644 --- a/meson.build +++ b/meson.build @@ -2618,7 +2618,17 @@ config_host_data.set('CONFIG_FSTRIM', qga_fstrim) # has_header config_host_data.set('CONFIG_EPOLL', cc.has_header('sys/epoll.h')) config_host_data.set('CONFIG_LINUX_MAGIC_H', cc.has_header('linux/magic.h')) -config_host_data.set('CONFIG_VALGRIND_H', cc.has_header('valgrind/valgrind.h')) +valgrind = false +if get_option('valgrind').allowed() + if cc.has_header('valgrind/valgrind.h') + valgrind = true + else + if get_option('valgrind').enabled() + error('valgrind requested but valgrind.h not found') + endif + endif +endif +config_host_data.set('CONFIG_VALGRIND_H', valgrind) config_host_data.set('HAVE_BTRFS_H', cc.has_header('linux/btrfs.h')) config_host_data.set('HAVE_DRM_H', cc.has_header('libdrm/drm.h')) config_host_data.set('HAVE_OPENAT2_H', cc.has_header('linux/openat2.h')) @@ -4905,6 +4915,7 @@ endif if host_os == 'darwin' summary_info += {'ParavirtualizedGraphics support': pvg} endif +summary_info += {'valgrind': valgrind} summary(summary_info, bool_yn: true, section: 'Dependencies') if host_arch == 'unknown' diff --git a/meson_options.txt b/meson_options.txt index 59d973bca0..0b4115e733 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -115,6 +115,8 @@ option('dbus_display', type: 'feature', value: 'auto', description: '-display dbus support') option('tpm', type : 'feature', value : 'auto', description: 'TPM support') +option('valgrind', type : 'feature', value: 'auto', + description: 'valgrind debug support for coroutine stacks') # Do not enable it by default even for Mingw32, because it doesn't # work on Wine. diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh index 3e8e00852b..d76a239130 100644 --- a/scripts/meson-buildoptions.sh +++ b/scripts/meson-buildoptions.sh @@ -198,6 +198,7 @@ meson_options_help() { printf "%s\n" ' u2f U2F emulation support' printf "%s\n" ' uadk UADK Library support' printf "%s\n" ' usb-redir libusbredir support' + printf "%s\n" ' valgrind valgrind debug support for coroutine stacks' printf "%s\n" ' vde vde network backend support' printf "%s\n" ' vdi vdi image format support' printf "%s\n" ' vduse-blk-export' @@ -526,6 +527,8 @@ _meson_option_parse() { --disable-ubsan) printf "%s" -Dubsan=false ;; --enable-usb-redir) printf "%s" -Dusb_redir=enabled ;; --disable-usb-redir) printf "%s" -Dusb_redir=disabled ;; + --enable-valgrind) printf "%s" -Dvalgrind=enabled ;; + --disable-valgrind) printf "%s" -Dvalgrind=disabled ;; --enable-vde) printf "%s" -Dvde=enabled ;; --disable-vde) printf "%s" -Dvde=disabled ;; --enable-vdi) printf "%s" -Dvdi=enabled ;; From d64db833d6e3cbe9ea5f36342480f920f3675cea Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 25 Apr 2025 14:07:10 +0200 Subject: [PATCH 0524/2760] Drop support for Python 3.8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Python 3.8 went "end of life" in October 2024 and Fedora 42 dropped this version already, so the "python" CI job is currently failing. Thus it's time to drop support for this Python version in QEMU, too. While we're at it, also look for "python3.13" in the configure script. Message-ID: <20250425120710.879518-1-thuth@redhat.com> Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Signed-off-by: Thomas Huth --- configure | 14 +++++++------- docs/about/build-platforms.rst | 2 +- python/Makefile | 8 ++++---- python/setup.cfg | 7 +++---- python/tests/minreqs.txt | 2 +- scripts/qapi/mypy.ini | 2 +- tests/docker/dockerfiles/python.docker | 1 - 7 files changed, 17 insertions(+), 19 deletions(-) diff --git a/configure b/configure index 000309cf61..40705afdf5 100755 --- a/configure +++ b/configure @@ -540,17 +540,17 @@ if test -n "$linux_arch" && ! test -d "$source_path/linux-headers/asm-$linux_arc fi check_py_version() { - # We require python >= 3.8. + # We require python >= 3.9. # NB: a True python conditional creates a non-zero return code (Failure) - "$1" -c 'import sys; sys.exit(sys.version_info < (3,8))' + "$1" -c 'import sys; sys.exit(sys.version_info < (3,9))' } first_python= if test -z "${PYTHON}"; then # A bare 'python' is traditionally python 2.x, but some distros # have it as python 3.x, so check in both places. - for binary in python3 python python3.12 python3.11 \ - python3.10 python3.9 python3.8; do + for binary in python3 python python3.13 python3.12 python3.11 \ + python3.10 python3.9 ; do if has "$binary"; then python=$(command -v "$binary") if check_py_version "$python"; then @@ -933,7 +933,7 @@ then # If first_python is set, there was a binary somewhere even though # it was not suitable. Use it for the error message. if test -n "$first_python"; then - error_exit "Cannot use '$first_python', Python >= 3.8 is required." \ + error_exit "Cannot use '$first_python', Python >= 3.9 is required." \ "Use --python=/path/to/python to specify a supported Python." else error_exit "Python not found. Use --python=/path/to/python" @@ -941,11 +941,11 @@ then fi if ! check_py_version "$python"; then - error_exit "Cannot use '$python', Python >= 3.8 is required." \ + error_exit "Cannot use '$python', Python >= 3.9 is required." \ "Use --python=/path/to/python to specify a supported Python." \ "Maybe try:" \ " openSUSE Leap 15.3+: zypper install python39" \ - " CentOS 8: dnf install python38" + " CentOS: dnf install python3.12" fi # Resolve PATH diff --git a/docs/about/build-platforms.rst b/docs/about/build-platforms.rst index 52521552c8..c3651871d2 100644 --- a/docs/about/build-platforms.rst +++ b/docs/about/build-platforms.rst @@ -101,7 +101,7 @@ Python runtime option of the ``configure`` script to point QEMU to a supported version of the Python runtime. - As of QEMU |version|, the minimum supported version of Python is 3.8. + As of QEMU |version|, the minimum supported version of Python is 3.9. Python build dependencies Some of QEMU's build dependencies are written in Python. Usually these diff --git a/python/Makefile b/python/Makefile index 1fa4ba2498..764b79ccb2 100644 --- a/python/Makefile +++ b/python/Makefile @@ -9,13 +9,13 @@ help: @echo "make check-minreqs:" @echo " Run tests in the minreqs virtual environment." @echo " These tests use the oldest dependencies." - @echo " Requires: Python 3.8" - @echo " Hint (Fedora): 'sudo dnf install python3.8'" + @echo " Requires: Python 3.9" + @echo " Hint (Fedora): 'sudo dnf install python3.9'" @echo "" @echo "make check-tox:" @echo " Run tests against multiple python versions." @echo " These tests use the newest dependencies." - @echo " Requires: Python 3.8 - 3.11, and tox." + @echo " Requires: Python 3.9 - 3.11, and tox." @echo " Hint (Fedora): 'sudo dnf install python3-tox python3.11'" @echo " The variable QEMU_TOX_EXTRA_ARGS can be use to pass extra" @echo " arguments to tox". @@ -59,7 +59,7 @@ PIP_INSTALL = pip install --disable-pip-version-check min-venv: $(QEMU_MINVENV_DIR) $(QEMU_MINVENV_DIR)/bin/activate $(QEMU_MINVENV_DIR) $(QEMU_MINVENV_DIR)/bin/activate: setup.cfg tests/minreqs.txt @echo "VENV $(QEMU_MINVENV_DIR)" - @python3.8 -m venv $(QEMU_MINVENV_DIR) + @python3.9 -m venv $(QEMU_MINVENV_DIR) @( \ echo "ACTIVATE $(QEMU_MINVENV_DIR)"; \ . $(QEMU_MINVENV_DIR)/bin/activate; \ diff --git a/python/setup.cfg b/python/setup.cfg index cf5af7e664..c48dff280a 100644 --- a/python/setup.cfg +++ b/python/setup.cfg @@ -14,7 +14,6 @@ classifiers = Natural Language :: English Operating System :: OS Independent Programming Language :: Python :: 3 :: Only - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 @@ -23,7 +22,7 @@ classifiers = Typing :: Typed [options] -python_requires = >= 3.8 +python_requires = >= 3.9 packages = qemu.qmp qemu.machine @@ -78,7 +77,7 @@ exclude = __pycache__, [mypy] strict = True -python_version = 3.8 +python_version = 3.9 warn_unused_configs = True namespace_packages = True warn_unused_ignores = False @@ -186,7 +185,7 @@ multi_line_output=3 # of python available on your system to run this test. [tox:tox] -envlist = py38, py39, py310, py311, py312, py313 +envlist = py39, py310, py311, py312, py313 skip_missing_interpreters = true [testenv] diff --git a/python/tests/minreqs.txt b/python/tests/minreqs.txt index a3f423efd8..6445407ba8 100644 --- a/python/tests/minreqs.txt +++ b/python/tests/minreqs.txt @@ -1,5 +1,5 @@ # This file lists the ***oldest possible dependencies*** needed to run -# "make check" successfully under ***Python 3.8***. It is used primarily +# "make check" successfully under ***Python 3.9***. It is used primarily # by GitLab CI to ensure that our stated minimum versions in setup.cfg # are truthful and regularly validated. # diff --git a/scripts/qapi/mypy.ini b/scripts/qapi/mypy.ini index 8109470a03..c9dbcec2db 100644 --- a/scripts/qapi/mypy.ini +++ b/scripts/qapi/mypy.ini @@ -1,4 +1,4 @@ [mypy] strict = True disallow_untyped_calls = False -python_version = 3.8 +python_version = 3.9 diff --git a/tests/docker/dockerfiles/python.docker b/tests/docker/dockerfiles/python.docker index 8f0af9ef25..59e70a0248 100644 --- a/tests/docker/dockerfiles/python.docker +++ b/tests/docker/dockerfiles/python.docker @@ -15,7 +15,6 @@ ENV PACKAGES \ python3.11 \ python3.12 \ python3.13 \ - python3.8 \ python3.9 RUN dnf install -y $PACKAGES From bcfee4938f8d4e8bf5f49981d3c8a78cf267cb4e Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 24 Apr 2025 10:54:26 +0200 Subject: [PATCH 0525/2760] tests/functional/test_ppc64_pseries: Skip test_ppc64_linux_smt_boot if necessary The test_ppc64_linux_smt_boot function lacks the set_machine('pseries'), so this test is currently failing in case the 'pseries' machine has not been compiled into the binary. Add the check now to fix it. Message-ID: <20250424085426.663377-1-thuth@redhat.com> Reviewed-by: Harsh Prateek Bora Signed-off-by: Thomas Huth --- tests/functional/test_ppc64_pseries.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/test_ppc64_pseries.py b/tests/functional/test_ppc64_pseries.py index fdc404ed03..67057934e8 100755 --- a/tests/functional/test_ppc64_pseries.py +++ b/tests/functional/test_ppc64_pseries.py @@ -63,6 +63,7 @@ class pseriesMachine(QemuSystemTest): wait_for_console_pattern(self, self.good_message, self.panic_message) def test_ppc64_linux_smt_boot(self): + self.set_machine('pseries') self.vm.add_args('-smp', '4,threads=4') self.do_test_ppc64_linux_boot() console_pattern = 'CPU maps initialized for 4 threads per core' From c6d82df70e0ad3477ea97e9dc99b97c2fbfa0c1a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 25 Mar 2025 06:51:25 +0100 Subject: [PATCH 0526/2760] meson.build: Put the D-Bus summary into the UI section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We've got a dedicated section for UI options nowadays, so the D-Bus display should get reported here, too. Message-ID: <20250325055125.253669-1-thuth@redhat.com> Reviewed-by: Marc-André Lureau Reviewed-by: Alex Bennée Signed-off-by: Thomas Huth --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ccd6c71577..6c61e1dcae 100644 --- a/meson.build +++ b/meson.build @@ -4619,7 +4619,6 @@ summary_info += {'Trace backends': ','.join(get_option('trace_backends'))} if 'simple' in get_option('trace_backends') summary_info += {'Trace output file': get_option('trace_file') + '-'} endif -summary_info += {'D-Bus display': dbus_display} summary_info += {'QOM debugging': get_option('qom_cast_debug')} summary_info += {'Relocatable install': get_option('relocatable')} summary_info += {'vhost-kernel support': have_vhost_kernel} @@ -4802,6 +4801,7 @@ summary_info = {} if host_os == 'darwin' summary_info += {'Cocoa support': cocoa} endif +summary_info += {'D-Bus display': dbus_display} summary_info += {'SDL support': sdl} summary_info += {'SDL image support': sdl_image} summary_info += {'GTK support': gtk} From 35817600089256a234eb23613564d94b80e93ac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Wed, 15 Jan 2025 22:00:48 +0100 Subject: [PATCH 0527/2760] hw/rtc/mc146818rtc: Drop pre-v3 migration stream support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mc146818rtc's migration stream is at version 3 since commit 56038ef6234 ("RTC: Update the RTC clock only when reading it") from 12 years ago, released in QEMU v1.3.0! No versioned machines are that old, we can safely remove support for older streams and the qdev_set_legacy_instance_id() call. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Fabiano Rosas Message-ID: <20250115210048.25396-1-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/rtc/mc146818rtc.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c index 6f787be7af..f9f5cf396f 100644 --- a/hw/rtc/mc146818rtc.c +++ b/hw/rtc/mc146818rtc.c @@ -819,7 +819,7 @@ static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = { static const VMStateDescription vmstate_rtc = { .name = "mc146818rtc", .version_id = 3, - .minimum_version_id = 1, + .minimum_version_id = 3, .pre_save = rtc_pre_save, .post_load = rtc_post_load, .fields = (const VMStateField[]) { @@ -829,13 +829,13 @@ static const VMStateDescription vmstate_rtc = { VMSTATE_TIMER_PTR(periodic_timer, MC146818RtcState), VMSTATE_INT64(next_periodic_time, MC146818RtcState), VMSTATE_UNUSED(3*8), - VMSTATE_UINT32_V(irq_coalesced, MC146818RtcState, 2), - VMSTATE_UINT32_V(period, MC146818RtcState, 2), - VMSTATE_UINT64_V(base_rtc, MC146818RtcState, 3), - VMSTATE_UINT64_V(last_update, MC146818RtcState, 3), - VMSTATE_INT64_V(offset, MC146818RtcState, 3), - VMSTATE_TIMER_PTR_V(update_timer, MC146818RtcState, 3), - VMSTATE_UINT64_V(next_alarm_time, MC146818RtcState, 3), + VMSTATE_UINT32(irq_coalesced, MC146818RtcState), + VMSTATE_UINT32(period, MC146818RtcState), + VMSTATE_UINT64(base_rtc, MC146818RtcState), + VMSTATE_UINT64(last_update, MC146818RtcState), + VMSTATE_INT64(offset, MC146818RtcState), + VMSTATE_TIMER_PTR(update_timer, MC146818RtcState), + VMSTATE_UINT64(next_alarm_time, MC146818RtcState), VMSTATE_END_OF_LIST() }, .subsections = (const VMStateDescription * const []) { @@ -929,8 +929,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion(&s->io, 0, &s->coalesced_io); memory_region_add_coalescing(&s->coalesced_io, 0, 1); - qdev_set_legacy_instance_id(dev, s->io_base, 3); - object_property_add_tm(OBJECT(s), "date", rtc_get_date); qdev_init_gpio_out(dev, &s->irq, 1); From dce324fa06b358ccb01bf35611b6fc53b1f56b96 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 30 Apr 2025 11:10:47 -0700 Subject: [PATCH 0528/2760] docs/devel/build-environment: enhance MSYS2 instructions Add missing prerequisite packages, and use more explicit makepkg command. Signed-off-by: Pierrick Bouvier Message-ID: <20250430181047.2043492-1-pierrick.bouvier@linaro.org> Signed-off-by: Thomas Huth --- docs/devel/build-environment.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/devel/build-environment.rst b/docs/devel/build-environment.rst index f133ef2e01..661f6ea850 100644 --- a/docs/devel/build-environment.rst +++ b/docs/devel/build-environment.rst @@ -97,11 +97,11 @@ build QEMU in MSYS2 itself. :: - pacman -S wget + pacman -S wget base-devel git wget https://raw.githubusercontent.com/msys2/MINGW-packages/refs/heads/master/mingw-w64-qemu/PKGBUILD # Some packages may be missing for your environment, installation will still # be done though. - makepkg -s PKGBUILD || true + makepkg --syncdeps --nobuild PKGBUILD || true Build on windows-aarch64 ++++++++++++++++++++++++ From 43625e35d9319821f6d51cbf2798991bca533b26 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 3 Apr 2025 16:59:29 -0700 Subject: [PATCH 0529/2760] accel/tcg: Add CPUState argument to page_unprotect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the next patch, page_unprotect will need to pass the CPUState to tb_invalidate_phys_page_unwind. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 8 +++++--- include/user/page-protection.h | 2 +- linux-user/elfload.c | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 5eef8e7f18..90b345a0cf 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -128,7 +128,7 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, uintptr_t host_pc, abi_ptr guest_addr) { - switch (page_unprotect(guest_addr, host_pc)) { + switch (page_unprotect(cpu, guest_addr, host_pc)) { case 0: /* * Fault not caused by a page marked unwritable to protect @@ -584,7 +584,7 @@ bool page_check_range(target_ulong start, target_ulong len, int flags) break; } /* Asking about writable, but has been protected: undo. */ - if (!page_unprotect(start, 0)) { + if (!page_unprotect(NULL, start, 0)) { ret = false; break; } @@ -704,11 +704,13 @@ void tb_lock_page0(tb_page_addr_t address) * immediately exited. (We can only return 2 if the 'pc' argument is * non-zero.) */ -int page_unprotect(tb_page_addr_t address, uintptr_t pc) +int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) { PageFlagsNode *p; bool current_tb_invalidated; + assert((cpu == NULL) == (pc == 0)); + /* * Technically this isn't safe inside a signal handler. However we * know this only ever happens in a synchronous SEGV handler, so in diff --git a/include/user/page-protection.h b/include/user/page-protection.h index d5c8748d49..1de72e31e6 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -16,7 +16,7 @@ #include "exec/target_long.h" #include "exec/translation-block.h" -int page_unprotect(tb_page_addr_t address, uintptr_t pc); +int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc); int page_get_flags(target_ulong address); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index fbfdec2f17..87c6d3ab9f 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -4260,7 +4260,7 @@ static int wmr_page_unprotect_regions(void *opaque, target_ulong start, size_t step = MAX(TARGET_PAGE_SIZE, qemu_real_host_page_size()); while (1) { - page_unprotect(start, 0); + page_unprotect(NULL, start, 0); if (end - start <= step) { break; } From 00f708841f00d8b7046d03ef88045908f394b27d Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 3 Apr 2025 18:06:21 -0700 Subject: [PATCH 0530/2760] accel/tcg: Add CPUState argument to tb_invalidate_phys_page_unwind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace existing usage of current_cpu. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-internal.h | 3 ++- accel/tcg/tb-maint.c | 8 ++++---- accel/tcg/user-exec.c | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/accel/tcg/tb-internal.h b/accel/tcg/tb-internal.h index 08538e2896..1078de6c99 100644 --- a/accel/tcg/tb-internal.h +++ b/accel/tcg/tb-internal.h @@ -50,6 +50,7 @@ void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, uintptr_t retaddr); #endif /* CONFIG_SOFTMMU */ -bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc); +bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, + uintptr_t pc); #endif diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index d479f53ae0..714dcaedc9 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1045,7 +1045,8 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr) * TB (because it was modified by this store and the guest CPU has * precise-SMC semantics). */ -bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc) +bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, + uintptr_t pc) { TranslationBlock *current_tb; bool current_tb_modified; @@ -1083,15 +1084,14 @@ bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc) * the CPU state. */ current_tb_modified = true; - cpu_restore_state_from_tb(current_cpu, current_tb, pc); + cpu_restore_state_from_tb(cpu, current_tb, pc); } tb_phys_invalidate__locked(tb); } if (current_tb_modified) { /* Force execution of one insn next time. */ - CPUState *cpu = current_cpu; - cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); return true; } return false; diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 90b345a0cf..39b76d9654 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -749,7 +749,8 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) len = TARGET_PAGE_SIZE; prot = p->flags | PAGE_WRITE; pageflags_set_clear(start, start + len - 1, PAGE_WRITE, 0); - current_tb_invalidated = tb_invalidate_phys_page_unwind(start, pc); + current_tb_invalidated = + tb_invalidate_phys_page_unwind(cpu, start, pc); } else { start = address & -host_page_size; len = host_page_size; @@ -772,7 +773,7 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) * the corresponding translated code. */ current_tb_invalidated |= - tb_invalidate_phys_page_unwind(addr, pc); + tb_invalidate_phys_page_unwind(cpu, addr, pc); } } if (prot & PAGE_EXEC) { From e4ad80ceac03cc47d8351172f0e4625bb40e2b78 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Apr 2025 12:23:30 -0700 Subject: [PATCH 0531/2760] accel/tcg: Add CPUState arg to tb_invalidate_phys_page_range__locked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-maint.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 714dcaedc9..927e9c8ede 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1100,9 +1100,12 @@ bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, /* * @p must be non-NULL. * Call with all @pages locked. + * (@cpu, @retaddr) may be (NULL, 0) outside of a cpu context, + * in which case precise_smc need not be detected. */ static void -tb_invalidate_phys_page_range__locked(struct page_collection *pages, +tb_invalidate_phys_page_range__locked(CPUState *cpu, + struct page_collection *pages, PageDesc *p, tb_page_addr_t start, tb_page_addr_t last, uintptr_t retaddr) @@ -1194,7 +1197,7 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last) page_start = index << TARGET_PAGE_BITS; page_last = page_start | ~TARGET_PAGE_MASK; page_last = MIN(page_last, last); - tb_invalidate_phys_page_range__locked(pages, pd, + tb_invalidate_phys_page_range__locked(NULL, pages, pd, page_start, page_last, 0); } page_collection_unlock(pages); @@ -1215,7 +1218,7 @@ static void tb_invalidate_phys_page_fast__locked(struct page_collection *pages, } assert_page_locked(p); - tb_invalidate_phys_page_range__locked(pages, p, start, start + len - 1, ra); + tb_invalidate_phys_page_range__locked(NULL, pages, p, start, start + len - 1, ra); } /* From 4af02681ff77bf105b11ee1a5ca289ca29b64a54 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Apr 2025 12:37:28 -0700 Subject: [PATCH 0532/2760] accel/tcg: Merge tb_invalidate_phys_range{__locked} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merge tb_invalidate_phys_page_fast__locked into its only caller, tb_invalidate_phys_range_fast. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-maint.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 927e9c8ede..c893ea3073 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1203,38 +1203,24 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last) page_collection_unlock(pages); } -/* - * Call with all @pages in the range [@start, @start + len[ locked. - */ -static void tb_invalidate_phys_page_fast__locked(struct page_collection *pages, - tb_page_addr_t start, - unsigned len, uintptr_t ra) -{ - PageDesc *p; - - p = page_find(start >> TARGET_PAGE_BITS); - if (!p) { - return; - } - - assert_page_locked(p); - tb_invalidate_phys_page_range__locked(NULL, pages, p, start, start + len - 1, ra); -} - /* * len must be <= 8 and start must be a multiple of len. * Called via softmmu_template.h when code areas are written to with * iothread mutex not held. */ -void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, - unsigned size, - uintptr_t retaddr) +void tb_invalidate_phys_range_fast(ram_addr_t start, + unsigned len, uintptr_t ra) { - struct page_collection *pages; + PageDesc *p = page_find(start >> TARGET_PAGE_BITS); - pages = page_collection_lock(ram_addr, ram_addr + size - 1); - tb_invalidate_phys_page_fast__locked(pages, ram_addr, size, retaddr); - page_collection_unlock(pages); + if (p) { + ram_addr_t last = start + len - 1; + struct page_collection *pages = page_collection_lock(start, last); + + tb_invalidate_phys_page_range__locked(NULL, pages, p, + start, last, ra); + page_collection_unlock(pages); + } } #endif /* CONFIG_USER_ONLY */ From 072e057ed90d6bbc4f01ac04e627e63f275f57f0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Apr 2025 13:06:12 -0700 Subject: [PATCH 0533/2760] accel/tcg: Add CPUState arg to tb_invalidate_phys_range MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-maint.c | 10 ++++++---- accel/tcg/translate-all.c | 2 +- accel/tcg/user-exec.c | 4 ++-- include/exec/exec-all.h | 3 ++- system/physmem.c | 2 +- target/arm/helper.c | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index c893ea3073..c7600fc6ac 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1012,7 +1012,8 @@ TranslationBlock *tb_link_page(TranslationBlock *tb) * Called with mmap_lock held for user-mode emulation. * NOTE: this function must not be called while a TB is running. */ -void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last) +void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, + tb_page_addr_t last) { TranslationBlock *tb; PageForEachNext n; @@ -1035,7 +1036,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr) start = addr & TARGET_PAGE_MASK; last = addr | ~TARGET_PAGE_MASK; - tb_invalidate_phys_range(start, last); + tb_invalidate_phys_range(NULL, start, last); } /* @@ -1178,7 +1179,8 @@ tb_invalidate_phys_page_range__locked(CPUState *cpu, * access: the virtual CPU will exit the current TB if code is modified inside * this TB. */ -void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last) +void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, + tb_page_addr_t last) { struct page_collection *pages; tb_page_addr_t index, index_last; @@ -1197,7 +1199,7 @@ void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last) page_start = index << TARGET_PAGE_BITS; page_last = page_start | ~TARGET_PAGE_MASK; page_last = MIN(page_last, last); - tb_invalidate_phys_page_range__locked(NULL, pages, pd, + tb_invalidate_phys_page_range__locked(cpu, pages, pd, page_start, page_last, 0); } page_collection_unlock(pages); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index c007b9a190..9bf8728064 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -599,7 +599,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); addr = get_page_addr_code(env, pc); if (addr != -1) { - tb_invalidate_phys_range(addr, addr); + tb_invalidate_phys_range(cpu, addr, addr); } } } diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 39b76d9654..2b12c077e9 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -529,7 +529,7 @@ void page_set_flags(target_ulong start, target_ulong last, int flags) ~(reset ? 0 : PAGE_STICKY)); } if (inval_tb) { - tb_invalidate_phys_range(start, last); + tb_invalidate_phys_range(NULL, start, last); } } @@ -1020,7 +1020,7 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr, * be under mmap_lock() in order to prevent the creation of * another TranslationBlock in between. */ - tb_invalidate_phys_range(addr, addr + l - 1); + tb_invalidate_phys_range(NULL, addr, addr + l - 1); written = pwrite(fd, buf, l, (off_t)(uintptr_t)g2h_untagged(addr)); if (written != l) { diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 944b579d91..bee3416e7e 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -122,7 +122,8 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, /* TranslationBlock invalidate API */ void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); -void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t last); +void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, + tb_page_addr_t last); void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); #if !defined(CONFIG_USER_ONLY) diff --git a/system/physmem.c b/system/physmem.c index 16cf557d1a..637f2d8532 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -2830,7 +2830,7 @@ static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr, } if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) { assert(tcg_enabled()); - tb_invalidate_phys_range(addr, addr + length - 1); + tb_invalidate_phys_range(NULL, addr, addr + length - 1); dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); } cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask); diff --git a/target/arm/helper.c b/target/arm/helper.c index 7fb6e88630..c6fd290012 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4987,7 +4987,7 @@ static void ic_ivau_write(CPUARMState *env, const ARMCPRegInfo *ri, mmap_lock(); - tb_invalidate_phys_range(start_address, end_address); + tb_invalidate_phys_range(env_cpu(env), start_address, end_address); mmap_unlock(); } From 7fa0f4a70c1550380b2a3ee1330f70ce6ee98072 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 23 Apr 2025 13:10:45 -0700 Subject: [PATCH 0534/2760] accel/tcg: Add CPUState arg to tb_invalidate_phys_range_fast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 2 +- accel/tcg/tb-internal.h | 5 ++--- accel/tcg/tb-maint.c | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d9fb68d719..ed6de1e96e 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1340,7 +1340,7 @@ static void notdirty_write(CPUState *cpu, vaddr mem_vaddr, unsigned size, trace_memory_notdirty_write_access(mem_vaddr, ram_addr, size); if (!cpu_physical_memory_get_dirty_flag(ram_addr, DIRTY_MEMORY_CODE)) { - tb_invalidate_phys_range_fast(ram_addr, size, retaddr); + tb_invalidate_phys_range_fast(cpu, ram_addr, size, retaddr); } /* diff --git a/accel/tcg/tb-internal.h b/accel/tcg/tb-internal.h index 1078de6c99..40439f03c3 100644 --- a/accel/tcg/tb-internal.h +++ b/accel/tcg/tb-internal.h @@ -45,9 +45,8 @@ void tb_unlock_pages(TranslationBlock *); #endif #ifdef CONFIG_SOFTMMU -void tb_invalidate_phys_range_fast(ram_addr_t ram_addr, - unsigned size, - uintptr_t retaddr); +void tb_invalidate_phys_range_fast(CPUState *cpu, ram_addr_t ram_addr, + unsigned size, uintptr_t retaddr); #endif /* CONFIG_SOFTMMU */ bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index c7600fc6ac..3837f2f633 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -1210,7 +1210,7 @@ void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, * Called via softmmu_template.h when code areas are written to with * iothread mutex not held. */ -void tb_invalidate_phys_range_fast(ram_addr_t start, +void tb_invalidate_phys_range_fast(CPUState *cpu, ram_addr_t start, unsigned len, uintptr_t ra) { PageDesc *p = page_find(start >> TARGET_PAGE_BITS); @@ -1219,7 +1219,7 @@ void tb_invalidate_phys_range_fast(ram_addr_t start, ram_addr_t last = start + len - 1; struct page_collection *pages = page_collection_lock(start, last); - tb_invalidate_phys_page_range__locked(NULL, pages, p, + tb_invalidate_phys_page_range__locked(cpu, pages, p, start, last, ra); page_collection_unlock(pages); } From 77ad412b326031687f0eeb7935350e597337c93b Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Apr 2025 08:43:44 -0700 Subject: [PATCH 0535/2760] accel/tcg: Convert TARGET_HAS_PRECISE_SMC to TCGCPUOps.precise_smc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of having a compile-time TARGET_HAS_PRECISE_SMC definition, have each target set the 'precise_smc' field in the TCGCPUOps structure. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-maint.c | 32 +++++++++++++------------------- accel/tcg/user-exec.c | 10 +++++----- include/accel/tcg/cpu-ops.h | 7 +++++++ include/exec/poison.h | 1 - target/i386/cpu.h | 4 ---- target/i386/tcg/tcg-cpu.c | 1 + target/s390x/cpu.c | 1 + target/s390x/cpu.h | 2 -- 8 files changed, 27 insertions(+), 31 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 3837f2f633..1596767879 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -28,6 +28,7 @@ #include "exec/mmap-lock.h" #include "exec/tb-flush.h" #include "exec/target_page.h" +#include "accel/tcg/cpu-ops.h" #include "tb-internal.h" #include "system/tcg.h" #include "tcg/tcg.h" @@ -1042,9 +1043,7 @@ static void tb_invalidate_phys_page(tb_page_addr_t addr) /* * Called with mmap_lock held. If pc is not 0 then it indicates the * host PC of the faulting store instruction that caused this invalidate. - * Returns true if the caller needs to abort execution of the current - * TB (because it was modified by this store and the guest CPU has - * precise-SMC semantics). + * Returns true if the caller needs to abort execution of the current TB. */ bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, uintptr_t pc) @@ -1059,10 +1058,7 @@ bool tb_invalidate_phys_page_unwind(CPUState *cpu, tb_page_addr_t addr, * Without precise smc semantics, or when outside of a TB, * we can skip to invalidate. */ -#ifndef TARGET_HAS_PRECISE_SMC - pc = 0; -#endif - if (!pc) { + if (!pc || !cpu || !cpu->cc->tcg_ops->precise_smc) { tb_invalidate_phys_page(addr); return false; } @@ -1113,14 +1109,16 @@ tb_invalidate_phys_page_range__locked(CPUState *cpu, { TranslationBlock *tb; PageForEachNext n; -#ifdef TARGET_HAS_PRECISE_SMC bool current_tb_modified = false; - TranslationBlock *current_tb = retaddr ? tcg_tb_lookup(retaddr) : NULL; -#endif /* TARGET_HAS_PRECISE_SMC */ + TranslationBlock *current_tb = NULL; /* Range may not cross a page. */ tcg_debug_assert(((start ^ last) & TARGET_PAGE_MASK) == 0); + if (retaddr && cpu && cpu->cc->tcg_ops->precise_smc) { + current_tb = tcg_tb_lookup(retaddr); + } + /* * We remove all the TBs in the range [start, last]. * XXX: see if in some cases it could be faster to invalidate all the code @@ -1138,8 +1136,7 @@ tb_invalidate_phys_page_range__locked(CPUState *cpu, tb_last = tb_start + (tb_last & ~TARGET_PAGE_MASK); } if (!(tb_last < start || tb_start > last)) { -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb == tb && + if (unlikely(current_tb == tb) && (tb_cflags(current_tb) & CF_COUNT_MASK) != 1) { /* * If we are modifying the current TB, we must stop @@ -1149,9 +1146,8 @@ tb_invalidate_phys_page_range__locked(CPUState *cpu, * restore the CPU state. */ current_tb_modified = true; - cpu_restore_state_from_tb(current_cpu, current_tb, retaddr); + cpu_restore_state_from_tb(cpu, current_tb, retaddr); } -#endif /* TARGET_HAS_PRECISE_SMC */ tb_phys_invalidate__locked(tb); } } @@ -1161,15 +1157,13 @@ tb_invalidate_phys_page_range__locked(CPUState *cpu, tlb_unprotect_code(start); } -#ifdef TARGET_HAS_PRECISE_SMC - if (current_tb_modified) { + if (unlikely(current_tb_modified)) { page_collection_unlock(pages); /* Force execution of one insn next time. */ - current_cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(current_cpu); + cpu->cflags_next_tb = 1 | CF_NOIRQ | curr_cflags(cpu); mmap_unlock(); - cpu_loop_exit_noexc(current_cpu); + cpu_loop_exit_noexc(cpu); } -#endif } /* diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 2b12c077e9..112292b729 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -733,12 +733,12 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) * this thread raced with another one which got here first and * set the page to PAGE_WRITE and did the TB invalidate for us. */ -#ifdef TARGET_HAS_PRECISE_SMC - TranslationBlock *current_tb = tcg_tb_lookup(pc); - if (current_tb) { - current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID; + if (pc && cpu->cc->tcg_ops->precise_smc) { + TranslationBlock *current_tb = tcg_tb_lookup(pc); + if (current_tb) { + current_tb_invalidated = tb_cflags(current_tb) & CF_INVALID; + } } -#endif } else { int host_page_size = qemu_real_host_page_size(); target_ulong start, len, i; diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 0e4352513d..60b5e97205 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -28,6 +28,13 @@ struct TCGCPUOps { */ bool mttcg_supported; + /** + * @precise_smc: Stores which modify code within the current TB force + * the TB to exit; the next executed instruction will see + * the result of the store. + */ + bool precise_smc; + /** * @guest_default_memory_order: default barrier that is required * for the guest memory ordering. diff --git a/include/exec/poison.h b/include/exec/poison.h index bc422719d8..a779adbb7a 100644 --- a/include/exec/poison.h +++ b/include/exec/poison.h @@ -37,7 +37,6 @@ #pragma GCC poison TARGET_NAME #pragma GCC poison TARGET_BIG_ENDIAN #pragma GCC poison TCG_GUEST_DEFAULT_MO -#pragma GCC poison TARGET_HAS_PRECISE_SMC #pragma GCC poison TARGET_LONG_BITS #pragma GCC poison TARGET_FMT_lx diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 54bf9639f1..3182ba413b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -35,10 +35,6 @@ #define XEN_NR_VIRQS 24 -/* support for self modifying code even if the modified instruction is - close to the modifying instruction */ -#define TARGET_HAS_PRECISE_SMC - #ifdef TARGET_X86_64 #define I386_ELF_MACHINE EM_X86_64 #define ELF_MACHINE_UNAME "x86_64" diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index e53aaa31bf..192812656c 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -126,6 +126,7 @@ static bool x86_debug_check_breakpoint(CPUState *cs) const TCGCPUOps x86_tcg_ops = { .mttcg_supported = true, + .precise_smc = true, /* * The x86 has a strong memory model with some store-after-load re-ordering */ diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 3d644f5e23..99ff58affc 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -346,6 +346,7 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, static const TCGCPUOps s390_tcg_ops = { .mttcg_supported = true, + .precise_smc = true, /* * The z/Architecture has a strong memory model with some * store-after-load re-ordering. diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index d9ca2506e2..530d97ccf1 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -35,8 +35,6 @@ #define ELF_MACHINE_UNAME "S390X" -#define TARGET_HAS_PRECISE_SMC - #define MMU_USER_IDX 0 #define S390_MAX_CPUS 248 From 80e865668d953c012723c3af9fd1ff7258cef864 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Apr 2025 08:40:31 -0700 Subject: [PATCH 0536/2760] accel/tcg: Simplify CPU_TLB_DYN_MAX_BITS Stop taking TARGET_VIRT_ADDR_SPACE_BITS into account. Since we currently bound CPU_TLB_DYN_MAX_BITS to 22, the new bound with a 4k page size is 20, which isn't so different. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tlb-bounds.h | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/accel/tcg/tlb-bounds.h b/accel/tcg/tlb-bounds.h index efd34d4793..f83d9ac9ee 100644 --- a/accel/tcg/tlb-bounds.h +++ b/accel/tcg/tlb-bounds.h @@ -7,26 +7,7 @@ #define ACCEL_TCG_TLB_BOUNDS_H #define CPU_TLB_DYN_MIN_BITS 6 +#define CPU_TLB_DYN_MAX_BITS (32 - TARGET_PAGE_BITS) #define CPU_TLB_DYN_DEFAULT_BITS 8 -# if HOST_LONG_BITS == 32 -/* Make sure we do not require a double-word shift for the TLB load */ -# define CPU_TLB_DYN_MAX_BITS (32 - TARGET_PAGE_BITS) -# else /* HOST_LONG_BITS == 64 */ -/* - * Assuming TARGET_PAGE_BITS==12, with 2**22 entries we can cover 2**(22+12) == - * 2**34 == 16G of address space. This is roughly what one would expect a - * TLB to cover in a modern (as of 2018) x86_64 CPU. For instance, Intel - * Skylake's Level-2 STLB has 16 1G entries. - * Also, make sure we do not size the TLB past the guest's address space. - */ -# ifdef TARGET_PAGE_BITS_VARY -# define CPU_TLB_DYN_MAX_BITS \ - MIN(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) -# else -# define CPU_TLB_DYN_MAX_BITS \ - MIN_CONST(22, TARGET_VIRT_ADDR_SPACE_BITS - TARGET_PAGE_BITS) -# endif -# endif - #endif /* ACCEL_TCG_TLB_BOUNDS_H */ From 2e8fe327eb67f90822a3e8a8fb6c914dd573f299 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 2 Apr 2025 12:30:39 -0700 Subject: [PATCH 0537/2760] accel/tcg: Simplify L1_MAP_ADDR_SPACE_BITS Stop taking TARGET_PHYS_ADDR_SPACE_BITS into account. Simply allow the entire ram_addr_t space. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/tb-maint.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 1596767879..13d0376bc7 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -160,11 +160,7 @@ static PageForEachNext foreach_tb_next(PageForEachNext tb, /* * In system mode we want L1_MAP to be based on ram offsets. */ -#if HOST_LONG_BITS < TARGET_PHYS_ADDR_SPACE_BITS -# define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS -#else -# define L1_MAP_ADDR_SPACE_BITS TARGET_PHYS_ADDR_SPACE_BITS -#endif +#define L1_MAP_ADDR_SPACE_BITS HOST_LONG_BITS /* Size of the L2 (and L3, etc) page tables. */ #define V_L2_BITS 10 From dfda9281266d57899dc03fc613a25587babd67aa Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Apr 2025 09:36:27 -0700 Subject: [PATCH 0538/2760] accel/tcg: Merge internal-target.h into internal-common.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There's nothing left in internal-target.h that is target specific. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 - accel/tcg/cputlb.c | 1 - accel/tcg/internal-common.h | 29 +++++++++++++++++++++++ accel/tcg/internal-target.h | 46 ------------------------------------- accel/tcg/tb-maint.c | 1 - accel/tcg/translate-all.c | 1 - accel/tcg/user-exec.c | 1 - 7 files changed, 29 insertions(+), 51 deletions(-) delete mode 100644 accel/tcg/internal-target.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 87eba83d7d..279df5fae7 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -46,7 +46,6 @@ #include "tb-context.h" #include "tb-internal.h" #include "internal-common.h" -#include "internal-target.h" /* -icount align implementation. */ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ed6de1e96e..ca69128232 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -43,7 +43,6 @@ #include "tb-internal.h" #include "tlb-bounds.h" #include "internal-common.h" -#include "internal-target.h" #ifdef CONFIG_PLUGIN #include "qemu/plugin-memory.h" #endif diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 2f00560d10..573e8438c3 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -11,6 +11,7 @@ #include "exec/cpu-common.h" #include "exec/translation-block.h" +#include "exec/mmap-lock.h" extern int64_t max_delay; extern int64_t max_advance; @@ -108,4 +109,32 @@ static inline tb_page_addr_t get_page_addr_code(CPUArchState *env, return get_page_addr_code_hostp(env, addr, NULL); } +/* + * Access to the various translations structures need to be serialised + * via locks for consistency. In user-mode emulation access to the + * memory related structures are protected with mmap_lock. + * In !user-mode we use per-page locks. + */ +#ifdef CONFIG_USER_ONLY +#define assert_memory_lock() tcg_debug_assert(have_mmap_lock()) +#else +#define assert_memory_lock() +#endif + +#if defined(CONFIG_SOFTMMU) && defined(CONFIG_DEBUG_TCG) +void assert_no_pages_locked(void); +#else +static inline void assert_no_pages_locked(void) { } +#endif + +#ifdef CONFIG_USER_ONLY +static inline void page_table_config_init(void) { } +#else +void page_table_config_init(void); +#endif + +#ifndef CONFIG_USER_ONLY +G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); +#endif /* CONFIG_USER_ONLY */ + #endif diff --git a/accel/tcg/internal-target.h b/accel/tcg/internal-target.h deleted file mode 100644 index 9a9cef3140..0000000000 --- a/accel/tcg/internal-target.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Internal execution defines for qemu (target specific) - * - * Copyright (c) 2003 Fabrice Bellard - * - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#ifndef ACCEL_TCG_INTERNAL_TARGET_H -#define ACCEL_TCG_INTERNAL_TARGET_H - -#include "cpu-param.h" -#include "exec/exec-all.h" -#include "exec/translation-block.h" -#include "tb-internal.h" -#include "exec/mmap-lock.h" - -/* - * Access to the various translations structures need to be serialised - * via locks for consistency. In user-mode emulation access to the - * memory related structures are protected with mmap_lock. - * In !user-mode we use per-page locks. - */ -#ifdef CONFIG_USER_ONLY -#define assert_memory_lock() tcg_debug_assert(have_mmap_lock()) -#else -#define assert_memory_lock() -#endif - -#if defined(CONFIG_SOFTMMU) && defined(CONFIG_DEBUG_TCG) -void assert_no_pages_locked(void); -#else -static inline void assert_no_pages_locked(void) { } -#endif - -#ifdef CONFIG_USER_ONLY -static inline void page_table_config_init(void) { } -#else -void page_table_config_init(void); -#endif - -#ifndef CONFIG_USER_ONLY -G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); -#endif /* CONFIG_USER_ONLY */ - -#endif /* ACCEL_TCG_INTERNAL_H */ diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index 13d0376bc7..b144fcd4a0 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -36,7 +36,6 @@ #include "tb-context.h" #include "tb-internal.h" #include "internal-common.h" -#include "internal-target.h" #ifdef CONFIG_USER_ONLY #include "user/page-protection.h" #endif diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 9bf8728064..38819a507b 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -66,7 +66,6 @@ #include "tb-context.h" #include "tb-internal.h" #include "internal-common.h" -#include "internal-target.h" #include "tcg/perf.h" #include "tcg/insn-start-words.h" #include "cpu.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 112292b729..17e3be337f 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -39,7 +39,6 @@ #include "tcg/tcg-ldst.h" #include "backend-ldst.h" #include "internal-common.h" -#include "internal-target.h" #include "tb-internal.h" __thread uintptr_t helper_retaddr; From 54bd0b135e53d3afe666c5c960d7b2a0c1767bf4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 5 Apr 2025 09:45:48 -0700 Subject: [PATCH 0539/2760] accel/tcg: Reduce scope of tb_phys_invalidate, tb_set_jmp_target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the declarations of these functions out of exec/exec-all.h to accel/tcg/internal-common.h. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/internal-common.h | 3 +++ include/exec/exec-all.h | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 573e8438c3..98c702422f 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -137,4 +137,7 @@ void page_table_config_init(void); G_NORETURN void cpu_io_recompile(CPUState *cpu, uintptr_t retaddr); #endif /* CONFIG_USER_ONLY */ +void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); +void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); + #endif diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index bee3416e7e..24383b6aba 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -121,10 +121,8 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif /* CONFIG_TCG */ /* TranslationBlock invalidate API */ -void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr); void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, tb_page_addr_t last); -void tb_set_jmp_target(TranslationBlock *tb, int n, uintptr_t addr); #if !defined(CONFIG_USER_ONLY) From e1c8eb8cfec059e882066403819288d036fbbe8e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 22:24:00 +0200 Subject: [PATCH 0540/2760] accel/tcg: Use vaddr for walk_memory_regions callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use vaddr instead of target_ulong. At the same time, use int instead of unsigned long for flags, to match page_set_flags(). Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 10 +++++----- include/user/page-protection.h | 5 ++--- linux-user/elfload.c | 19 +++++++++---------- linux-user/syscall.c | 8 ++++---- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 17e3be337f..25d86567e7 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -199,13 +199,13 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn) return rc; } -static int dump_region(void *priv, target_ulong start, - target_ulong end, unsigned long prot) +static int dump_region(void *opaque, vaddr start, vaddr end, int prot) { - FILE *f = (FILE *)priv; + FILE *f = opaque; - fprintf(f, TARGET_FMT_lx"-"TARGET_FMT_lx" "TARGET_FMT_lx" %c%c%c\n", - start, end, end - start, + fprintf(f, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr + " " TARGET_ABI_FMT_ptr " %c%c%c\n", + (abi_ptr)start, (abi_ptr)end, (abi_ptr)(end - start), ((prot & PAGE_READ) ? 'r' : '-'), ((prot & PAGE_WRITE) ? 'w' : '-'), ((prot & PAGE_EXEC) ? 'x' : '-')); diff --git a/include/user/page-protection.h b/include/user/page-protection.h index 1de72e31e6..8f0b769b13 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -14,6 +14,7 @@ #include "cpu-param.h" #include "exec/target_long.h" +#include "exec/vaddr.h" #include "exec/translation-block.h" int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc); @@ -88,9 +89,7 @@ target_ulong page_find_range_empty(target_ulong min, target_ulong max, __attribute__((returns_nonnull)) void *page_get_target_data(target_ulong address); -typedef int (*walk_memory_regions_fn)(void *, target_ulong, - target_ulong, unsigned long); - +typedef int (*walk_memory_regions_fn)(void *, vaddr, vaddr, int); int walk_memory_regions(void *, walk_memory_regions_fn); void page_dump(FILE *f); diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 87c6d3ab9f..82ebf6a212 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -4059,8 +4059,7 @@ static void bswap_note(struct elf_note *en) /* * Calculate file (dump) size of given memory region. */ -static size_t vma_dump_size(target_ulong start, target_ulong end, - unsigned long flags) +static size_t vma_dump_size(vaddr start, vaddr end, int flags) { /* The area must be readable. */ if (!(flags & PAGE_READ)) { @@ -4253,8 +4252,8 @@ static int dump_write(int fd, const void *ptr, size_t size) return (0); } -static int wmr_page_unprotect_regions(void *opaque, target_ulong start, - target_ulong end, unsigned long flags) +static int wmr_page_unprotect_regions(void *opaque, vaddr start, + vaddr end, int flags) { if ((flags & (PAGE_WRITE | PAGE_WRITE_ORG)) == PAGE_WRITE_ORG) { size_t step = MAX(TARGET_PAGE_SIZE, qemu_real_host_page_size()); @@ -4275,8 +4274,8 @@ typedef struct { size_t size; } CountAndSizeRegions; -static int wmr_count_and_size_regions(void *opaque, target_ulong start, - target_ulong end, unsigned long flags) +static int wmr_count_and_size_regions(void *opaque, vaddr start, + vaddr end, int flags) { CountAndSizeRegions *css = opaque; @@ -4290,8 +4289,8 @@ typedef struct { off_t offset; } FillRegionPhdr; -static int wmr_fill_region_phdr(void *opaque, target_ulong start, - target_ulong end, unsigned long flags) +static int wmr_fill_region_phdr(void *opaque, vaddr start, + vaddr end, int flags) { FillRegionPhdr *d = opaque; struct elf_phdr *phdr = d->phdr; @@ -4313,8 +4312,8 @@ static int wmr_fill_region_phdr(void *opaque, target_ulong start, return 0; } -static int wmr_write_region(void *opaque, target_ulong start, - target_ulong end, unsigned long flags) +static int wmr_write_region(void *opaque, vaddr start, + vaddr end, int flags) { int fd = *(int *)opaque; size_t size = vma_dump_size(start, end, flags); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5826ac3adb..23b901b713 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8135,8 +8135,8 @@ static void open_self_maps_4(const struct open_self_maps_data *d, * Callback for walk_memory_regions, when read_self_maps() fails. * Proceed without the benefit of host /proc/self/maps cross-check. */ -static int open_self_maps_3(void *opaque, target_ulong guest_start, - target_ulong guest_end, unsigned long flags) +static int open_self_maps_3(void *opaque, vaddr guest_start, + vaddr guest_end, int flags) { static const MapInfo mi = { .is_priv = true }; @@ -8147,8 +8147,8 @@ static int open_self_maps_3(void *opaque, target_ulong guest_start, /* * Callback for walk_memory_regions, when read_self_maps() succeeds. */ -static int open_self_maps_2(void *opaque, target_ulong guest_start, - target_ulong guest_end, unsigned long flags) +static int open_self_maps_2(void *opaque, vaddr guest_start, + vaddr guest_end, int flags) { const struct open_self_maps_data *d = opaque; uintptr_t host_start = (uintptr_t)g2h_untagged(guest_start); From 5627d5c00a256cc180b659f7c21383e36934a80c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 22:24:01 +0200 Subject: [PATCH 0541/2760] accel/tcg: Use vaddr in user/page-protection.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Anton Johansson Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 51 ++++++++++++++++------------------ include/user/page-protection.h | 17 +++++------- 2 files changed, 31 insertions(+), 37 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 25d86567e7..43d005e24e 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -161,7 +161,7 @@ typedef struct PageFlagsNode { static IntervalTreeRoot pageflags_root; -static PageFlagsNode *pageflags_find(target_ulong start, target_ulong last) +static PageFlagsNode *pageflags_find(vaddr start, vaddr last) { IntervalTreeNode *n; @@ -169,8 +169,7 @@ static PageFlagsNode *pageflags_find(target_ulong start, target_ulong last) return n ? container_of(n, PageFlagsNode, itree) : NULL; } -static PageFlagsNode *pageflags_next(PageFlagsNode *p, target_ulong start, - target_ulong last) +static PageFlagsNode *pageflags_next(PageFlagsNode *p, vaddr start, vaddr last) { IntervalTreeNode *n; @@ -215,14 +214,14 @@ static int dump_region(void *opaque, vaddr start, vaddr end, int prot) /* dump memory mappings */ void page_dump(FILE *f) { - const int length = sizeof(target_ulong) * 2; + const int length = sizeof(abi_ptr) * 2; fprintf(f, "%-*s %-*s %-*s %s\n", length, "start", length, "end", length, "size", "prot"); walk_memory_regions(f, dump_region); } -int page_get_flags(target_ulong address) +int page_get_flags(vaddr address) { PageFlagsNode *p = pageflags_find(address, address); @@ -245,7 +244,7 @@ int page_get_flags(target_ulong address) } /* A subroutine of page_set_flags: insert a new node for [start,last]. */ -static void pageflags_create(target_ulong start, target_ulong last, int flags) +static void pageflags_create(vaddr start, vaddr last, int flags) { PageFlagsNode *p = g_new(PageFlagsNode, 1); @@ -256,13 +255,13 @@ static void pageflags_create(target_ulong start, target_ulong last, int flags) } /* A subroutine of page_set_flags: remove everything in [start,last]. */ -static bool pageflags_unset(target_ulong start, target_ulong last) +static bool pageflags_unset(vaddr start, vaddr last) { bool inval_tb = false; while (true) { PageFlagsNode *p = pageflags_find(start, last); - target_ulong p_last; + vaddr p_last; if (!p) { break; @@ -301,8 +300,7 @@ static bool pageflags_unset(target_ulong start, target_ulong last) * A subroutine of page_set_flags: nothing overlaps [start,last], * but check adjacent mappings and maybe merge into a single range. */ -static void pageflags_create_merge(target_ulong start, target_ulong last, - int flags) +static void pageflags_create_merge(vaddr start, vaddr last, int flags) { PageFlagsNode *next = NULL, *prev = NULL; @@ -353,11 +351,11 @@ static void pageflags_create_merge(target_ulong start, target_ulong last, #define PAGE_STICKY (PAGE_ANON | PAGE_PASSTHROUGH | PAGE_TARGET_STICKY) /* A subroutine of page_set_flags: add flags to [start,last]. */ -static bool pageflags_set_clear(target_ulong start, target_ulong last, +static bool pageflags_set_clear(vaddr start, vaddr last, int set_flags, int clear_flags) { PageFlagsNode *p; - target_ulong p_start, p_last; + vaddr p_start, p_last; int p_flags, merge_flags; bool inval_tb = false; @@ -492,7 +490,7 @@ static bool pageflags_set_clear(target_ulong start, target_ulong last, return inval_tb; } -void page_set_flags(target_ulong start, target_ulong last, int flags) +void page_set_flags(vaddr start, vaddr last, int flags) { bool reset = false; bool inval_tb = false; @@ -532,9 +530,9 @@ void page_set_flags(target_ulong start, target_ulong last, int flags) } } -bool page_check_range(target_ulong start, target_ulong len, int flags) +bool page_check_range(vaddr start, vaddr len, int flags) { - target_ulong last; + vaddr last; int locked; /* tri-state: =0: unlocked, +1: global, -1: local */ bool ret; @@ -610,17 +608,16 @@ bool page_check_range(target_ulong start, target_ulong len, int flags) return ret; } -bool page_check_range_empty(target_ulong start, target_ulong last) +bool page_check_range_empty(vaddr start, vaddr last) { assert(last >= start); assert_memory_lock(); return pageflags_find(start, last) == NULL; } -target_ulong page_find_range_empty(target_ulong min, target_ulong max, - target_ulong len, target_ulong align) +vaddr page_find_range_empty(vaddr min, vaddr max, vaddr len, vaddr align) { - target_ulong len_m1, align_m1; + vaddr len_m1, align_m1; assert(min <= max); assert(max <= GUEST_ADDR_MAX); @@ -661,7 +658,7 @@ target_ulong page_find_range_empty(target_ulong min, target_ulong max, void tb_lock_page0(tb_page_addr_t address) { PageFlagsNode *p; - target_ulong start, last; + vaddr start, last; int host_page_size = qemu_real_host_page_size(); int prot; @@ -740,7 +737,7 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) } } else { int host_page_size = qemu_real_host_page_size(); - target_ulong start, len, i; + vaddr start, len, i; int prot; if (host_page_size <= TARGET_PAGE_SIZE) { @@ -756,7 +753,7 @@ int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc) prot = 0; for (i = 0; i < len; i += TARGET_PAGE_SIZE) { - target_ulong addr = start + i; + vaddr addr = start + i; p = pageflags_find(addr, addr); if (p) { @@ -883,7 +880,7 @@ typedef struct TargetPageDataNode { static IntervalTreeRoot targetdata_root; -void page_reset_target_data(target_ulong start, target_ulong last) +void page_reset_target_data(vaddr start, vaddr last) { IntervalTreeNode *n, *next; @@ -897,7 +894,7 @@ void page_reset_target_data(target_ulong start, target_ulong last) n != NULL; n = next, next = next ? interval_tree_iter_next(n, start, last) : NULL) { - target_ulong n_start, n_last, p_ofs, p_len; + vaddr n_start, n_last, p_ofs, p_len; TargetPageDataNode *t = container_of(n, TargetPageDataNode, itree); if (n->start >= start && n->last <= last) { @@ -921,11 +918,11 @@ void page_reset_target_data(target_ulong start, target_ulong last) } } -void *page_get_target_data(target_ulong address) +void *page_get_target_data(vaddr address) { IntervalTreeNode *n; TargetPageDataNode *t; - target_ulong page, region, p_ofs; + vaddr page, region, p_ofs; page = address & TARGET_PAGE_MASK; region = address & TBD_MASK; @@ -956,7 +953,7 @@ void *page_get_target_data(target_ulong address) return t->data + p_ofs * TARGET_PAGE_DATA_SIZE; } #else -void page_reset_target_data(target_ulong start, target_ulong last) { } +void page_reset_target_data(vaddr start, vaddr last) { } #endif /* TARGET_PAGE_DATA_SIZE */ /* The system-mode versions of these helpers are in cputlb.c. */ diff --git a/include/user/page-protection.h b/include/user/page-protection.h index 8f0b769b13..86143212fd 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -12,14 +12,12 @@ #error Cannot include this header from system emulation #endif -#include "cpu-param.h" -#include "exec/target_long.h" #include "exec/vaddr.h" #include "exec/translation-block.h" int page_unprotect(CPUState *cpu, tb_page_addr_t address, uintptr_t pc); -int page_get_flags(target_ulong address); +int page_get_flags(vaddr address); /** * page_set_flags: @@ -32,9 +30,9 @@ int page_get_flags(target_ulong address); * The flag PAGE_WRITE_ORG is positioned automatically depending * on PAGE_WRITE. The mmap_lock should already be held. */ -void page_set_flags(target_ulong start, target_ulong last, int flags); +void page_set_flags(vaddr start, vaddr last, int flags); -void page_reset_target_data(target_ulong start, target_ulong last); +void page_reset_target_data(vaddr start, vaddr last); /** * page_check_range @@ -46,7 +44,7 @@ void page_reset_target_data(target_ulong start, target_ulong last); * Return false if any page is unmapped. Thus testing flags == 0 is * equivalent to testing for flags == PAGE_VALID. */ -bool page_check_range(target_ulong start, target_ulong last, int flags); +bool page_check_range(vaddr start, vaddr last, int flags); /** * page_check_range_empty: @@ -58,7 +56,7 @@ bool page_check_range(target_ulong start, target_ulong last, int flags); * The memory lock must be held so that the caller will can ensure * the result stays true until a new mapping can be installed. */ -bool page_check_range_empty(target_ulong start, target_ulong last); +bool page_check_range_empty(vaddr start, vaddr last); /** * page_find_range_empty @@ -72,8 +70,7 @@ bool page_check_range_empty(target_ulong start, target_ulong last); * The memory lock must be held, as the caller will want to ensure * the returned range stays empty until a new mapping can be installed. */ -target_ulong page_find_range_empty(target_ulong min, target_ulong max, - target_ulong len, target_ulong align); +vaddr page_find_range_empty(vaddr min, vaddr max, vaddr len, vaddr align); /** * page_get_target_data(address) @@ -87,7 +84,7 @@ target_ulong page_find_range_empty(target_ulong min, target_ulong max, * e.g. with the munmap system call. */ __attribute__((returns_nonnull)) -void *page_get_target_data(target_ulong address); +void *page_get_target_data(vaddr address); typedef int (*walk_memory_regions_fn)(void *, vaddr, vaddr, int); int walk_memory_regions(void *, walk_memory_regions_fn); From 5f2446eb82bcb89c0969feffdd88c4eea05edfcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:03 +0200 Subject: [PATCH 0542/2760] include/exec: Include missing headers in exec-all.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "exec/exec-all.h" declares prototypes such: void *probe_access(CPUArchState *env, vaddr addr, int size, ^^^^^ MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); MemoryRegionSection *iotlb_to_section(CPUState *cpu, hwaddr index, ^^^^^^ MemTxAttrs attrs); ^^^^^^^^^^ vaddr is defined in "exec/vaddr.h", hwaddr in "exec/hwaddr.h" and MemTxAttrs in "exec/memattrs.h". All these headers are indirectly pulled in via "exec/translation-block.h". Since we will remove "exec/translation-block.h" in the next commit, include the missing ones, otherwise we'd get errors such: include/exec/exec-all.h:51:1: error: unknown type name 'hwaddr' 51 | hwaddr memory_region_section_get_iotlb(CPUState *cpu, | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-5-philmd@linaro.org> --- include/exec/exec-all.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 24383b6aba..c46255e66e 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -20,8 +20,11 @@ #ifndef EXEC_ALL_H #define EXEC_ALL_H +#include "exec/hwaddr.h" +#include "exec/memattrs.h" #include "exec/mmu-access-type.h" #include "exec/translation-block.h" +#include "exec/vaddr.h" #if defined(CONFIG_TCG) #include "accel/tcg/getpc.h" From 0b87b740c27cabbd4f8447631d026c28ca83f7db Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 22:24:04 +0200 Subject: [PATCH 0543/2760] include/exec: Move tb_invalidate_phys_range to translation-block.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Anton Johansson Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- include/exec/exec-all.h | 5 ----- include/exec/translation-block.h | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index c46255e66e..4c5ad98c6a 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -23,7 +23,6 @@ #include "exec/hwaddr.h" #include "exec/memattrs.h" #include "exec/mmu-access-type.h" -#include "exec/translation-block.h" #include "exec/vaddr.h" #if defined(CONFIG_TCG) @@ -123,10 +122,6 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif /* !CONFIG_USER_ONLY */ #endif /* CONFIG_TCG */ -/* TranslationBlock invalidate API */ -void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, - tb_page_addr_t last); - #if !defined(CONFIG_USER_ONLY) /** diff --git a/include/exec/translation-block.h b/include/exec/translation-block.h index 8b8e730561..cdce399eba 100644 --- a/include/exec/translation-block.h +++ b/include/exec/translation-block.h @@ -207,4 +207,8 @@ static inline void tb_set_page_addr1(TranslationBlock *tb, #endif } +/* TranslationBlock invalidate API */ +void tb_invalidate_phys_range(CPUState *cpu, tb_page_addr_t start, + tb_page_addr_t last); + #endif /* EXEC_TRANSLATION_BLOCK_H */ From 7795eded0477f21c8518176492c4e19d103dde2c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 24 Apr 2025 22:24:05 +0200 Subject: [PATCH 0544/2760] accel/tcg: Compile tb-maint.c twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Anton Johansson Reviewed-by: Pierrick Bouvier Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 2 +- accel/tcg/tb-hash.h | 3 +-- accel/tcg/tb-maint.c | 2 -- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 047afa49a2..3f7b127130 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -8,6 +8,7 @@ tcg_ss.add(files( 'cpu-exec-common.c', 'tcg-runtime.c', 'tcg-runtime-gvec.c', + 'tb-maint.c', 'translator.c', )) if get_option('plugins') @@ -21,7 +22,6 @@ tcg_specific_ss = ss.source_set() tcg_specific_ss.add(files( 'tcg-all.c', 'cpu-exec.c', - 'tb-maint.c', 'translate-all.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) diff --git a/accel/tcg/tb-hash.h b/accel/tcg/tb-hash.h index 3bc5042d9d..f7b159f04c 100644 --- a/accel/tcg/tb-hash.h +++ b/accel/tcg/tb-hash.h @@ -20,8 +20,7 @@ #ifndef EXEC_TB_HASH_H #define EXEC_TB_HASH_H -#include "exec/cpu-defs.h" -#include "exec/exec-all.h" +#include "exec/vaddr.h" #include "exec/target_page.h" #include "exec/translation-block.h" #include "qemu/xxhash.h" diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c index b144fcd4a0..0048316f99 100644 --- a/accel/tcg/tb-maint.c +++ b/accel/tcg/tb-maint.c @@ -20,10 +20,8 @@ #include "qemu/osdep.h" #include "qemu/interval-tree.h" #include "qemu/qtree.h" -#include "cpu.h" #include "exec/cputlb.h" #include "exec/log.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "exec/tb-flush.h" From 3ea423c27f4eabee5068fce27412761fa3db8b0f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Apr 2025 19:35:00 +0000 Subject: [PATCH 0545/2760] accel/tcg: Remove #error for non-tcg in getpc.h Signed-off-by: Richard Henderson --- include/accel/tcg/getpc.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/accel/tcg/getpc.h b/include/accel/tcg/getpc.h index 8a97ce34e7..0fc08addcf 100644 --- a/include/accel/tcg/getpc.h +++ b/include/accel/tcg/getpc.h @@ -8,10 +8,6 @@ #ifndef ACCEL_TCG_GETPC_H #define ACCEL_TCG_GETPC_H -#ifndef CONFIG_TCG -#error Can only include this header with TCG -#endif - /* GETPC is the true target of the return instruction that we'll execute. */ #ifdef CONFIG_TCG_INTERPRETER extern __thread uintptr_t tci_tb_ptr; From 0f81774dd1c19de5dedb3c8f2d74e5b9a73d8c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:06 +0200 Subject: [PATCH 0546/2760] target/riscv: Include missing 'accel/tcg/getpc.h' in csr.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "accel/tcg/getpc.h" is pulled in indirectly. Include it explicitly to avoid when refactoring unrelated headers: target/riscv/csr.c:2117:25: error: call to undeclared function 'GETPC' [-Wimplicit-function-declaration] 2117 | if ((val & RVC) && (GETPC() & ~3) != 0) { | ^ Note the TODO comment around GETPC() added upon introduction in commit f18637cd611 ("RISC-V: Add misa runtime write support"): 2099 static RISCVException write_misa(CPURISCVState *env, int csrno, 2100 target_ulong val) 2101 { ... 2113 /* 2114 * Suppress 'C' if next instruction is not aligned 2115 * TODO: this should check next_pc 2116 */ 2117 if ((val & RVC) && (GETPC() & ~3) != 0) { 2118 val &= ~RVC; 2119 } Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Acked-by: Alistair Francis Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-8-philmd@linaro.org> --- target/riscv/csr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index c52c87faae..1308643855 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -28,6 +28,7 @@ #include "exec/cputlb.h" #include "exec/tb-flush.h" #include "exec/icount.h" +#include "accel/tcg/getpc.h" #include "qemu/guest-random.h" #include "qapi/error.h" #include From 98db62318ae98be9a57b3c01f7f97a984ac1b79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:08 +0200 Subject: [PATCH 0547/2760] accel/tcg: Include 'accel/tcg/getpc.h' in 'exec/helper-proto' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most files including "exec/helper-proto.h" call GETPC(). Include it there (in the common part) instead of the unspecific "exec/exec-all.h" header. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-10-philmd@linaro.org> --- accel/tcg/translate-all.c | 1 + include/exec/exec-all.h | 1 - include/exec/helper-proto-common.h | 2 ++ target/avr/helper.c | 1 - 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 38819a507b..0408e2522a 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -61,6 +61,7 @@ #include "system/tcg.h" #include "qapi/error.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/getpc.h" #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 4c5ad98c6a..816274bf90 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -26,7 +26,6 @@ #include "exec/vaddr.h" #if defined(CONFIG_TCG) -#include "accel/tcg/getpc.h" /** * probe_access: diff --git a/include/exec/helper-proto-common.h b/include/exec/helper-proto-common.h index 16782ef46c..76e6c25bec 100644 --- a/include/exec/helper-proto-common.h +++ b/include/exec/helper-proto-common.h @@ -13,4 +13,6 @@ #include "exec/helper-proto.h.inc" #undef HELPER_H +#include "accel/tcg/getpc.h" + #endif /* HELPER_PROTO_COMMON_H */ diff --git a/target/avr/helper.c b/target/avr/helper.c index afa591470f..b9cd6d5ef2 100644 --- a/target/avr/helper.c +++ b/target/avr/helper.c @@ -23,7 +23,6 @@ #include "qemu/error-report.h" #include "cpu.h" #include "accel/tcg/cpu-ops.h" -#include "accel/tcg/getpc.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" From 1381ea53a84234a0aac212baeae922137ad4bbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:09 +0200 Subject: [PATCH 0548/2760] physmem: Move TCG IOTLB methods around MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The next commit will restrict TCG specific code in physmem.c using some #ifdef'ry. In order to keep it simple, move iotlb_to_section() and memory_region_section_get_iotlb() around close together. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Reviewed-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-11-philmd@linaro.org> --- system/physmem.c | 50 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/system/physmem.c b/system/physmem.c index 637f2d8532..ccbeae241c 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -746,6 +746,31 @@ translate_fail: return &d->map.sections[PHYS_SECTION_UNASSIGNED]; } +MemoryRegionSection *iotlb_to_section(CPUState *cpu, + hwaddr index, MemTxAttrs attrs) +{ + int asidx = cpu_asidx_from_attrs(cpu, attrs); + CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; + AddressSpaceDispatch *d = cpuas->memory_dispatch; + int section_index = index & ~TARGET_PAGE_MASK; + MemoryRegionSection *ret; + + assert(section_index < d->map.sections_nb); + ret = d->map.sections + section_index; + assert(ret->mr); + assert(ret->mr->ops); + + return ret; +} + +/* Called from RCU critical section */ +hwaddr memory_region_section_get_iotlb(CPUState *cpu, + MemoryRegionSection *section) +{ + AddressSpaceDispatch *d = flatview_to_dispatch(section->fv); + return section - d->map.sections; +} + void cpu_address_space_init(CPUState *cpu, int asidx, const char *prefix, MemoryRegion *mr) { @@ -1002,14 +1027,6 @@ bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap, return false; } -/* Called from RCU critical section */ -hwaddr memory_region_section_get_iotlb(CPUState *cpu, - MemoryRegionSection *section) -{ - AddressSpaceDispatch *d = flatview_to_dispatch(section->fv); - return section - d->map.sections; -} - static int subpage_register(subpage_t *mmio, uint32_t start, uint32_t end, uint16_t section); static subpage_t *subpage_init(FlatView *fv, hwaddr base); @@ -2669,23 +2686,6 @@ static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr) return phys_section_add(map, §ion); } -MemoryRegionSection *iotlb_to_section(CPUState *cpu, - hwaddr index, MemTxAttrs attrs) -{ - int asidx = cpu_asidx_from_attrs(cpu, attrs); - CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx]; - AddressSpaceDispatch *d = cpuas->memory_dispatch; - int section_index = index & ~TARGET_PAGE_MASK; - MemoryRegionSection *ret; - - assert(section_index < d->map.sections_nb); - ret = d->map.sections + section_index; - assert(ret->mr); - assert(ret->mr->ops); - - return ret; -} - static void io_mem_init(void) { memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL, From f12b717717c45627d667b609326fda54f0ad0394 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:10 +0200 Subject: [PATCH 0549/2760] physmem: Restrict TCG IOTLB code to TCG accel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restrict iotlb_to_section(), address_space_translate_for_iotlb() and memory_region_section_get_iotlb() to TCG. Declare them in the new "accel/tcg/iommu.h" header. Declare iotlb_to_section() using the MemoryRegionSection typedef. Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-12-philmd@linaro.org> --- MAINTAINERS | 2 +- accel/tcg/cputlb.c | 1 + include/accel/tcg/iommu.h | 41 +++++++++++++++++++++++++++++++++++++++ include/exec/exec-all.h | 26 ------------------------- system/physmem.c | 5 +++++ 5 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 include/accel/tcg/iommu.h diff --git a/MAINTAINERS b/MAINTAINERS index b3f9f2680b..f3f491c8c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -168,7 +168,7 @@ F: include/exec/helper*.h.inc F: include/exec/helper-info.c.inc F: include/exec/page-protection.h F: include/system/tcg.h -F: include/accel/tcg/cpu-ops.h +F: include/accel/tcg/ F: host/include/*/host/cpuinfo.h F: util/cpuinfo-*.c F: include/tcg/ diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index ca69128232..d11989f567 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/iommu.h" #include "exec/exec-all.h" #include "exec/page-protection.h" #include "system/memory.h" diff --git a/include/accel/tcg/iommu.h b/include/accel/tcg/iommu.h new file mode 100644 index 0000000000..90cfd6c0ed --- /dev/null +++ b/include/accel/tcg/iommu.h @@ -0,0 +1,41 @@ +/* + * TCG IOMMU translations. + * + * Copyright (c) 2003 Fabrice Bellard + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#ifndef ACCEL_TCG_IOMMU_H +#define ACCEL_TCG_IOMMU_H + +#ifdef CONFIG_USER_ONLY +#error Cannot include accel/tcg/iommu.h from user emulation +#endif + +#include "exec/hwaddr.h" +#include "exec/memattrs.h" + +/** + * iotlb_to_section: + * @cpu: CPU performing the access + * @index: TCG CPU IOTLB entry + * + * Given a TCG CPU IOTLB entry, return the MemoryRegionSection that + * it refers to. @index will have been initially created and returned + * by memory_region_section_get_iotlb(). + */ +MemoryRegionSection *iotlb_to_section(CPUState *cpu, + hwaddr index, MemTxAttrs attrs); + +MemoryRegionSection *address_space_translate_for_iotlb(CPUState *cpu, + int asidx, + hwaddr addr, + hwaddr *xlat, + hwaddr *plen, + MemTxAttrs attrs, + int *prot); + +hwaddr memory_region_section_get_iotlb(CPUState *cpu, + MemoryRegionSection *section); + +#endif + diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 816274bf90..b9eb9bc4b6 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -21,7 +21,6 @@ #define EXEC_ALL_H #include "exec/hwaddr.h" -#include "exec/memattrs.h" #include "exec/mmu-access-type.h" #include "exec/vaddr.h" @@ -121,29 +120,4 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif /* !CONFIG_USER_ONLY */ #endif /* CONFIG_TCG */ -#if !defined(CONFIG_USER_ONLY) - -/** - * iotlb_to_section: - * @cpu: CPU performing the access - * @index: TCG CPU IOTLB entry - * - * Given a TCG CPU IOTLB entry, return the MemoryRegionSection that - * it refers to. @index will have been initially created and returned - * by memory_region_section_get_iotlb(). - */ -struct MemoryRegionSection *iotlb_to_section(CPUState *cpu, - hwaddr index, MemTxAttrs attrs); -#endif - -#if !defined(CONFIG_USER_ONLY) - -MemoryRegionSection * -address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, - hwaddr *xlat, hwaddr *plen, - MemTxAttrs attrs, int *prot); -hwaddr memory_region_section_get_iotlb(CPUState *cpu, - MemoryRegionSection *section); -#endif - #endif diff --git a/system/physmem.c b/system/physmem.c index ccbeae241c..f1ec0902c7 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -29,6 +29,7 @@ #ifdef CONFIG_TCG #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/iommu.h" #endif /* CONFIG_TCG */ #include "exec/exec-all.h" @@ -587,6 +588,8 @@ MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat, return mr; } +#ifdef CONFIG_TCG + typedef struct TCGIOMMUNotifier { IOMMUNotifier n; MemoryRegion *mr; @@ -771,6 +774,8 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu, return section - d->map.sections; } +#endif /* CONFIG_TCG */ + void cpu_address_space_init(CPUState *cpu, int asidx, const char *prefix, MemoryRegion *mr) { From fe1a3ace13a8b53fc20c74fb7e3337f754396e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:11 +0200 Subject: [PATCH 0550/2760] accel/tcg: Extract probe API out of 'exec/exec-all.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare probe methods in "accel/tcg/probe.h" to emphasize they are specific to TCG accelerator. Suggested-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-13-philmd@linaro.org> --- accel/tcg/cputlb.c | 1 + accel/tcg/user-exec.c | 1 + include/accel/tcg/probe.h | 106 +++++++++++++++++++++++++++ include/exec/exec-all.h | 100 ------------------------- semihosting/uaccess.c | 1 + target/arm/helper.c | 1 + target/arm/ptw.c | 1 + target/arm/tcg/helper-a64.c | 1 + target/arm/tcg/mte_helper.c | 1 + target/arm/tcg/op_helper.c | 1 + target/arm/tcg/sve_helper.c | 1 + target/hexagon/mmvec/macros.h | 1 + target/hexagon/op_helper.c | 1 + target/hppa/mem_helper.c | 1 + target/hppa/op_helper.c | 1 + target/i386/tcg/access.c | 1 + target/i386/tcg/seg_helper.c | 1 + target/i386/tcg/system/excp_helper.c | 1 + target/mips/tcg/msa_helper.c | 1 + target/ppc/mem_helper.c | 1 + target/riscv/op_helper.c | 1 + target/riscv/vector_helper.c | 1 + target/s390x/tcg/mem_helper.c | 1 + target/xtensa/mmu_helper.c | 1 + 24 files changed, 128 insertions(+), 100 deletions(-) create mode 100644 include/accel/tcg/probe.h diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index d11989f567..b346af942a 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -21,6 +21,7 @@ #include "qemu/main-loop.h" #include "accel/tcg/cpu-ops.h" #include "accel/tcg/iommu.h" +#include "accel/tcg/probe.h" #include "exec/exec-all.h" #include "exec/page-protection.h" #include "system/memory.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 43d005e24e..697fdf1824 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -27,6 +27,7 @@ #include "qemu/bitops.h" #include "qemu/rcu.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "user/cpu_loop.h" #include "qemu/main-loop.h" #include "user/page-protection.h" diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h new file mode 100644 index 0000000000..177bd1608d --- /dev/null +++ b/include/accel/tcg/probe.h @@ -0,0 +1,106 @@ +/* + * Probe guest virtual addresses for access permissions. + * + * Copyright (c) 2003 Fabrice Bellard + * SPDX-License-Identifier: LGPL-2.1-or-later + */ +#ifndef ACCEL_TCG_PROBE_H +#define ACCEL_TCG_PROBE_H + +#include "exec/mmu-access-type.h" +#include "exec/vaddr.h" + +/** + * probe_access: + * @env: CPUArchState + * @addr: guest virtual address to look up + * @size: size of the access + * @access_type: read, write or execute permission + * @mmu_idx: MMU index to use for lookup + * @retaddr: return address for unwinding + * + * Look up the guest virtual address @addr. Raise an exception if the + * page does not satisfy @access_type. Raise an exception if the + * access (@addr, @size) hits a watchpoint. For writes, mark a clean + * page as dirty. + * + * Finally, return the host address for a page that is backed by RAM, + * or NULL if the page requires I/O. + */ +void *probe_access(CPUArchState *env, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); + +static inline void *probe_write(CPUArchState *env, vaddr addr, int size, + int mmu_idx, uintptr_t retaddr) +{ + return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); +} + +static inline void *probe_read(CPUArchState *env, vaddr addr, int size, + int mmu_idx, uintptr_t retaddr) +{ + return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); +} + +/** + * probe_access_flags: + * @env: CPUArchState + * @addr: guest virtual address to look up + * @size: size of the access + * @access_type: read, write or execute permission + * @mmu_idx: MMU index to use for lookup + * @nonfault: suppress the fault + * @phost: return value for host address + * @retaddr: return address for unwinding + * + * Similar to probe_access, loosely returning the TLB_FLAGS_MASK for + * the page, and storing the host address for RAM in @phost. + * + * If @nonfault is set, do not raise an exception but return TLB_INVALID_MASK. + * Do not handle watchpoints, but include TLB_WATCHPOINT in the returned flags. + * Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags. + * For simplicity, all "mmio-like" flags are folded to TLB_MMIO. + */ +int probe_access_flags(CPUArchState *env, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, uintptr_t retaddr); + +#ifndef CONFIG_USER_ONLY + +/** + * probe_access_full: + * Like probe_access_flags, except also return into @pfull. + * + * The CPUTLBEntryFull structure returned via @pfull is transient + * and must be consumed or copied immediately, before any further + * access or changes to TLB @mmu_idx. + * + * This function will not fault if @nonfault is set, but will + * return TLB_INVALID_MASK if the page is not mapped, or is not + * accessible with @access_type. + * + * This function will return TLB_MMIO in order to force the access + * to be handled out-of-line if plugins wish to instrument the access. + */ +int probe_access_full(CPUArchState *env, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + bool nonfault, void **phost, + CPUTLBEntryFull **pfull, uintptr_t retaddr); + +/** + * probe_access_full_mmu: + * Like probe_access_full, except: + * + * This function is intended to be used for page table accesses by + * the target mmu itself. Since such page walking happens while + * handling another potential mmu fault, this function never raises + * exceptions (akin to @nonfault true for probe_access_full). + * Likewise this function does not trigger plugin instrumentation. + */ +int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, + MMUAccessType access_type, int mmu_idx, + void **phost, CPUTLBEntryFull **pfull); + +#endif /* !CONFIG_USER_ONLY */ + +#endif diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index b9eb9bc4b6..9ef7569a0b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -20,104 +20,4 @@ #ifndef EXEC_ALL_H #define EXEC_ALL_H -#include "exec/hwaddr.h" -#include "exec/mmu-access-type.h" -#include "exec/vaddr.h" - -#if defined(CONFIG_TCG) - -/** - * probe_access: - * @env: CPUArchState - * @addr: guest virtual address to look up - * @size: size of the access - * @access_type: read, write or execute permission - * @mmu_idx: MMU index to use for lookup - * @retaddr: return address for unwinding - * - * Look up the guest virtual address @addr. Raise an exception if the - * page does not satisfy @access_type. Raise an exception if the - * access (@addr, @size) hits a watchpoint. For writes, mark a clean - * page as dirty. - * - * Finally, return the host address for a page that is backed by RAM, - * or NULL if the page requires I/O. - */ -void *probe_access(CPUArchState *env, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, uintptr_t retaddr); - -static inline void *probe_write(CPUArchState *env, vaddr addr, int size, - int mmu_idx, uintptr_t retaddr) -{ - return probe_access(env, addr, size, MMU_DATA_STORE, mmu_idx, retaddr); -} - -static inline void *probe_read(CPUArchState *env, vaddr addr, int size, - int mmu_idx, uintptr_t retaddr) -{ - return probe_access(env, addr, size, MMU_DATA_LOAD, mmu_idx, retaddr); -} - -/** - * probe_access_flags: - * @env: CPUArchState - * @addr: guest virtual address to look up - * @size: size of the access - * @access_type: read, write or execute permission - * @mmu_idx: MMU index to use for lookup - * @nonfault: suppress the fault - * @phost: return value for host address - * @retaddr: return address for unwinding - * - * Similar to probe_access, loosely returning the TLB_FLAGS_MASK for - * the page, and storing the host address for RAM in @phost. - * - * If @nonfault is set, do not raise an exception but return TLB_INVALID_MASK. - * Do not handle watchpoints, but include TLB_WATCHPOINT in the returned flags. - * Do handle clean pages, so exclude TLB_NOTDIRY from the returned flags. - * For simplicity, all "mmio-like" flags are folded to TLB_MMIO. - */ -int probe_access_flags(CPUArchState *env, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, - bool nonfault, void **phost, uintptr_t retaddr); - -#ifndef CONFIG_USER_ONLY - -/** - * probe_access_full: - * Like probe_access_flags, except also return into @pfull. - * - * The CPUTLBEntryFull structure returned via @pfull is transient - * and must be consumed or copied immediately, before any further - * access or changes to TLB @mmu_idx. - * - * This function will not fault if @nonfault is set, but will - * return TLB_INVALID_MASK if the page is not mapped, or is not - * accessible with @access_type. - * - * This function will return TLB_MMIO in order to force the access - * to be handled out-of-line if plugins wish to instrument the access. - */ -int probe_access_full(CPUArchState *env, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, - bool nonfault, void **phost, - CPUTLBEntryFull **pfull, uintptr_t retaddr); - -/** - * probe_access_full_mmu: - * Like probe_access_full, except: - * - * This function is intended to be used for page table accesses by - * the target mmu itself. Since such page walking happens while - * handling another potential mmu fault, this function never raises - * exceptions (akin to @nonfault true for probe_access_full). - * Likewise this function does not trigger plugin instrumentation. - */ -int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, - MMUAccessType access_type, int mmu_idx, - void **phost, CPUTLBEntryFull **pfull); - -#endif /* !CONFIG_USER_ONLY */ -#endif /* CONFIG_TCG */ - #endif diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index 81ffecaaba..ebbb300f86 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -9,6 +9,7 @@ #include "qemu/osdep.h" #include "accel/tcg/cpu-mmu-index.h" +#include "accel/tcg/probe.h" #include "exec/exec-all.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" diff --git a/target/arm/helper.c b/target/arm/helper.c index c6fd290012..2f039b2db3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -30,6 +30,7 @@ #include "qapi/error.h" #include "qemu/guest-random.h" #ifdef CONFIG_TCG +#include "accel/tcg/probe.h" #include "semihosting/common-semi.h" #endif #include "cpregs.h" diff --git a/target/arm/ptw.c b/target/arm/ptw.c index e0e82ae507..87d707b592 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -14,6 +14,7 @@ #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" +#include "accel/tcg/probe.h" #include "cpu.h" #include "internals.h" #include "cpu-features.h" diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 842d9e6000..cfe5faba19 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -31,6 +31,7 @@ #include "exec/cpu-common.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "qemu/int128.h" diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 7dc5fb776b..8fbdcc8fb9 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -30,6 +30,7 @@ #include "system/ram_addr.h" #endif #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index 38d49cbb9d..d50b8720ad 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -25,6 +25,7 @@ #include "cpu-features.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "cpregs.h" #define SIGNBIT (uint32_t)0x80000000 diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index 87b6b4b3e6..50aca54eaa 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -32,6 +32,7 @@ #include "sve_ldst_internal.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/probe.h" #ifdef CONFIG_USER_ONLY #include "user/page-protection.h" #endif diff --git a/target/hexagon/mmvec/macros.h b/target/hexagon/mmvec/macros.h index c1a88392c0..c7840fbf2e 100644 --- a/target/hexagon/mmvec/macros.h +++ b/target/hexagon/mmvec/macros.h @@ -22,6 +22,7 @@ #include "arch.h" #include "mmvec/system_ext_mmvec.h" #include "accel/tcg/getpc.h" +#include "accel/tcg/probe.h" #ifndef QEMU_GENERATE #define VdV (*(MMVector *restrict)(VdV_void)) diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index 3f3d86db2b..dd726b4318 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -19,6 +19,7 @@ #include "qemu/log.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "cpu.h" diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index 554d7bf4d1..a5f73aedf8 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" +#include "accel/tcg/probe.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/helper-proto.h" diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 2398ce2c64..32207c1a4c 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -23,6 +23,7 @@ #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "qemu/timer.h" #include "trace.h" #ifdef CONFIG_USER_ONLY diff --git a/target/i386/tcg/access.c b/target/i386/tcg/access.c index 0fdd587edd..ee5b451459 100644 --- a/target/i386/tcg/access.c +++ b/target/i386/tcg/access.c @@ -4,6 +4,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/exec-all.h" #include "exec/target_page.h" #include "access.h" diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index 3af902e0ec..e45d71fa1a 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/log.h" #include "helper-tcg.h" #include "seg_helper.h" diff --git a/target/i386/tcg/system/excp_helper.c b/target/i386/tcg/system/excp_helper.c index 93614aa3e5..c162621587 100644 --- a/target/i386/tcg/system/excp_helper.c +++ b/target/i386/tcg/system/excp_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index e349344647..fde34a39e1 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -23,6 +23,7 @@ #include "tcg/tcg.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/helper-proto.h" #include "exec/memop.h" #include "exec/target_page.h" diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index d7e8d678f4..50f05a915e 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -25,6 +25,7 @@ #include "exec/helper-proto.h" #include "helper_regs.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "internal.h" #include "qemu/atomic128.h" diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 5b0db2c45a..abb1d284dc 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" #include "trace.h" diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index b8ae704457..5ccb294e31 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -23,6 +23,7 @@ #include "exec/memop.h" #include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "exec/tlb-flags.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 0cdfd380ce..9e77cde81b 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -29,6 +29,7 @@ #include "exec/cputlb.h" #include "exec/page-protection.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/probe.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index a7dd810055..182c6e35c1 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -34,6 +34,7 @@ #include "qemu/host-utils.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" +#include "accel/tcg/probe.h" #include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" From 84307cd6027c4602913177ff09aeefa4743b7234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 24 Apr 2025 22:24:12 +0200 Subject: [PATCH 0551/2760] include: Remove 'exec/exec-all.h' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "exec/exec-all.h" is now fully empty, let's remove it. Mechanical change running: $ sed -i '/exec\/exec-all.h/d' $(git grep -wl exec/exec-all.h) Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Mark Cave-Ayland Signed-off-by: Richard Henderson Message-ID: <20250424202412.91612-14-philmd@linaro.org> --- MAINTAINERS | 1 - accel/hvf/hvf-accel-ops.c | 1 - accel/tcg/cputlb.c | 1 - accel/tcg/translate-all.c | 1 - accel/tcg/user-exec.c | 1 - bsd-user/main.c | 1 - bsd-user/qemu.h | 1 - hw/ppc/spapr_nested.c | 1 - hw/riscv/riscv-iommu-sys.c | 1 - hw/sh4/sh7750.c | 1 - include/exec/exec-all.h | 23 ----------------------- include/system/ram_addr.h | 1 - linux-user/main.c | 1 - linux-user/user-internals.h | 1 - semihosting/uaccess.c | 1 - system/physmem.c | 1 - target/alpha/cpu.c | 1 - target/alpha/fpu_helper.c | 1 - target/alpha/int_helper.c | 1 - target/alpha/mem_helper.c | 1 - target/alpha/translate.c | 1 - target/alpha/vax_helper.c | 1 - target/arm/cpu.c | 1 - target/arm/debug_helper.c | 1 - target/arm/helper.c | 1 - target/arm/ptw.c | 1 - target/arm/tcg/helper-a64.c | 1 - target/arm/tcg/m_helper.c | 1 - target/arm/tcg/mte_helper.c | 1 - target/arm/tcg/mve_helper.c | 1 - target/arm/tcg/op_helper.c | 1 - target/arm/tcg/pauth_helper.c | 1 - target/arm/tcg/sme_helper.c | 1 - target/arm/tcg/sve_helper.c | 1 - target/arm/tcg/tlb_helper.c | 1 - target/arm/tcg/translate-a64.c | 1 - target/arm/tcg/translate.h | 1 - target/avr/cpu.c | 1 - target/avr/translate.c | 1 - target/hexagon/cpu.c | 1 - target/hexagon/op_helper.c | 1 - target/hppa/cpu.c | 1 - target/hppa/fpu_helper.c | 1 - target/hppa/helper.c | 1 - target/hppa/mem_helper.c | 1 - target/hppa/op_helper.c | 1 - target/hppa/sys_helper.c | 1 - target/hppa/translate.c | 1 - target/i386/tcg/access.c | 1 - target/i386/tcg/excp_helper.c | 1 - target/i386/tcg/helper-tcg.h | 1 - target/i386/tcg/int_helper.c | 1 - target/i386/tcg/mem_helper.c | 1 - target/i386/tcg/mpx_helper.c | 1 - target/i386/tcg/seg_helper.c | 1 - target/i386/tcg/system/bpt_helper.c | 1 - target/i386/tcg/translate.c | 1 - target/i386/tcg/user/excp_helper.c | 1 - target/i386/tcg/user/seg_helper.c | 1 - target/loongarch/cpu.c | 1 - target/loongarch/tcg/fpu_helper.c | 1 - target/loongarch/tcg/iocsr_helper.c | 1 - target/loongarch/tcg/op_helper.c | 1 - target/loongarch/tcg/tlb_helper.c | 1 - target/loongarch/tcg/vec_helper.c | 1 - target/m68k/fpu_helper.c | 1 - target/m68k/helper.c | 1 - target/m68k/op_helper.c | 1 - target/m68k/translate.c | 1 - target/microblaze/cpu.c | 1 - target/microblaze/op_helper.c | 1 - target/microblaze/translate.c | 1 - target/mips/cpu.c | 1 - target/mips/system/physaddr.c | 1 - target/mips/tcg/exception.c | 1 - target/mips/tcg/fpu_helper.c | 1 - target/mips/tcg/ldst_helper.c | 1 - target/mips/tcg/msa_helper.c | 1 - target/mips/tcg/op_helper.c | 1 - target/mips/tcg/system/special_helper.c | 1 - target/mips/tcg/system/tlb_helper.c | 1 - target/openrisc/cpu.c | 1 - target/openrisc/exception.c | 1 - target/openrisc/exception_helper.c | 1 - target/openrisc/fpu_helper.c | 1 - target/openrisc/interrupt.c | 1 - target/openrisc/interrupt_helper.c | 1 - target/openrisc/sys_helper.c | 1 - target/openrisc/translate.c | 1 - target/ppc/excp_helper.c | 1 - target/ppc/fpu_helper.c | 1 - target/ppc/machine.c | 1 - target/ppc/mem_helper.c | 1 - target/ppc/misc_helper.c | 1 - target/ppc/mmu-hash32.c | 1 - target/ppc/mmu-hash64.c | 1 - target/ppc/mmu-radix64.c | 1 - target/ppc/mmu_common.c | 1 - target/ppc/mmu_helper.c | 1 - target/ppc/power8-pmu.c | 1 - target/ppc/tcg-excp_helper.c | 1 - target/ppc/timebase_helper.c | 1 - target/ppc/translate.c | 1 - target/ppc/user_only_helper.c | 1 - target/riscv/cpu.c | 1 - target/riscv/cpu_helper.c | 1 - target/riscv/crypto_helper.c | 1 - target/riscv/csr.c | 1 - target/riscv/debug.c | 1 - target/riscv/fpu_helper.c | 1 - target/riscv/m128_helper.c | 1 - target/riscv/op_helper.c | 1 - target/riscv/tcg/tcg-cpu.c | 1 - target/riscv/translate.c | 1 - target/riscv/vcrypto_helper.c | 1 - target/riscv/vector_helper.c | 1 - target/riscv/zce_helper.c | 1 - target/rx/op_helper.c | 1 - target/rx/translate.c | 1 - target/s390x/interrupt.c | 1 - target/s390x/mmu_helper.c | 1 - target/s390x/sigp.c | 1 - target/s390x/tcg/cc_helper.c | 1 - target/s390x/tcg/crypto_helper.c | 1 - target/s390x/tcg/excp_helper.c | 1 - target/s390x/tcg/fpu_helper.c | 1 - target/s390x/tcg/int_helper.c | 1 - target/s390x/tcg/mem_helper.c | 1 - target/s390x/tcg/misc_helper.c | 1 - target/s390x/tcg/translate.c | 1 - target/s390x/tcg/vec_fpu_helper.c | 1 - target/s390x/tcg/vec_helper.c | 1 - target/sh4/cpu.c | 1 - target/sh4/helper.c | 1 - target/sh4/op_helper.c | 1 - target/sh4/translate.c | 1 - target/sparc/cpu.c | 1 - target/sparc/fop_helper.c | 1 - target/sparc/helper.c | 1 - target/sparc/ldst_helper.c | 1 - target/sparc/machine.c | 1 - target/sparc/translate.c | 1 - target/sparc/win_helper.c | 1 - target/tricore/cpu.c | 1 - target/tricore/op_helper.c | 1 - target/tricore/translate.c | 1 - target/xtensa/dbg_helper.c | 1 - target/xtensa/exc_helper.c | 1 - target/xtensa/fpu_helper.c | 1 - target/xtensa/mmu_helper.c | 1 - target/xtensa/op_helper.c | 1 - target/xtensa/translate.c | 1 - target/xtensa/win_helper.c | 1 - 153 files changed, 175 deletions(-) delete mode 100644 include/exec/exec-all.h diff --git a/MAINTAINERS b/MAINTAINERS index f3f491c8c2..3706601ea5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -493,7 +493,6 @@ M: Richard Henderson R: Paolo Bonzini S: Maintained F: include/exec/cpu*.h -F: include/exec/exec-all.h F: include/exec/target_long.h F: include/qemu/accel.h F: include/system/accel-*.h diff --git a/accel/hvf/hvf-accel-ops.c b/accel/hvf/hvf-accel-ops.c index 5375de7bcf..b8b6116bc8 100644 --- a/accel/hvf/hvf-accel-ops.c +++ b/accel/hvf/hvf-accel-ops.c @@ -51,7 +51,6 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "system/address-spaces.h" -#include "exec/exec-all.h" #include "gdbstub/enums.h" #include "hw/boards.h" #include "system/accel-ops.h" diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index b346af942a..5b6d6f7975 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -22,7 +22,6 @@ #include "accel/tcg/cpu-ops.h" #include "accel/tcg/iommu.h" #include "accel/tcg/probe.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "system/memory.h" #include "accel/tcg/cpu-ldst.h" diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 0408e2522a..31c7f9927f 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -21,7 +21,6 @@ #include "trace.h" #include "disas/disas.h" -#include "exec/exec-all.h" #include "tcg/tcg.h" #if defined(CONFIG_USER_ONLY) #include "qemu.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 697fdf1824..70feee8df9 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -21,7 +21,6 @@ #include "disas/disas.h" #include "cpu.h" #include "exec/vaddr.h" -#include "exec/exec-all.h" #include "exec/tlb-flags.h" #include "tcg/tcg.h" #include "qemu/bitops.h" diff --git a/bsd-user/main.c b/bsd-user/main.c index fdb160bed0..fa7645a56e 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -36,7 +36,6 @@ #include "qemu/help_option.h" #include "qemu/module.h" #include "qemu/plugin.h" -#include "exec/exec-all.h" #include "user/guest-base.h" #include "user/page-protection.h" #include "tcg/startup.h" diff --git a/bsd-user/qemu.h b/bsd-user/qemu.h index 244670dd24..93388e7c34 100644 --- a/bsd-user/qemu.h +++ b/bsd-user/qemu.h @@ -23,7 +23,6 @@ #include "cpu.h" #include "qemu/units.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" #include "user/abitypes.h" #include "user/cpu_loop.h" diff --git a/hw/ppc/spapr_nested.c b/hw/ppc/spapr_nested.c index 820f752b9e..10cf634da1 100644 --- a/hw/ppc/spapr_nested.c +++ b/hw/ppc/spapr_nested.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "qemu/cutils.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/target_long.h" #include "helper_regs.h" diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c index be2e3944dc..74e76b94a5 100644 --- a/hw/riscv/riscv-iommu-sys.c +++ b/hw/riscv/riscv-iommu-sys.c @@ -26,7 +26,6 @@ #include "qemu/host-utils.h" #include "qemu/module.h" #include "qom/object.h" -#include "exec/exec-all.h" #include "trace.h" #include "riscv-iommu.h" diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c index 41306fb600..300eabc595 100644 --- a/hw/sh4/sh7750.c +++ b/hw/sh4/sh7750.c @@ -36,7 +36,6 @@ #include "sh7750_regnames.h" #include "hw/sh4/sh_intc.h" #include "hw/timer/tmu012.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "trace.h" diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h deleted file mode 100644 index 9ef7569a0b..0000000000 --- a/include/exec/exec-all.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * internal execution defines for qemu - * - * Copyright (c) 2003 Fabrice Bellard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - */ - -#ifndef EXEC_ALL_H -#define EXEC_ALL_H - -#endif diff --git a/include/system/ram_addr.h b/include/system/ram_addr.h index b4e4425acb..15a1b1a4fa 100644 --- a/include/system/ram_addr.h +++ b/include/system/ram_addr.h @@ -24,7 +24,6 @@ #include "exec/cputlb.h" #include "exec/ramlist.h" #include "system/ramblock.h" -#include "exec/exec-all.h" #include "system/memory.h" #include "exec/target_page.h" #include "qemu/rcu.h" diff --git a/linux-user/main.c b/linux-user/main.c index e2ec5970be..4af7f49f38 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -40,7 +40,6 @@ #include "qemu/plugin.h" #include "user/guest-base.h" #include "user/page-protection.h" -#include "exec/exec-all.h" #include "exec/gdbstub.h" #include "gdbstub/user.h" #include "tcg/startup.h" diff --git a/linux-user/user-internals.h b/linux-user/user-internals.h index 4aa253b566..691b9a1775 100644 --- a/linux-user/user-internals.h +++ b/linux-user/user-internals.h @@ -19,7 +19,6 @@ #define LINUX_USER_USER_INTERNALS_H #include "user/thunk.h" -#include "exec/exec-all.h" #include "qemu/log.h" extern char *exec_path; diff --git a/semihosting/uaccess.c b/semihosting/uaccess.c index ebbb300f86..4554844e15 100644 --- a/semihosting/uaccess.c +++ b/semihosting/uaccess.c @@ -10,7 +10,6 @@ #include "qemu/osdep.h" #include "accel/tcg/cpu-mmu-index.h" #include "accel/tcg/probe.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "semihosting/uaccess.h" diff --git a/system/physmem.c b/system/physmem.c index f1ec0902c7..3f4fd69d9a 100644 --- a/system/physmem.c +++ b/system/physmem.c @@ -32,7 +32,6 @@ #include "accel/tcg/iommu.h" #endif /* CONFIG_TCG */ -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 27e2008a4e..68414af8d3 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -23,7 +23,6 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "exec/target_page.h" #include "fpu/softfloat.h" diff --git a/target/alpha/fpu_helper.c b/target/alpha/fpu_helper.c index 6aefb9b851..30f3c7fd18 100644 --- a/target/alpha/fpu_helper.c +++ b/target/alpha/fpu_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/alpha/int_helper.c b/target/alpha/int_helper.c index 5672696f6f..6bfe63500e 100644 --- a/target/alpha/int_helper.c +++ b/target/alpha/int_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" diff --git a/target/alpha/mem_helper.c b/target/alpha/mem_helper.c index a4d5adb40c..2113fe33ae 100644 --- a/target/alpha/mem_helper.c +++ b/target/alpha/mem_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" static void do_unaligned_access(CPUAlphaState *env, vaddr addr, uintptr_t retaddr) diff --git a/target/alpha/translate.c b/target/alpha/translate.c index 7f3195a5dc..cebab0318c 100644 --- a/target/alpha/translate.c +++ b/target/alpha/translate.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "system/cpus.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" diff --git a/target/alpha/vax_helper.c b/target/alpha/vax_helper.c index f94fb519db..c1d201e7b4 100644 --- a/target/alpha/vax_helper.c +++ b/target/alpha/vax_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 5e951675c6..7b801eb3aa 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -33,7 +33,6 @@ #endif /* CONFIG_TCG */ #include "internals.h" #include "cpu-features.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "hw/qdev-properties.h" #if !defined(CONFIG_USER_ONLY) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index 473ee2af38..de7999f6a9 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -11,7 +11,6 @@ #include "internals.h" #include "cpu-features.h" #include "cpregs.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/watchpoint.h" #include "system/tcg.h" diff --git a/target/arm/helper.c b/target/arm/helper.c index 2f039b2db3..8de4eb2c1f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -20,7 +20,6 @@ #include "qemu/bitops.h" #include "qemu/qemu-print.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "hw/irq.h" #include "system/cpu-timers.h" diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 87d707b592..1040a18962 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -10,7 +10,6 @@ #include "qemu/log.h" #include "qemu/range.h" #include "qemu/main-loop.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index cfe5faba19..9cffda07cd 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -29,7 +29,6 @@ #include "internals.h" #include "qemu/crc32c.h" #include "exec/cpu-common.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "exec/target_page.h" diff --git a/target/arm/tcg/m_helper.c b/target/arm/tcg/m_helper.c index 37dc98dc35..6614719832 100644 --- a/target/arm/tcg/m_helper.c +++ b/target/arm/tcg/m_helper.c @@ -15,7 +15,6 @@ #include "qemu/main-loop.h" #include "qemu/bitops.h" #include "qemu/log.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #ifdef CONFIG_TCG #include "accel/tcg/cpu-ldst.h" diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 8fbdcc8fb9..13d7ac0097 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -21,7 +21,6 @@ #include "qemu/log.h" #include "cpu.h" #include "internals.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #ifdef CONFIG_USER_ONLY #include "user/cpu_loop.h" diff --git a/target/arm/tcg/mve_helper.c b/target/arm/tcg/mve_helper.c index f9f67d1f88..506d1c3475 100644 --- a/target/arm/tcg/mve_helper.c +++ b/target/arm/tcg/mve_helper.c @@ -23,7 +23,6 @@ #include "vec_internal.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" #include "tcg/tcg.h" #include "fpu/softfloat.h" #include "crypto/clmul.h" diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index d50b8720ad..dc3f83c37d 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -23,7 +23,6 @@ #include "exec/target_page.h" #include "internals.h" #include "cpu-features.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "cpregs.h" diff --git a/target/arm/tcg/pauth_helper.c b/target/arm/tcg/pauth_helper.c index 59bf27541d..c591c3052c 100644 --- a/target/arm/tcg/pauth_helper.c +++ b/target/arm/tcg/pauth_helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 96b84c37a2..3226895cae 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -23,7 +23,6 @@ #include "tcg/tcg-gvec-desc.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" #include "qemu/int128.h" #include "fpu/softfloat.h" #include "vec_internal.h" diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index 50aca54eaa..9f20ecb51d 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internals.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/helper-proto.h" #include "exec/target_page.h" diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index 8841f039bc..5ea4d6590f 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -9,7 +9,6 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index d9305f9d26..52cf47e775 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -17,7 +17,6 @@ * License along with this library; if not, see . */ #include "qemu/osdep.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "translate.h" #include "translate-a64.h" diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index 53e485d28a..1bfdb0fb9b 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -4,7 +4,6 @@ #include "cpu.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" -#include "exec/exec-all.h" #include "exec/translator.h" #include "exec/translation-block.h" #include "exec/helper-gen.h" diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 3f261c6fec..69fface7e9 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "qemu/qemu-print.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "system/address-spaces.h" #include "cpu.h" diff --git a/target/avr/translate.c b/target/avr/translate.c index b9c592c899..804b0b21db 100644 --- a/target/avr/translate.c +++ b/target/avr/translate.c @@ -22,7 +22,6 @@ #include "qemu/qemu-print.h" #include "tcg/tcg.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index a5d31c33bd..c1bfa80252 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -19,7 +19,6 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "internal.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "qapi/error.h" #include "hw/qdev-properties.h" diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c index dd726b4318..444799d3ad 100644 --- a/target/hexagon/op_helper.c +++ b/target/hexagon/op_helper.c @@ -17,7 +17,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "exec/helper-proto.h" diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index b792cb247a..b083693b57 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -24,7 +24,6 @@ #include "qemu/timer.h" #include "cpu.h" #include "qemu/module.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "exec/target_page.h" #include "fpu/softfloat.h" diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c index a62d9d3083..ddd0a343d6 100644 --- a/target/hppa/fpu_helper.c +++ b/target/hppa/fpu_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/hppa/helper.c b/target/hppa/helper.c index ac7f58f0af..d7f8495d98 100644 --- a/target/hppa/helper.c +++ b/target/hppa/helper.c @@ -21,7 +21,6 @@ #include "qemu/log.h" #include "cpu.h" #include "fpu/softfloat.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/qemu-print.h" #include "hw/hppa/hppa_hardware.h" diff --git a/target/hppa/mem_helper.c b/target/hppa/mem_helper.c index a5f73aedf8..9bdd0a6f23 100644 --- a/target/hppa/mem_helper.c +++ b/target/hppa/mem_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "accel/tcg/probe.h" diff --git a/target/hppa/op_helper.c b/target/hppa/op_helper.c index 32207c1a4c..0458378abb 100644 --- a/target/hppa/op_helper.c +++ b/target/hppa/op_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" diff --git a/target/hppa/sys_helper.c b/target/hppa/sys_helper.c index 052a6a88a2..6e65fadcc7 100644 --- a/target/hppa/sys_helper.c +++ b/target/hppa/sys_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/timer.h" #include "system/runstate.h" diff --git a/target/hppa/translate.c b/target/hppa/translate.c index 88a7d339eb..7a81cfcb88 100644 --- a/target/hppa/translate.c +++ b/target/hppa/translate.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" diff --git a/target/i386/tcg/access.c b/target/i386/tcg/access.c index ee5b451459..97e3f0e756 100644 --- a/target/i386/tcg/access.c +++ b/target/i386/tcg/access.c @@ -5,7 +5,6 @@ #include "cpu.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "access.h" diff --git a/target/i386/tcg/excp_helper.c b/target/i386/tcg/excp_helper.c index de71e68f98..6fb8036d98 100644 --- a/target/i386/tcg/excp_helper.c +++ b/target/i386/tcg/excp_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "qemu/log.h" #include "system/runstate.h" #include "exec/helper-proto.h" diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 54d845379c..6b3f19855f 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -20,7 +20,6 @@ #ifndef I386_HELPER_TCG_H #define I386_HELPER_TCG_H -#include "exec/exec-all.h" #include "qemu/host-utils.h" /* Maximum instruction code size */ diff --git a/target/i386/tcg/int_helper.c b/target/i386/tcg/int_helper.c index 1a02e9d843..46741d9f68 100644 --- a/target/i386/tcg/int_helper.c +++ b/target/i386/tcg/int_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "qapi/error.h" diff --git a/target/i386/tcg/mem_helper.c b/target/i386/tcg/mem_helper.c index 84a0815217..9e7c2d8029 100644 --- a/target/i386/tcg/mem_helper.c +++ b/target/i386/tcg/mem_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "qemu/int128.h" #include "qemu/atomic128.h" diff --git a/target/i386/tcg/mpx_helper.c b/target/i386/tcg/mpx_helper.c index a0f816dfae..fa8abcc482 100644 --- a/target/i386/tcg/mpx_helper.c +++ b/target/i386/tcg/mpx_helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "helper-tcg.h" diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c index e45d71fa1a..0ca081b286 100644 --- a/target/i386/tcg/seg_helper.c +++ b/target/i386/tcg/seg_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "qemu/log.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "exec/log.h" diff --git a/target/i386/tcg/system/bpt_helper.c b/target/i386/tcg/system/bpt_helper.c index 08ccd3f5e6..aebb5caac3 100644 --- a/target/i386/tcg/system/bpt_helper.c +++ b/target/i386/tcg/system/bpt_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/watchpoint.h" #include "tcg/helper-tcg.h" diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 8a641951cd..8c3023407d 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -21,7 +21,6 @@ #include "qemu/host-utils.h" #include "cpu.h" #include "accel/tcg/cpu-mmu-index.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" diff --git a/target/i386/tcg/user/excp_helper.c b/target/i386/tcg/user/excp_helper.c index b3bdb7831a..98fab4cbc3 100644 --- a/target/i386/tcg/user/excp_helper.c +++ b/target/i386/tcg/user/excp_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "tcg/helper-tcg.h" void x86_cpu_record_sigsegv(CPUState *cs, vaddr addr, diff --git a/target/i386/tcg/user/seg_helper.c b/target/i386/tcg/user/seg_helper.c index 5692dd5195..263f59937f 100644 --- a/target/i386/tcg/user/seg_helper.c +++ b/target/i386/tcg/user/seg_helper.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "tcg/helper-tcg.h" #include "tcg/seg_helper.h" diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 8ad45b453d..c083ad4fd9 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -15,7 +15,6 @@ #include "system/kvm.h" #include "kvm/kvm_loongarch.h" #include "hw/qdev-properties.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "cpu.h" #include "internals.h" diff --git a/target/loongarch/tcg/fpu_helper.c b/target/loongarch/tcg/fpu_helper.c index fc3fd0561e..fc9c64c20a 100644 --- a/target/loongarch/tcg/fpu_helper.c +++ b/target/loongarch/tcg/fpu_helper.c @@ -8,7 +8,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" #include "internals.h" diff --git a/target/loongarch/tcg/iocsr_helper.c b/target/loongarch/tcg/iocsr_helper.c index e62170de3c..c155f48564 100644 --- a/target/loongarch/tcg/iocsr_helper.c +++ b/target/loongarch/tcg/iocsr_helper.c @@ -9,7 +9,6 @@ #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #define GET_MEMTXATTRS(cas) \ diff --git a/target/loongarch/tcg/op_helper.c b/target/loongarch/tcg/op_helper.c index 94e3b28016..16ac0d43bc 100644 --- a/target/loongarch/tcg/op_helper.c +++ b/target/loongarch/tcg/op_helper.c @@ -10,7 +10,6 @@ #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "internals.h" #include "qemu/crc32c.h" diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c index af208d75ae..dc48b0f4d2 100644 --- a/target/loongarch/tcg/tlb_helper.c +++ b/target/loongarch/tcg/tlb_helper.c @@ -13,7 +13,6 @@ #include "internals.h" #include "exec/helper-proto.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "accel/tcg/cpu-ldst.h" diff --git a/target/loongarch/tcg/vec_helper.c b/target/loongarch/tcg/vec_helper.c index 3faf52cbc4..a270998e63 100644 --- a/target/loongarch/tcg/vec_helper.c +++ b/target/loongarch/tcg/vec_helper.c @@ -7,7 +7,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "internals.h" diff --git a/target/m68k/fpu_helper.c b/target/m68k/fpu_helper.c index ac4a0d85be..56012863c8 100644 --- a/target/m68k/fpu_helper.c +++ b/target/m68k/fpu_helper.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "softfloat.h" diff --git a/target/m68k/helper.c b/target/m68k/helper.c index 3b880dd4d9..15f110fa7a 100644 --- a/target/m68k/helper.c +++ b/target/m68k/helper.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/gdbstub.h" diff --git a/target/m68k/op_helper.c b/target/m68k/op_helper.c index 242aecccbb..f29ae12af8 100644 --- a/target/m68k/op_helper.c +++ b/target/m68k/op_helper.c @@ -20,7 +20,6 @@ #include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "semihosting/semihost.h" diff --git a/target/m68k/translate.c b/target/m68k/translate.c index b1266a7875..97afceb129 100644 --- a/target/m68k/translate.c +++ b/target/m68k/translate.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "exec/target_page.h" #include "tcg/tcg-op.h" diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 00a2730de4..2720e5c1d2 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -27,7 +27,6 @@ #include "cpu.h" #include "qemu/module.h" #include "hw/qdev-properties.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "exec/gdbstub.h" #include "exec/translation-block.h" diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 4624ce5b67..9e838dfa15 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -23,7 +23,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 23f1037236..671b1ae4db 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" diff --git a/target/mips/cpu.c b/target/mips/cpu.c index d13361a150..96fe4da255 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -29,7 +29,6 @@ #include "qemu/module.h" #include "system/kvm.h" #include "system/qtest.h" -#include "exec/exec-all.h" #include "hw/qdev-properties.h" #include "hw/qdev-clock.h" #include "fpu_helper.h" diff --git a/target/mips/system/physaddr.c b/target/mips/system/physaddr.c index 505781d84c..b8e1a5ac98 100644 --- a/target/mips/system/physaddr.c +++ b/target/mips/system/physaddr.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "../internal.h" diff --git a/target/mips/tcg/exception.c b/target/mips/tcg/exception.c index 1a8902ea1b..d32bcebf46 100644 --- a/target/mips/tcg/exception.c +++ b/target/mips/tcg/exception.c @@ -23,7 +23,6 @@ #include "cpu.h" #include "internal.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" target_ulong exception_resume_pc(CPUMIPSState *env) diff --git a/target/mips/tcg/fpu_helper.c b/target/mips/tcg/fpu_helper.c index 45d593de48..36af980802 100644 --- a/target/mips/tcg/fpu_helper.c +++ b/target/mips/tcg/fpu_helper.c @@ -24,7 +24,6 @@ #include "cpu.h" #include "internal.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "fpu/softfloat.h" #include "fpu_helper.h" diff --git a/target/mips/tcg/ldst_helper.c b/target/mips/tcg/ldst_helper.c index 2fb879fcbc..10319bf03a 100644 --- a/target/mips/tcg/ldst_helper.c +++ b/target/mips/tcg/ldst_helper.c @@ -23,7 +23,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "exec/memop.h" #include "internal.h" diff --git a/target/mips/tcg/msa_helper.c b/target/mips/tcg/msa_helper.c index fde34a39e1..f554b3d10e 100644 --- a/target/mips/tcg/msa_helper.c +++ b/target/mips/tcg/msa_helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "internal.h" #include "tcg/tcg.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "exec/helper-proto.h" diff --git a/target/mips/tcg/op_helper.c b/target/mips/tcg/op_helper.c index 65403f1a87..b906d10204 100644 --- a/target/mips/tcg/op_helper.c +++ b/target/mips/tcg/op_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "internal.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exec/memop.h" #include "fpu_helper.h" diff --git a/target/mips/tcg/system/special_helper.c b/target/mips/tcg/system/special_helper.c index 3ce3ae1e12..b54cbe88a3 100644 --- a/target/mips/tcg/system/special_helper.c +++ b/target/mips/tcg/system/special_helper.c @@ -22,7 +22,6 @@ #include "qemu/log.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "internal.h" diff --git a/target/mips/tcg/system/tlb_helper.c b/target/mips/tcg/system/tlb_helper.c index e477ef812a..eccaf3624c 100644 --- a/target/mips/tcg/system/tlb_helper.c +++ b/target/mips/tcg/system/tlb_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "internal.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "accel/tcg/cpu-ldst.h" diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 2ec267efec..8c8165d666 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -21,7 +21,6 @@ #include "qapi/error.h" #include "qemu/qemu-print.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" diff --git a/target/openrisc/exception.c b/target/openrisc/exception.c index 8699c3dcea..e213be36b6 100644 --- a/target/openrisc/exception.c +++ b/target/openrisc/exception.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exception.h" G_NORETURN void raise_exception(OpenRISCCPU *cpu, uint32_t excp) diff --git a/target/openrisc/exception_helper.c b/target/openrisc/exception_helper.c index 1f5be4bed9..c2c9d13652 100644 --- a/target/openrisc/exception_helper.c +++ b/target/openrisc/exception_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exception.h" diff --git a/target/openrisc/fpu_helper.c b/target/openrisc/fpu_helper.c index 8b81d2f62f..dba997255c 100644 --- a/target/openrisc/fpu_helper.c +++ b/target/openrisc/fpu_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c index b3b5b40577..486823094c 100644 --- a/target/openrisc/interrupt.c +++ b/target/openrisc/interrupt.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "gdbstub/helpers.h" #include "qemu/host-utils.h" #ifndef CONFIG_USER_ONLY diff --git a/target/openrisc/interrupt_helper.c b/target/openrisc/interrupt_helper.c index ab4ea88b69..1553ebc71b 100644 --- a/target/openrisc/interrupt_helper.c +++ b/target/openrisc/interrupt_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" void HELPER(rfe)(CPUOpenRISCState *env) diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 92badf017f..951f8e247a 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/target_page.h" #include "exec/helper-proto.h" diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c index baadea4448..5ab3bc7021 100644 --- a/target/openrisc/translate.c +++ b/target/openrisc/translate.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "accel/tcg/cpu-mmu-index.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "qemu/log.h" #include "qemu/bitops.h" diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c index da8b525a41..1efdc4066e 100644 --- a/target/ppc/excp_helper.c +++ b/target/ppc/excp_helper.c @@ -24,7 +24,6 @@ #include "system/system.h" #include "system/runstate.h" #include "cpu.h" -#include "exec/exec-all.h" #include "internal.h" #include "helper_regs.h" #include "hw/ppc/ppc.h" diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c index d93cfed17b..07b782f971 100644 --- a/target/ppc/fpu_helper.c +++ b/target/ppc/fpu_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "internal.h" #include "fpu/softfloat.h" diff --git a/target/ppc/machine.c b/target/ppc/machine.c index 98df5b4a3a..d72e5ecb94 100644 --- a/target/ppc/machine.c +++ b/target/ppc/machine.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "system/kvm.h" #include "system/tcg.h" #include "helper_regs.h" diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index 50f05a915e..aa1af44d22 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c index 46ae454afd..e7d9462518 100644 --- a/target/ppc/misc_helper.c +++ b/target/ppc/misc_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/helper-proto.h" #include "qemu/error-report.h" diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c index 5bd3efe70e..8b980a5aa9 100644 --- a/target/ppc/mmu-hash32.c +++ b/target/ppc/mmu-hash32.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "system/kvm.h" diff --git a/target/ppc/mmu-hash64.c b/target/ppc/mmu-hash64.c index 3ba4810497..dd337558aa 100644 --- a/target/ppc/mmu-hash64.c +++ b/target/ppc/mmu-hash64.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/units.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "qemu/error-report.h" #include "qemu/qemu-print.h" diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c index 4ab5f3bb92..33ac341290 100644 --- a/target/ppc/mmu-radix64.c +++ b/target/ppc/mmu-radix64.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "qemu/error-report.h" #include "system/kvm.h" diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c index 394a0c9bb6..52d48615ac 100644 --- a/target/ppc/mmu_common.c +++ b/target/ppc/mmu_common.c @@ -24,7 +24,6 @@ #include "kvm_ppc.h" #include "mmu-hash64.h" #include "mmu-hash32.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/log.h" diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c index 2138666122..ac60705402 100644 --- a/target/ppc/mmu_helper.c +++ b/target/ppc/mmu_helper.c @@ -25,7 +25,6 @@ #include "mmu-hash64.h" #include "mmu-hash32.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/log.h" diff --git a/target/ppc/power8-pmu.c b/target/ppc/power8-pmu.c index db9ee8e96b..2a7a5b493a 100644 --- a/target/ppc/power8-pmu.c +++ b/target/ppc/power8-pmu.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "helper_regs.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/error-report.h" #include "qemu/timer.h" diff --git a/target/ppc/tcg-excp_helper.c b/target/ppc/tcg-excp_helper.c index 2b15e5f2f0..f835be5156 100644 --- a/target/ppc/tcg-excp_helper.c +++ b/target/ppc/tcg-excp_helper.c @@ -21,7 +21,6 @@ #include "qemu/log.h" #include "target/ppc/cpu.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "system/runstate.h" diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c index 73120323b4..7209b418fb 100644 --- a/target/ppc/timebase_helper.c +++ b/target/ppc/timebase_helper.c @@ -20,7 +20,6 @@ #include "cpu.h" #include "hw/ppc/ppc.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "qemu/log.h" #include "qemu/main-loop.h" diff --git a/target/ppc/translate.c b/target/ppc/translate.c index 62dd008e36..27f90c3cc5 100644 --- a/target/ppc/translate.c +++ b/target/ppc/translate.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internal.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" diff --git a/target/ppc/user_only_helper.c b/target/ppc/user_only_helper.c index a4d07a0d0d..ae210eb847 100644 --- a/target/ppc/user_only_helper.c +++ b/target/ppc/user_only_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "internal.h" void ppc_cpu_record_sigsegv(CPUState *cs, vaddr address, diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index e0604f4c78..d92874baa0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -24,7 +24,6 @@ #include "cpu.h" #include "cpu_vendorid.h" #include "internals.h" -#include "exec/exec-all.h" #include "qapi/error.h" #include "qapi/visitor.h" #include "qemu/error-report.h" diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 619c76cc00..f2e90a9889 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -24,7 +24,6 @@ #include "internals.h" #include "pmu.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "system/memory.h" diff --git a/target/riscv/crypto_helper.c b/target/riscv/crypto_helper.c index bb084e00ef..a0fb54bc50 100644 --- a/target/riscv/crypto_helper.c +++ b/target/riscv/crypto_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "crypto/aes.h" #include "crypto/aes-round.h" diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 1308643855..a32e1455c9 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -24,7 +24,6 @@ #include "tcg/tcg-cpu.h" #include "pmu.h" #include "time_helper.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" #include "exec/icount.h" diff --git a/target/riscv/debug.c b/target/riscv/debug.c index 8564f0b371..5664466749 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -28,7 +28,6 @@ #include "qapi/error.h" #include "cpu.h" #include "trace.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/watchpoint.h" #include "system/cpu-timers.h" diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c index 91b1a56d10..706bdfa61d 100644 --- a/target/riscv/fpu_helper.c +++ b/target/riscv/fpu_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" #include "internals.h" diff --git a/target/riscv/m128_helper.c b/target/riscv/m128_helper.c index ec14aaa901..7d9b83b1b2 100644 --- a/target/riscv/m128_helper.c +++ b/target/riscv/m128_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" target_ulong HELPER(divu_i128)(CPURISCVState *env, diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index abb1d284dc..05316f2088 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -21,7 +21,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "internals.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 54ac54f2e1..2f757c2a5e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -18,7 +18,6 @@ */ #include "qemu/osdep.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "tcg-cpu.h" #include "cpu.h" diff --git a/target/riscv/translate.c b/target/riscv/translate.c index cef61b5b29..85128f997b 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -20,7 +20,6 @@ #include "qemu/log.h" #include "cpu.h" #include "tcg/tcg-op.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" #include "exec/target_page.h" diff --git a/target/riscv/vcrypto_helper.c b/target/riscv/vcrypto_helper.c index 1526de96f5..9a0d9b4f53 100644 --- a/target/riscv/vcrypto_helper.c +++ b/target/riscv/vcrypto_helper.c @@ -26,7 +26,6 @@ #include "crypto/aes-round.h" #include "crypto/sm4.h" #include "exec/memop.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "internals.h" #include "vector_internals.h" diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 5ccb294e31..8eea3e6df0 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -21,7 +21,6 @@ #include "qemu/bitops.h" #include "cpu.h" #include "exec/memop.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/probe.h" #include "exec/page-protection.h" diff --git a/target/riscv/zce_helper.c b/target/riscv/zce_helper.c index 50d65f386c..55221f5f37 100644 --- a/target/riscv/zce_helper.c +++ b/target/riscv/zce_helper.c @@ -18,7 +18,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" diff --git a/target/rx/op_helper.c b/target/rx/op_helper.c index a2f1f3824d..2b190a4b2c 100644 --- a/target/rx/op_helper.c +++ b/target/rx/op_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "qemu/bitops.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" diff --git a/target/rx/translate.c b/target/rx/translate.c index bbda703be8..19a9584a82 100644 --- a/target/rx/translate.c +++ b/target/rx/translate.c @@ -20,7 +20,6 @@ #include "qemu/bswap.h" #include "qemu/qemu-print.h" #include "cpu.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index 4ae6e2ddea..1dca835c5d 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -11,7 +11,6 @@ #include "cpu.h" #include "kvm/kvm_s390x.h" #include "s390x-internal.h" -#include "exec/exec-all.h" #include "system/kvm.h" #include "system/tcg.h" #include "hw/s390x/ioinst.h" diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 0e133cb9a5..00946e9c0f 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -23,7 +23,6 @@ #include "kvm/kvm_s390x.h" #include "system/kvm.h" #include "system/tcg.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "hw/hw.h" diff --git a/target/s390x/sigp.c b/target/s390x/sigp.c index a3347f1236..5e95c4978f 100644 --- a/target/s390x/sigp.c +++ b/target/s390x/sigp.c @@ -16,7 +16,6 @@ #include "system/runstate.h" #include "system/address-spaces.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "system/tcg.h" #include "trace.h" #include "qapi/qapi-types-machine.h" diff --git a/target/s390x/tcg/cc_helper.c b/target/s390x/tcg/cc_helper.c index b36f8cdc8b..6595ac763c 100644 --- a/target/s390x/tcg/cc_helper.c +++ b/target/s390x/tcg/cc_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "s390x-internal.h" #include "tcg_s390x.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" diff --git a/target/s390x/tcg/crypto_helper.c b/target/s390x/tcg/crypto_helper.c index 642c1b18c4..4447bb66ee 100644 --- a/target/s390x/tcg/crypto_helper.c +++ b/target/s390x/tcg/crypto_helper.c @@ -17,7 +17,6 @@ #include "s390x-internal.h" #include "tcg_s390x.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" static uint64_t R(uint64_t x, int c) diff --git a/target/s390x/tcg/excp_helper.c b/target/s390x/tcg/excp_helper.c index 6cd813e1ab..e4c75d0ce0 100644 --- a/target/s390x/tcg/excp_helper.c +++ b/target/s390x/tcg/excp_helper.c @@ -23,7 +23,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "exec/watchpoint.h" #include "s390x-internal.h" diff --git a/target/s390x/tcg/fpu_helper.c b/target/s390x/tcg/fpu_helper.c index 5041c13962..1ba43715ac 100644 --- a/target/s390x/tcg/fpu_helper.c +++ b/target/s390x/tcg/fpu_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "s390x-internal.h" #include "tcg_s390x.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/s390x/tcg/int_helper.c b/target/s390x/tcg/int_helper.c index 253c036415..fbda396f5b 100644 --- a/target/s390x/tcg/int_helper.c +++ b/target/s390x/tcg/int_helper.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "s390x-internal.h" #include "tcg_s390x.h" -#include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 9e77cde81b..857005b120 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -25,7 +25,6 @@ #include "tcg_s390x.h" #include "exec/helper-proto.h" #include "exec/cpu-common.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "accel/tcg/cpu-ldst.h" diff --git a/target/s390x/tcg/misc_helper.c b/target/s390x/tcg/misc_helper.c index d5088493ea..f7101be574 100644 --- a/target/s390x/tcg/misc_helper.c +++ b/target/s390x/tcg/misc_helper.c @@ -26,7 +26,6 @@ #include "qemu/host-utils.h" #include "exec/helper-proto.h" #include "qemu/timer.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "accel/tcg/cpu-ldst.h" #include "exec/target_page.h" diff --git a/target/s390x/tcg/translate.c b/target/s390x/tcg/translate.c index a714f9c0c2..c7e8574438 100644 --- a/target/s390x/tcg/translate.c +++ b/target/s390x/tcg/translate.c @@ -31,7 +31,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "s390x-internal.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" #include "qemu/log.h" diff --git a/target/s390x/tcg/vec_fpu_helper.c b/target/s390x/tcg/vec_fpu_helper.c index 1bbaa82fe8..744f800fb6 100644 --- a/target/s390x/tcg/vec_fpu_helper.c +++ b/target/s390x/tcg/vec_fpu_helper.c @@ -15,7 +15,6 @@ #include "vec.h" #include "tcg_s390x.h" #include "tcg/tcg-gvec-desc.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/s390x/tcg/vec_helper.c b/target/s390x/tcg/vec_helper.c index 781ccc565b..46ec4a947d 100644 --- a/target/s390x/tcg/vec_helper.c +++ b/target/s390x/tcg/vec_helper.c @@ -17,7 +17,6 @@ #include "tcg/tcg-gvec-desc.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" -#include "exec/exec-all.h" void HELPER(gvec_vbperm)(void *v1, const void *v2, const void *v3, uint32_t desc) diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 57d7b5fbc8..1885e7d5b2 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -24,7 +24,6 @@ #include "qemu/qemu-print.h" #include "cpu.h" #include "migration/vmstate.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" diff --git a/target/sh4/helper.c b/target/sh4/helper.c index b41d14d5d7..fb7642bda1 100644 --- a/target/sh4/helper.c +++ b/target/sh4/helper.c @@ -21,7 +21,6 @@ #include "cpu.h" #include "exec/cputlb.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "exec/log.h" diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index e7fcad3c1b..557b1bf497 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include "fpu/softfloat.h" diff --git a/target/sh4/translate.c b/target/sh4/translate.c index 712117be22..bf8828fce8 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index bc753d5f62..690e74f109 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -23,7 +23,6 @@ #include "qemu/module.h" #include "qemu/qemu-print.h" #include "accel/tcg/cpu-mmu-index.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "hw/qdev-properties.h" #include "qapi/visitor.h" diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c index c25097d07f..a49334150d 100644 --- a/target/sparc/fop_helper.c +++ b/target/sparc/fop_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" diff --git a/target/sparc/helper.c b/target/sparc/helper.c index 7846ddd6f6..9163b9d46a 100644 --- a/target/sparc/helper.c +++ b/target/sparc/helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "qemu/timer.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" diff --git a/target/sparc/ldst_helper.c b/target/sparc/ldst_helper.c index 4c5dba19d1..2c63eb9e03 100644 --- a/target/sparc/ldst_helper.c +++ b/target/sparc/ldst_helper.c @@ -23,7 +23,6 @@ #include "cpu.h" #include "tcg/tcg.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exec/cputlb.h" #include "exec/page-protection.h" #include "exec/target_page.h" diff --git a/target/sparc/machine.c b/target/sparc/machine.c index 222e5709c5..4dd75aff74 100644 --- a/target/sparc/machine.c +++ b/target/sparc/machine.c @@ -1,6 +1,5 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "qemu/timer.h" #include "migration/cpu.h" diff --git a/target/sparc/translate.c b/target/sparc/translate.c index 63dd90447b..b922e53bf1 100644 --- a/target/sparc/translate.c +++ b/target/sparc/translate.c @@ -22,7 +22,6 @@ #include "cpu.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "exec/target_page.h" #include "tcg/tcg-op.h" #include "tcg/tcg-op-gvec.h" diff --git a/target/sparc/win_helper.c b/target/sparc/win_helper.c index 0c4b09f2c1..9ad9d01e8b 100644 --- a/target/sparc/win_helper.c +++ b/target/sparc/win_helper.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/helper-proto.h" #include "trace.h" diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 098cd06c54..9f19e903bc 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#include "exec/exec-all.h" #include "exec/translation-block.h" #include "qemu/error-report.h" #include "tcg/debug-assert.h" diff --git a/target/tricore/op_helper.c b/target/tricore/op_helper.c index ae559b6922..9910c13f4b 100644 --- a/target/tricore/op_helper.c +++ b/target/tricore/op_helper.c @@ -18,7 +18,6 @@ #include "cpu.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" -#include "exec/exec-all.h" #include "accel/tcg/cpu-ldst.h" #include /* for crc32 */ diff --git a/target/tricore/translate.c b/target/tricore/translate.c index ba36c9fcc8..3d0e7a10bd 100644 --- a/target/tricore/translate.c +++ b/target/tricore/translate.c @@ -20,7 +20,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "accel/tcg/cpu-ldst.h" #include "qemu/qemu-print.h" diff --git a/target/xtensa/dbg_helper.c b/target/xtensa/dbg_helper.c index c4f4298a50..3b91f7c38a 100644 --- a/target/xtensa/dbg_helper.c +++ b/target/xtensa/dbg_helper.c @@ -30,7 +30,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "exec/watchpoint.h" #include "system/address-spaces.h" diff --git a/target/xtensa/exc_helper.c b/target/xtensa/exc_helper.c index ca629f071d..b611c9bf97 100644 --- a/target/xtensa/exc_helper.c +++ b/target/xtensa/exc_helper.c @@ -32,7 +32,6 @@ #include "exec/helper-proto.h" #include "qemu/host-utils.h" #include "qemu/atomic.h" -#include "exec/exec-all.h" void HELPER(exception)(CPUXtensaState *env, uint32_t excp) { diff --git a/target/xtensa/fpu_helper.c b/target/xtensa/fpu_helper.c index 53fc7cfd2a..5358060c50 100644 --- a/target/xtensa/fpu_helper.c +++ b/target/xtensa/fpu_helper.c @@ -30,7 +30,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "fpu/softfloat.h" enum { diff --git a/target/xtensa/mmu_helper.c b/target/xtensa/mmu_helper.c index 182c6e35c1..71330fc84b 100644 --- a/target/xtensa/mmu_helper.c +++ b/target/xtensa/mmu_helper.c @@ -35,7 +35,6 @@ #include "exec/cputlb.h" #include "accel/tcg/cpu-mmu-index.h" #include "accel/tcg/probe.h" -#include "exec/exec-all.h" #include "exec/page-protection.h" #include "exec/target_page.h" #include "system/memory.h" diff --git a/target/xtensa/op_helper.c b/target/xtensa/op_helper.c index c125fa4946..fc47ebaaf5 100644 --- a/target/xtensa/op_helper.c +++ b/target/xtensa/op_helper.c @@ -30,7 +30,6 @@ #include "exec/helper-proto.h" #include "exec/page-protection.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" #include "system/memory.h" #include "qemu/atomic.h" #include "qemu/timer.h" diff --git a/target/xtensa/translate.c b/target/xtensa/translate.c index 2af83c07c2..34ae2f4e16 100644 --- a/target/xtensa/translate.c +++ b/target/xtensa/translate.c @@ -31,7 +31,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "qemu/log.h" #include "qemu/qemu-print.h" diff --git a/target/xtensa/win_helper.c b/target/xtensa/win_helper.c index ec9ff44db0..4b25f8f4de 100644 --- a/target/xtensa/win_helper.c +++ b/target/xtensa/win_helper.c @@ -30,7 +30,6 @@ #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" -#include "exec/exec-all.h" static void copy_window_from_phys(CPUXtensaState *env, uint32_t window, uint32_t phys, uint32_t n) From 9a1e3713232f9641353e63fd279eb83cc723faf2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 26 Apr 2025 20:20:24 +0000 Subject: [PATCH 0552/2760] accel/tcg: Generalize fake_user_interrupt test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test for the hook being present instead of ifdef TARGET_I386. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 279df5fae7..8ff4a34509 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -732,10 +732,10 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) * If user mode only, we simulate a fake exception which will be * handled outside the cpu execution loop. */ -#if defined(TARGET_I386) const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; - tcg_ops->fake_user_interrupt(cpu); -#endif /* TARGET_I386 */ + if (tcg_ops->fake_user_interrupt) { + tcg_ops->fake_user_interrupt(cpu); + } *ret = cpu->exception_index; cpu->exception_index = -1; return true; From 81ef6a2295740c4b2de9db2f81ebb9ad346b8cfc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 11:02:25 -0700 Subject: [PATCH 0553/2760] accel/tcg: Unconditionally use CPU_DUMP_CCOP in log_cpu_exec This flag is only tested by target/i386, so including this makes no functional change. This is similar to other places like cpu-target.c which use CPU_DUMP_CCOP unconditionally. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8ff4a34509..ff979a2c57 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -285,14 +285,11 @@ static void log_cpu_exec(vaddr pc, CPUState *cpu, if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) { FILE *logfile = qemu_log_trylock(); if (logfile) { - int flags = 0; + int flags = CPU_DUMP_CCOP; if (qemu_loglevel_mask(CPU_LOG_TB_FPU)) { flags |= CPU_DUMP_FPU; } -#if defined(TARGET_I386) - flags |= CPU_DUMP_CCOP; -#endif if (qemu_loglevel_mask(CPU_LOG_TB_VPU)) { flags |= CPU_DUMP_VPU; } From 9181ab452893a3f45cdc0f6196fbb9e389a4e5cd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 11:31:30 -0700 Subject: [PATCH 0554/2760] accel/tcg: Introduce TCGCPUOps.cpu_exec_reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialize all instances with cpu_reset(), so that there is no functional change. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 3 ++- include/accel/tcg/cpu-ops.h | 2 ++ target/alpha/cpu.c | 1 + target/arm/cpu.c | 1 + target/arm/tcg/cpu-v7m.c | 1 + target/avr/cpu.c | 1 + target/hppa/cpu.c | 1 + target/i386/tcg/tcg-cpu.c | 1 + target/loongarch/cpu.c | 1 + target/m68k/cpu.c | 1 + target/microblaze/cpu.c | 1 + target/mips/cpu.c | 1 + target/openrisc/cpu.c | 1 + target/ppc/cpu_init.c | 1 + target/riscv/tcg/tcg-cpu.c | 1 + target/rx/cpu.c | 1 + target/s390x/cpu.c | 1 + target/sh4/cpu.c | 1 + target/sparc/cpu.c | 1 + target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 1 + 21 files changed, 23 insertions(+), 1 deletion(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index ff979a2c57..010f38edaa 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -834,7 +834,7 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, #else else if (interrupt_request & CPU_INTERRUPT_RESET) { replay_interrupt(); - cpu_reset(cpu); + cpu->cc->tcg_ops->cpu_exec_reset(cpu); bql_unlock(); return true; } @@ -1070,6 +1070,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp) #ifndef CONFIG_USER_ONLY assert(tcg_ops->cpu_exec_halt); assert(tcg_ops->cpu_exec_interrupt); + assert(tcg_ops->cpu_exec_reset); #endif /* !CONFIG_USER_ONLY */ assert(tcg_ops->translate_code); assert(tcg_ops->mmu_index); diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 60b5e97205..3ff72b8d9d 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -155,6 +155,8 @@ struct TCGCPUOps { void (*do_interrupt)(CPUState *cpu); /** @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec */ bool (*cpu_exec_interrupt)(CPUState *cpu, int interrupt_request); + /** @cpu_exec_reset: Callback for reset in cpu_exec. */ + void (*cpu_exec_reset)(CPUState *cpu); /** * @cpu_exec_halt: Callback for handling halt in cpu_exec. * diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 68414af8d3..d4e66aa432 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -251,6 +251,7 @@ static const TCGCPUOps alpha_tcg_ops = { .tlb_fill = alpha_cpu_tlb_fill, .cpu_exec_interrupt = alpha_cpu_exec_interrupt, .cpu_exec_halt = alpha_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = alpha_cpu_do_interrupt, .do_transaction_failed = alpha_cpu_do_transaction_failed, .do_unaligned_access = alpha_cpu_do_unaligned_access, diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 7b801eb3aa..3dde70b04a 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2705,6 +2705,7 @@ static const TCGCPUOps arm_tcg_ops = { .tlb_fill_align = arm_cpu_tlb_fill_align, .cpu_exec_interrupt = arm_cpu_exec_interrupt, .cpu_exec_halt = arm_cpu_exec_halt, + .cpu_exec_reset = cpu_reset, .do_interrupt = arm_cpu_do_interrupt, .do_transaction_failed = arm_cpu_do_transaction_failed, .do_unaligned_access = arm_cpu_do_unaligned_access, diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index b34b657857..5c8c374885 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -250,6 +250,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = { .tlb_fill_align = arm_cpu_tlb_fill_align, .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt, .cpu_exec_halt = arm_cpu_exec_halt, + .cpu_exec_reset = cpu_reset, .do_interrupt = arm_v7m_cpu_do_interrupt, .do_transaction_failed = arm_cpu_do_transaction_failed, .do_unaligned_access = arm_cpu_do_unaligned_access, diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 69fface7e9..50b835e1ae 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -232,6 +232,7 @@ static const TCGCPUOps avr_tcg_ops = { .mmu_index = avr_cpu_mmu_index, .cpu_exec_interrupt = avr_cpu_exec_interrupt, .cpu_exec_halt = avr_cpu_has_work, + .cpu_exec_reset = cpu_reset, .tlb_fill = avr_cpu_tlb_fill, .do_interrupt = avr_cpu_do_interrupt, }; diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index b083693b57..60b618a22b 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -271,6 +271,7 @@ static const TCGCPUOps hppa_tcg_ops = { .tlb_fill_align = hppa_cpu_tlb_fill_align, .cpu_exec_interrupt = hppa_cpu_exec_interrupt, .cpu_exec_halt = hppa_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = hppa_cpu_do_interrupt, .do_unaligned_access = hppa_cpu_do_unaligned_access, .do_transaction_failed = hppa_cpu_do_transaction_failed, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 192812656c..5d1c758ae3 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -147,6 +147,7 @@ const TCGCPUOps x86_tcg_ops = { .do_interrupt = x86_cpu_do_interrupt, .cpu_exec_halt = x86_cpu_exec_halt, .cpu_exec_interrupt = x86_cpu_exec_interrupt, + .cpu_exec_reset = cpu_reset, .do_unaligned_access = x86_cpu_do_unaligned_access, .debug_excp_handler = breakpoint_handler, .debug_check_breakpoint = x86_debug_check_breakpoint, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index c083ad4fd9..c64cba72dd 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -877,6 +877,7 @@ static const TCGCPUOps loongarch_tcg_ops = { .tlb_fill = loongarch_cpu_tlb_fill, .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, .cpu_exec_halt = loongarch_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = loongarch_cpu_do_interrupt, .do_transaction_failed = loongarch_cpu_do_transaction_failed, #endif diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 6f33b86c7d..f446c6c8f7 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -602,6 +602,7 @@ static const TCGCPUOps m68k_tcg_ops = { .tlb_fill = m68k_cpu_tlb_fill, .cpu_exec_interrupt = m68k_cpu_exec_interrupt, .cpu_exec_halt = m68k_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = m68k_cpu_do_interrupt, .do_transaction_failed = m68k_cpu_transaction_failed, #endif /* !CONFIG_USER_ONLY */ diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 2720e5c1d2..f305ed04f6 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -440,6 +440,7 @@ static const TCGCPUOps mb_tcg_ops = { .tlb_fill = mb_cpu_tlb_fill, .cpu_exec_interrupt = mb_cpu_exec_interrupt, .cpu_exec_halt = mb_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = mb_cpu_do_interrupt, .do_transaction_failed = mb_cpu_transaction_failed, .do_unaligned_access = mb_cpu_do_unaligned_access, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 96fe4da255..09ed330027 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -563,6 +563,7 @@ static const TCGCPUOps mips_tcg_ops = { .tlb_fill = mips_cpu_tlb_fill, .cpu_exec_interrupt = mips_cpu_exec_interrupt, .cpu_exec_halt = mips_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = mips_cpu_do_interrupt, .do_transaction_failed = mips_cpu_do_transaction_failed, .do_unaligned_access = mips_cpu_do_unaligned_access, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 8c8165d666..94776e0ad8 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -255,6 +255,7 @@ static const TCGCPUOps openrisc_tcg_ops = { .tlb_fill = openrisc_cpu_tlb_fill, .cpu_exec_interrupt = openrisc_cpu_exec_interrupt, .cpu_exec_halt = openrisc_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = openrisc_cpu_do_interrupt, #endif /* !CONFIG_USER_ONLY */ }; diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index b0973b6df9..3a01731402 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7492,6 +7492,7 @@ static const TCGCPUOps ppc_tcg_ops = { .tlb_fill = ppc_cpu_tlb_fill, .cpu_exec_interrupt = ppc_cpu_exec_interrupt, .cpu_exec_halt = ppc_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = ppc_cpu_do_interrupt, .cpu_exec_enter = ppc_cpu_exec_enter, .cpu_exec_exit = ppc_cpu_exec_exit, diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 2f757c2a5e..50782e0f0e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -153,6 +153,7 @@ const TCGCPUOps riscv_tcg_ops = { .tlb_fill = riscv_cpu_tlb_fill, .cpu_exec_interrupt = riscv_cpu_exec_interrupt, .cpu_exec_halt = riscv_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = riscv_cpu_do_interrupt, .do_transaction_failed = riscv_cpu_do_transaction_failed, .do_unaligned_access = riscv_cpu_do_unaligned_access, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index a51b543028..de2e6a22ff 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -217,6 +217,7 @@ static const TCGCPUOps rx_tcg_ops = { .cpu_exec_interrupt = rx_cpu_exec_interrupt, .cpu_exec_halt = rx_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = rx_cpu_do_interrupt, }; diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 99ff58affc..71338aae77 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -365,6 +365,7 @@ static const TCGCPUOps s390_tcg_ops = { .tlb_fill = s390_cpu_tlb_fill, .cpu_exec_interrupt = s390_cpu_exec_interrupt, .cpu_exec_halt = s390_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = s390_cpu_do_interrupt, .debug_excp_handler = s390x_cpu_debug_excp_handler, .do_unaligned_access = s390x_cpu_do_unaligned_access, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 1885e7d5b2..681237c511 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -275,6 +275,7 @@ static const TCGCPUOps superh_tcg_ops = { .tlb_fill = superh_cpu_tlb_fill, .cpu_exec_interrupt = superh_cpu_exec_interrupt, .cpu_exec_halt = superh_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = superh_cpu_do_interrupt, .do_unaligned_access = superh_cpu_do_unaligned_access, .io_recompile_replay_branch = superh_io_recompile_replay_branch, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 690e74f109..bbdea8556a 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1034,6 +1034,7 @@ static const TCGCPUOps sparc_tcg_ops = { .tlb_fill = sparc_cpu_tlb_fill, .cpu_exec_interrupt = sparc_cpu_exec_interrupt, .cpu_exec_halt = sparc_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = sparc_cpu_do_interrupt, .do_transaction_failed = sparc_cpu_do_transaction_failed, .do_unaligned_access = sparc_cpu_do_unaligned_access, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 9f19e903bc..0fcac697f6 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -182,6 +182,7 @@ static const TCGCPUOps tricore_tcg_ops = { .tlb_fill = tricore_cpu_tlb_fill, .cpu_exec_interrupt = tricore_cpu_exec_interrupt, .cpu_exec_halt = tricore_cpu_has_work, + .cpu_exec_reset = cpu_reset, }; static void tricore_cpu_class_init(ObjectClass *c, const void *data) diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 27d6e40195..9dcb883208 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -246,6 +246,7 @@ static const TCGCPUOps xtensa_tcg_ops = { .tlb_fill = xtensa_cpu_tlb_fill, .cpu_exec_interrupt = xtensa_cpu_exec_interrupt, .cpu_exec_halt = xtensa_cpu_has_work, + .cpu_exec_reset = cpu_reset, .do_interrupt = xtensa_cpu_do_interrupt, .do_transaction_failed = xtensa_cpu_do_transaction_failed, .do_unaligned_access = xtensa_cpu_do_unaligned_access, From c2d5897d3b712402d9543570c550a40cc0836522 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 11:44:23 -0700 Subject: [PATCH 0555/2760] target/i386: Split out x86_cpu_exec_reset Note that target/i386/cpu.h defines CPU_INTERRUPT_INIT as CPU_INTERRUPT_RESET. Therefore we can handle the new TCGCPUOps.cpu_exec_reset hook. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 39 ++++++++++++++------------------------- target/i386/tcg/tcg-cpu.c | 11 ++++++++++- 2 files changed, 24 insertions(+), 26 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 010f38edaa..c21c5d202d 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -819,33 +819,22 @@ static inline bool cpu_handle_interrupt(CPUState *cpu, cpu->exception_index = EXCP_HLT; bql_unlock(); return true; - } -#if defined(TARGET_I386) - else if (interrupt_request & CPU_INTERRUPT_INIT) { - X86CPU *x86_cpu = X86_CPU(cpu); - CPUArchState *env = &x86_cpu->env; - replay_interrupt(); - cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0); - do_cpu_init(x86_cpu); - cpu->exception_index = EXCP_HALTED; - bql_unlock(); - return true; - } -#else - else if (interrupt_request & CPU_INTERRUPT_RESET) { - replay_interrupt(); - cpu->cc->tcg_ops->cpu_exec_reset(cpu); - bql_unlock(); - return true; - } -#endif /* !TARGET_I386 */ - /* The target hook has 3 exit conditions: - False when the interrupt isn't processed, - True when it is, and we should restart on a new TB, - and via longjmp via cpu_loop_exit. */ - else { + } else { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; + if (interrupt_request & CPU_INTERRUPT_RESET) { + replay_interrupt(); + tcg_ops->cpu_exec_reset(cpu); + bql_unlock(); + return true; + } + + /* + * The target hook has 3 exit conditions: + * False when the interrupt isn't processed, + * True when it is, and we should restart on a new TB, + * and via longjmp via cpu_loop_exit. + */ if (tcg_ops->cpu_exec_interrupt(cpu, interrupt_request)) { if (!tcg_ops->need_replay_interrupt || tcg_ops->need_replay_interrupt(interrupt_request)) { diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 5d1c758ae3..f3f0380e70 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -120,6 +120,15 @@ static bool x86_debug_check_breakpoint(CPUState *cs) /* RF disables all architectural breakpoints. */ return !(env->eflags & RF_MASK); } + +static void x86_cpu_exec_reset(CPUState *cs) +{ + CPUArchState *env = cpu_env(cs); + + cpu_svm_check_intercept_param(env, SVM_EXIT_INIT, 0, 0); + do_cpu_init(env_archcpu(env)); + cs->exception_index = EXCP_HALTED; +} #endif #include "accel/tcg/cpu-ops.h" @@ -147,7 +156,7 @@ const TCGCPUOps x86_tcg_ops = { .do_interrupt = x86_cpu_do_interrupt, .cpu_exec_halt = x86_cpu_exec_halt, .cpu_exec_interrupt = x86_cpu_exec_interrupt, - .cpu_exec_reset = cpu_reset, + .cpu_exec_reset = x86_cpu_exec_reset, .do_unaligned_access = x86_cpu_do_unaligned_access, .debug_excp_handler = breakpoint_handler, .debug_check_breakpoint = x86_debug_check_breakpoint, From a59a876999344be426144a3e6d163885220c1e93 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 15:15:14 -0700 Subject: [PATCH 0556/2760] accel/tcg: Hoist cpu_get_tb_cpu_state decl to accl/tcg/cpu-ops.h For some targets, simply remove the local definition. For other targets, move the inline definition out of line. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/accel/tcg/cpu-ops.h | 3 ++ target/alpha/cpu.c | 14 ++++++-- target/alpha/cpu.h | 11 ------ target/arm/cpu.h | 3 -- target/arm/helper.c | 1 + target/avr/cpu.c | 21 +++++++++-- target/avr/cpu.h | 18 ---------- target/hexagon/cpu.c | 18 ++++++++-- target/hexagon/cpu.h | 15 -------- target/hppa/cpu.c | 3 +- target/hppa/cpu.h | 3 -- target/i386/cpu.h | 14 -------- target/i386/tcg/tcg-cpu.c | 17 +++++++-- target/loongarch/cpu.c | 15 ++++++-- target/loongarch/cpu.h | 12 ------- target/m68k/cpu.c | 19 ++++++++-- target/m68k/cpu.h | 16 --------- target/microblaze/cpu.c | 11 ++++-- target/microblaze/cpu.h | 8 ----- target/mips/cpu.c | 9 +++++ target/mips/cpu.h | 9 ----- target/openrisc/cpu.c | 13 +++++-- target/openrisc/cpu.h | 10 ------ target/ppc/cpu.h | 13 ------- target/ppc/helper_regs.c | 16 ++++----- target/riscv/cpu.h | 3 -- target/rx/cpu.c | 12 +++++-- target/rx/cpu.h | 9 ----- target/s390x/cpu.c | 1 + target/s390x/cpu.h | 9 ----- target/sh4/cpu.c | 18 ++++++++-- target/sh4/cpu.h | 15 -------- target/sparc/cpu.h | 3 -- target/tricore/cpu.c | 15 ++++++-- target/tricore/cpu.h | 12 ------- target/xtensa/cpu.c | 71 +++++++++++++++++++++++++++++++++++-- target/xtensa/cpu.h | 68 ----------------------------------- 37 files changed, 243 insertions(+), 285 deletions(-) diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 3ff72b8d9d..f5e5746976 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -18,6 +18,9 @@ #include "exec/vaddr.h" #include "tcg/tcg-mo.h" +void cpu_get_tb_cpu_state(CPUArchState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags); + struct TCGCPUOps { /** * mttcg_supported: multi-threaded TCG is supported diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index d4e66aa432..134806e755 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -25,6 +25,7 @@ #include "cpu.h" #include "exec/translation-block.h" #include "exec/target_page.h" +#include "accel/tcg/cpu-ops.h" #include "fpu/softfloat.h" @@ -40,6 +41,17 @@ static vaddr alpha_cpu_get_pc(CPUState *cs) return env->pc; } +void cpu_get_tb_cpu_state(CPUAlphaState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) +{ + *pc = env->pc; + *cs_base = 0; + *pflags = env->flags & ENV_FLAG_TB_MASK; +#ifdef CONFIG_USER_ONLY + *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; +#endif +} + static void alpha_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -231,8 +243,6 @@ static const struct SysemuCPUOps alpha_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps alpha_tcg_ops = { /* Alpha processors have a weak memory model */ .guest_default_memory_order = 0, diff --git a/target/alpha/cpu.h b/target/alpha/cpu.h index 849f673489..45944e46b5 100644 --- a/target/alpha/cpu.h +++ b/target/alpha/cpu.h @@ -464,17 +464,6 @@ void alpha_cpu_do_transaction_failed(CPUState *cs, hwaddr physaddr, MemTxResult response, uintptr_t retaddr); #endif -static inline void cpu_get_tb_cpu_state(CPUAlphaState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) -{ - *pc = env->pc; - *cs_base = 0; - *pflags = env->flags & ENV_FLAG_TB_MASK; -#ifdef CONFIG_USER_ONLY - *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; -#endif -} - #ifdef CONFIG_USER_ONLY /* Copied from linux ieee_swcr_to_fpcr. */ static inline uint64_t alpha_ieee_swcr_to_fpcr(uint64_t swcr) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index fdcf8cd1ae..be4449ca06 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3119,9 +3119,6 @@ static inline bool bswap_code(bool sctlr_b) #endif } -void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags); - enum { QEMU_PSCI_CONDUIT_DISABLED = 0, QEMU_PSCI_CONDUIT_SMC = 1, diff --git a/target/arm/helper.c b/target/arm/helper.c index 8de4eb2c1f..98adeb7086 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -30,6 +30,7 @@ #include "qemu/guest-random.h" #ifdef CONFIG_TCG #include "accel/tcg/probe.h" +#include "accel/tcg/cpu-ops.h" #include "semihosting/common-semi.h" #endif #include "cpregs.h" diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 50b835e1ae..d9fecb272e 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -27,6 +27,7 @@ #include "disas/dis-asm.h" #include "tcg/debug-assert.h" #include "hw/qdev-properties.h" +#include "accel/tcg/cpu-ops.h" static void avr_cpu_set_pc(CPUState *cs, vaddr value) { @@ -53,6 +54,24 @@ static int avr_cpu_mmu_index(CPUState *cs, bool ifetch) return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; } +void cpu_get_tb_cpu_state(CPUAVRState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) +{ + uint32_t flags = 0; + + *pc = env->pc_w * 2; + *cs_base = 0; + + if (env->fullacc) { + flags |= TB_FLAGS_FULL_ACCESS; + } + if (env->skip) { + flags |= TB_FLAGS_SKIP; + } + + *pflags = flags; +} + static void avr_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -220,8 +239,6 @@ static const struct SysemuCPUOps avr_sysemu_ops = { .get_phys_page_debug = avr_cpu_get_phys_page_debug, }; -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps avr_tcg_ops = { .guest_default_memory_order = 0, .mttcg_supported = false, diff --git a/target/avr/cpu.h b/target/avr/cpu.h index d6666175a9..518e243d81 100644 --- a/target/avr/cpu.h +++ b/target/avr/cpu.h @@ -205,24 +205,6 @@ enum { TB_FLAGS_SKIP = 2, }; -static inline void cpu_get_tb_cpu_state(CPUAVRState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) -{ - uint32_t flags = 0; - - *pc = env->pc_w * 2; - *cs_base = 0; - - if (env->fullacc) { - flags |= TB_FLAGS_FULL_ACCESS; - } - if (env->skip) { - flags |= TB_FLAGS_SKIP; - } - - *pflags = flags; -} - static inline int cpu_interrupts_enabled(CPUAVRState *env) { return env->sregI != 0; diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index c1bfa80252..2272f1222b 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -25,6 +25,7 @@ #include "fpu/softfloat-helpers.h" #include "tcg/tcg.h" #include "exec/gdbstub.h" +#include "accel/tcg/cpu-ops.h" static void hexagon_v66_cpu_init(Object *obj) { } static void hexagon_v67_cpu_init(Object *obj) { } @@ -254,6 +255,21 @@ static vaddr hexagon_cpu_get_pc(CPUState *cs) return cpu_env(cs)->gpr[HEX_REG_PC]; } +void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + uint32_t hex_flags = 0; + *pc = env->gpr[HEX_REG_PC]; + *cs_base = 0; + if (*pc == env->gpr[HEX_REG_SA0]) { + hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); + } + *flags = hex_flags; + if (*pc & PCALIGN_MASK) { + hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0); + } +} + static void hexagon_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -321,8 +337,6 @@ static void hexagon_cpu_init(Object *obj) { } -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps hexagon_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h index c065fa8ddc..43a854f517 100644 --- a/target/hexagon/cpu.h +++ b/target/hexagon/cpu.h @@ -137,21 +137,6 @@ G_NORETURN void hexagon_raise_exception_err(CPUHexagonState *env, uint32_t exception, uintptr_t pc); -static inline void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - uint32_t hex_flags = 0; - *pc = env->gpr[HEX_REG_PC]; - *cs_base = 0; - if (*pc == env->gpr[HEX_REG_SA0]) { - hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); - } - *flags = hex_flags; - if (*pc & PCALIGN_MASK) { - hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0); - } -} - typedef HexagonCPU ArchCPU; void hexagon_translate_init(void); diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 60b618a22b..4cdaf98ab1 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -29,6 +29,7 @@ #include "fpu/softfloat.h" #include "tcg/tcg.h" #include "hw/hppa/hppa_hardware.h" +#include "accel/tcg/cpu-ops.h" static void hppa_cpu_set_pc(CPUState *cs, vaddr value) { @@ -249,8 +250,6 @@ static const struct SysemuCPUOps hppa_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps hppa_tcg_ops = { /* PA-RISC 1.x processors have a strong memory model. */ /* diff --git a/target/hppa/cpu.h b/target/hppa/cpu.h index acc9937240..11d59d11ca 100644 --- a/target/hppa/cpu.h +++ b/target/hppa/cpu.h @@ -351,9 +351,6 @@ hwaddr hppa_abs_to_phys_pa2_w1(vaddr addr); #define CS_BASE_DIFFPAGE (1 << 12) #define CS_BASE_DIFFSPACE (1 << 13) -void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags); - target_ulong cpu_hppa_get_psw(CPUHPPAState *env); void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong); void update_gva_offset_mask(CPUHPPAState *env); diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 3182ba413b..4f8ed8868e 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2599,20 +2599,6 @@ static inline bool is_mmu_index_32(int mmu_index) #include "hw/i386/apic.h" #endif -static inline void cpu_get_tb_cpu_state(CPUX86State *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *flags = env->hflags | - (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK)); - if (env->hflags & HF_CS64_MASK) { - *cs_base = 0; - *pc = env->eip; - } else { - *cs_base = env->segs[R_CS].base; - *pc = (uint32_t)(*cs_base + env->eip); - } -} - void do_cpu_init(X86CPU *cpu); #define MCE_INJECT_BROADCAST 1 diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index f3f0380e70..bb6f82befb 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -24,6 +24,7 @@ #include "accel/accel-cpu-target.h" #include "exec/translation-block.h" #include "exec/target_page.h" +#include "accel/tcg/cpu-ops.h" #include "tcg-cpu.h" /* Frob eflags into and out of the CPU temporary format. */ @@ -47,6 +48,20 @@ static void x86_cpu_exec_exit(CPUState *cs) env->eflags = cpu_compute_eflags(env); } +void cpu_get_tb_cpu_state(CPUX86State *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *flags = env->hflags | + (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK)); + if (env->hflags & HF_CS64_MASK) { + *cs_base = 0; + *pc = env->eip; + } else { + *cs_base = env->segs[R_CS].base; + *pc = (uint32_t)(*cs_base + env->eip); + } +} + static void x86_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -131,8 +146,6 @@ static void x86_cpu_exec_reset(CPUState *cs) } #endif -#include "accel/tcg/cpu-ops.h" - const TCGCPUOps x86_tcg_ops = { .mttcg_supported = true, .precise_smc = true, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index c64cba72dd..be770b7e19 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -29,6 +29,7 @@ #endif #ifdef CONFIG_TCG #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ops.h" #include "tcg/tcg.h" #endif #include "tcg/tcg_loongarch.h" @@ -335,6 +336,18 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #endif +void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); + *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; + *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; + *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE; + *flags |= is_va32(env) * HW_FLAGS_VA32; +} + static void loongarch_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -861,8 +874,6 @@ static void loongarch_cpu_dump_state(CPUState *cs, FILE *f, int flags) } #ifdef CONFIG_TCG -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps loongarch_tcg_ops = { .guest_default_memory_order = 0, .mttcg_supported = true, diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h index 70ff56e60c..262bf87f7b 100644 --- a/target/loongarch/cpu.h +++ b/target/loongarch/cpu.h @@ -492,18 +492,6 @@ static inline void set_pc(CPULoongArchState *env, uint64_t value) #define HW_FLAGS_VA32 0x20 #define HW_FLAGS_EUEN_ASXE 0x40 -static inline void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE; - *flags |= is_va32(env) * HW_FLAGS_VA32; -} - #define CPU_RESOLVING_TYPE TYPE_LOONGARCH_CPU void loongarch_cpu_post_init(Object *obj); diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index f446c6c8f7..2b4ec40509 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "fpu/softfloat.h" +#include "accel/tcg/cpu-ops.h" static void m68k_cpu_set_pc(CPUState *cs, vaddr value) { @@ -38,6 +39,22 @@ static vaddr m68k_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPUM68KState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = (env->macsr >> 4) & TB_FLAGS_MACSR; + if (env->sr & SR_S) { + *flags |= TB_FLAGS_MSR_S; + *flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S; + *flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S; + } + if (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS) { + *flags |= TB_FLAGS_TRACE; + } +} + static void m68k_restore_state_to_opc(CPUState *cs, const TranslationBlock *tb, const uint64_t *data) @@ -586,8 +603,6 @@ static const struct SysemuCPUOps m68k_sysemu_ops = { }; #endif /* !CONFIG_USER_ONLY */ -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps m68k_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/m68k/cpu.h b/target/m68k/cpu.h index 39d0b9d6d7..d9db6a486a 100644 --- a/target/m68k/cpu.h +++ b/target/m68k/cpu.h @@ -605,22 +605,6 @@ void m68k_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, #define TB_FLAGS_TRACE 16 #define TB_FLAGS_TRACE_BIT (1 << TB_FLAGS_TRACE) -static inline void cpu_get_tb_cpu_state(CPUM68KState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = (env->macsr >> 4) & TB_FLAGS_MACSR; - if (env->sr & SR_S) { - *flags |= TB_FLAGS_MSR_S; - *flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S; - *flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S; - } - if (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS) { - *flags |= TB_FLAGS_TRACE; - } -} - void dump_mmu(CPUM68KState *env); #endif diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index f305ed04f6..105ede0b1e 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -31,6 +31,7 @@ #include "exec/gdbstub.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" +#include "accel/tcg/cpu-ops.h" #include "tcg/tcg.h" static const struct { @@ -94,6 +95,14 @@ static vaddr mb_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPUMBState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK); + *cs_base = (*flags & IMM_FLAG ? env->imm : 0); +} + static void mb_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -423,8 +432,6 @@ static const struct SysemuCPUOps mb_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps mb_tcg_ops = { /* MicroBlaze is always in-order. */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index d511f22a55..6ad8643f2e 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -419,14 +419,6 @@ static inline bool mb_cpu_is_big_endian(CPUState *cs) return !cpu->cfg.endi; } -static inline void cpu_get_tb_cpu_state(CPUMBState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK); - *cs_base = (*flags & IMM_FLAG ? env->imm : 0); -} - #if !defined(CONFIG_USER_ONLY) bool mb_cpu_tlb_fill(CPUState *cs, vaddr address, int size, MMUAccessType access_type, int mmu_idx, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 09ed330027..ab00adf86b 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -549,6 +549,15 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) return mips_env_mmu_index(cpu_env(cs)); } +void cpu_get_tb_cpu_state(CPUMIPSState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->active_tc.PC; + *cs_base = 0; + *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | + MIPS_HFLAG_HWRENA_ULR); +} + static const TCGCPUOps mips_tcg_ops = { .mttcg_supported = TARGET_LONG_BITS == 32, .guest_default_memory_order = 0, diff --git a/target/mips/cpu.h b/target/mips/cpu.h index d16f9a7220..5cd4c6c818 100644 --- a/target/mips/cpu.h +++ b/target/mips/cpu.h @@ -1366,15 +1366,6 @@ void cpu_mips_clock_init(MIPSCPU *cpu); /* helper.c */ target_ulong exception_resume_pc(CPUMIPSState *env); -static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->active_tc.PC; - *cs_base = 0; - *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | - MIPS_HFLAG_HWRENA_ULR); -} - /** * mips_cpu_create_with_clock: * @typename: a MIPS CPU type. diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 94776e0ad8..d798127d67 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" +#include "accel/tcg/cpu-ops.h" #include "tcg/tcg.h" static void openrisc_cpu_set_pc(CPUState *cs, vaddr value) @@ -40,6 +41,16 @@ static vaddr openrisc_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPUOpenRISCState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = (env->dflag ? TB_FLAGS_DFLAG : 0) + | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0) + | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE)); +} + static void openrisc_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -239,8 +250,6 @@ static const struct SysemuCPUOps openrisc_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps openrisc_tcg_ops = { .guest_default_memory_order = 0, .mttcg_supported = true, diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h index 569819bfb0..f4bcf00b07 100644 --- a/target/openrisc/cpu.h +++ b/target/openrisc/cpu.h @@ -349,16 +349,6 @@ static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val) env->shadow_gpr[0][i] = val; } -static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = (env->dflag ? TB_FLAGS_DFLAG : 0) - | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0) - | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE)); -} - static inline uint32_t cpu_get_sr(const CPUOpenRISCState *env) { return (env->sr diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index 13115a89ff..6b90543811 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -2751,19 +2751,6 @@ void cpu_write_xer(CPUPPCState *env, target_ulong xer); */ #define is_book3s_arch2x(ctx) (!!((ctx)->insns_flags & PPC_SEGMENT_64B)) -#ifdef CONFIG_DEBUG_TCG -void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags); -#else -static inline void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->nip; - *cs_base = 0; - *flags = env->hflags; -} -#endif - G_NORETURN void raise_exception_err_ra(CPUPPCState *env, uint32_t exception, uint32_t error_code, uintptr_t raddr); diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index f211bc9830..8d248bcbb9 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -27,6 +27,7 @@ #include "power8-pmu.h" #include "cpu-models.h" #include "spr_common.h" +#include "accel/tcg/cpu-ops.h" /* Swap temporary saved registers with GPRs */ void hreg_swap_gpr_tgpr(CPUPPCState *env) @@ -255,26 +256,25 @@ void hreg_update_pmu_hflags(CPUPPCState *env) env->hflags |= hreg_compute_pmu_hflags_value(env); } -#ifdef CONFIG_DEBUG_TCG void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, uint64_t *cs_base, uint32_t *flags) { uint32_t hflags_current = env->hflags; - uint32_t hflags_rebuilt; - *pc = env->nip; - *cs_base = 0; - *flags = hflags_current; - - hflags_rebuilt = hreg_compute_hflags_value(env); +#ifdef CONFIG_DEBUG_TCG + uint32_t hflags_rebuilt = hreg_compute_hflags_value(env); if (unlikely(hflags_current != hflags_rebuilt)) { cpu_abort(env_cpu(env), "TCG hflags mismatch (current:0x%08x rebuilt:0x%08x)\n", hflags_current, hflags_rebuilt); } -} #endif + *pc = env->nip; + *cs_base = 0; + *flags = hflags_current; +} + void cpu_interrupt_exittb(CPUState *cs) { /* diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 167909c89b..c66ac3bc27 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -802,9 +802,6 @@ static inline uint32_t vext_get_vlmax(uint32_t vlenb, uint32_t vsew, return vlen >> (vsew + 3 - lmul); } -void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags); - bool riscv_cpu_is_32bit(RISCVCPU *cpu); bool riscv_cpu_virt_mem_enabled(CPURISCVState *env); diff --git a/target/rx/cpu.c b/target/rx/cpu.c index de2e6a22ff..e8b47be675 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -28,6 +28,7 @@ #include "hw/loader.h" #include "fpu/softfloat.h" #include "tcg/debug-assert.h" +#include "accel/tcg/cpu-ops.h" static void rx_cpu_set_pc(CPUState *cs, vaddr value) { @@ -43,6 +44,15 @@ static vaddr rx_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPURXState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = FIELD_DP32(0, PSW, PM, env->psw_pm); + *flags = FIELD_DP32(*flags, PSW, U, env->psw_u); +} + static void rx_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -201,8 +211,6 @@ static const struct SysemuCPUOps rx_sysemu_ops = { .get_phys_page_debug = rx_cpu_get_phys_page_debug, }; -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps rx_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/rx/cpu.h b/target/rx/cpu.h index 5c19c83219..ba5761b647 100644 --- a/target/rx/cpu.h +++ b/target/rx/cpu.h @@ -153,15 +153,6 @@ void rx_cpu_unpack_psw(CPURXState *env, uint32_t psw, int rte); #define RX_CPU_IRQ 0 #define RX_CPU_FIR 1 -static inline void cpu_get_tb_cpu_state(CPURXState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = FIELD_DP32(0, PSW, PM, env->psw_pm); - *flags = FIELD_DP32(*flags, PSW, U, env->psw_u); -} - static inline uint32_t rx_cpu_pack_psw(CPURXState *env) { uint32_t psw = 0; diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 71338aae77..435b2034ff 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -302,6 +302,7 @@ static const Property s390x_cpu_properties[] = { #ifdef CONFIG_TCG #include "accel/tcg/cpu-ops.h" +#include "tcg/tcg_s390x.h" static int s390x_cpu_mmu_index(CPUState *cs, bool ifetch) { diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 530d97ccf1..aa931cb674 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -411,15 +411,6 @@ static inline int s390x_env_mmu_index(CPUS390XState *env, bool ifetch) #endif } -#ifdef CONFIG_TCG - -#include "tcg/tcg_s390x.h" - -void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags); - -#endif /* CONFIG_TCG */ - /* PER bits from control register 9 */ #define PER_CR9_EVENT_BRANCH 0x80000000 #define PER_CR9_EVENT_IFETCH 0x40000000 diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 681237c511..5fb18bf55e 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -26,6 +26,7 @@ #include "migration/vmstate.h" #include "exec/translation-block.h" #include "fpu/softfloat-helpers.h" +#include "accel/tcg/cpu-ops.h" #include "tcg/tcg.h" static void superh_cpu_set_pc(CPUState *cs, vaddr value) @@ -42,6 +43,21 @@ static vaddr superh_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPUSH4State *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + /* For a gUSA region, notice the end of the region. */ + *cs_base = env->flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0; + *flags = env->flags + | (env->fpscr & TB_FLAG_FPSCR_MASK) + | (env->sr & TB_FLAG_SR_MASK) + | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ +#ifdef CONFIG_USER_ONLY + *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; +#endif +} + static void superh_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -258,8 +274,6 @@ static const struct SysemuCPUOps sh4_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps superh_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 906f99ddf0..c41ab70dd7 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -380,19 +380,4 @@ static inline void cpu_write_sr(CPUSH4State *env, target_ulong sr) env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T)); } -static inline void cpu_get_tb_cpu_state(CPUSH4State *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - /* For a gUSA region, notice the end of the region. */ - *cs_base = env->flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0; - *flags = env->flags - | (env->fpscr & TB_FLAG_FPSCR_MASK) - | (env->sr & TB_FLAG_SR_MASK) - | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ -#ifdef CONFIG_USER_ONLY - *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; -#endif -} - #endif /* SH4_CPU_H */ diff --git a/target/sparc/cpu.h b/target/sparc/cpu.h index 37fd1e066e..31cb3d97eb 100644 --- a/target/sparc/cpu.h +++ b/target/sparc/cpu.h @@ -741,9 +741,6 @@ trap_state* cpu_tsptr(CPUSPARCState* env); #define TB_FLAG_FSR_QNE (1 << 8) #define TB_FLAG_ASI_SHIFT 24 -void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags); - static inline bool tb_fpu_enabled(int tb_flags) { #if defined(CONFIG_USER_ONLY) diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 0fcac697f6..81b3bb6362 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -23,6 +23,7 @@ #include "exec/translation-block.h" #include "qemu/error-report.h" #include "tcg/debug-assert.h" +#include "accel/tcg/cpu-ops.h" static inline void set_feature(CPUTriCoreState *env, int feature) { @@ -44,6 +45,18 @@ static vaddr tricore_cpu_get_pc(CPUState *cs) return cpu_env(cs)->PC; } +void cpu_get_tb_cpu_state(CPUTriCoreState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + uint32_t new_flags = 0; + *pc = env->PC; + *cs_base = 0; + + new_flags |= FIELD_DP32(new_flags, TB_FLAGS, PRIV, + extract32(env->PSW, 10, 2)); + *flags = new_flags; +} + static void tricore_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { @@ -168,8 +181,6 @@ static const struct SysemuCPUOps tricore_sysemu_ops = { .get_phys_page_debug = tricore_cpu_get_phys_page_debug, }; -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps tricore_tcg_ops = { /* MTTCG not yet supported: require strict ordering */ .guest_default_memory_order = TCG_MO_ALL, diff --git a/target/tricore/cpu.h b/target/tricore/cpu.h index c76e65f818..82085fbc32 100644 --- a/target/tricore/cpu.h +++ b/target/tricore/cpu.h @@ -258,18 +258,6 @@ void tricore_tcg_init(void); void tricore_translate_code(CPUState *cs, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); -static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - uint32_t new_flags = 0; - *pc = env->PC; - *cs_base = 0; - - new_flags |= FIELD_DP32(new_flags, TB_FLAGS, PRIV, - extract32(env->PSW, 10, 2)); - *flags = new_flags; -} - #define CPU_RESOLVING_TYPE TYPE_TRICORE_CPU /* helpers.c */ diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 9dcb883208..c78ef9421c 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -35,6 +35,7 @@ #include "qemu/module.h" #include "migration/vmstate.h" #include "hw/qdev-clock.h" +#include "accel/tcg/cpu-ops.h" #ifndef CONFIG_USER_ONLY #include "system/memory.h" #endif @@ -54,6 +55,74 @@ static vaddr xtensa_cpu_get_pc(CPUState *cs) return cpu->env.pc; } +void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *flags) +{ + *pc = env->pc; + *cs_base = 0; + *flags = 0; + *flags |= xtensa_get_ring(env); + if (env->sregs[PS] & PS_EXCM) { + *flags |= XTENSA_TBFLAG_EXCM; + } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) { + target_ulong lend_dist = + env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS)); + + /* + * 0 in the csbase_lend field means that there may not be a loopback + * for any instruction that starts inside this page. Any other value + * means that an instruction that ends at this offset from the page + * start may loop back and will need loopback code to be generated. + * + * lend_dist is 0 when LEND points to the start of the page, but + * no instruction that starts inside this page may end at offset 0, + * so it's still correct. + * + * When an instruction ends at a page boundary it may only start in + * the previous page. lend_dist will be encoded as TARGET_PAGE_SIZE + * for the TB that contains this instruction. + */ + if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) { + target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG]; + + *cs_base = lend_dist; + if (lbeg_off < 256) { + *cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT; + } + } + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && + (env->sregs[LITBASE] & 1)) { + *flags |= XTENSA_TBFLAG_LITBASE; + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) { + if (xtensa_get_cintlevel(env) < env->config->debug_level) { + *flags |= XTENSA_TBFLAG_DEBUG; + } + if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { + *flags |= XTENSA_TBFLAG_ICOUNT; + } + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { + *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; + } + if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) && + (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) { + uint32_t windowstart = xtensa_replicate_windowstart(env) >> + (env->sregs[WINDOW_BASE] + 1); + uint32_t w = ctz32(windowstart | 0x8); + + *flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE; + *flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT, + PS_CALLINC_LEN) << XTENSA_TBFLAG_CALLINC_SHIFT; + } else { + *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; + } + if (env->yield_needed) { + *flags |= XTENSA_TBFLAG_YIELD; + } +} + static void xtensa_restore_state_to_opc(CPUState *cs, const TranslationBlock *tb, const uint64_t *data) @@ -229,8 +298,6 @@ static const struct SysemuCPUOps xtensa_sysemu_ops = { }; #endif -#include "accel/tcg/cpu-ops.h" - static const TCGCPUOps xtensa_tcg_ops = { /* Xtensa processors have a weak memory model */ .guest_default_memory_order = 0, diff --git a/target/xtensa/cpu.h b/target/xtensa/cpu.h index c03ed71c94..74122ebe15 100644 --- a/target/xtensa/cpu.h +++ b/target/xtensa/cpu.h @@ -733,74 +733,6 @@ static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) #define XTENSA_CSBASE_LBEG_OFF_MASK 0x00ff0000 #define XTENSA_CSBASE_LBEG_OFF_SHIFT 16 -static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) -{ - *pc = env->pc; - *cs_base = 0; - *flags = 0; - *flags |= xtensa_get_ring(env); - if (env->sregs[PS] & PS_EXCM) { - *flags |= XTENSA_TBFLAG_EXCM; - } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) { - target_ulong lend_dist = - env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS)); - - /* - * 0 in the csbase_lend field means that there may not be a loopback - * for any instruction that starts inside this page. Any other value - * means that an instruction that ends at this offset from the page - * start may loop back and will need loopback code to be generated. - * - * lend_dist is 0 when LEND points to the start of the page, but - * no instruction that starts inside this page may end at offset 0, - * so it's still correct. - * - * When an instruction ends at a page boundary it may only start in - * the previous page. lend_dist will be encoded as TARGET_PAGE_SIZE - * for the TB that contains this instruction. - */ - if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) { - target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG]; - - *cs_base = lend_dist; - if (lbeg_off < 256) { - *cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT; - } - } - } - if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && - (env->sregs[LITBASE] & 1)) { - *flags |= XTENSA_TBFLAG_LITBASE; - } - if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) { - if (xtensa_get_cintlevel(env) < env->config->debug_level) { - *flags |= XTENSA_TBFLAG_DEBUG; - } - if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { - *flags |= XTENSA_TBFLAG_ICOUNT; - } - } - if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { - *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; - } - if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) && - (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) { - uint32_t windowstart = xtensa_replicate_windowstart(env) >> - (env->sregs[WINDOW_BASE] + 1); - uint32_t w = ctz32(windowstart | 0x8); - - *flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE; - *flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT, - PS_CALLINC_LEN) << XTENSA_TBFLAG_CALLINC_SHIFT; - } else { - *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; - } - if (env->yield_needed) { - *flags |= XTENSA_TBFLAG_YIELD; - } -} - XtensaCPU *xtensa_cpu_create_with_clock(const char *cpu_type, Clock *cpu_refclk); From b6aeb8d243c5ab8b914b55f0036e8289a99322c8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 11:35:26 -0700 Subject: [PATCH 0557/2760] target/arm: Move cpu_get_tb_cpu_state to hflags.c This is a tcg-specific function, so move it to a tcg file. Also move mve_no_pred, a static function only used within cpu_get_tb_cpu_state. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/arm/helper.c | 110 ---------------------------------------- target/arm/tcg/hflags.c | 110 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 110 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 98adeb7086..360e6ac0f5 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -30,7 +30,6 @@ #include "qemu/guest-random.h" #ifdef CONFIG_TCG #include "accel/tcg/probe.h" -#include "accel/tcg/cpu-ops.h" #include "semihosting/common-semi.h" #endif #include "cpregs.h" @@ -11424,115 +11423,6 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } -static bool mve_no_pred(CPUARMState *env) -{ - /* - * Return true if there is definitely no predication of MVE - * instructions by VPR or LTPSIZE. (Returning false even if there - * isn't any predication is OK; generated code will just be - * a little worse.) - * If the CPU does not implement MVE then this TB flag is always 0. - * - * NOTE: if you change this logic, the "recalculate s->mve_no_pred" - * logic in gen_update_fp_context() needs to be updated to match. - * - * We do not include the effect of the ECI bits here -- they are - * tracked in other TB flags. This simplifies the logic for - * "when did we emit code that changes the MVE_NO_PRED TB flag - * and thus need to end the TB?". - */ - if (cpu_isar_feature(aa32_mve, env_archcpu(env))) { - return false; - } - if (env->v7m.vpr) { - return false; - } - if (env->v7m.ltpsize < 4) { - return false; - } - return true; -} - -void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) -{ - CPUARMTBFlags flags; - - assert_hflags_rebuild_correctly(env); - flags = env->hflags; - - if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) { - *pc = env->pc; - if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { - DP_TBFLAG_A64(flags, BTYPE, env->btype); - } - } else { - *pc = env->regs[15]; - - if (arm_feature(env, ARM_FEATURE_M)) { - if (arm_feature(env, ARM_FEATURE_M_SECURITY) && - FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) - != env->v7m.secure) { - DP_TBFLAG_M32(flags, FPCCR_S_WRONG, 1); - } - - if ((env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) && - (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) || - (env->v7m.secure && - !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) { - /* - * ASPEN is set, but FPCA/SFPA indicate that there is no - * active FP context; we must create a new FP context before - * executing any FP insn. - */ - DP_TBFLAG_M32(flags, NEW_FP_CTXT_NEEDED, 1); - } - - bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; - if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) { - DP_TBFLAG_M32(flags, LSPACT, 1); - } - - if (mve_no_pred(env)) { - DP_TBFLAG_M32(flags, MVE_NO_PRED, 1); - } - } else { - /* - * Note that XSCALE_CPAR shares bits with VECSTRIDE. - * Note that VECLEN+VECSTRIDE are RES0 for M-profile. - */ - if (arm_feature(env, ARM_FEATURE_XSCALE)) { - DP_TBFLAG_A32(flags, XSCALE_CPAR, env->cp15.c15_cpar); - } else { - DP_TBFLAG_A32(flags, VECLEN, env->vfp.vec_len); - DP_TBFLAG_A32(flags, VECSTRIDE, env->vfp.vec_stride); - } - if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) { - DP_TBFLAG_A32(flags, VFPEN, 1); - } - } - - DP_TBFLAG_AM32(flags, THUMB, env->thumb); - DP_TBFLAG_AM32(flags, CONDEXEC, env->condexec_bits); - } - - /* - * The SS_ACTIVE and PSTATE_SS bits correspond to the state machine - * states defined in the ARM ARM for software singlestep: - * SS_ACTIVE PSTATE.SS State - * 0 x Inactive (the TB flag for SS is always 0) - * 1 0 Active-pending - * 1 1 Active-not-pending - * SS_ACTIVE is set in hflags; PSTATE__SS is computed every TB. - */ - if (EX_TBFLAG_ANY(flags, SS_ACTIVE) && (env->pstate & PSTATE_SS)) { - DP_TBFLAG_ANY(flags, PSTATE__SS, 1); - } - - *pflags = flags.flags; - *cs_base = flags.flags2; -} - #ifdef TARGET_AARCH64 /* * The manual says that when SVE is enabled and VQ is widened the diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index e51d9f7b15..e530f65ed7 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -10,6 +10,7 @@ #include "internals.h" #include "cpu-features.h" #include "exec/helper-proto.h" +#include "accel/tcg/cpu-ops.h" #include "cpregs.h" static inline bool fgt_svc(CPUARMState *env, int el) @@ -513,3 +514,112 @@ void assert_hflags_rebuild_correctly(CPUARMState *env) } #endif } + +static bool mve_no_pred(CPUARMState *env) +{ + /* + * Return true if there is definitely no predication of MVE + * instructions by VPR or LTPSIZE. (Returning false even if there + * isn't any predication is OK; generated code will just be + * a little worse.) + * If the CPU does not implement MVE then this TB flag is always 0. + * + * NOTE: if you change this logic, the "recalculate s->mve_no_pred" + * logic in gen_update_fp_context() needs to be updated to match. + * + * We do not include the effect of the ECI bits here -- they are + * tracked in other TB flags. This simplifies the logic for + * "when did we emit code that changes the MVE_NO_PRED TB flag + * and thus need to end the TB?". + */ + if (cpu_isar_feature(aa32_mve, env_archcpu(env))) { + return false; + } + if (env->v7m.vpr) { + return false; + } + if (env->v7m.ltpsize < 4) { + return false; + } + return true; +} + +void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) +{ + CPUARMTBFlags flags; + + assert_hflags_rebuild_correctly(env); + flags = env->hflags; + + if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) { + *pc = env->pc; + if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { + DP_TBFLAG_A64(flags, BTYPE, env->btype); + } + } else { + *pc = env->regs[15]; + + if (arm_feature(env, ARM_FEATURE_M)) { + if (arm_feature(env, ARM_FEATURE_M_SECURITY) && + FIELD_EX32(env->v7m.fpccr[M_REG_S], V7M_FPCCR, S) + != env->v7m.secure) { + DP_TBFLAG_M32(flags, FPCCR_S_WRONG, 1); + } + + if ((env->v7m.fpccr[env->v7m.secure] & R_V7M_FPCCR_ASPEN_MASK) && + (!(env->v7m.control[M_REG_S] & R_V7M_CONTROL_FPCA_MASK) || + (env->v7m.secure && + !(env->v7m.control[M_REG_S] & R_V7M_CONTROL_SFPA_MASK)))) { + /* + * ASPEN is set, but FPCA/SFPA indicate that there is no + * active FP context; we must create a new FP context before + * executing any FP insn. + */ + DP_TBFLAG_M32(flags, NEW_FP_CTXT_NEEDED, 1); + } + + bool is_secure = env->v7m.fpccr[M_REG_S] & R_V7M_FPCCR_S_MASK; + if (env->v7m.fpccr[is_secure] & R_V7M_FPCCR_LSPACT_MASK) { + DP_TBFLAG_M32(flags, LSPACT, 1); + } + + if (mve_no_pred(env)) { + DP_TBFLAG_M32(flags, MVE_NO_PRED, 1); + } + } else { + /* + * Note that XSCALE_CPAR shares bits with VECSTRIDE. + * Note that VECLEN+VECSTRIDE are RES0 for M-profile. + */ + if (arm_feature(env, ARM_FEATURE_XSCALE)) { + DP_TBFLAG_A32(flags, XSCALE_CPAR, env->cp15.c15_cpar); + } else { + DP_TBFLAG_A32(flags, VECLEN, env->vfp.vec_len); + DP_TBFLAG_A32(flags, VECSTRIDE, env->vfp.vec_stride); + } + if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) { + DP_TBFLAG_A32(flags, VFPEN, 1); + } + } + + DP_TBFLAG_AM32(flags, THUMB, env->thumb); + DP_TBFLAG_AM32(flags, CONDEXEC, env->condexec_bits); + } + + /* + * The SS_ACTIVE and PSTATE_SS bits correspond to the state machine + * states defined in the ARM ARM for software singlestep: + * SS_ACTIVE PSTATE.SS State + * 0 x Inactive (the TB flag for SS is always 0) + * 1 0 Active-pending + * 1 1 Active-not-pending + * SS_ACTIVE is set in hflags; PSTATE__SS is computed every TB. + */ + if (EX_TBFLAG_ANY(flags, SS_ACTIVE) && (env->pstate & PSTATE_SS)) { + DP_TBFLAG_ANY(flags, PSTATE__SS, 1); + } + + *pflags = flags.flags; + *cs_base = flags.flags2; +} From 9da84372c4e9efedc5326e71358197930ee06445 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 11:37:24 -0700 Subject: [PATCH 0558/2760] target/arm: Unexport assert_hflags_rebuild_correctly This function is no longer used outside of hflags.c. We can remove the stub as well. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/arm/internals.h | 2 -- target/arm/tcg-stubs.c | 4 ---- target/arm/tcg/hflags.c | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 4d3d84ffeb..382a4d1015 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1906,8 +1906,6 @@ static inline bool arm_fgt_active(CPUARMState *env, int el) (!arm_feature(env, ARM_FEATURE_EL3) || (env->cp15.scr_el3 & SCR_FGTEN)); } -void assert_hflags_rebuild_correctly(CPUARMState *env); - /* * Although the ARM implementation of hardware assisted debugging * allows for different breakpoints per-core, the current GDB diff --git a/target/arm/tcg-stubs.c b/target/arm/tcg-stubs.c index 93a15cad61..5e5166c049 100644 --- a/target/arm/tcg-stubs.c +++ b/target/arm/tcg-stubs.c @@ -21,10 +21,6 @@ void raise_exception_ra(CPUARMState *env, uint32_t excp, uint32_t syndrome, { g_assert_not_reached(); } -/* Temporarily while cpu_get_tb_cpu_state() is still in common code */ -void assert_hflags_rebuild_correctly(CPUARMState *env) -{ -} /* TLBI insns are only used by TCG, so we don't need to do anything for KVM */ void define_tlb_insn_regs(ARMCPU *cpu) diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index e530f65ed7..5315264c28 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -499,7 +499,7 @@ void HELPER(rebuild_hflags_a64)(CPUARMState *env, int el) env->hflags = rebuild_hflags_a64(env, el, fp_el, mmu_idx); } -void assert_hflags_rebuild_correctly(CPUARMState *env) +static void assert_hflags_rebuild_correctly(CPUARMState *env) { #ifdef CONFIG_DEBUG_TCG CPUARMTBFlags c = env->hflags; From 5b1c93be57ce6364eb7bbaaab6ecbf2b1d5d979e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 14:15:45 -0700 Subject: [PATCH 0559/2760] target/riscv: Move cpu_get_tb_cpu_state to tcg-cpu.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is only relevant to tcg. Move it to a tcg-specific file. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- target/riscv/cpu_helper.c | 97 ------------------------------------- target/riscv/tcg/tcg-cpu.c | 98 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 97 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index f2e90a9889..d5039f69a9 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -135,103 +135,6 @@ bool riscv_env_smode_dbltrp_enabled(CPURISCVState *env, bool virt) #endif } -void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) -{ - RISCVCPU *cpu = env_archcpu(env); - RISCVExtStatus fs, vs; - uint32_t flags = 0; - bool pm_signext = riscv_cpu_virt_mem_enabled(env); - - *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; - *cs_base = 0; - - if (cpu->cfg.ext_zve32x) { - /* - * If env->vl equals to VLMAX, we can use generic vector operation - * expanders (GVEC) to accerlate the vector operations. - * However, as LMUL could be a fractional number. The maximum - * vector size can be operated might be less than 8 bytes, - * which is not supported by GVEC. So we set vl_eq_vlmax flag to true - * only when maxsz >= 8 bytes. - */ - - /* lmul encoded as in DisasContext::lmul */ - int8_t lmul = sextract32(FIELD_EX64(env->vtype, VTYPE, VLMUL), 0, 3); - uint32_t vsew = FIELD_EX64(env->vtype, VTYPE, VSEW); - uint32_t vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul); - uint32_t maxsz = vlmax << vsew; - bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && - (maxsz >= 8); - flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill); - flags = FIELD_DP32(flags, TB_FLAGS, SEW, vsew); - flags = FIELD_DP32(flags, TB_FLAGS, LMUL, - FIELD_EX64(env->vtype, VTYPE, VLMUL)); - flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); - flags = FIELD_DP32(flags, TB_FLAGS, VTA, - FIELD_EX64(env->vtype, VTYPE, VTA)); - flags = FIELD_DP32(flags, TB_FLAGS, VMA, - FIELD_EX64(env->vtype, VTYPE, VMA)); - flags = FIELD_DP32(flags, TB_FLAGS, VSTART_EQ_ZERO, env->vstart == 0); - } else { - flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); - } - - if (cpu_get_fcfien(env)) { - /* - * For Forward CFI, only the expectation of a lpad at - * the start of the block is tracked via env->elp. env->elp - * is turned on during jalr translation. - */ - flags = FIELD_DP32(flags, TB_FLAGS, FCFI_LP_EXPECTED, env->elp); - flags = FIELD_DP32(flags, TB_FLAGS, FCFI_ENABLED, 1); - } - - if (cpu_get_bcfien(env)) { - flags = FIELD_DP32(flags, TB_FLAGS, BCFI_ENABLED, 1); - } - -#ifdef CONFIG_USER_ONLY - fs = EXT_STATUS_DIRTY; - vs = EXT_STATUS_DIRTY; -#else - flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv); - - flags |= riscv_env_mmu_index(env, 0); - fs = get_field(env->mstatus, MSTATUS_FS); - vs = get_field(env->mstatus, MSTATUS_VS); - - if (env->virt_enabled) { - flags = FIELD_DP32(flags, TB_FLAGS, VIRT_ENABLED, 1); - /* - * Merge DISABLED and !DIRTY states using MIN. - * We will set both fields when dirtying. - */ - fs = MIN(fs, get_field(env->mstatus_hs, MSTATUS_FS)); - vs = MIN(vs, get_field(env->mstatus_hs, MSTATUS_VS)); - } - - /* With Zfinx, floating point is enabled/disabled by Smstateen. */ - if (!riscv_has_ext(env, RVF)) { - fs = (smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR) == RISCV_EXCP_NONE) - ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED; - } - - if (cpu->cfg.debug && !icount_enabled()) { - flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled); - } -#endif - - flags = FIELD_DP32(flags, TB_FLAGS, FS, fs); - flags = FIELD_DP32(flags, TB_FLAGS, VS, vs); - flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl); - flags = FIELD_DP32(flags, TB_FLAGS, AXL, cpu_address_xl(env)); - flags = FIELD_DP32(flags, TB_FLAGS, PM_PMM, riscv_pm_get_pmm(env)); - flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext); - - *pflags = flags; -} - RISCVPmPmm riscv_pm_get_pmm(CPURISCVState *env) { #ifndef CONFIG_USER_ONLY diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 50782e0f0e..e67de7dfe2 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -36,6 +36,7 @@ #ifndef CONFIG_USER_ONLY #include "hw/boards.h" #include "system/tcg.h" +#include "exec/icount.h" #endif /* Hash that stores user set extensions */ @@ -97,6 +98,103 @@ static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch) return riscv_env_mmu_index(cpu_env(cs), ifetch); } +void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, + uint64_t *cs_base, uint32_t *pflags) +{ + RISCVCPU *cpu = env_archcpu(env); + RISCVExtStatus fs, vs; + uint32_t flags = 0; + bool pm_signext = riscv_cpu_virt_mem_enabled(env); + + *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; + *cs_base = 0; + + if (cpu->cfg.ext_zve32x) { + /* + * If env->vl equals to VLMAX, we can use generic vector operation + * expanders (GVEC) to accerlate the vector operations. + * However, as LMUL could be a fractional number. The maximum + * vector size can be operated might be less than 8 bytes, + * which is not supported by GVEC. So we set vl_eq_vlmax flag to true + * only when maxsz >= 8 bytes. + */ + + /* lmul encoded as in DisasContext::lmul */ + int8_t lmul = sextract32(FIELD_EX64(env->vtype, VTYPE, VLMUL), 0, 3); + uint32_t vsew = FIELD_EX64(env->vtype, VTYPE, VSEW); + uint32_t vlmax = vext_get_vlmax(cpu->cfg.vlenb, vsew, lmul); + uint32_t maxsz = vlmax << vsew; + bool vl_eq_vlmax = (env->vstart == 0) && (vlmax == env->vl) && + (maxsz >= 8); + flags = FIELD_DP32(flags, TB_FLAGS, VILL, env->vill); + flags = FIELD_DP32(flags, TB_FLAGS, SEW, vsew); + flags = FIELD_DP32(flags, TB_FLAGS, LMUL, + FIELD_EX64(env->vtype, VTYPE, VLMUL)); + flags = FIELD_DP32(flags, TB_FLAGS, VL_EQ_VLMAX, vl_eq_vlmax); + flags = FIELD_DP32(flags, TB_FLAGS, VTA, + FIELD_EX64(env->vtype, VTYPE, VTA)); + flags = FIELD_DP32(flags, TB_FLAGS, VMA, + FIELD_EX64(env->vtype, VTYPE, VMA)); + flags = FIELD_DP32(flags, TB_FLAGS, VSTART_EQ_ZERO, env->vstart == 0); + } else { + flags = FIELD_DP32(flags, TB_FLAGS, VILL, 1); + } + + if (cpu_get_fcfien(env)) { + /* + * For Forward CFI, only the expectation of a lpad at + * the start of the block is tracked via env->elp. env->elp + * is turned on during jalr translation. + */ + flags = FIELD_DP32(flags, TB_FLAGS, FCFI_LP_EXPECTED, env->elp); + flags = FIELD_DP32(flags, TB_FLAGS, FCFI_ENABLED, 1); + } + + if (cpu_get_bcfien(env)) { + flags = FIELD_DP32(flags, TB_FLAGS, BCFI_ENABLED, 1); + } + +#ifdef CONFIG_USER_ONLY + fs = EXT_STATUS_DIRTY; + vs = EXT_STATUS_DIRTY; +#else + flags = FIELD_DP32(flags, TB_FLAGS, PRIV, env->priv); + + flags |= riscv_env_mmu_index(env, 0); + fs = get_field(env->mstatus, MSTATUS_FS); + vs = get_field(env->mstatus, MSTATUS_VS); + + if (env->virt_enabled) { + flags = FIELD_DP32(flags, TB_FLAGS, VIRT_ENABLED, 1); + /* + * Merge DISABLED and !DIRTY states using MIN. + * We will set both fields when dirtying. + */ + fs = MIN(fs, get_field(env->mstatus_hs, MSTATUS_FS)); + vs = MIN(vs, get_field(env->mstatus_hs, MSTATUS_VS)); + } + + /* With Zfinx, floating point is enabled/disabled by Smstateen. */ + if (!riscv_has_ext(env, RVF)) { + fs = (smstateen_acc_ok(env, 0, SMSTATEEN0_FCSR) == RISCV_EXCP_NONE) + ? EXT_STATUS_DIRTY : EXT_STATUS_DISABLED; + } + + if (cpu->cfg.debug && !icount_enabled()) { + flags = FIELD_DP32(flags, TB_FLAGS, ITRIGGER, env->itrigger_enabled); + } +#endif + + flags = FIELD_DP32(flags, TB_FLAGS, FS, fs); + flags = FIELD_DP32(flags, TB_FLAGS, VS, vs); + flags = FIELD_DP32(flags, TB_FLAGS, XL, env->xl); + flags = FIELD_DP32(flags, TB_FLAGS, AXL, cpu_address_xl(env)); + flags = FIELD_DP32(flags, TB_FLAGS, PM_PMM, riscv_pm_get_pmm(env)); + flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext); + + *pflags = flags; +} + static void riscv_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb) { From 4759aae43235cd00e1c9b67ff5bd920db89fddc5 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 15:32:11 -0700 Subject: [PATCH 0560/2760] accel/tcg: Return TCGTBCPUState from cpu_get_tb_cpu_state Combine 3 different pointer returns into one structure return. Include a cflags field in TCGTBCPUState, not filled in by cpu_get_tb_cpu_state, but used by all callers. This fills a hole in the structure and is useful in some subroutines. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 56 +++++++++++++------------------- accel/tcg/translate-all.c | 8 ++--- include/accel/tcg/cpu-ops.h | 4 +-- include/accel/tcg/tb-cpu-state.h | 18 ++++++++++ target/alpha/cpu.c | 13 ++++---- target/arm/tcg/hflags.c | 17 ++++++---- target/avr/cpu.c | 9 ++--- target/hexagon/cpu.c | 15 +++++---- target/hppa/cpu.c | 10 +++--- target/i386/tcg/tcg-cpu.c | 19 +++++++---- target/loongarch/cpu.c | 20 +++++++----- target/m68k/cpu.c | 21 +++++++----- target/microblaze/cpu.c | 13 +++++--- target/mips/cpu.c | 14 ++++---- target/openrisc/cpu.c | 16 +++++---- target/ppc/helper_regs.c | 8 ++--- target/riscv/tcg/tcg-cpu.c | 12 +++---- target/rx/cpu.c | 14 ++++---- target/s390x/cpu.c | 14 ++++---- target/sh4/cpu.c | 22 +++++++++---- target/sparc/cpu.c | 17 ++++++---- target/tricore/cpu.c | 14 ++++---- target/xtensa/cpu.c | 40 +++++++++++++---------- 23 files changed, 218 insertions(+), 176 deletions(-) create mode 100644 include/accel/tcg/tb-cpu-state.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index c21c5d202d..f7e7e7949d 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -385,9 +385,6 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) { CPUState *cpu = env_cpu(env); TranslationBlock *tb; - vaddr pc; - uint64_t cs_base; - uint32_t flags, cflags; /* * By definition we've just finished a TB, so I/O is OK. @@ -397,20 +394,21 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) * The next TB, if we chain to it, will clear the flag again. */ cpu->neg.can_do_io = true; - cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - cflags = curr_cflags(cpu); - if (check_for_breakpoints(cpu, pc, &cflags)) { + TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + s.cflags = curr_cflags(cpu); + + if (check_for_breakpoints(cpu, s.pc, &s.cflags)) { cpu_loop_exit(cpu); } - tb = tb_lookup(cpu, pc, cs_base, flags, cflags); + tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); if (tb == NULL) { return tcg_code_gen_epilogue; } if (qemu_loglevel_mask(CPU_LOG_TB_CPU | CPU_LOG_EXEC)) { - log_cpu_exec(pc, cpu, tb); + log_cpu_exec(s.pc, cpu, tb); } return tb->tc.ptr; @@ -560,11 +558,7 @@ static void cpu_exec_longjmp_cleanup(CPUState *cpu) void cpu_exec_step_atomic(CPUState *cpu) { - CPUArchState *env = cpu_env(cpu); TranslationBlock *tb; - vaddr pc; - uint64_t cs_base; - uint32_t flags, cflags; int tb_exit; if (sigsetjmp(cpu->jmp_env, 0) == 0) { @@ -573,13 +567,13 @@ void cpu_exec_step_atomic(CPUState *cpu) g_assert(!cpu->running); cpu->running = true; - cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); + TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + s.cflags = curr_cflags(cpu); - cflags = curr_cflags(cpu); /* Execute in a serial context. */ - cflags &= ~CF_PARALLEL; + s.cflags &= ~CF_PARALLEL; /* After 1 insn, return and release the exclusive lock. */ - cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | 1; + s.cflags |= CF_NO_GOTO_TB | CF_NO_GOTO_PTR | 1; /* * No need to check_for_breakpoints here. * We only arrive in cpu_exec_step_atomic after beginning execution @@ -587,16 +581,16 @@ void cpu_exec_step_atomic(CPUState *cpu) * Any breakpoint for this insn will have been recognized earlier. */ - tb = tb_lookup(cpu, pc, cs_base, flags, cflags); + tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); if (tb == NULL) { mmap_lock(); - tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); + tb = tb_gen_code(cpu, s.pc, s.cs_base, s.flags, s.cflags); mmap_unlock(); } cpu_exec_enter(cpu); /* execute the generated code */ - trace_exec_tb(tb, pc); + trace_exec_tb(tb, s.pc); cpu_tb_exec(cpu, tb, &tb_exit); cpu_exec_exit(cpu); } else { @@ -941,11 +935,8 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) while (!cpu_handle_interrupt(cpu, &last_tb)) { TranslationBlock *tb; - vaddr pc; - uint64_t cs_base; - uint32_t flags, cflags; - - cpu_get_tb_cpu_state(cpu_env(cpu), &pc, &cs_base, &flags); + TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + s.cflags = cpu->cflags_next_tb; /* * When requested, use an exact setting for cflags for the next @@ -954,33 +945,32 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) * have CF_INVALID set, -1 is a convenient invalid value that * does not require tcg headers for cpu_common_reset. */ - cflags = cpu->cflags_next_tb; - if (cflags == -1) { - cflags = curr_cflags(cpu); + if (s.cflags == -1) { + s.cflags = curr_cflags(cpu); } else { cpu->cflags_next_tb = -1; } - if (check_for_breakpoints(cpu, pc, &cflags)) { + if (check_for_breakpoints(cpu, s.pc, &s.cflags)) { break; } - tb = tb_lookup(cpu, pc, cs_base, flags, cflags); + tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); if (tb == NULL) { CPUJumpCache *jc; uint32_t h; mmap_lock(); - tb = tb_gen_code(cpu, pc, cs_base, flags, cflags); + tb = tb_gen_code(cpu, s.pc, s.cs_base, s.flags, s.cflags); mmap_unlock(); /* * We add the TB in the virtual pc hash table * for the fast lookup */ - h = tb_jmp_cache_hash_func(pc); + h = tb_jmp_cache_hash_func(s.pc); jc = cpu->tb_jmp_cache; - jc->array[h].pc = pc; + jc->array[h].pc = s.pc; qatomic_set(&jc->array[h].tb, tb); } @@ -1000,7 +990,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) tb_add_jump(last_tb, tb_exit, tb); } - cpu_loop_exec_tb(cpu, tb, pc, &last_tb, &tb_exit); + cpu_loop_exec_tb(cpu, tb, s.pc, &last_tb, &tb_exit); /* Try to align the host and virtual clocks if the guest is in advance */ diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 31c7f9927f..f2766cedfc 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -590,13 +590,9 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) /* The exception probably happened in a helper. The CPU state should have been saved before calling it. Fetch the PC from there. */ CPUArchState *env = cpu_env(cpu); - vaddr pc; - uint64_t cs_base; - tb_page_addr_t addr; - uint32_t flags; + TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + tb_page_addr_t addr = get_page_addr_code(env, s.pc); - cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags); - addr = get_page_addr_code(env, pc); if (addr != -1) { tb_invalidate_phys_range(cpu, addr, addr); } diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index f5e5746976..43a39c2e13 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -16,10 +16,10 @@ #include "exec/memop.h" #include "exec/mmu-access-type.h" #include "exec/vaddr.h" +#include "accel/tcg/tb-cpu-state.h" #include "tcg/tcg-mo.h" -void cpu_get_tb_cpu_state(CPUArchState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags); +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs); struct TCGCPUOps { /** diff --git a/include/accel/tcg/tb-cpu-state.h b/include/accel/tcg/tb-cpu-state.h new file mode 100644 index 0000000000..8f912900ca --- /dev/null +++ b/include/accel/tcg/tb-cpu-state.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Definition of TCGTBCPUState. + */ + +#ifndef EXEC_TB_CPU_STATE_H +#define EXEC_TB_CPU_STATE_H + +#include "exec/vaddr.h" + +typedef struct TCGTBCPUState { + vaddr pc; + uint32_t flags; + uint32_t cflags; + uint64_t cs_base; +} TCGTBCPUState; + +#endif diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 134806e755..90e3a2e748 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -41,15 +41,16 @@ static vaddr alpha_cpu_get_pc(CPUState *cs) return env->pc; } -void cpu_get_tb_cpu_state(CPUAlphaState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *pflags = env->flags & ENV_FLAG_TB_MASK; + CPUAlphaState *env = cpu_env(cs); + uint32_t flags = env->flags & ENV_FLAG_TB_MASK; + #ifdef CONFIG_USER_ONLY - *pflags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; + flags |= TB_FLAG_UNALIGN * !cs->prctl_unalign_sigbus; #endif + + return (TCGTBCPUState){ .pc = env->pc, .flags = flags }; } static void alpha_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index 5315264c28..b49381924b 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -10,6 +10,7 @@ #include "internals.h" #include "cpu-features.h" #include "exec/helper-proto.h" +#include "exec/translation-block.h" #include "accel/tcg/cpu-ops.h" #include "cpregs.h" @@ -544,21 +545,22 @@ static bool mve_no_pred(CPUARMState *env) return true; } -void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUARMState *env = cpu_env(cs); CPUARMTBFlags flags; + vaddr pc; assert_hflags_rebuild_correctly(env); flags = env->hflags; if (EX_TBFLAG_ANY(flags, AARCH64_STATE)) { - *pc = env->pc; + pc = env->pc; if (cpu_isar_feature(aa64_bti, env_archcpu(env))) { DP_TBFLAG_A64(flags, BTYPE, env->btype); } } else { - *pc = env->regs[15]; + pc = env->regs[15]; if (arm_feature(env, ARM_FEATURE_M)) { if (arm_feature(env, ARM_FEATURE_M_SECURITY) && @@ -620,6 +622,9 @@ void cpu_get_tb_cpu_state(CPUARMState *env, vaddr *pc, DP_TBFLAG_ANY(flags, PSTATE__SS, 1); } - *pflags = flags.flags; - *cs_base = flags.flags2; + return (TCGTBCPUState){ + .pc = pc, + .flags = flags.flags, + .cs_base = flags.flags2, + }; } diff --git a/target/avr/cpu.c b/target/avr/cpu.c index d9fecb272e..683195b61d 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -54,14 +54,11 @@ static int avr_cpu_mmu_index(CPUState *cs, bool ifetch) return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; } -void cpu_get_tb_cpu_state(CPUAVRState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUAVRState *env = cpu_env(cs); uint32_t flags = 0; - *pc = env->pc_w * 2; - *cs_base = 0; - if (env->fullacc) { flags |= TB_FLAGS_FULL_ACCESS; } @@ -69,7 +66,7 @@ void cpu_get_tb_cpu_state(CPUAVRState *env, vaddr *pc, flags |= TB_FLAGS_SKIP; } - *pflags = flags; + return (TCGTBCPUState){ .pc = env->pc_w * 2, .flags = flags }; } static void avr_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index 2272f1222b..a7f76dd089 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -255,19 +255,20 @@ static vaddr hexagon_cpu_get_pc(CPUState *cs) return cpu_env(cs)->gpr[HEX_REG_PC]; } -void cpu_get_tb_cpu_state(CPUHexagonState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUHexagonState *env = cpu_env(cs); + vaddr pc = env->gpr[HEX_REG_PC]; uint32_t hex_flags = 0; - *pc = env->gpr[HEX_REG_PC]; - *cs_base = 0; - if (*pc == env->gpr[HEX_REG_SA0]) { + + if (pc == env->gpr[HEX_REG_SA0]) { hex_flags = FIELD_DP32(hex_flags, TB_FLAGS, IS_TIGHT_LOOP, 1); } - *flags = hex_flags; - if (*pc & PCALIGN_MASK) { + if (pc & PCALIGN_MASK) { hexagon_raise_exception_err(env, HEX_CAUSE_PC_NOT_ALIGNED, 0); } + + return (TCGTBCPUState){ .pc = pc, .flags = hex_flags }; } static void hexagon_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 4cdaf98ab1..40cbc191bb 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -51,11 +51,12 @@ static vaddr hppa_cpu_get_pc(CPUState *cs) env->iaoq_f & -4); } -void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, - uint64_t *pcsbase, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUHPPAState *env = cpu_env(cs); uint32_t flags = 0; uint64_t cs_base = 0; + vaddr pc; /* * TB lookup assumes that PC contains the complete virtual address. @@ -63,7 +64,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, * incomplete virtual address. This also means that we must separate * out current cpu privilege from the low bits of IAOQ_F. */ - *pc = hppa_cpu_get_pc(env_cpu(env)); + pc = hppa_cpu_get_pc(env_cpu(env)); flags |= (env->iaoq_f & 3) << TB_FLAG_PRIV_SHIFT; /* @@ -99,8 +100,7 @@ void cpu_get_tb_cpu_state(CPUHPPAState *env, vaddr *pc, } #endif - *pcsbase = cs_base; - *pflags = flags; + return (TCGTBCPUState){ .pc = pc, .flags = flags, .cs_base = cs_base }; } static void hppa_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index bb6f82befb..3004fb3023 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -48,18 +48,23 @@ static void x86_cpu_exec_exit(CPUState *cs) env->eflags = cpu_compute_eflags(env); } -void cpu_get_tb_cpu_state(CPUX86State *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *flags = env->hflags | + CPUX86State *env = cpu_env(cs); + uint32_t flags, cs_base; + vaddr pc; + + flags = env->hflags | (env->eflags & (IOPL_MASK | TF_MASK | RF_MASK | VM_MASK | AC_MASK)); if (env->hflags & HF_CS64_MASK) { - *cs_base = 0; - *pc = env->eip; + cs_base = 0; + pc = env->eip; } else { - *cs_base = env->segs[R_CS].base; - *pc = (uint32_t)(*cs_base + env->eip); + cs_base = env->segs[R_CS].base; + pc = (uint32_t)(cs_base + env->eip); } + + return (TCGTBCPUState){ .pc = pc, .flags = flags, .cs_base = cs_base }; } static void x86_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index be770b7e19..446cf43914 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -336,16 +336,18 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #endif -void cpu_get_tb_cpu_state(CPULoongArchState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; - *flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE; - *flags |= is_va32(env) * HW_FLAGS_VA32; + CPULoongArchState *env = cpu_env(cs); + uint32_t flags; + + flags = env->CSR_CRMD & (R_CSR_CRMD_PLV_MASK | R_CSR_CRMD_PG_MASK); + flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, FPE) * HW_FLAGS_EUEN_FPE; + flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, SXE) * HW_FLAGS_EUEN_SXE; + flags |= FIELD_EX64(env->CSR_EUEN, CSR_EUEN, ASXE) * HW_FLAGS_EUEN_ASXE; + flags |= is_va32(env) * HW_FLAGS_VA32; + + return (TCGTBCPUState){ .pc = env->pc, .flags = flags }; } static void loongarch_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index 2b4ec40509..b75ed6e887 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -23,6 +23,7 @@ #include "cpu.h" #include "migration/vmstate.h" #include "fpu/softfloat.h" +#include "exec/translation-block.h" #include "accel/tcg/cpu-ops.h" static void m68k_cpu_set_pc(CPUState *cs, vaddr value) @@ -39,20 +40,22 @@ static vaddr m68k_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPUM68KState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *flags = (env->macsr >> 4) & TB_FLAGS_MACSR; + CPUM68KState *env = cpu_env(cs); + uint32_t flags; + + flags = (env->macsr >> 4) & TB_FLAGS_MACSR; if (env->sr & SR_S) { - *flags |= TB_FLAGS_MSR_S; - *flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S; - *flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S; + flags |= TB_FLAGS_MSR_S; + flags |= (env->sfc << (TB_FLAGS_SFC_S_BIT - 2)) & TB_FLAGS_SFC_S; + flags |= (env->dfc << (TB_FLAGS_DFC_S_BIT - 2)) & TB_FLAGS_DFC_S; } if (M68K_SR_TRACE(env->sr) == M68K_SR_TRACE_ANY_INS) { - *flags |= TB_FLAGS_TRACE; + flags |= TB_FLAGS_TRACE; } + + return (TCGTBCPUState){ .pc = env->pc, .flags = flags }; } static void m68k_restore_state_to_opc(CPUState *cs, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 105ede0b1e..72a0d0583c 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -95,12 +95,15 @@ static vaddr mb_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPUMBState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK); - *cs_base = (*flags & IMM_FLAG ? env->imm : 0); + CPUMBState *env = cpu_env(cs); + + return (TCGTBCPUState){ + .pc = env->pc, + .flags = (env->iflags & IFLAGS_TB_MASK) | (env->msr & MSR_TB_MASK), + .cs_base = (env->iflags & IMM_FLAG ? env->imm : 0), + }; } static void mb_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index ab00adf86b..b0f7612a64 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -549,13 +549,15 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) return mips_env_mmu_index(cpu_env(cs)); } -void cpu_get_tb_cpu_state(CPUMIPSState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->active_tc.PC; - *cs_base = 0; - *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | - MIPS_HFLAG_HWRENA_ULR); + CPUMIPSState *env = cpu_env(cs); + + return (TCGTBCPUState){ + .pc = env->active_tc.PC, + .flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | + MIPS_HFLAG_HWRENA_ULR), + }; } static const TCGCPUOps mips_tcg_ops = { diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index d798127d67..aba4639bbb 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -41,14 +41,16 @@ static vaddr openrisc_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPUOpenRISCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *flags = (env->dflag ? TB_FLAGS_DFLAG : 0) - | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0) - | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE)); + CPUOpenRISCState *env = cpu_env(cs); + + return (TCGTBCPUState){ + .pc = env->pc, + .flags = ((env->dflag ? TB_FLAGS_DFLAG : 0) + | (cpu_get_gpr(env, 0) ? 0 : TB_FLAGS_R0_0) + | (env->sr & (SR_SM | SR_DME | SR_IME | SR_OVE))), + }; } static void openrisc_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index 8d248bcbb9..ccaf2b0343 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -256,9 +256,9 @@ void hreg_update_pmu_hflags(CPUPPCState *env) env->hflags |= hreg_compute_pmu_hflags_value(env); } -void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUPPCState *env = cpu_env(cs); uint32_t hflags_current = env->hflags; #ifdef CONFIG_DEBUG_TCG @@ -270,9 +270,7 @@ void cpu_get_tb_cpu_state(CPUPPCState *env, vaddr *pc, } #endif - *pc = env->nip; - *cs_base = 0; - *flags = hflags_current; + return (TCGTBCPUState){ .pc = env->nip, .flags = hflags_current }; } void cpu_interrupt_exittb(CPUState *cs) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index e67de7dfe2..927153377e 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -98,17 +98,14 @@ static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch) return riscv_env_mmu_index(cpu_env(cs), ifetch); } -void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPURISCVState *env = cpu_env(cs); RISCVCPU *cpu = env_archcpu(env); RISCVExtStatus fs, vs; uint32_t flags = 0; bool pm_signext = riscv_cpu_virt_mem_enabled(env); - *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; - *cs_base = 0; - if (cpu->cfg.ext_zve32x) { /* * If env->vl equals to VLMAX, we can use generic vector operation @@ -192,7 +189,10 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, flags = FIELD_DP32(flags, TB_FLAGS, PM_PMM, riscv_pm_get_pmm(env)); flags = FIELD_DP32(flags, TB_FLAGS, PM_SIGNEXTEND, pm_signext); - *pflags = flags; + return (TCGTBCPUState){ + .pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc, + .flags = flags + }; } static void riscv_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index e8b47be675..be778c9f65 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -44,13 +44,15 @@ static vaddr rx_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPURXState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *flags = FIELD_DP32(0, PSW, PM, env->psw_pm); - *flags = FIELD_DP32(*flags, PSW, U, env->psw_u); + CPURXState *env = cpu_env(cs); + uint32_t flags = 0; + + flags = FIELD_DP32(flags, PSW, PM, env->psw_pm); + flags = FIELD_DP32(flags, PSW, U, env->psw_u); + + return (TCGTBCPUState){ .pc = env->pc, .flags = flags }; } static void rx_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 435b2034ff..279289f265 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -309,9 +309,9 @@ static int s390x_cpu_mmu_index(CPUState *cs, bool ifetch) return s390x_env_mmu_index(cpu_env(cs), ifetch); } -void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { + CPUS390XState *env = cpu_env(cs); uint32_t flags; if (env->psw.addr & 1) { @@ -323,9 +323,6 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, tcg_s390_program_interrupt(env, PGM_SPECIFICATION, 0); } - *pc = env->psw.addr; - *cs_base = env->ex_value; - flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW; if (env->psw.mask & PSW_MASK_PER) { flags |= env->cregs[9] & (FLAG_MASK_PER_BRANCH | @@ -342,7 +339,12 @@ void cpu_get_tb_cpu_state(CPUS390XState *env, vaddr *pc, if (env->cregs[0] & CR0_VECTOR) { flags |= FLAG_MASK_VECTOR; } - *pflags = flags; + + return (TCGTBCPUState){ + .pc = env->psw.addr, + .flags = flags, + .cs_base = env->ex_value, + }; } static const TCGCPUOps s390_tcg_ops = { diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index 5fb18bf55e..cbd43b55e5 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -43,19 +43,27 @@ static vaddr superh_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPUSH4State *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - /* For a gUSA region, notice the end of the region. */ - *cs_base = env->flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0; - *flags = env->flags + CPUSH4State *env = cpu_env(cs); + uint32_t flags; + + flags = env->flags | (env->fpscr & TB_FLAG_FPSCR_MASK) | (env->sr & TB_FLAG_SR_MASK) | (env->movcal_backup ? TB_FLAG_PENDING_MOVCA : 0); /* Bit 3 */ #ifdef CONFIG_USER_ONLY - *flags |= TB_FLAG_UNALIGN * !env_cpu(env)->prctl_unalign_sigbus; + flags |= TB_FLAG_UNALIGN * !cs->prctl_unalign_sigbus; #endif + + return (TCGTBCPUState){ + .pc = env->pc, + .flags = flags, +#ifdef CONFIG_USER_ONLY + /* For a gUSA region, notice the end of the region. */ + .cs_base = flags & TB_FLAG_GUSA_MASK ? env->gregs[0] : 0, +#endif + }; } static void superh_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index bbdea8556a..6166b81f71 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -716,13 +716,11 @@ static void sparc_cpu_synchronize_from_tb(CPUState *cs, cpu->env.npc = tb->cs_base; } -void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *pflags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - uint32_t flags; - *pc = env->pc; - *cs_base = env->npc; - flags = cpu_mmu_index(env_cpu(env), false); + CPUSPARCState *env = cpu_env(cs); + uint32_t flags = cpu_mmu_index(cs, false); + #ifndef CONFIG_USER_ONLY if (cpu_supervisor_mode(env)) { flags |= TB_FLAG_SUPER; @@ -751,7 +749,12 @@ void cpu_get_tb_cpu_state(CPUSPARCState *env, vaddr *pc, } #endif /* !CONFIG_USER_ONLY */ #endif /* TARGET_SPARC64 */ - *pflags = flags; + + return (TCGTBCPUState){ + .pc = env->pc, + .flags = flags, + .cs_base = env->npc, + }; } static void sparc_restore_state_to_opc(CPUState *cs, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 81b3bb6362..1151a812b6 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -45,16 +45,14 @@ static vaddr tricore_cpu_get_pc(CPUState *cs) return cpu_env(cs)->PC; } -void cpu_get_tb_cpu_state(CPUTriCoreState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - uint32_t new_flags = 0; - *pc = env->PC; - *cs_base = 0; + CPUTriCoreState *env = cpu_env(cs); - new_flags |= FIELD_DP32(new_flags, TB_FLAGS, PRIV, - extract32(env->PSW, 10, 2)); - *flags = new_flags; + return (TCGTBCPUState){ + .pc = env->PC, + .flags = FIELD_DP32(0, TB_FLAGS, PRIV, extract32(env->PSW, 10, 2)), + }; } static void tricore_cpu_synchronize_from_tb(CPUState *cs, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index c78ef9421c..431b7ebd7b 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -55,15 +55,15 @@ static vaddr xtensa_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, - uint64_t *cs_base, uint32_t *flags) +TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) { - *pc = env->pc; - *cs_base = 0; - *flags = 0; - *flags |= xtensa_get_ring(env); + CPUXtensaState *env = cpu_env(cs); + uint32_t flags = 0; + target_ulong cs_base = 0; + + flags |= xtensa_get_ring(env); if (env->sregs[PS] & PS_EXCM) { - *flags |= XTENSA_TBFLAG_EXCM; + flags |= XTENSA_TBFLAG_EXCM; } else if (xtensa_option_enabled(env->config, XTENSA_OPTION_LOOP)) { target_ulong lend_dist = env->sregs[LEND] - (env->pc & -(1u << TARGET_PAGE_BITS)); @@ -85,26 +85,26 @@ void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, if (lend_dist < (1u << TARGET_PAGE_BITS) + env->config->max_insn_size) { target_ulong lbeg_off = env->sregs[LEND] - env->sregs[LBEG]; - *cs_base = lend_dist; + cs_base = lend_dist; if (lbeg_off < 256) { - *cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT; + cs_base |= lbeg_off << XTENSA_CSBASE_LBEG_OFF_SHIFT; } } } if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && (env->sregs[LITBASE] & 1)) { - *flags |= XTENSA_TBFLAG_LITBASE; + flags |= XTENSA_TBFLAG_LITBASE; } if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) { if (xtensa_get_cintlevel(env) < env->config->debug_level) { - *flags |= XTENSA_TBFLAG_DEBUG; + flags |= XTENSA_TBFLAG_DEBUG; } if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { - *flags |= XTENSA_TBFLAG_ICOUNT; + flags |= XTENSA_TBFLAG_ICOUNT; } } if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { - *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; + flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; } if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) && (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) { @@ -112,15 +112,21 @@ void cpu_get_tb_cpu_state(CPUXtensaState *env, vaddr *pc, (env->sregs[WINDOW_BASE] + 1); uint32_t w = ctz32(windowstart | 0x8); - *flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE; - *flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT, + flags |= (w << XTENSA_TBFLAG_WINDOW_SHIFT) | XTENSA_TBFLAG_CWOE; + flags |= extract32(env->sregs[PS], PS_CALLINC_SHIFT, PS_CALLINC_LEN) << XTENSA_TBFLAG_CALLINC_SHIFT; } else { - *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; + flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; } if (env->yield_needed) { - *flags |= XTENSA_TBFLAG_YIELD; + flags |= XTENSA_TBFLAG_YIELD; } + + return (TCGTBCPUState){ + .pc = env->pc, + .flags = flags, + .cs_base = cs_base, + }; } static void xtensa_restore_state_to_opc(CPUState *cs, From c37f8978d9e23066132a0717b8cb4ed37a0cbd96 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 27 Apr 2025 17:22:04 -0700 Subject: [PATCH 0561/2760] accel/tcg: Move cpu_get_tb_cpu_state to TCGCPUOps Move the global function name to a hook on TCGCPUOps. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 7 ++++--- accel/tcg/translate-all.c | 2 +- include/accel/tcg/cpu-ops.h | 8 ++++++-- target/alpha/cpu.c | 3 ++- target/arm/cpu.c | 1 + target/arm/internals.h | 2 ++ target/arm/tcg/cpu-v7m.c | 1 + target/arm/tcg/hflags.c | 2 +- target/avr/cpu.c | 3 ++- target/hexagon/cpu.c | 3 ++- target/hppa/cpu.c | 3 ++- target/i386/tcg/tcg-cpu.c | 3 ++- target/loongarch/cpu.c | 3 ++- target/m68k/cpu.c | 3 ++- target/microblaze/cpu.c | 3 ++- target/mips/cpu.c | 3 ++- target/openrisc/cpu.c | 3 ++- target/ppc/cpu_init.c | 2 +- target/ppc/helper_regs.c | 3 ++- target/ppc/internal.h | 3 +++ target/riscv/tcg/tcg-cpu.c | 3 ++- target/rx/cpu.c | 3 ++- target/s390x/cpu.c | 3 ++- target/sh4/cpu.c | 3 ++- target/sparc/cpu.c | 3 ++- target/tricore/cpu.c | 3 ++- target/xtensa/cpu.c | 3 ++- 27 files changed, 56 insertions(+), 26 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index f7e7e7949d..4a405d7b56 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -395,7 +395,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) */ cpu->neg.can_do_io = true; - TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + TCGTBCPUState s = cpu->cc->tcg_ops->get_tb_cpu_state(cpu); s.cflags = curr_cflags(cpu); if (check_for_breakpoints(cpu, s.pc, &s.cflags)) { @@ -567,7 +567,7 @@ void cpu_exec_step_atomic(CPUState *cpu) g_assert(!cpu->running); cpu->running = true; - TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + TCGTBCPUState s = cpu->cc->tcg_ops->get_tb_cpu_state(cpu); s.cflags = curr_cflags(cpu); /* Execute in a serial context. */ @@ -935,7 +935,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) while (!cpu_handle_interrupt(cpu, &last_tb)) { TranslationBlock *tb; - TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + TCGTBCPUState s = cpu->cc->tcg_ops->get_tb_cpu_state(cpu); s.cflags = cpu->cflags_next_tb; /* @@ -1052,6 +1052,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp) assert(tcg_ops->cpu_exec_reset); #endif /* !CONFIG_USER_ONLY */ assert(tcg_ops->translate_code); + assert(tcg_ops->get_tb_cpu_state); assert(tcg_ops->mmu_index); tcg_ops->initialize(); tcg_target_initialized = true; diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index f2766cedfc..97aadee52c 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -590,7 +590,7 @@ void tb_check_watchpoint(CPUState *cpu, uintptr_t retaddr) /* The exception probably happened in a helper. The CPU state should have been saved before calling it. Fetch the PC from there. */ CPUArchState *env = cpu_env(cpu); - TCGTBCPUState s = cpu_get_tb_cpu_state(cpu); + TCGTBCPUState s = cpu->cc->tcg_ops->get_tb_cpu_state(cpu); tb_page_addr_t addr = get_page_addr_code(env, s.pc); if (addr != -1) { diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 43a39c2e13..23cd6af0b2 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -19,8 +19,6 @@ #include "accel/tcg/tb-cpu-state.h" #include "tcg/tcg-mo.h" -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs); - struct TCGCPUOps { /** * mttcg_supported: multi-threaded TCG is supported @@ -63,6 +61,12 @@ struct TCGCPUOps { */ void (*translate_code)(CPUState *cpu, TranslationBlock *tb, int *max_insns, vaddr pc, void *host_pc); + /** + * @get_tb_cpu_state: Extract CPU state for a TCG #TranslationBlock + * + * Fill in all data required to select or compile a TranslationBlock. + */ + TCGTBCPUState (*get_tb_cpu_state)(CPUState *cs); /** * @synchronize_from_tb: Synchronize state from a TCG #TranslationBlock * diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 90e3a2e748..890b84c032 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -41,7 +41,7 @@ static vaddr alpha_cpu_get_pc(CPUState *cs) return env->pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState alpha_get_tb_cpu_state(CPUState *cs) { CPUAlphaState *env = cpu_env(cs); uint32_t flags = env->flags & ENV_FLAG_TB_MASK; @@ -251,6 +251,7 @@ static const TCGCPUOps alpha_tcg_ops = { .initialize = alpha_translate_init, .translate_code = alpha_translate_code, + .get_tb_cpu_state = alpha_get_tb_cpu_state, .synchronize_from_tb = alpha_cpu_synchronize_from_tb, .restore_state_to_opc = alpha_restore_state_to_opc, .mmu_index = alpha_cpu_mmu_index, diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 3dde70b04a..2020aec54a 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2693,6 +2693,7 @@ static const TCGCPUOps arm_tcg_ops = { .initialize = arm_translate_init, .translate_code = arm_translate_code, + .get_tb_cpu_state = arm_get_tb_cpu_state, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, .restore_state_to_opc = arm_restore_state_to_opc, diff --git a/target/arm/internals.h b/target/arm/internals.h index 382a4d1015..660d3a88e0 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -28,6 +28,7 @@ #include "exec/hwaddr.h" #include "exec/vaddr.h" #include "exec/breakpoint.h" +#include "accel/tcg/tb-cpu-state.h" #include "hw/registerfields.h" #include "tcg/tcg-gvec-desc.h" #include "system/memory.h" @@ -372,6 +373,7 @@ void arm_restore_state_to_opc(CPUState *cs, const uint64_t *data); #ifdef CONFIG_TCG +TCGTBCPUState arm_get_tb_cpu_state(CPUState *cs); void arm_cpu_synchronize_from_tb(CPUState *cs, const TranslationBlock *tb); /* Our implementation of TCGCPUOps::cpu_exec_halt */ diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 5c8c374885..95b23d9b55 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -238,6 +238,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = { .initialize = arm_translate_init, .translate_code = arm_translate_code, + .get_tb_cpu_state = arm_get_tb_cpu_state, .synchronize_from_tb = arm_cpu_synchronize_from_tb, .debug_excp_handler = arm_debug_excp_handler, .restore_state_to_opc = arm_restore_state_to_opc, diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index b49381924b..fd407a7b28 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -545,7 +545,7 @@ static bool mve_no_pred(CPUARMState *env) return true; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +TCGTBCPUState arm_get_tb_cpu_state(CPUState *cs) { CPUARMState *env = cpu_env(cs); CPUARMTBFlags flags; diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 683195b61d..250241541b 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -54,7 +54,7 @@ static int avr_cpu_mmu_index(CPUState *cs, bool ifetch) return ifetch ? MMU_CODE_IDX : MMU_DATA_IDX; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState avr_get_tb_cpu_state(CPUState *cs) { CPUAVRState *env = cpu_env(cs); uint32_t flags = 0; @@ -241,6 +241,7 @@ static const TCGCPUOps avr_tcg_ops = { .mttcg_supported = false, .initialize = avr_cpu_tcg_init, .translate_code = avr_cpu_translate_code, + .get_tb_cpu_state = avr_get_tb_cpu_state, .synchronize_from_tb = avr_cpu_synchronize_from_tb, .restore_state_to_opc = avr_restore_state_to_opc, .mmu_index = avr_cpu_mmu_index, diff --git a/target/hexagon/cpu.c b/target/hexagon/cpu.c index a7f76dd089..a5a04173ab 100644 --- a/target/hexagon/cpu.c +++ b/target/hexagon/cpu.c @@ -255,7 +255,7 @@ static vaddr hexagon_cpu_get_pc(CPUState *cs) return cpu_env(cs)->gpr[HEX_REG_PC]; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState hexagon_get_tb_cpu_state(CPUState *cs) { CPUHexagonState *env = cpu_env(cs); vaddr pc = env->gpr[HEX_REG_PC]; @@ -344,6 +344,7 @@ static const TCGCPUOps hexagon_tcg_ops = { .mttcg_supported = false, .initialize = hexagon_translate_init, .translate_code = hexagon_translate_code, + .get_tb_cpu_state = hexagon_get_tb_cpu_state, .synchronize_from_tb = hexagon_cpu_synchronize_from_tb, .restore_state_to_opc = hexagon_restore_state_to_opc, .mmu_index = hexagon_cpu_mmu_index, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 40cbc191bb..6465181543 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -51,7 +51,7 @@ static vaddr hppa_cpu_get_pc(CPUState *cs) env->iaoq_f & -4); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState hppa_get_tb_cpu_state(CPUState *cs) { CPUHPPAState *env = cpu_env(cs); uint32_t flags = 0; @@ -262,6 +262,7 @@ static const TCGCPUOps hppa_tcg_ops = { .initialize = hppa_translate_init, .translate_code = hppa_translate_code, + .get_tb_cpu_state = hppa_get_tb_cpu_state, .synchronize_from_tb = hppa_cpu_synchronize_from_tb, .restore_state_to_opc = hppa_restore_state_to_opc, .mmu_index = hppa_cpu_mmu_index, diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 3004fb3023..179dfdf064 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -48,7 +48,7 @@ static void x86_cpu_exec_exit(CPUState *cs) env->eflags = cpu_compute_eflags(env); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState x86_get_tb_cpu_state(CPUState *cs) { CPUX86State *env = cpu_env(cs); uint32_t flags, cs_base; @@ -160,6 +160,7 @@ const TCGCPUOps x86_tcg_ops = { .guest_default_memory_order = TCG_MO_ALL & ~TCG_MO_ST_LD, .initialize = tcg_x86_init, .translate_code = x86_translate_code, + .get_tb_cpu_state = x86_get_tb_cpu_state, .synchronize_from_tb = x86_cpu_synchronize_from_tb, .restore_state_to_opc = x86_restore_state_to_opc, .mmu_index = x86_cpu_mmu_index, diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index 446cf43914..f7535d1be7 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -336,7 +336,7 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #endif -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState loongarch_get_tb_cpu_state(CPUState *cs) { CPULoongArchState *env = cpu_env(cs); uint32_t flags; @@ -882,6 +882,7 @@ static const TCGCPUOps loongarch_tcg_ops = { .initialize = loongarch_translate_init, .translate_code = loongarch_translate_code, + .get_tb_cpu_state = loongarch_get_tb_cpu_state, .synchronize_from_tb = loongarch_cpu_synchronize_from_tb, .restore_state_to_opc = loongarch_restore_state_to_opc, .mmu_index = loongarch_cpu_mmu_index, diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index b75ed6e887..c5196a612e 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -40,7 +40,7 @@ static vaddr m68k_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState m68k_get_tb_cpu_state(CPUState *cs) { CPUM68KState *env = cpu_env(cs); uint32_t flags; @@ -613,6 +613,7 @@ static const TCGCPUOps m68k_tcg_ops = { .initialize = m68k_tcg_init, .translate_code = m68k_translate_code, + .get_tb_cpu_state = m68k_get_tb_cpu_state, .restore_state_to_opc = m68k_restore_state_to_opc, .mmu_index = m68k_cpu_mmu_index, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 72a0d0583c..d069e40e70 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -95,7 +95,7 @@ static vaddr mb_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState mb_get_tb_cpu_state(CPUState *cs) { CPUMBState *env = cpu_env(cs); @@ -442,6 +442,7 @@ static const TCGCPUOps mb_tcg_ops = { .initialize = mb_tcg_init, .translate_code = mb_translate_code, + .get_tb_cpu_state = mb_get_tb_cpu_state, .synchronize_from_tb = mb_cpu_synchronize_from_tb, .restore_state_to_opc = mb_restore_state_to_opc, .mmu_index = mb_cpu_mmu_index, diff --git a/target/mips/cpu.c b/target/mips/cpu.c index b0f7612a64..4cbfb9435a 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -549,7 +549,7 @@ static int mips_cpu_mmu_index(CPUState *cs, bool ifunc) return mips_env_mmu_index(cpu_env(cs)); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState mips_get_tb_cpu_state(CPUState *cs) { CPUMIPSState *env = cpu_env(cs); @@ -566,6 +566,7 @@ static const TCGCPUOps mips_tcg_ops = { .initialize = mips_tcg_init, .translate_code = mips_translate_code, + .get_tb_cpu_state = mips_get_tb_cpu_state, .synchronize_from_tb = mips_cpu_synchronize_from_tb, .restore_state_to_opc = mips_restore_state_to_opc, .mmu_index = mips_cpu_mmu_index, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index aba4639bbb..054ad33360 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -41,7 +41,7 @@ static vaddr openrisc_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState openrisc_get_tb_cpu_state(CPUState *cs) { CPUOpenRISCState *env = cpu_env(cs); @@ -258,6 +258,7 @@ static const TCGCPUOps openrisc_tcg_ops = { .initialize = openrisc_translate_init, .translate_code = openrisc_translate_code, + .get_tb_cpu_state = openrisc_get_tb_cpu_state, .synchronize_from_tb = openrisc_cpu_synchronize_from_tb, .restore_state_to_opc = openrisc_restore_state_to_opc, .mmu_index = openrisc_cpu_mmu_index, diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 3a01731402..cf88a18244 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -45,7 +45,6 @@ #include "internal.h" #include "spr_common.h" #include "power8-pmu.h" - #ifndef CONFIG_USER_ONLY #include "hw/boards.h" #include "hw/intc/intc.h" @@ -7483,6 +7482,7 @@ static const TCGCPUOps ppc_tcg_ops = { .guest_default_memory_order = 0, .initialize = ppc_translate_init, .translate_code = ppc_translate_code, + .get_tb_cpu_state = ppc_get_tb_cpu_state, .restore_state_to_opc = ppc_restore_state_to_opc, .mmu_index = ppc_cpu_mmu_index, diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c index ccaf2b0343..7e5726871e 100644 --- a/target/ppc/helper_regs.c +++ b/target/ppc/helper_regs.c @@ -28,6 +28,7 @@ #include "cpu-models.h" #include "spr_common.h" #include "accel/tcg/cpu-ops.h" +#include "internal.h" /* Swap temporary saved registers with GPRs */ void hreg_swap_gpr_tgpr(CPUPPCState *env) @@ -256,7 +257,7 @@ void hreg_update_pmu_hflags(CPUPPCState *env) env->hflags |= hreg_compute_pmu_hflags_value(env); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +TCGTBCPUState ppc_get_tb_cpu_state(CPUState *cs) { CPUPPCState *env = cpu_env(cs); uint32_t hflags_current = env->hflags; diff --git a/target/ppc/internal.h b/target/ppc/internal.h index 9012d3809c..7723350227 100644 --- a/target/ppc/internal.h +++ b/target/ppc/internal.h @@ -21,6 +21,7 @@ #include "exec/breakpoint.h" #include "hw/registerfields.h" #include "exec/page-protection.h" +#include "accel/tcg/tb-cpu-state.h" /* PM instructions */ typedef enum { @@ -308,4 +309,6 @@ static inline int ger_pack_masks(int pmsk, int ymsk, int xmsk) return msk; } +TCGTBCPUState ppc_get_tb_cpu_state(CPUState *cs); + #endif /* PPC_INTERNAL_H */ diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 927153377e..55e00972b7 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -98,7 +98,7 @@ static int riscv_cpu_mmu_index(CPUState *cs, bool ifetch) return riscv_env_mmu_index(cpu_env(cs), ifetch); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState riscv_get_tb_cpu_state(CPUState *cs) { CPURISCVState *env = cpu_env(cs); RISCVCPU *cpu = env_archcpu(env); @@ -243,6 +243,7 @@ const TCGCPUOps riscv_tcg_ops = { .initialize = riscv_translate_init, .translate_code = riscv_translate_code, + .get_tb_cpu_state = riscv_get_tb_cpu_state, .synchronize_from_tb = riscv_cpu_synchronize_from_tb, .restore_state_to_opc = riscv_restore_state_to_opc, .mmu_index = riscv_cpu_mmu_index, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index be778c9f65..36eba75545 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -44,7 +44,7 @@ static vaddr rx_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState rx_get_tb_cpu_state(CPUState *cs) { CPURXState *env = cpu_env(cs); uint32_t flags = 0; @@ -220,6 +220,7 @@ static const TCGCPUOps rx_tcg_ops = { .initialize = rx_translate_init, .translate_code = rx_translate_code, + .get_tb_cpu_state = rx_get_tb_cpu_state, .synchronize_from_tb = rx_cpu_synchronize_from_tb, .restore_state_to_opc = rx_restore_state_to_opc, .mmu_index = rx_cpu_mmu_index, diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 279289f265..9c1158ebcc 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -309,7 +309,7 @@ static int s390x_cpu_mmu_index(CPUState *cs, bool ifetch) return s390x_env_mmu_index(cpu_env(cs), ifetch); } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState s390x_get_tb_cpu_state(CPUState *cs) { CPUS390XState *env = cpu_env(cs); uint32_t flags; @@ -358,6 +358,7 @@ static const TCGCPUOps s390_tcg_ops = { .initialize = s390x_translate_init, .translate_code = s390x_translate_code, + .get_tb_cpu_state = s390x_get_tb_cpu_state, .restore_state_to_opc = s390x_restore_state_to_opc, .mmu_index = s390x_cpu_mmu_index, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index cbd43b55e5..b35f18e250 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -43,7 +43,7 @@ static vaddr superh_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState superh_get_tb_cpu_state(CPUState *cs) { CPUSH4State *env = cpu_env(cs); uint32_t flags; @@ -289,6 +289,7 @@ static const TCGCPUOps superh_tcg_ops = { .initialize = sh4_translate_init, .translate_code = sh4_translate_code, + .get_tb_cpu_state = superh_get_tb_cpu_state, .synchronize_from_tb = superh_cpu_synchronize_from_tb, .restore_state_to_opc = superh_restore_state_to_opc, .mmu_index = sh4_cpu_mmu_index, diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 6166b81f71..2a3e408923 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -716,7 +716,7 @@ static void sparc_cpu_synchronize_from_tb(CPUState *cs, cpu->env.npc = tb->cs_base; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState sparc_get_tb_cpu_state(CPUState *cs) { CPUSPARCState *env = cpu_env(cs); uint32_t flags = cpu_mmu_index(cs, false); @@ -1029,6 +1029,7 @@ static const TCGCPUOps sparc_tcg_ops = { .initialize = sparc_tcg_init, .translate_code = sparc_translate_code, + .get_tb_cpu_state = sparc_get_tb_cpu_state, .synchronize_from_tb = sparc_cpu_synchronize_from_tb, .restore_state_to_opc = sparc_restore_state_to_opc, .mmu_index = sparc_cpu_mmu_index, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index 1151a812b6..e56f90fde9 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -45,7 +45,7 @@ static vaddr tricore_cpu_get_pc(CPUState *cs) return cpu_env(cs)->PC; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState tricore_get_tb_cpu_state(CPUState *cs) { CPUTriCoreState *env = cpu_env(cs); @@ -185,6 +185,7 @@ static const TCGCPUOps tricore_tcg_ops = { .mttcg_supported = false, .initialize = tricore_tcg_init, .translate_code = tricore_translate_code, + .get_tb_cpu_state = tricore_get_tb_cpu_state, .synchronize_from_tb = tricore_cpu_synchronize_from_tb, .restore_state_to_opc = tricore_restore_state_to_opc, .mmu_index = tricore_cpu_mmu_index, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 431b7ebd7b..91b71b6caa 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -55,7 +55,7 @@ static vaddr xtensa_cpu_get_pc(CPUState *cs) return cpu->env.pc; } -TCGTBCPUState cpu_get_tb_cpu_state(CPUState *cs) +static TCGTBCPUState xtensa_get_tb_cpu_state(CPUState *cs) { CPUXtensaState *env = cpu_env(cs); uint32_t flags = 0; @@ -312,6 +312,7 @@ static const TCGCPUOps xtensa_tcg_ops = { .initialize = xtensa_translate_init, .translate_code = xtensa_translate_code, .debug_excp_handler = xtensa_breakpoint_handler, + .get_tb_cpu_state = xtensa_get_tb_cpu_state, .restore_state_to_opc = xtensa_restore_state_to_opc, .mmu_index = xtensa_cpu_mmu_index, From b46357db323bf21d2816970a2f15540dfff84ecc Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 12:13:18 -0700 Subject: [PATCH 0562/2760] accel/tcg: Pass TCGTBCPUState to tb_lookup Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 4a405d7b56..808983e461 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -232,35 +232,33 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc, * * Returns: an existing translation block or NULL. */ -static inline TranslationBlock *tb_lookup(CPUState *cpu, vaddr pc, - uint64_t cs_base, uint32_t flags, - uint32_t cflags) +static inline TranslationBlock *tb_lookup(CPUState *cpu, TCGTBCPUState s) { TranslationBlock *tb; CPUJumpCache *jc; uint32_t hash; /* we should never be trying to look up an INVALID tb */ - tcg_debug_assert(!(cflags & CF_INVALID)); + tcg_debug_assert(!(s.cflags & CF_INVALID)); - hash = tb_jmp_cache_hash_func(pc); + hash = tb_jmp_cache_hash_func(s.pc); jc = cpu->tb_jmp_cache; tb = qatomic_read(&jc->array[hash].tb); if (likely(tb && - jc->array[hash].pc == pc && - tb->cs_base == cs_base && - tb->flags == flags && - tb_cflags(tb) == cflags)) { + jc->array[hash].pc == s.pc && + tb->cs_base == s.cs_base && + tb->flags == s.flags && + tb_cflags(tb) == s.cflags)) { goto hit; } - tb = tb_htable_lookup(cpu, pc, cs_base, flags, cflags); + tb = tb_htable_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); if (tb == NULL) { return NULL; } - jc->array[hash].pc = pc; + jc->array[hash].pc = s.pc; qatomic_set(&jc->array[hash].tb, tb); hit: @@ -268,7 +266,7 @@ hit: * As long as tb is not NULL, the contents are consistent. Therefore, * the virtual PC has to match for non-CF_PCREL translations. */ - assert((tb_cflags(tb) & CF_PCREL) || tb->pc == pc); + assert((tb_cflags(tb) & CF_PCREL) || tb->pc == s.pc); return tb; } @@ -402,7 +400,7 @@ const void *HELPER(lookup_tb_ptr)(CPUArchState *env) cpu_loop_exit(cpu); } - tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_lookup(cpu, s); if (tb == NULL) { return tcg_code_gen_epilogue; } @@ -581,7 +579,7 @@ void cpu_exec_step_atomic(CPUState *cpu) * Any breakpoint for this insn will have been recognized earlier. */ - tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_lookup(cpu, s); if (tb == NULL) { mmap_lock(); tb = tb_gen_code(cpu, s.pc, s.cs_base, s.flags, s.cflags); @@ -955,7 +953,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) break; } - tb = tb_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_lookup(cpu, s); if (tb == NULL) { CPUJumpCache *jc; uint32_t h; From 088caf3de4e48e70d6716195afc0e47edd823ac0 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 13:02:32 -0700 Subject: [PATCH 0563/2760] accel/tcg: Pass TCGTBCPUState to tb_htable_lookup Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 808983e461..8e6899950e 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -195,26 +195,24 @@ static bool tb_lookup_cmp(const void *p, const void *d) return false; } -static TranslationBlock *tb_htable_lookup(CPUState *cpu, vaddr pc, - uint64_t cs_base, uint32_t flags, - uint32_t cflags) +static TranslationBlock *tb_htable_lookup(CPUState *cpu, TCGTBCPUState s) { tb_page_addr_t phys_pc; struct tb_desc desc; uint32_t h; desc.env = cpu_env(cpu); - desc.cs_base = cs_base; - desc.flags = flags; - desc.cflags = cflags; - desc.pc = pc; - phys_pc = get_page_addr_code(desc.env, pc); + desc.cs_base = s.cs_base; + desc.flags = s.flags; + desc.cflags = s.cflags; + desc.pc = s.pc; + phys_pc = get_page_addr_code(desc.env, s.pc); if (phys_pc == -1) { return NULL; } desc.page_addr0 = phys_pc; - h = tb_hash_func(phys_pc, (cflags & CF_PCREL ? 0 : pc), - flags, cs_base, cflags); + h = tb_hash_func(phys_pc, (s.cflags & CF_PCREL ? 0 : s.pc), + s.flags, s.cs_base, s.cflags); return qht_lookup_custom(&tb_ctx.htable, &desc, h, tb_lookup_cmp); } @@ -253,7 +251,7 @@ static inline TranslationBlock *tb_lookup(CPUState *cpu, TCGTBCPUState s) goto hit; } - tb = tb_htable_lookup(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_htable_lookup(cpu, s); if (tb == NULL) { return NULL; } From cec7176a23bfb46ce54481f278e235f58eb9c456 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 18:39:08 -0700 Subject: [PATCH 0564/2760] accel/tcg: Use TCGTBCPUState in struct tb_desc Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 8e6899950e..4ad84c2db8 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -150,12 +150,9 @@ static void init_delay_params(SyncClocks *sc, const CPUState *cpu) #endif /* CONFIG USER ONLY */ struct tb_desc { - vaddr pc; - uint64_t cs_base; + TCGTBCPUState s; CPUArchState *env; tb_page_addr_t page_addr0; - uint32_t flags; - uint32_t cflags; }; static bool tb_lookup_cmp(const void *p, const void *d) @@ -163,11 +160,11 @@ static bool tb_lookup_cmp(const void *p, const void *d) const TranslationBlock *tb = p; const struct tb_desc *desc = d; - if ((tb_cflags(tb) & CF_PCREL || tb->pc == desc->pc) && + if ((tb_cflags(tb) & CF_PCREL || tb->pc == desc->s.pc) && tb_page_addr0(tb) == desc->page_addr0 && - tb->cs_base == desc->cs_base && - tb->flags == desc->flags && - tb_cflags(tb) == desc->cflags) { + tb->cs_base == desc->s.cs_base && + tb->flags == desc->s.flags && + tb_cflags(tb) == desc->s.cflags) { /* check next page if needed */ tb_page_addr_t tb_phys_page1 = tb_page_addr1(tb); if (tb_phys_page1 == -1) { @@ -185,7 +182,7 @@ static bool tb_lookup_cmp(const void *p, const void *d) * is different for the new TB. Therefore any exception raised * here by the faulting lookup is not premature. */ - virt_page1 = TARGET_PAGE_ALIGN(desc->pc); + virt_page1 = TARGET_PAGE_ALIGN(desc->s.pc); phys_page1 = get_page_addr_code(desc->env, virt_page1); if (tb_phys_page1 == phys_page1) { return true; @@ -201,11 +198,8 @@ static TranslationBlock *tb_htable_lookup(CPUState *cpu, TCGTBCPUState s) struct tb_desc desc; uint32_t h; + desc.s = s; desc.env = cpu_env(cpu); - desc.cs_base = s.cs_base; - desc.flags = s.flags; - desc.cflags = s.cflags; - desc.pc = s.pc; phys_pc = get_page_addr_code(desc.env, s.pc); if (phys_pc == -1) { return NULL; From 18a77386f15d4fed13b3d162e73e784e1da1f862 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Tue, 29 Apr 2025 18:59:26 -0700 Subject: [PATCH 0565/2760] accel/tcg: Pass TCGTBCPUState to tb_gen_code Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 4 ++-- accel/tcg/internal-common.h | 5 ++--- accel/tcg/translate-all.c | 28 +++++++++++++--------------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index 4ad84c2db8..a7436d2873 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -574,7 +574,7 @@ void cpu_exec_step_atomic(CPUState *cpu) tb = tb_lookup(cpu, s); if (tb == NULL) { mmap_lock(); - tb = tb_gen_code(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_gen_code(cpu, s); mmap_unlock(); } @@ -951,7 +951,7 @@ cpu_exec_loop(CPUState *cpu, SyncClocks *sc) uint32_t h; mmap_lock(); - tb = tb_gen_code(cpu, s.pc, s.cs_base, s.flags, s.cflags); + tb = tb_gen_code(cpu, s); mmap_unlock(); /* diff --git a/accel/tcg/internal-common.h b/accel/tcg/internal-common.h index 98c702422f..1dbc45dd95 100644 --- a/accel/tcg/internal-common.h +++ b/accel/tcg/internal-common.h @@ -12,6 +12,7 @@ #include "exec/cpu-common.h" #include "exec/translation-block.h" #include "exec/mmap-lock.h" +#include "accel/tcg/tb-cpu-state.h" extern int64_t max_delay; extern int64_t max_advance; @@ -46,9 +47,7 @@ static inline bool cpu_plugin_mem_cbs_enabled(const CPUState *cpu) #endif } -TranslationBlock *tb_gen_code(CPUState *cpu, vaddr pc, - uint64_t cs_base, uint32_t flags, - int cflags); +TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s); void page_init(void); void tb_htable_init(void); void tb_reset_jump(TranslationBlock *tb, int n); diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 97aadee52c..7b0bd50904 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -290,9 +290,7 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb, } /* Called with mmap_lock held for user mode emulation. */ -TranslationBlock *tb_gen_code(CPUState *cpu, - vaddr pc, uint64_t cs_base, - uint32_t flags, int cflags) +TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) { CPUArchState *env = cpu_env(cpu); TranslationBlock *tb, *existing_tb; @@ -305,14 +303,14 @@ TranslationBlock *tb_gen_code(CPUState *cpu, assert_memory_lock(); qemu_thread_jit_write(); - phys_pc = get_page_addr_code_hostp(env, pc, &host_pc); + phys_pc = get_page_addr_code_hostp(env, s.pc, &host_pc); if (phys_pc == -1) { /* Generate a one-shot TB with 1 insn in it */ - cflags = (cflags & ~CF_COUNT_MASK) | 1; + s.cflags = (s.cflags & ~CF_COUNT_MASK) | 1; } - max_insns = cflags & CF_COUNT_MASK; + max_insns = s.cflags & CF_COUNT_MASK; if (max_insns == 0) { max_insns = TCG_MAX_INSNS; } @@ -332,12 +330,12 @@ TranslationBlock *tb_gen_code(CPUState *cpu, gen_code_buf = tcg_ctx->code_gen_ptr; tb->tc.ptr = tcg_splitwx_to_rx(gen_code_buf); - if (!(cflags & CF_PCREL)) { - tb->pc = pc; + if (!(s.cflags & CF_PCREL)) { + tb->pc = s.pc; } - tb->cs_base = cs_base; - tb->flags = flags; - tb->cflags = cflags; + tb->cs_base = s.cs_base; + tb->flags = s.flags; + tb->cflags = s.cflags; tb_set_page_addr0(tb, phys_pc); tb_set_page_addr1(tb, -1); if (phys_pc != -1) { @@ -355,9 +353,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu, tcg_ctx->guest_mo = cpu->cc->tcg_ops->guest_default_memory_order; restart_translate: - trace_translate_block(tb, pc, tb->tc.ptr); + trace_translate_block(tb, s.pc, tb->tc.ptr); - gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti); + gen_code_size = setjmp_gen_code(env, tb, s.pc, host_pc, &max_insns, &ti); if (unlikely(gen_code_size < 0)) { switch (gen_code_size) { case -1: @@ -434,10 +432,10 @@ TranslationBlock *tb_gen_code(CPUState *cpu, * For CF_PCREL, attribute all executions of the generated code * to its first mapping. */ - perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf)); + perf_report_code(s.pc, tb, tcg_splitwx_to_rx(gen_code_buf)); if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) && - qemu_log_in_addr_range(pc)) { + qemu_log_in_addr_range(s.pc)) { FILE *logfile = qemu_log_trylock(); if (logfile) { int code_size, data_size; From 0baf907b718e1602383b973de7822c25db4c4a36 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Apr 2025 10:16:52 -0700 Subject: [PATCH 0566/2760] accel/tcg: Split out accel/tcg/helper-retaddr.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move set_helper_retaddr and clear_helper_retaddr to a new header file. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + accel/tcg/user-exec.c | 1 + include/accel/tcg/cpu-ldst.h | 34 ----------------------- include/accel/tcg/helper-retaddr.h | 43 ++++++++++++++++++++++++++++++ target/arm/tcg/helper-a64.c | 1 + target/arm/tcg/sme_helper.c | 1 + target/arm/tcg/sve_helper.c | 1 + target/ppc/mem_helper.c | 1 + target/s390x/tcg/mem_helper.c | 1 + 9 files changed, 50 insertions(+), 34 deletions(-) create mode 100644 include/accel/tcg/helper-retaddr.h diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index a7436d2873..a8fbda31ba 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -24,6 +24,7 @@ #include "hw/core/cpu.h" #include "accel/tcg/cpu-ldst.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/helper-retaddr.h" #include "trace.h" #include "disas/disas.h" #include "exec/cpu-common.h" diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 70feee8df9..68e01fc584 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -26,6 +26,7 @@ #include "qemu/bitops.h" #include "qemu/rcu.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/helper-retaddr.h" #include "accel/tcg/probe.h" #include "user/cpu_loop.h" #include "qemu/main-loop.h" diff --git a/include/accel/tcg/cpu-ldst.h b/include/accel/tcg/cpu-ldst.h index f97a730703..44a62b54da 100644 --- a/include/accel/tcg/cpu-ldst.h +++ b/include/accel/tcg/cpu-ldst.h @@ -526,38 +526,4 @@ void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr, MMUAccessType access_type, int mmu_idx); #endif -/* - * For user-only, helpers that use guest to host address translation - * must protect the actual host memory access by recording 'retaddr' - * for the signal handler. This is required for a race condition in - * which another thread unmaps the page between a probe and the - * actual access. - */ -#ifdef CONFIG_USER_ONLY -extern __thread uintptr_t helper_retaddr; - -static inline void set_helper_retaddr(uintptr_t ra) -{ - helper_retaddr = ra; - /* - * Ensure that this write is visible to the SIGSEGV handler that - * may be invoked due to a subsequent invalid memory operation. - */ - signal_barrier(); -} - -static inline void clear_helper_retaddr(void) -{ - /* - * Ensure that previous memory operations have succeeded before - * removing the data visible to the signal handler. - */ - signal_barrier(); - helper_retaddr = 0; -} -#else -#define set_helper_retaddr(ra) do { } while (0) -#define clear_helper_retaddr() do { } while (0) -#endif - #endif /* ACCEL_TCG_CPU_LDST_H */ diff --git a/include/accel/tcg/helper-retaddr.h b/include/accel/tcg/helper-retaddr.h new file mode 100644 index 0000000000..037fda2b83 --- /dev/null +++ b/include/accel/tcg/helper-retaddr.h @@ -0,0 +1,43 @@ +/* + * Get user helper pc for memory unwinding. + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +#ifndef ACCEL_TCG_HELPER_RETADDR_H +#define ACCEL_TCG_HELPER_RETADDR_H + +/* + * For user-only, helpers that use guest to host address translation + * must protect the actual host memory access by recording 'retaddr' + * for the signal handler. This is required for a race condition in + * which another thread unmaps the page between a probe and the + * actual access. + */ +#ifdef CONFIG_USER_ONLY +extern __thread uintptr_t helper_retaddr; + +static inline void set_helper_retaddr(uintptr_t ra) +{ + helper_retaddr = ra; + /* + * Ensure that this write is visible to the SIGSEGV handler that + * may be invoked due to a subsequent invalid memory operation. + */ + signal_barrier(); +} + +static inline void clear_helper_retaddr(void) +{ + /* + * Ensure that previous memory operations have succeeded before + * removing the data visible to the signal handler. + */ + signal_barrier(); + helper_retaddr = 0; +} +#else +#define set_helper_retaddr(ra) do { } while (0) +#define clear_helper_retaddr() do { } while (0) +#endif + +#endif /* ACCEL_TCG_HELPER_RETADDR_H */ diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index 9cffda07cd..4f618ae390 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -30,6 +30,7 @@ #include "qemu/crc32c.h" #include "exec/cpu-common.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/helper-retaddr.h" #include "accel/tcg/probe.h" #include "exec/target_page.h" #include "exec/tlb-flags.h" diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index 3226895cae..de0c6e54d4 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -23,6 +23,7 @@ #include "tcg/tcg-gvec-desc.h" #include "exec/helper-proto.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/helper-retaddr.h" #include "qemu/int128.h" #include "fpu/softfloat.h" #include "vec_internal.h" diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index 9f20ecb51d..a2c363a4e1 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -30,6 +30,7 @@ #include "vec_internal.h" #include "sve_ldst_internal.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/helper-retaddr.h" #include "accel/tcg/cpu-ops.h" #include "accel/tcg/probe.h" #ifdef CONFIG_USER_ONLY diff --git a/target/ppc/mem_helper.c b/target/ppc/mem_helper.c index aa1af44d22..6ab71a6fcb 100644 --- a/target/ppc/mem_helper.c +++ b/target/ppc/mem_helper.c @@ -24,6 +24,7 @@ #include "exec/helper-proto.h" #include "helper_regs.h" #include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/helper-retaddr.h" #include "accel/tcg/probe.h" #include "internal.h" #include "qemu/atomic128.h" diff --git a/target/s390x/tcg/mem_helper.c b/target/s390x/tcg/mem_helper.c index 857005b120..a03609a140 100644 --- a/target/s390x/tcg/mem_helper.c +++ b/target/s390x/tcg/mem_helper.c @@ -32,6 +32,7 @@ #include "exec/target_page.h" #include "exec/tlb-flags.h" #include "accel/tcg/cpu-ops.h" +#include "accel/tcg/helper-retaddr.h" #include "qemu/int128.h" #include "qemu/atomic128.h" From 5e5a9aea793cfd67541153105b6046436f6ae4a8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 28 Apr 2025 10:20:41 -0700 Subject: [PATCH 0567/2760] accel/tcg: Compile cpu-exec.c twice Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 2 -- accel/tcg/meson.build | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index a8fbda31ba..cc5f362305 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -22,7 +22,6 @@ #include "qapi/error.h" #include "qapi/type-helpers.h" #include "hw/core/cpu.h" -#include "accel/tcg/cpu-ldst.h" #include "accel/tcg/cpu-ops.h" #include "accel/tcg/helper-retaddr.h" #include "trace.h" @@ -37,7 +36,6 @@ #include "qemu/rcu.h" #include "exec/log.h" #include "qemu/main-loop.h" -#include "cpu.h" #include "exec/icount.h" #include "exec/replay-core.h" #include "system/tcg.h" diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 3f7b127130..0bb089299b 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -5,6 +5,7 @@ endif tcg_ss = ss.source_set() tcg_ss.add(files( + 'cpu-exec.c', 'cpu-exec-common.c', 'tcg-runtime.c', 'tcg-runtime-gvec.c', @@ -21,7 +22,6 @@ libsystem_ss.add_all(tcg_ss) tcg_specific_ss = ss.source_set() tcg_specific_ss.add(files( 'tcg-all.c', - 'cpu-exec.c', 'translate-all.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) From 28502121be7b1422af55bbed6f65a273b889ef01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 22:46:34 +0100 Subject: [PATCH 0568/2760] system/vl: Filter machine list available for a particular target binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Binaries can register a QOM type to filter their machines by filling their TargetInfo::machine_typename field. This can be used by example by main() -> machine_help_func() to filter the machines list. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson --- include/qemu/target-info-impl.h | 2 ++ include/qemu/target-info.h | 8 ++++++++ system/vl.c | 3 ++- target-info-stub.c | 2 ++ target-info.c | 5 +++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index d30805f7f2..d0e8c86176 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -14,6 +14,8 @@ typedef struct TargetInfo { /* runtime equivalent of TARGET_NAME definition */ const char *target_name; + /* QOM typename machines for this binary must implement */ + const char *machine_typename; } TargetInfo; /** diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index 58d4136897..2b6ccabb11 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -16,6 +16,14 @@ */ const char *target_name(void); +/** + * target_machine_typename: + * + * Returns: Name of the QOM interface implemented by machines + * usable on this target binary. + */ +const char *target_machine_typename(void); + /** * target_cpu_type: * diff --git a/system/vl.c b/system/vl.c index 520956f4a1..7223f1ff17 100644 --- a/system/vl.c +++ b/system/vl.c @@ -27,6 +27,7 @@ #include "qemu/datadir.h" #include "qemu/units.h" #include "qemu/module.h" +#include "qemu/target-info.h" #include "exec/cpu-common.h" #include "exec/page-vary.h" #include "hw/qdev-properties.h" @@ -1564,7 +1565,7 @@ static void machine_help_func(const QDict *qdict) GSList *el; const char *type = qdict_get_try_str(qdict, "type"); - machines = object_class_get_list(TYPE_MACHINE, false); + machines = object_class_get_list(target_machine_typename(), false); if (type) { ObjectClass *machine_class = OBJECT_CLASS(find_machine(type, machines)); if (machine_class) { diff --git a/target-info-stub.c b/target-info-stub.c index 773a10188c..bcf834f71d 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -9,10 +9,12 @@ #include "qemu/osdep.h" #include "qemu/target-info.h" #include "qemu/target-info-impl.h" +#include "hw/boards.h" #include "cpu.h" static const TargetInfo target_info_stub = { .target_name = TARGET_NAME, + .machine_typename = TYPE_MACHINE, }; const TargetInfo *target_info(void) diff --git a/target-info.c b/target-info.c index 84b18931e7..0042769e3a 100644 --- a/target-info.c +++ b/target-info.c @@ -14,3 +14,8 @@ const char *target_name(void) { return target_info()->target_name; } + +const char *target_machine_typename(void) +{ + return target_info()->machine_typename; +} From b113dfa081a6a7e061551a70e6ede7af0941a845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Tue, 29 Apr 2025 20:18:03 +0200 Subject: [PATCH 0569/2760] qemu/target_info: Add %target_cpu_type field to TargetInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé --- include/qemu/target-info-impl.h | 2 ++ target-info-stub.c | 6 +----- target-info.c | 5 +++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index d0e8c86176..76766eeaae 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -14,6 +14,8 @@ typedef struct TargetInfo { /* runtime equivalent of TARGET_NAME definition */ const char *target_name; + /* runtime equivalent of CPU_RESOLVING_TYPE definition */ + const char *cpu_type; /* QOM typename machines for this binary must implement */ const char *machine_typename; } TargetInfo; diff --git a/target-info-stub.c b/target-info-stub.c index bcf834f71d..86da297277 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -14,6 +14,7 @@ static const TargetInfo target_info_stub = { .target_name = TARGET_NAME, + .cpu_type = CPU_RESOLVING_TYPE, .machine_typename = TYPE_MACHINE, }; @@ -21,8 +22,3 @@ const TargetInfo *target_info(void) { return &target_info_stub; } - -const char *target_cpu_type(void) -{ - return CPU_RESOLVING_TYPE; -} diff --git a/target-info.c b/target-info.c index 0042769e3a..5f5ef1f932 100644 --- a/target-info.c +++ b/target-info.c @@ -15,6 +15,11 @@ const char *target_name(void) return target_info()->target_name; } +const char *target_cpu_type(void) +{ + return target_info()->cpu_type; +} + const char *target_machine_typename(void) { return target_info()->machine_typename; From c1be135ad5b124b08715ca836b95b738c6b9d7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Sun, 23 Mar 2025 13:20:24 +0100 Subject: [PATCH 0570/2760] qemu: Introduce target_long_bits() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé --- include/qemu/target-info-impl.h | 2 ++ include/qemu/target-info.h | 7 +++++++ target-info-stub.c | 1 + target-info.c | 5 +++++ 4 files changed, 15 insertions(+) diff --git a/include/qemu/target-info-impl.h b/include/qemu/target-info-impl.h index 76766eeaae..1b51cbcfe1 100644 --- a/include/qemu/target-info-impl.h +++ b/include/qemu/target-info-impl.h @@ -14,6 +14,8 @@ typedef struct TargetInfo { /* runtime equivalent of TARGET_NAME definition */ const char *target_name; + /* runtime equivalent of TARGET_LONG_BITS definition */ + unsigned long_bits; /* runtime equivalent of CPU_RESOLVING_TYPE definition */ const char *cpu_type; /* QOM typename machines for this binary must implement */ diff --git a/include/qemu/target-info.h b/include/qemu/target-info.h index 2b6ccabb11..850a2958b9 100644 --- a/include/qemu/target-info.h +++ b/include/qemu/target-info.h @@ -16,6 +16,13 @@ */ const char *target_name(void); +/** + * target_long_bits: + * + * Returns: number of bits in a long type for this target (i.e. 64). + */ +unsigned target_long_bits(void); + /** * target_machine_typename: * diff --git a/target-info-stub.c b/target-info-stub.c index 86da297277..fecc0e7128 100644 --- a/target-info-stub.c +++ b/target-info-stub.c @@ -14,6 +14,7 @@ static const TargetInfo target_info_stub = { .target_name = TARGET_NAME, + .long_bits = TARGET_LONG_BITS, .cpu_type = CPU_RESOLVING_TYPE, .machine_typename = TYPE_MACHINE, }; diff --git a/target-info.c b/target-info.c index 5f5ef1f932..16fdca7aaa 100644 --- a/target-info.c +++ b/target-info.c @@ -15,6 +15,11 @@ const char *target_name(void) return target_info()->target_name; } +unsigned target_long_bits(void) +{ + return target_info()->long_bits; +} + const char *target_cpu_type(void) { return target_info()->cpu_type; From 0648c76ad198e91515771fbbeaac3a3807669a4a Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 26 Oct 2024 18:30:07 +0200 Subject: [PATCH 0571/2760] block: refactor error handling of commit_iteration Signed-off-by: Vincent Vanlaer Message-Id: <20241026163010.2865002-4-libvirt-e6954efa@volkihar.be> [vsementsov]: move action declaration to the top of the function Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/commit.c | 67 ++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/block/commit.c b/block/commit.c index 3ee0ade7df..5c6596a52e 100644 --- a/block/commit.c +++ b/block/commit.c @@ -129,51 +129,60 @@ static void commit_clean(Job *job) } static int commit_iteration(CommitBlockJob *s, int64_t offset, - int64_t *n, void *buf) + int64_t *requested_bytes, void *buf) { + BlockErrorAction action; + int64_t bytes = *requested_bytes; int ret = 0; - bool copy; bool error_in_source = true; /* Copy if allocated above the base */ WITH_GRAPH_RDLOCK_GUARD() { ret = bdrv_co_common_block_status_above(blk_bs(s->top), s->base_overlay, true, true, offset, COMMIT_BUFFER_SIZE, - n, NULL, NULL, NULL); + &bytes, NULL, NULL, NULL); } - copy = (ret >= 0 && ret & BDRV_BLOCK_ALLOCATED); - trace_commit_one_iteration(s, offset, *n, ret); - if (copy) { - assert(*n < SIZE_MAX); + trace_commit_one_iteration(s, offset, bytes, ret); - ret = blk_co_pread(s->top, offset, *n, buf, 0); - if (ret >= 0) { - ret = blk_co_pwrite(s->base, offset, *n, buf, 0); - if (ret < 0) { - error_in_source = false; - } - } - } if (ret < 0) { - BlockErrorAction action = block_job_error_action(&s->common, - s->on_error, - error_in_source, - -ret); - if (action == BLOCK_ERROR_ACTION_REPORT) { - return ret; - } else { - *n = 0; - return 0; - } + goto fail; } - /* Publish progress */ - job_progress_update(&s->common.job, *n); - if (copy) { - block_job_ratelimit_processed_bytes(&s->common, *n); + if (ret & BDRV_BLOCK_ALLOCATED) { + assert(bytes < SIZE_MAX); + + ret = blk_co_pread(s->top, offset, bytes, buf, 0); + if (ret < 0) { + goto fail; + } + + ret = blk_co_pwrite(s->base, offset, bytes, buf, 0); + if (ret < 0) { + error_in_source = false; + goto fail; + } + + block_job_ratelimit_processed_bytes(&s->common, bytes); } + /* Publish progress */ + + job_progress_update(&s->common.job, bytes); + + *requested_bytes = bytes; + + return 0; + +fail: + action = block_job_error_action(&s->common, s->on_error, + error_in_source, -ret); + if (action == BLOCK_ERROR_ACTION_REPORT) { + return ret; + } + + *requested_bytes = 0; + return 0; } From 6f3199f99600fe75f32f78574e507f347de80854 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 26 Oct 2024 18:30:08 +0200 Subject: [PATCH 0572/2760] block: allow commit to unmap zero blocks Non-active block commits do not discard blocks only containing zeros, causing images to lose sparseness after the commit. This commit fixes that by writing zero blocks using blk_co_pwrite_zeroes rather than writing them out as any other arbitrary data. Signed-off-by: Vincent Vanlaer Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20241026163010.2865002-5-libvirt-e6954efa@volkihar.be> Signed-off-by: Vladimir Sementsov-Ogievskiy --- block/commit.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/block/commit.c b/block/commit.c index 5c6596a52e..7cc8c0f0df 100644 --- a/block/commit.c +++ b/block/commit.c @@ -150,19 +150,39 @@ static int commit_iteration(CommitBlockJob *s, int64_t offset, } if (ret & BDRV_BLOCK_ALLOCATED) { - assert(bytes < SIZE_MAX); + if (ret & BDRV_BLOCK_ZERO) { + /* + * If the top (sub)clusters are smaller than the base + * (sub)clusters, this will not unmap unless the underlying device + * does some tracking of these requests. Ideally, we would find + * the maximal extent of the zero clusters. + */ + ret = blk_co_pwrite_zeroes(s->base, offset, bytes, + BDRV_REQ_MAY_UNMAP); + if (ret < 0) { + error_in_source = false; + goto fail; + } + } else { + assert(bytes < SIZE_MAX); - ret = blk_co_pread(s->top, offset, bytes, buf, 0); - if (ret < 0) { - goto fail; - } - - ret = blk_co_pwrite(s->base, offset, bytes, buf, 0); - if (ret < 0) { - error_in_source = false; - goto fail; + ret = blk_co_pread(s->top, offset, bytes, buf, 0); + if (ret < 0) { + goto fail; + } + + ret = blk_co_pwrite(s->base, offset, bytes, buf, 0); + if (ret < 0) { + error_in_source = false; + goto fail; + } } + /* + * Whether zeroes actually end up on disk depends on the details of + * the underlying driver. Therefore, this might rate limit more than + * is necessary. + */ block_job_ratelimit_processed_bytes(&s->common, bytes); } From 68aba2a9350345d109f8036f9eff68b81b1c2167 Mon Sep 17 00:00:00 2001 From: Vincent Vanlaer Date: Sat, 26 Oct 2024 18:30:09 +0200 Subject: [PATCH 0573/2760] block: add test non-active commit with zeroed data Signed-off-by: Vincent Vanlaer Tested-by: Vladimir Sementsov-Ogievskiy Reviewed-by: Vladimir Sementsov-Ogievskiy Message-Id: <20241026163010.2865002-6-libvirt-e6954efa@volkihar.be> Signed-off-by: Vladimir Sementsov-Ogievskiy --- tests/qemu-iotests/tests/commit-zero-blocks | 96 +++++++++++++++++++ .../qemu-iotests/tests/commit-zero-blocks.out | 54 +++++++++++ 2 files changed, 150 insertions(+) create mode 100755 tests/qemu-iotests/tests/commit-zero-blocks create mode 100644 tests/qemu-iotests/tests/commit-zero-blocks.out diff --git a/tests/qemu-iotests/tests/commit-zero-blocks b/tests/qemu-iotests/tests/commit-zero-blocks new file mode 100755 index 0000000000..de00273e72 --- /dev/null +++ b/tests/qemu-iotests/tests/commit-zero-blocks @@ -0,0 +1,96 @@ +#!/usr/bin/env bash +# group: rw quick +# +# Test for commit of discarded blocks +# +# This tests committing a live snapshot where some of the blocks that +# are present in the base image are discarded in the intermediate image. +# This intends to check that these blocks are also discarded in the base +# image after the commit. +# +# Copyright (C) 2024 Vincent Vanlaer. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# creator +owner=libvirt-e6954efa@volkihar.be + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_qemu + _rm_test_img "${TEST_IMG}.base" + _rm_test_img "${TEST_IMG}.mid" + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +cd .. +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 +_supported_proto file + +size="1M" + +TEST_IMG="$TEST_IMG.base" _make_test_img $size +TEST_IMG="$TEST_IMG.mid" _make_test_img -b "$TEST_IMG.base" -F $IMGFMT $size +_make_test_img -b "${TEST_IMG}.mid" -F $IMGFMT $size + +$QEMU_IO -c "write -P 0x01 64k 128k" "$TEST_IMG.base" | _filter_qemu_io +$QEMU_IO -c "discard 64k 64k" "$TEST_IMG.mid" | _filter_qemu_io + +echo +echo "=== Base image info before commit ===" +TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info +$QEMU_IMG map --output=json "$TEST_IMG.base" | _filter_qemu_img_map + +echo +echo "=== Middle image info before commit ===" +TEST_IMG="${TEST_IMG}.mid" _img_info | _filter_img_info +$QEMU_IMG map --output=json "$TEST_IMG.mid" | _filter_qemu_img_map + +echo +echo === Running QEMU Live Commit Test === +echo + +qemu_comm_method="qmp" +_launch_qemu -drive file="${TEST_IMG}",if=virtio,id=test +h=$QEMU_HANDLE + +_send_qemu_cmd $h "{ 'execute': 'qmp_capabilities' }" "return" + +_send_qemu_cmd $h "{ 'execute': 'block-commit', + 'arguments': { 'device': 'test', + 'top': '"${TEST_IMG}.mid"', + 'base': '"${TEST_IMG}.base"'} }" '"status": "null"' + +_cleanup_qemu + +echo +echo "=== Base image info after commit ===" +TEST_IMG="${TEST_IMG}.base" _img_info | _filter_img_info +$QEMU_IMG map --output=json "$TEST_IMG.base" | _filter_qemu_img_map + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/tests/commit-zero-blocks.out b/tests/qemu-iotests/tests/commit-zero-blocks.out new file mode 100644 index 0000000000..85bdc46aaf --- /dev/null +++ b/tests/qemu-iotests/tests/commit-zero-blocks.out @@ -0,0 +1,54 @@ +QA output created by commit-zero-blocks +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1048576 +Formatting 'TEST_DIR/t.IMGFMT.mid', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576 backing_file=TEST_DIR/t.IMGFMT.mid backing_fmt=IMGFMT +wrote 131072/131072 bytes at offset 65536 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 65536/65536 bytes at offset 65536 +64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) + +=== Base image info before commit === +image: TEST_DIR/t.IMGFMT.base +file format: IMGFMT +virtual size: 1 MiB (1048576 bytes) +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, +{ "start": 65536, "length": 131072, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, +{ "start": 196608, "length": 851968, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] + +=== Middle image info before commit === +image: TEST_DIR/t.IMGFMT.mid +file format: IMGFMT +virtual size: 1 MiB (1048576 bytes) +backing file: TEST_DIR/t.IMGFMT.base +backing file format: IMGFMT +[{ "start": 0, "length": 65536, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}, +{ "start": 65536, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, +{ "start": 131072, "length": 65536, "depth": 1, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, +{ "start": 196608, "length": 851968, "depth": 1, "present": false, "zero": true, "data": false, "compressed": false}] + +=== Running QEMU Live Commit Test === + +{ 'execute': 'qmp_capabilities' } +{"return": {}} +{ 'execute': 'block-commit', + 'arguments': { 'device': 'test', + 'top': 'TEST_DIR/t.IMGFMT.mid', + 'base': 'TEST_DIR/t.IMGFMT.base'} } +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "test"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "test"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "test"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "test"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "test", "len": 1048576, "offset": 1048576, "speed": 0, "type": "commit"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "test"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "test"}} + +=== Base image info after commit === +image: TEST_DIR/t.IMGFMT.base +file format: IMGFMT +virtual size: 1 MiB (1048576 bytes) +[{ "start": 0, "length": 65536, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}, +{ "start": 65536, "length": 65536, "depth": 0, "present": true, "zero": true, "data": false, "compressed": false}, +{ "start": 131072, "length": 65536, "depth": 0, "present": true, "zero": false, "data": true, "compressed": false, "offset": OFFSET}, +{ "start": 196608, "length": 851968, "depth": 0, "present": false, "zero": true, "data": false, "compressed": false}] +*** done From da17dd5c5ee8e33124da0bf91aed11491d0c04de Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 9 Apr 2025 11:42:30 +0300 Subject: [PATCH 0574/2760] qapi: synchronize jobs and block-jobs documentation Actualize documentation and synchronize it for commands which actually call the same functions internally. Reviewed-by: Markus Armbruster Signed-off-by: Vladimir Sementsov-Ogievskiy Message-ID: <20250409084232.28201-2-vsementsov@yandex-team.ru> --- qapi/block-core.json | 61 ++++++++++++++++++++++++++------------------ qapi/job.json | 30 ++++++++++++++++++++-- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index b1937780e1..6beab0dc12 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2956,13 +2956,14 @@ # # Pause an active background block operation. # -# This command returns immediately after marking the active background -# block operation for pausing. It is an error to call this command if -# no operation is in progress or if the job is already paused. +# This command returns immediately after marking the active job for +# pausing. Pausing an already paused job is an error. # -# The operation will pause as soon as possible. No event is emitted -# when the operation is actually paused. Cancelling a paused job -# automatically resumes it. +# The job will pause as soon as possible, which means transitioning +# into the PAUSED state if it was RUNNING, or into STANDBY if it was +# READY. The corresponding JOB_STATUS_CHANGE event will be emitted. +# +# Cancelling a paused job automatically resumes it. # # @device: The job identifier. This used to be a device name (hence # the name of the parameter), but since QEMU 2.7 it can have other @@ -2982,9 +2983,8 @@ # # Resume an active background block operation. # -# This command returns immediately after resuming a paused background -# block operation. It is an error to call this command if no -# operation is in progress or if the job is not paused. +# This command returns immediately after resuming a paused job. +# Resuming an already running job is an error. # # This command also clears the error status of the job. # @@ -3004,10 +3004,15 @@ ## # @block-job-complete: # -# Manually trigger completion of an active background block operation. -# This is supported for drive mirroring, where it also switches the -# device to write to the target path only. The ability to complete is -# signaled with a BLOCK_JOB_READY event. +# Manually trigger completion of an active job in the READY or STANDBY +# state. Completing the job in any other state is an error. +# +# This is supported only for drive mirroring, where it also switches +# the device to write to the target path only. Note that drive +# mirroring includes drive-mirror, blockdev-mirror and block-commit +# job (only in case of "active commit", when the node being commited +# is used by the guest). The ability to complete is signaled with a +# BLOCK_JOB_READY event. # # This command completes an active background block operation # synchronously. The ordering of this command's return with the @@ -3017,8 +3022,6 @@ # rerror/werror arguments that were specified when starting the # operation. # -# A cancelled or paused job cannot be completed. -# # @device: The job identifier. This used to be a device name (hence # the name of the parameter), but since QEMU 2.7 it can have other # values. @@ -3035,10 +3038,13 @@ ## # @block-job-dismiss: # -# For jobs that have already concluded, remove them from the -# block-job-query list. This command only needs to be run for jobs -# which were started with QEMU 2.12+ job lifetime management -# semantics. +# Deletes a job that is in the CONCLUDED state. This command only +# needs to be run explicitly for jobs that don't have automatic +# dismiss enabled. In turn, automatic dismiss may be enabled only +# for jobs that have @auto-dismiss option, which are drive-backup, +# blockdev-backup, drive-mirror, blockdev-mirror, block-commit and +# block-stream. @auto-dismiss is enabled by default for these +# jobs. # # This command will refuse to operate on any job that has not yet # reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that @@ -3055,12 +3061,17 @@ ## # @block-job-finalize: # -# Once a job that has manual=true reaches the pending state, it can be -# instructed to finalize any graph changes and do any necessary -# cleanup via this command. For jobs in a transaction, instructing -# one job to finalize will force ALL jobs in the transaction to -# finalize, so it is only necessary to instruct a single member job to -# finalize. +# Instructs all jobs in a transaction (or a single job if it is not +# part of any transaction) to finalize any graph changes and do any +# necessary cleanup. This command requires that all involved jobs are +# in the PENDING state. +# +# For jobs in a transaction, instructing one job to finalize will +# force ALL jobs in the transaction to finalize, so it is only +# necessary to instruct a single member job to finalize. +# +# The command is applicable only to jobs which have @auto-finalize option +# and only when this option is set to false. # # @id: The job identifier. # diff --git a/qapi/job.json b/qapi/job.json index cfc3beedd2..b03f80bc84 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -156,6 +156,9 @@ # This command returns immediately after resuming a paused job. # Resuming an already running job is an error. # +# This command also clears the error status for block-jobs (stream, +# commit, mirror, backup). +# # @id: The job identifier. # # Since: 3.0 @@ -184,7 +187,23 @@ ## # @job-complete: # -# Manually trigger completion of an active job in the READY state. +# Manually trigger completion of an active job in the READY or STANDBY +# state. Completing the job in any other state is an error. +# +# This is supported only for drive mirroring, where it also switches +# the device to write to the target path only. Note that drive +# mirroring includes drive-mirror, blockdev-mirror and block-commit +# job (only in case of "active commit", when the node being commited +# is used by the guest). The ability to complete is signaled with a +# BLOCK_JOB_READY event. +# +# This command completes an active background block operation +# synchronously. The ordering of this command's return with the +# BLOCK_JOB_COMPLETED event is not defined. Note that if an I/O error +# occurs during the processing of this command: 1) the command itself +# will fail; 2) the error will be processed according to the +# rerror/werror arguments that were specified when starting the +# operation. # # @id: The job identifier. # @@ -197,7 +216,11 @@ # # Deletes a job that is in the CONCLUDED state. This command only # needs to be run explicitly for jobs that don't have automatic -# dismiss enabled. +# dismiss enabled. In turn, automatic dismiss may be enabled only +# for jobs that have @auto-dismiss option, which are drive-backup, +# blockdev-backup, drive-mirror, blockdev-mirror, block-commit and +# block-stream. @auto-dismiss is enabled by default for these +# jobs. # # This command will refuse to operate on any job that has not yet # reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that @@ -222,6 +245,9 @@ # force ALL jobs in the transaction to finalize, so it is only # necessary to instruct a single member job to finalize. # +# The command is applicable only to jobs which have @auto-finalize option +# and only when this option is set to false. +# # @id: The identifier of any job in the transaction, or of a job that # is not part of any transaction. # From b836bf2ab68fbc1e253c10bee95fa36399762967 Mon Sep 17 00:00:00 2001 From: Vladimir Sementsov-Ogievskiy Date: Wed, 9 Apr 2025 11:42:31 +0300 Subject: [PATCH 0575/2760] qapi/block-core: deprecate some block-job- APIs For change, pause, resume, complete, dismiss and finalize actions corresponding job- and block-job commands are almost equal. The difference is in find_block_job_locked() vs find_job_locked() functions. What's different? 1. find_block_job_locked() checks whether the found job is a block-job. This is OK when moving to more generic API, no needs to document this change. 2. find_block_job_locked() reports DeviceNotActive on failure, when find_job_locked() reports GenericError. So, let's document this difference in deprecated.txt. Still, for dismiss and finalize errors are not documented at all, so be silent in deprecated.txt as well. ACKed-by: Peter Krempa Reviewed-by: Eric Blake Reviewed-by: Markus Armbruster Signed-off-by: Vladimir Sementsov-Ogievskiy Message-ID: <20250409084232.28201-3-vsementsov@yandex-team.ru> --- docs/about/deprecated.rst | 31 +++++++++++++++++++++++++++++++ qapi/block-core.json | 30 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 05381441a9..b0d3ae6b32 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -148,6 +148,37 @@ options are removed in favor of using explicit ``blockdev-create`` and ``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for details. +``block-job-pause`` (since 10.1) +'''''''''''''''''''''''''''''''' + +Use ``job-pause`` instead. The only difference is that ``job-pause`` +always reports GenericError on failure when ``block-job-pause`` reports +DeviceNotActive when block-job is not found. + +``block-job-resume`` (since 10.1) +''''''''''''''''''''''''''''''''' + +Use ``job-resume`` instead. The only difference is that ``job-resume`` +always reports GenericError on failure when ``block-job-resume`` reports +DeviceNotActive when block-job is not found. + +``block-job-complete`` (since 10.1) +''''''''''''''''''''''''''''''''''' + +Use ``job-complete`` instead. The only difference is that ``job-complete`` +always reports GenericError on failure when ``block-job-complete`` reports +DeviceNotActive when block-job is not found. + +``block-job-dismiss`` (since 10.1) +'''''''''''''''''''''''''''''''''' + +Use ``job-dismiss`` instead. + +``block-job-finalize`` (since 10.1) +''''''''''''''''''''''''''''''''''' + +Use ``job-finalize`` instead. + ``query-migrationthreads`` (since 9.2) '''''''''''''''''''''''''''''''''''''' diff --git a/qapi/block-core.json b/qapi/block-core.json index 6beab0dc12..22061227ca 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2969,6 +2969,11 @@ # the name of the parameter), but since QEMU 2.7 it can have other # values. # +# Features: +# +# @deprecated: This command is deprecated. Use @job-pause +# instead. +# # Errors: # - If no background operation is active on this device, # DeviceNotActive @@ -2976,6 +2981,7 @@ # Since: 1.3 ## { 'command': 'block-job-pause', 'data': { 'device': 'str' }, + 'features': ['deprecated'], 'allow-preconfig': true } ## @@ -2992,6 +2998,11 @@ # the name of the parameter), but since QEMU 2.7 it can have other # values. # +# Features: +# +# @deprecated: This command is deprecated. Use @job-resume +# instead. +# # Errors: # - If no background operation is active on this device, # DeviceNotActive @@ -2999,6 +3010,7 @@ # Since: 1.3 ## { 'command': 'block-job-resume', 'data': { 'device': 'str' }, + 'features': ['deprecated'], 'allow-preconfig': true } ## @@ -3026,6 +3038,11 @@ # the name of the parameter), but since QEMU 2.7 it can have other # values. # +# Features: +# +# @deprecated: This command is deprecated. Use @job-complete +# instead. +# # Errors: # - If no background operation is active on this device, # DeviceNotActive @@ -3033,6 +3050,7 @@ # Since: 1.3 ## { 'command': 'block-job-complete', 'data': { 'device': 'str' }, + 'features': ['deprecated'], 'allow-preconfig': true } ## @@ -3053,9 +3071,15 @@ # # @id: The job identifier. # +# Features: +# +# @deprecated: This command is deprecated. Use @job-dismiss +# instead. +# # Since: 2.12 ## { 'command': 'block-job-dismiss', 'data': { 'id': 'str' }, + 'features': ['deprecated'], 'allow-preconfig': true } ## @@ -3075,9 +3099,15 @@ # # @id: The job identifier. # +# Features: +# +# @deprecated: This command is deprecated. Use @job-finalize +# instead. +# # Since: 2.12 ## { 'command': 'block-job-finalize', 'data': { 'id': 'str' }, + 'features': ['deprecated'], 'allow-preconfig': true } ## From e1d8fabc20adb6a766773adb4a9b5bfe93e329bb Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 13:57:30 -0700 Subject: [PATCH 0576/2760] tcg: Define INSN_START_WORDS as constant 3 Use the same value for all targets. Rename TARGET_INSN_START_WORDS and do not depend on TARGET_INSN_START_EXTRA_WORDS. Remove TCGContext.insn_start_words. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 19 +++++++++---------- include/tcg/insn-start-words.h | 11 +++++------ include/tcg/tcg-op.h | 17 ++++++++++++++--- include/tcg/tcg-opc.h | 3 +-- include/tcg/tcg.h | 12 +++++++----- target/i386/helper.c | 2 +- target/openrisc/sys_helper.c | 2 +- tcg/perf.c | 5 ++--- tcg/tcg.c | 12 +++++------- 9 files changed, 45 insertions(+), 38 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 7b0bd50904..fa4998b341 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -120,7 +120,7 @@ static int64_t decode_sleb128(const uint8_t **pp) /* Encode the data collected about the instructions while compiling TB. Place the data at BLOCK, and return the number of bytes consumed. - The logical table consists of TARGET_INSN_START_WORDS target_ulong's, + The logical table consists of INSN_START_WORDS uint64_t's, which come from the target's insn_start data, followed by a uintptr_t which comes from the host pc of the end of the code implementing the insn. @@ -140,13 +140,13 @@ static int encode_search(TranslationBlock *tb, uint8_t *block) for (i = 0, n = tb->icount; i < n; ++i) { uint64_t prev, curr; - for (j = 0; j < TARGET_INSN_START_WORDS; ++j) { + for (j = 0; j < INSN_START_WORDS; ++j) { if (i == 0) { prev = (!(tb_cflags(tb) & CF_PCREL) && j == 0 ? tb->pc : 0); } else { - prev = insn_data[(i - 1) * TARGET_INSN_START_WORDS + j]; + prev = insn_data[(i - 1) * INSN_START_WORDS + j]; } - curr = insn_data[i * TARGET_INSN_START_WORDS + j]; + curr = insn_data[i * INSN_START_WORDS + j]; p = encode_sleb128(p, curr - prev); } prev = (i == 0 ? 0 : insn_end_off[i - 1]); @@ -178,7 +178,7 @@ static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc, return -1; } - memset(data, 0, sizeof(uint64_t) * TARGET_INSN_START_WORDS); + memset(data, 0, sizeof(uint64_t) * INSN_START_WORDS); if (!(tb_cflags(tb) & CF_PCREL)) { data[0] = tb->pc; } @@ -188,7 +188,7 @@ static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc, * at which the end of the insn exceeds host_pc. */ for (i = 0; i < num_insns; ++i) { - for (j = 0; j < TARGET_INSN_START_WORDS; ++j) { + for (j = 0; j < INSN_START_WORDS; ++j) { data[j] += decode_sleb128(&p); } iter_pc += decode_sleb128(&p); @@ -206,7 +206,7 @@ static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc, void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb, uintptr_t host_pc) { - uint64_t data[TARGET_INSN_START_WORDS]; + uint64_t data[INSN_START_WORDS]; int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data); if (insns_left < 0) { @@ -349,7 +349,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) tcg_ctx->page_mask = TARGET_PAGE_MASK; tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; #endif - tcg_ctx->insn_start_words = TARGET_INSN_START_WORDS; tcg_ctx->guest_mo = cpu->cc->tcg_ops->guest_default_memory_order; restart_translate: @@ -457,7 +456,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) fprintf(logfile, "OUT: [size=%d]\n", gen_code_size); fprintf(logfile, " -- guest addr 0x%016" PRIx64 " + tb prologue\n", - tcg_ctx->gen_insn_data[insn * TARGET_INSN_START_WORDS]); + tcg_ctx->gen_insn_data[insn * INSN_START_WORDS]); chunk_start = tcg_ctx->gen_insn_end_off[insn]; disas(logfile, tb->tc.ptr, chunk_start); @@ -470,7 +469,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) size_t chunk_end = tcg_ctx->gen_insn_end_off[insn]; if (chunk_end > chunk_start) { fprintf(logfile, " -- guest addr 0x%016" PRIx64 "\n", - tcg_ctx->gen_insn_data[insn * TARGET_INSN_START_WORDS]); + tcg_ctx->gen_insn_data[insn * INSN_START_WORDS]); disas(logfile, tb->tc.ptr + chunk_start, chunk_end - chunk_start); chunk_start = chunk_end; diff --git a/include/tcg/insn-start-words.h b/include/tcg/insn-start-words.h index d416d19bcf..c52aec50a7 100644 --- a/include/tcg/insn-start-words.h +++ b/include/tcg/insn-start-words.h @@ -1,13 +1,12 @@ /* SPDX-License-Identifier: MIT */ /* - * Define TARGET_INSN_START_WORDS + * Define INSN_START_WORDS * Copyright (c) 2008 Fabrice Bellard */ -#ifndef TARGET_INSN_START_WORDS +#ifndef TCG_INSN_START_WORDS +#define TCG_INSN_START_WORDS -#include "cpu-param.h" +#define INSN_START_WORDS 3 -# define TARGET_INSN_START_WORDS (1 + TARGET_INSN_START_EXTRA_WORDS) - -#endif /* TARGET_INSN_START_WORDS */ +#endif /* TCG_INSN_START_WORDS */ diff --git a/include/tcg/tcg-op.h b/include/tcg/tcg-op.h index 59d19755e6..c912578fdd 100644 --- a/include/tcg/tcg-op.h +++ b/include/tcg/tcg-op.h @@ -9,6 +9,7 @@ #define TCG_TCG_OP_H #include "tcg/tcg-op-common.h" +#include "tcg/insn-start-words.h" #include "exec/target_long.h" #ifndef TARGET_LONG_BITS @@ -23,24 +24,34 @@ # error #endif +#if INSN_START_WORDS != 3 +# error Mismatch with insn-start-words.h +#endif + #if TARGET_INSN_START_EXTRA_WORDS == 0 static inline void tcg_gen_insn_start(target_ulong pc) { - TCGOp *op = tcg_emit_op(INDEX_op_insn_start, 64 / TCG_TARGET_REG_BITS); + TCGOp *op = tcg_emit_op(INDEX_op_insn_start, + INSN_START_WORDS * 64 / TCG_TARGET_REG_BITS); tcg_set_insn_start_param(op, 0, pc); + tcg_set_insn_start_param(op, 1, 0); + tcg_set_insn_start_param(op, 2, 0); } #elif TARGET_INSN_START_EXTRA_WORDS == 1 static inline void tcg_gen_insn_start(target_ulong pc, target_ulong a1) { - TCGOp *op = tcg_emit_op(INDEX_op_insn_start, 2 * 64 / TCG_TARGET_REG_BITS); + TCGOp *op = tcg_emit_op(INDEX_op_insn_start, + INSN_START_WORDS * 64 / TCG_TARGET_REG_BITS); tcg_set_insn_start_param(op, 0, pc); tcg_set_insn_start_param(op, 1, a1); + tcg_set_insn_start_param(op, 2, 0); } #elif TARGET_INSN_START_EXTRA_WORDS == 2 static inline void tcg_gen_insn_start(target_ulong pc, target_ulong a1, target_ulong a2) { - TCGOp *op = tcg_emit_op(INDEX_op_insn_start, 3 * 64 / TCG_TARGET_REG_BITS); + TCGOp *op = tcg_emit_op(INDEX_op_insn_start, + INSN_START_WORDS * 64 / TCG_TARGET_REG_BITS); tcg_set_insn_start_param(op, 0, pc); tcg_set_insn_start_param(op, 1, a1); tcg_set_insn_start_param(op, 2, a2); diff --git a/include/tcg/tcg-opc.h b/include/tcg/tcg-opc.h index 995b79383e..e988edd93a 100644 --- a/include/tcg/tcg-opc.h +++ b/include/tcg/tcg-opc.h @@ -114,8 +114,7 @@ DEF(extrh_i64_i32, 1, 1, 0, 0) #define DATA64_ARGS (TCG_TARGET_REG_BITS == 64 ? 1 : 2) -/* There are tcg_ctx->insn_start_words here, not just one. */ -DEF(insn_start, 0, 0, DATA64_ARGS, TCG_OPF_NOT_PRESENT) +DEF(insn_start, 0, 0, DATA64_ARGS * INSN_START_WORDS, TCG_OPF_NOT_PRESENT) DEF(exit_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) DEF(goto_tb, 0, 0, 1, TCG_OPF_BB_EXIT | TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT) diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index aa300a2f8b..a8c00c72cc 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -34,6 +34,7 @@ #include "tcg-target-reg-bits.h" #include "tcg-target.h" #include "tcg/tcg-cond.h" +#include "tcg/insn-start-words.h" #include "tcg/debug-assert.h" /* XXX: make safe guess about sizes */ @@ -359,7 +360,6 @@ struct TCGContext { int page_mask; uint8_t page_bits; uint8_t tlb_dyn_max_bits; - uint8_t insn_start_words; TCGBar guest_mo; TCGRegSet reserved_regs; @@ -582,18 +582,19 @@ static inline TCGv_vec temp_tcgv_vec(TCGTemp *t) return (TCGv_vec)temp_tcgv_i32(t); } -static inline TCGArg tcg_get_insn_param(TCGOp *op, int arg) +static inline TCGArg tcg_get_insn_param(TCGOp *op, unsigned arg) { return op->args[arg]; } -static inline void tcg_set_insn_param(TCGOp *op, int arg, TCGArg v) +static inline void tcg_set_insn_param(TCGOp *op, unsigned arg, TCGArg v) { op->args[arg] = v; } -static inline uint64_t tcg_get_insn_start_param(TCGOp *op, int arg) +static inline uint64_t tcg_get_insn_start_param(TCGOp *op, unsigned arg) { + tcg_debug_assert(arg < INSN_START_WORDS); if (TCG_TARGET_REG_BITS == 64) { return tcg_get_insn_param(op, arg); } else { @@ -602,8 +603,9 @@ static inline uint64_t tcg_get_insn_start_param(TCGOp *op, int arg) } } -static inline void tcg_set_insn_start_param(TCGOp *op, int arg, uint64_t v) +static inline void tcg_set_insn_start_param(TCGOp *op, unsigned arg, uint64_t v) { + tcg_debug_assert(arg < INSN_START_WORDS); if (TCG_TARGET_REG_BITS == 64) { tcg_set_insn_param(op, arg, v); } else { diff --git a/target/i386/helper.c b/target/i386/helper.c index 197fdac7dd..e0aaed3c4c 100644 --- a/target/i386/helper.c +++ b/target/i386/helper.c @@ -526,7 +526,7 @@ void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank, static inline target_ulong get_memio_eip(CPUX86State *env) { #ifdef CONFIG_TCG - uint64_t data[TARGET_INSN_START_WORDS]; + uint64_t data[INSN_START_WORDS]; CPUState *cs = env_cpu(env); if (!cpu_unwind_state_data(cs, cs->mem_io_pc, data)) { diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c index 951f8e247a..d96b41a01c 100644 --- a/target/openrisc/sys_helper.c +++ b/target/openrisc/sys_helper.c @@ -218,7 +218,7 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd, { OpenRISCCPU *cpu = env_archcpu(env); #ifndef CONFIG_USER_ONLY - uint64_t data[TARGET_INSN_START_WORDS]; + uint64_t data[INSN_START_WORDS]; MachineState *ms = MACHINE(qdev_get_machine()); CPUState *cs = env_cpu(env); int idx; diff --git a/tcg/perf.c b/tcg/perf.c index 412a987d95..4e8d2c1bee 100644 --- a/tcg/perf.c +++ b/tcg/perf.c @@ -313,7 +313,7 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, const void *start) { struct debuginfo_query *q; - size_t insn, start_words; + size_t insn; uint64_t *gen_insn_data; if (!perfmap && !jitdump) { @@ -329,11 +329,10 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, /* Query debuginfo for each guest instruction. */ gen_insn_data = tcg_ctx->gen_insn_data; - start_words = tcg_ctx->insn_start_words; for (insn = 0; insn < tb->icount; insn++) { /* FIXME: This replicates the restore_state_to_opc() logic. */ - q[insn].address = gen_insn_data[insn * start_words + 0]; + q[insn].address = gen_insn_data[insn * INSN_START_WORDS + 0]; if (tb_cflags(tb) & CF_PCREL) { q[insn].address |= (guest_pc & qemu_target_page_mask()); } diff --git a/tcg/tcg.c b/tcg/tcg.c index c4e866e9c3..648333a9fb 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -1989,7 +1989,6 @@ void tcg_func_start(TCGContext *s) QSIMPLEQ_INIT(&s->labels); tcg_debug_assert(s->addr_type <= TCG_TYPE_REG); - tcg_debug_assert(s->insn_start_words > 0); } static TCGTemp *tcg_temp_alloc(TCGContext *s) @@ -2943,7 +2942,7 @@ void tcg_dump_ops(TCGContext *s, FILE *f, bool have_prefs) nb_oargs = 0; col += ne_fprintf(f, "\n ----"); - for (i = 0, k = s->insn_start_words; i < k; ++i) { + for (i = 0, k = INSN_START_WORDS; i < k; ++i) { col += ne_fprintf(f, " %016" PRIx64, tcg_get_insn_start_param(op, i)); } @@ -6835,7 +6834,7 @@ static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst, int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) { - int i, start_words, num_insns; + int i, num_insns; TCGOp *op; if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP) @@ -6925,9 +6924,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) QSIMPLEQ_INIT(&s->ldst_labels); s->pool_labels = NULL; - start_words = s->insn_start_words; s->gen_insn_data = - tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * start_words); + tcg_malloc(sizeof(uint64_t) * s->gen_tb->icount * INSN_START_WORDS); tcg_out_tb_start(s); @@ -6969,8 +6967,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start) assert(s->gen_insn_end_off[num_insns] == off); } num_insns++; - for (i = 0; i < start_words; ++i) { - s->gen_insn_data[num_insns * start_words + i] = + for (i = 0; i < INSN_START_WORDS; ++i) { + s->gen_insn_data[num_insns * INSN_START_WORDS + i] = tcg_get_insn_start_param(op, i); } break; From 9401f91b9b0c46886388735b3f2033a9c254895a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 14:35:47 -0700 Subject: [PATCH 0577/2760] accel/tcg: Don't use TARGET_LONG_BITS in decode_sleb128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we changed decode_sleb128 from target_long to int64_t, we failed to adjust the shift limit. Cc: qemu-stable@nongnu.org Fixes: c9ad8d27caa ("tcg: Widen gen_insn_data to uint64_t") Reviewed-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index fa4998b341..acf32e6c08 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -109,7 +109,7 @@ static int64_t decode_sleb128(const uint8_t **pp) val |= (int64_t)(byte & 0x7f) << shift; shift += 7; } while (byte & 0x80); - if (shift < TARGET_LONG_BITS && (byte & 0x40)) { + if (shift < 64 && (byte & 0x40)) { val |= -(int64_t)1 << shift; } From d2bbc0d6b90cd82b3cecb2d57bb317ba982a30a3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 14:40:30 -0700 Subject: [PATCH 0578/2760] accel/tcg: Use target_long_bits() in translate-all.c Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index acf32e6c08..6b6e10be9d 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -54,6 +54,7 @@ #include "qemu/qemu-print.h" #include "qemu/main-loop.h" #include "qemu/cacheinfo.h" +#include "qemu/target-info.h" #include "qemu/timer.h" #include "exec/log.h" #include "exec/icount.h" @@ -343,7 +344,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) } tcg_ctx->gen_tb = tb; - tcg_ctx->addr_type = TARGET_LONG_BITS == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; + tcg_ctx->addr_type = target_long_bits() == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; #ifdef CONFIG_SOFTMMU tcg_ctx->page_bits = TARGET_PAGE_BITS; tcg_ctx->page_mask = TARGET_PAGE_MASK; From b5dee28732209eaf93656807810c9c5340e907e1 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 15:10:46 -0700 Subject: [PATCH 0579/2760] accel/tcg: Build translate-all.c twice Remove lots and lots of unused headers. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 2 +- accel/tcg/translate-all.c | 32 -------------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 0bb089299b..7eb4619aea 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -10,6 +10,7 @@ tcg_ss.add(files( 'tcg-runtime.c', 'tcg-runtime-gvec.c', 'tb-maint.c', + 'translate-all.c', 'translator.c', )) if get_option('plugins') @@ -22,7 +23,6 @@ libsystem_ss.add_all(tcg_ss) tcg_specific_ss = ss.source_set() tcg_specific_ss.add(files( 'tcg-all.c', - 'translate-all.c', )) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 6b6e10be9d..451b383aa8 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -22,46 +22,15 @@ #include "trace.h" #include "disas/disas.h" #include "tcg/tcg.h" -#if defined(CONFIG_USER_ONLY) -#include "qemu.h" -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include -#if __FreeBSD_version >= 700104 -#define HAVE_KINFO_GETVMMAP -#define sigqueue sigqueue_freebsd /* avoid redefinition */ -#include -#include -#define _KERNEL -#include -#undef _KERNEL -#undef sigqueue -#include -#endif -#endif -#else -#include "system/ram_addr.h" -#endif - -#include "cpu-param.h" -#include "exec/cputlb.h" -#include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "tb-internal.h" #include "tlb-bounds.h" -#include "exec/translator.h" #include "exec/tb-flush.h" -#include "qemu/bitmap.h" -#include "qemu/qemu-print.h" -#include "qemu/main-loop.h" #include "qemu/cacheinfo.h" #include "qemu/target-info.h" -#include "qemu/timer.h" #include "exec/log.h" #include "exec/icount.h" -#include "system/tcg.h" -#include "qapi/error.h" #include "accel/tcg/cpu-ops.h" -#include "accel/tcg/getpc.h" #include "tb-jmp-cache.h" #include "tb-hash.h" #include "tb-context.h" @@ -69,7 +38,6 @@ #include "internal-common.h" #include "tcg/perf.h" #include "tcg/insn-start-words.h" -#include "cpu.h" TBContext tb_ctx; From 97f0d52435ec9da8fd58dc73b6765181fcb25965 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 15:25:29 -0700 Subject: [PATCH 0580/2760] accel/tcg: Build tcg-all.c twice Remove some unused headers. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 4 +--- accel/tcg/tcg-all.c | 6 +----- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 7eb4619aea..d6bd304add 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -10,6 +10,7 @@ tcg_ss.add(files( 'tcg-runtime.c', 'tcg-runtime-gvec.c', 'tb-maint.c', + 'tcg-all.c', 'translate-all.c', 'translator.c', )) @@ -21,9 +22,6 @@ libuser_ss.add_all(tcg_ss) libsystem_ss.add_all(tcg_ss) tcg_specific_ss = ss.source_set() -tcg_specific_ss.add(files( - 'tcg-all.c', -)) tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) diff --git a/accel/tcg/tcg-all.c b/accel/tcg/tcg-all.c index 0ce34ac912..6e5dc333d5 100644 --- a/accel/tcg/tcg-all.c +++ b/accel/tcg/tcg-all.c @@ -36,15 +36,11 @@ #include "qapi/qapi-builtin-visit.h" #include "qemu/units.h" #include "qemu/target-info.h" -#if defined(CONFIG_USER_ONLY) -#include "hw/qdev-core.h" -#else +#ifndef CONFIG_USER_ONLY #include "hw/boards.h" -#include "system/tcg.h" #endif #include "accel/tcg/cpu-ops.h" #include "internal-common.h" -#include "cpu-param.h" struct TCGState { From e578dcc7e1590b20a84036afe5bdfa8d23a6048e Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 29 Apr 2025 14:28:20 +0800 Subject: [PATCH 0581/2760] pc-bios: Add AST27x0 vBootrom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The boot ROM is a minimal implementation designed to load an AST27x0 boot image. Its source code is available at: https://github.com/google/vbootrom Commit id: d6e3386709b3e49322a94ffadc2aaab9944ab77b Build Information: ``` Build Date : Apr 29 2025 01:23:18 FW Version : git-d6e3386 ``` Signed-off-by: Jamin Lin Reviewed-by: Nabih Estefan Reviewed-by: Cédric Le Goater Tested-by: Nabih Estefan Link: https://lore.kernel.org/qemu-devel/20250429062822.1184920-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- MAINTAINERS | 1 + pc-bios/README | 6 ++++++ pc-bios/ast27x0_bootrom.bin | Bin 0 -> 15552 bytes pc-bios/meson.build | 1 + 4 files changed, 8 insertions(+) create mode 100644 pc-bios/ast27x0_bootrom.bin diff --git a/MAINTAINERS b/MAINTAINERS index b3f9f2680b..cc94e62be4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1174,6 +1174,7 @@ F: docs/system/arm/fby35.rst F: tests/*/*aspeed* F: tests/*/*ast2700* F: hw/arm/fby35.c +F: pc-bios/ast27x0_bootrom.bin NRF51 M: Joel Stanley diff --git a/pc-bios/README b/pc-bios/README index f0f13e15f2..d009c37895 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -89,6 +89,12 @@ more features over time as needed. The source code is available at: https://github.com/google/vbootrom +- ast27x0_bootrom.bin is a simplified, free (Apache 2.0) boot ROM for + ASPEED AST27x0 BMC SOC. It currently implements the bare minimum to + load, parse, initialize and run boot images stored in SPI flash, but may grow + more features over time as needed. The source code is available at: + https://github.com/google/vbootrom + - hppa-firmware.img (32-bit) and hppa-firmware64.img (64-bit) are firmware files for the HP-PARISC (hppa) architecture. They are built form the SeaBIOS-hppa sources, which is a fork of SeaBIOS diff --git a/pc-bios/ast27x0_bootrom.bin b/pc-bios/ast27x0_bootrom.bin new file mode 100644 index 0000000000000000000000000000000000000000..0b9b3a2360e375bb6007ecdf13b39d931870f6fa GIT binary patch literal 15552 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 Date: Wed, 5 Mar 2025 14:28:21 +0800 Subject: [PATCH 0582/2760] migration: check RDMA and capabilities are compatible on both sides Depending on the order of starting RDMA and setting capability, they can be categorized into the following scenarios: Source: S1: [set capabilities] -> [Start RDMA outgoing] Destination: D1: [set capabilities] -> [Start RDMA incoming] D2: [Start RDMA incoming] -> [set capabilities] Previously, compatibility between RDMA and capabilities was verified only in scenario D1, potentially causing migration failures in other situations. For scenarios S1 and D1, we can seamlessly incorporate migration_transport_compatible() to address compatibility between channels and capabilities vs transport. For scenario D2, ensure compatibility within migrate_caps_check(). Reviewed-by: Peter Xu Signed-off-by: Li Zhijian Message-ID: <20250305062825.772629-3-lizhijian@fujitsu.com> Signed-off-by: Fabiano Rosas --- migration/migration.c | 30 ++++++++++++++++++++---------- migration/options.c | 21 +++++++++++++++++++++ migration/options.h | 1 + 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 55ec4bfab6..54fce997aa 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -259,6 +259,24 @@ migration_channels_and_transport_compatible(MigrationAddress *addr, return true; } +static bool +migration_capabilities_and_transport_compatible(MigrationAddress *addr, + Error **errp) +{ + if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) { + return migrate_rdma_caps_check(migrate_get_current()->capabilities, + errp); + } + + return true; +} + +static bool migration_transport_compatible(MigrationAddress *addr, Error **errp) +{ + return migration_channels_and_transport_compatible(addr, errp) && + migration_capabilities_and_transport_compatible(addr, errp); +} + static gint page_request_addr_cmp(gconstpointer ap, gconstpointer bp) { uintptr_t a = (uintptr_t) ap, b = (uintptr_t) bp; @@ -750,7 +768,7 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels, } /* transport mechanism not suitable for migration? */ - if (!migration_channels_and_transport_compatible(addr, errp)) { + if (!migration_transport_compatible(addr, errp)) { return; } @@ -769,14 +787,6 @@ static void qemu_start_incoming_migration(const char *uri, bool has_channels, } #ifdef CONFIG_RDMA } else if (addr->transport == MIGRATION_ADDRESS_TYPE_RDMA) { - if (migrate_xbzrle()) { - error_setg(errp, "RDMA and XBZRLE can't be used together"); - return; - } - if (migrate_multifd()) { - error_setg(errp, "RDMA and multifd can't be used together"); - return; - } rdma_start_incoming_migration(&addr->u.rdma, errp); #endif } else if (addr->transport == MIGRATION_ADDRESS_TYPE_EXEC) { @@ -2208,7 +2218,7 @@ void qmp_migrate(const char *uri, bool has_channels, } /* transport mechanism not suitable for migration? */ - if (!migration_channels_and_transport_compatible(addr, errp)) { + if (!migration_transport_compatible(addr, errp)) { return; } diff --git a/migration/options.c b/migration/options.c index b0ac2ea408..1f3602839d 100644 --- a/migration/options.c +++ b/migration/options.c @@ -448,6 +448,20 @@ static bool migrate_incoming_started(void) return !!migration_incoming_get_current()->transport_data; } +bool migrate_rdma_caps_check(bool *caps, Error **errp) +{ + if (caps[MIGRATION_CAPABILITY_XBZRLE]) { + error_setg(errp, "RDMA and XBZRLE can't be used together"); + return false; + } + if (caps[MIGRATION_CAPABILITY_MULTIFD]) { + error_setg(errp, "RDMA and multifd can't be used together"); + return false; + } + + return true; +} + /** * @migration_caps_check - check capability compatibility * @@ -611,6 +625,13 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) } } + /* + * On destination side, check the cases that capability is being set + * after incoming thread has started. + */ + if (migrate_rdma() && !migrate_rdma_caps_check(new_caps, errp)) { + return false; + } return true; } diff --git a/migration/options.h b/migration/options.h index 762be4e641..82d839709e 100644 --- a/migration/options.h +++ b/migration/options.h @@ -57,6 +57,7 @@ bool migrate_tls(void); /* capabilities helpers */ +bool migrate_rdma_caps_check(bool *caps, Error **errp); bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp); /* parameters */ From 103fa641953bfadfe88fbe5f16c0afc9f1e508db Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Wed, 5 Mar 2025 14:28:22 +0800 Subject: [PATCH 0583/2760] migration: disable RDMA + postcopy-ram It's believed that RDMA + postcopy-ram has been broken for a while. Rather than spending time re-enabling it, let's simply disable it as a trade-off. Reviewed-by: Peter Xu Signed-off-by: Li Zhijian Message-ID: <20250305062825.772629-4-lizhijian@fujitsu.com> Signed-off-by: Fabiano Rosas --- migration/options.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/migration/options.c b/migration/options.c index 1f3602839d..4ba8fcb7dc 100644 --- a/migration/options.c +++ b/migration/options.c @@ -458,6 +458,10 @@ bool migrate_rdma_caps_check(bool *caps, Error **errp) error_setg(errp, "RDMA and multifd can't be used together"); return false; } + if (caps[MIGRATION_CAPABILITY_POSTCOPY_RAM]) { + error_setg(errp, "RDMA and postcopy-ram can't be used together"); + return false; + } return true; } From 4ecd6beaf9ff4ad88a33eab78789335a6e929564 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Wed, 5 Mar 2025 14:28:23 +0800 Subject: [PATCH 0584/2760] migration/rdma: Remove redundant migration_in_postcopy checks Since we have disabled RDMA + postcopy, it's safe to remove the migration_in_postcopy() that follows the migrate_rdma(). Reviewed-by: Peter Xu Signed-off-by: Li Zhijian Message-ID: <20250305062825.772629-5-lizhijian@fujitsu.com> Signed-off-by: Fabiano Rosas --- migration/rdma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index b31652baac..a3c3b432d1 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3284,7 +3284,7 @@ err: int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { - if (!migrate_rdma() || migration_in_postcopy()) { + if (!migrate_rdma()) { return RAM_SAVE_CONTROL_NOT_SUPP; } @@ -3829,7 +3829,7 @@ int rdma_block_notification_handle(QEMUFile *f, const char *name) int rdma_registration_start(QEMUFile *f, uint64_t flags) { - if (!migrate_rdma() || migration_in_postcopy()) { + if (!migrate_rdma()) { return 0; } @@ -3861,7 +3861,7 @@ int rdma_registration_stop(QEMUFile *f, uint64_t flags) RDMAControlHeader head = { .len = 0, .repeat = 1 }; int ret; - if (!migrate_rdma() || migration_in_postcopy()) { + if (!migrate_rdma()) { return 0; } From 5e7ca4a7d79da6c9e584886879002f24917c8d27 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Wed, 5 Mar 2025 14:28:24 +0800 Subject: [PATCH 0585/2760] migration: Unfold control_save_page() control_save_page() is for RDMA only, unfold it to make the code more clear. In addition: - Similar to other branches style in ram_save_target_page(), involve RDMA only if the condition 'migrate_rdma()' is true. - Further simplify the code by removing the RAM_SAVE_CONTROL_NOT_SUPP. Reviewed-by: Peter Xu Signed-off-by: Li Zhijian Message-ID: <20250305062825.772629-6-lizhijian@fujitsu.com> Signed-off-by: Fabiano Rosas --- migration/ram.c | 34 +++++++--------------------------- migration/rdma.c | 7 ++----- migration/rdma.h | 3 +-- 3 files changed, 10 insertions(+), 34 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index cb8b2ed493..1181a99cf6 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1143,32 +1143,6 @@ static int save_zero_page(RAMState *rs, PageSearchStatus *pss, return len; } -/* - * @pages: the number of pages written by the control path, - * < 0 - error - * > 0 - number of pages written - * - * Return true if the pages has been saved, otherwise false is returned. - */ -static bool control_save_page(PageSearchStatus *pss, - ram_addr_t offset, int *pages) -{ - int ret; - - ret = rdma_control_save_page(pss->pss_channel, pss->block->offset, offset, - TARGET_PAGE_SIZE); - if (ret == RAM_SAVE_CONTROL_NOT_SUPP) { - return false; - } - - if (ret == RAM_SAVE_CONTROL_DELAYED) { - *pages = 1; - return true; - } - *pages = ret; - return true; -} - /* * directly send the page to the stream * @@ -1965,7 +1939,13 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) int res; /* Hand over to RDMA first */ - if (control_save_page(pss, offset, &res)) { + if (migrate_rdma()) { + res = rdma_control_save_page(pss->pss_channel, pss->block->offset, + offset, TARGET_PAGE_SIZE); + + if (res == RAM_SAVE_CONTROL_DELAYED) { + res = 1; + } return res; } diff --git a/migration/rdma.c b/migration/rdma.c index a3c3b432d1..4875ca1987 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -3284,14 +3284,11 @@ err: int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { - if (!migrate_rdma()) { - return RAM_SAVE_CONTROL_NOT_SUPP; - } + assert(migrate_rdma()); int ret = qemu_rdma_save_page(f, block_offset, offset, size); - if (ret != RAM_SAVE_CONTROL_DELAYED && - ret != RAM_SAVE_CONTROL_NOT_SUPP) { + if (ret != RAM_SAVE_CONTROL_DELAYED) { if (ret < 0) { qemu_file_set_error(f, ret); } diff --git a/migration/rdma.h b/migration/rdma.h index 4d3386b84a..f74f16a459 100644 --- a/migration/rdma.h +++ b/migration/rdma.h @@ -33,7 +33,6 @@ void rdma_start_incoming_migration(InetSocketAddress *host_port, Error **errp); #define RAM_CONTROL_ROUND 1 #define RAM_CONTROL_FINISH 3 -#define RAM_SAVE_CONTROL_NOT_SUPP -1000 #define RAM_SAVE_CONTROL_DELAYED -2000 #ifdef CONFIG_RDMA @@ -56,7 +55,7 @@ static inline int rdma_control_save_page(QEMUFile *f, ram_addr_t block_offset, ram_addr_t offset, size_t size) { - return RAM_SAVE_CONTROL_NOT_SUPP; + g_assert_not_reached(); } #endif #endif From 7d9849c3c41463ab9ba40348a8606927dc0fb85d Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 11 Mar 2025 10:42:21 +0800 Subject: [PATCH 0586/2760] migration: Add qtest for migration over RDMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This qtest requires there is a RDMA(RoCE) link in the host. In order to make the test work smoothly, introduce a scripts/rdma-migration-helper.sh to detect existing RoCE link before running the test. Test will be skipped if there is no available RoCE link. # Start of rdma tests # Running /x86_64/migration/precopy/rdma/plain ok 1 /x86_64/migration/precopy/rdma/plain # SKIP No rdma link available # To enable the test: # Run 'scripts/rdma-migration-helper.sh setup' with root to setup a new rdma/rxe link and rerun the test # Optional: run 'scripts/rdma-migration-helper.sh clean' to revert the 'setup' # End of rdma tests Cc: Philippe Mathieu-Daudé Cc: Stefan Hajnoczi Reviewed-by: Peter Xu Signed-off-by: Li Zhijian Message-ID: <20250311024221.363421-1-lizhijian@fujitsu.com> [add 'head -1' to script, reformat test message] Signed-off-by: Fabiano Rosas --- MAINTAINERS | 1 + scripts/rdma-migration-helper.sh | 70 +++++++++++++++++++++++++++ tests/qtest/migration/precopy-tests.c | 66 +++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100755 scripts/rdma-migration-helper.sh diff --git a/MAINTAINERS b/MAINTAINERS index b3f9f2680b..8cd96269b2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3538,6 +3538,7 @@ R: Li Zhijian R: Peter Xu S: Odd Fixes F: migration/rdma* +F: scripts/rdma-migration-helper.sh Migration dirty limit and dirty page rate M: Hyman Huang diff --git a/scripts/rdma-migration-helper.sh b/scripts/rdma-migration-helper.sh new file mode 100755 index 0000000000..a39f2fb0e5 --- /dev/null +++ b/scripts/rdma-migration-helper.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Copied from blktests +get_ipv4_addr() +{ + ip -4 -o addr show dev "$1" | + sed -n 's/.*[[:blank:]]inet[[:blank:]]*\([^[:blank:]/]*\).*/\1/p' | + head -1 | tr -d '\n' +} + +# existing rdma interfaces +rdma_interfaces() +{ + rdma link show | sed -nE 's/^link .* netdev ([^ ]+).*$/\1 /p' +} + +# existing valid ipv4 interfaces +ipv4_interfaces() +{ + ip -o addr show | awk '/inet / {print $2}' | grep -v -w lo +} + +rdma_rxe_detect() +{ + for r in $(rdma_interfaces) + do + ipv4_interfaces | grep -qw $r && get_ipv4_addr $r && return + done + + return 1 +} + +rdma_rxe_setup() +{ + for i in $(ipv4_interfaces) + do + rdma_interfaces | grep -qw $i && continue + rdma link add "${i}_rxe" type rxe netdev "$i" && { + echo "Setup new rdma/rxe ${i}_rxe for $i with $(get_ipv4_addr $i)" + return + } + done + + echo "Failed to setup any new rdma/rxe link" >&2 + return 1 +} + +rdma_rxe_clean() +{ + modprobe -r rdma_rxe +} + +operation=${1:-detect} + +command -v rdma >/dev/null || { + echo "Command 'rdma' is not available, please install it first." >&2 + exit 1 +} + +if [ "$operation" == "setup" ] || [ "$operation" == "clean" ]; then + [ "$UID" == 0 ] || { + echo "Root privilege is required to setup/clean a rdma/rxe link" >&2 + exit 1 + } + rdma_rxe_"$operation" +elif [ "$operation" == "detect" ]; then + rdma_rxe_detect +else + echo "Usage: $0 [setup | detect | clean]" +fi diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index ba273d10b9..565630dddf 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -99,6 +99,68 @@ static void test_precopy_unix_dirty_ring(void) test_precopy_common(&args); } +#ifdef CONFIG_RDMA + +#define RDMA_MIGRATION_HELPER "scripts/rdma-migration-helper.sh" +static int new_rdma_link(char *buffer) +{ + char cmd[256]; + bool verbose = g_getenv("QTEST_LOG"); + + snprintf(cmd, sizeof(cmd), "%s detect %s", RDMA_MIGRATION_HELPER, + verbose ? "" : "2>/dev/null"); + + FILE *pipe = popen(cmd, "r"); + if (pipe == NULL) { + perror("Failed to run script"); + return -1; + } + + int idx = 0; + while (fgets(buffer + idx, 128 - idx, pipe) != NULL) { + idx += strlen(buffer); + } + + int status = pclose(pipe); + if (status == -1) { + perror("Error reported by pclose()"); + return -1; + } else if (WIFEXITED(status)) { + return WEXITSTATUS(status); + } + + return -1; +} + +static void test_precopy_rdma_plain(void) +{ + char buffer[128] = {}; + + if (new_rdma_link(buffer)) { + g_test_skip("No rdma link available\n" + "# To enable the test:\n" + "# Run \'" RDMA_MIGRATION_HELPER " setup\' with root to " + "setup a new rdma/rxe link and rerun the test\n" + "# Optional: run 'scripts/rdma-migration-helper.sh clean' " + "to revert the 'setup'"); + return; + } + + /* + * TODO: query a free port instead of hard code. + * 29200=('R'+'D'+'M'+'A')*100 + **/ + g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer); + + MigrateCommon args = { + .listen_uri = uri, + .connect_uri = uri, + }; + + test_precopy_common(&args); +} +#endif + static void test_precopy_tcp_plain(void) { MigrateCommon args = { @@ -1124,6 +1186,10 @@ static void migration_test_add_precopy_smoke(MigrationTestEnv *env) test_multifd_tcp_uri_none); migration_test_add("/migration/multifd/tcp/plain/cancel", test_multifd_tcp_cancel); +#ifdef CONFIG_RDMA + migration_test_add("/migration/precopy/rdma/plain", + test_precopy_rdma_plain); +#endif } void migration_test_add_precopy(MigrationTestEnv *env) From b407c9e74753ca0dbc00832bf5fcec44efd05308 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 7 Apr 2025 09:28:33 +0200 Subject: [PATCH 0587/2760] migration: Fix latent bug in migrate_params_test_apply() migrate_params_test_apply() neglects to apply tls_authz. Currently harmless, because migrate_params_check() doesn't care. Fix it anyway. Signed-off-by: Markus Armbruster Reviewed-by: Fabiano Rosas Message-ID: <20250407072833.2118928-1-armbru@redhat.com> Signed-off-by: Fabiano Rosas --- migration/options.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/migration/options.c b/migration/options.c index 4ba8fcb7dc..b6ae95358d 100644 --- a/migration/options.c +++ b/migration/options.c @@ -1218,6 +1218,11 @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->tls_hostname = params->tls_hostname->u.s; } + if (params->tls_authz) { + assert(params->tls_authz->type == QTYPE_QSTRING); + dest->tls_authz = params->tls_authz->u.s; + } + if (params->has_max_bandwidth) { dest->max_bandwidth = params->max_bandwidth; } From 56e3c89f44ecebc946fbe4ffed325d1a79b26e38 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Fri, 11 Apr 2025 17:15:28 +0530 Subject: [PATCH 0588/2760] migration/multifd: move macros to multifd header Move MULTIFD_ macros to the header file so that they are accessible from other source files. Reviewed-by: Fabiano Rosas Signed-off-by: Prasad Pandit Reviewed-by: Peter Xu Message-ID: <20250411114534.3370816-2-ppandit@redhat.com> Signed-off-by: Fabiano Rosas --- migration/multifd.c | 5 ----- migration/multifd.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index 86c83e43c0..ec108af624 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -36,11 +36,6 @@ #include "io/channel-socket.h" #include "yank_functions.h" -/* Multiple fd's */ - -#define MULTIFD_MAGIC 0x11223344U -#define MULTIFD_VERSION 1 - typedef struct { uint32_t magic; uint32_t version; diff --git a/migration/multifd.h b/migration/multifd.h index 2d337e7b3b..9b6d81e7ed 100644 --- a/migration/multifd.h +++ b/migration/multifd.h @@ -49,6 +49,11 @@ bool multifd_queue_page(RAMBlock *block, ram_addr_t offset); bool multifd_recv(void); MultiFDRecvData *multifd_get_recv_data(void); +/* Multiple fd's */ + +#define MULTIFD_MAGIC 0x11223344U +#define MULTIFD_VERSION 1 + /* Multifd Compression flags */ #define MULTIFD_FLAG_SYNC (1 << 0) From 00f3fcef1981eb23f98b956d9cda2df528bfef40 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Fri, 11 Apr 2025 17:15:29 +0530 Subject: [PATCH 0589/2760] migration: refactor channel discovery mechanism The various logical migration channels don't have a standardized way of advertising themselves and their connections may be seen out of order by the migration destination. When a new connection arrives, the incoming migration currently make use of heuristics to determine which channel it belongs to. The next few patches will need to change how the multifd and postcopy capabilities interact and that affects the channel discovery heuristic. Refactor the channel discovery heuristic to make it less opaque and simplify the subsequent patches. Signed-off-by: Prasad Pandit Reviewed-by: Fabiano Rosas Message-ID: <20250411114534.3370816-3-ppandit@redhat.com> Signed-off-by: Fabiano Rosas --- migration/migration.c | 130 +++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 60 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 54fce997aa..f18cadcc5e 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -95,6 +95,9 @@ enum mig_rp_message_type { MIG_RP_MSG_MAX }; +/* Migration channel types */ +enum { CH_MAIN, CH_MULTIFD, CH_POSTCOPY }; + /* When we add fault tolerance, we could have several migrations at once. For now we don't need to add dynamic creation of migration */ @@ -941,9 +944,8 @@ static void migration_incoming_setup(QEMUFile *f) { MigrationIncomingState *mis = migration_incoming_get_current(); - if (!mis->from_src_file) { - mis->from_src_file = f; - } + assert(!mis->from_src_file); + mis->from_src_file = f; qemu_file_set_blocking(f, false); } @@ -995,28 +997,19 @@ void migration_fd_process_incoming(QEMUFile *f) migration_incoming_process(); } -/* - * Returns true when we want to start a new incoming migration process, - * false otherwise. - */ -static bool migration_should_start_incoming(bool main_channel) +static bool migration_has_main_and_multifd_channels(void) { - /* Multifd doesn't start unless all channels are established */ - if (migrate_multifd()) { - return migration_has_all_channels(); + MigrationIncomingState *mis = migration_incoming_get_current(); + if (!mis->from_src_file) { + /* main channel not established */ + return false; } - /* Preempt channel only starts when the main channel is created */ - if (migrate_postcopy_preempt()) { - return main_channel; + if (migrate_multifd() && !multifd_recv_all_channels_created()) { + return false; } - /* - * For all the rest types of migration, we should only reach here when - * it's the main channel that's being created, and we should always - * proceed with this channel. - */ - assert(main_channel); + /* main and all multifd channels are established */ return true; } @@ -1025,59 +1018,81 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) MigrationIncomingState *mis = migration_incoming_get_current(); Error *local_err = NULL; QEMUFile *f; - bool default_channel = true; + uint8_t channel; uint32_t channel_magic = 0; int ret = 0; - if (migrate_multifd() && !migrate_mapped_ram() && - !migrate_postcopy_ram() && - qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) { - /* - * With multiple channels, it is possible that we receive channels - * out of order on destination side, causing incorrect mapping of - * source channels on destination side. Check channel MAGIC to - * decide type of channel. Please note this is best effort, postcopy - * preempt channel does not send any magic number so avoid it for - * postcopy live migration. Also tls live migration already does - * tls handshake while initializing main channel so with tls this - * issue is not possible. - */ - ret = migration_channel_read_peek(ioc, (void *)&channel_magic, - sizeof(channel_magic), errp); + if (!migration_has_main_and_multifd_channels()) { + if (qio_channel_has_feature(ioc, QIO_CHANNEL_FEATURE_READ_MSG_PEEK)) { + /* + * With multiple channels, it is possible that we receive channels + * out of order on destination side, causing incorrect mapping of + * source channels on destination side. Check channel MAGIC to + * decide type of channel. Please note this is best effort, + * postcopy preempt channel does not send any magic number so + * avoid it for postcopy live migration. Also tls live migration + * already does tls handshake while initializing main channel so + * with tls this issue is not possible. + */ + ret = migration_channel_read_peek(ioc, (void *)&channel_magic, + sizeof(channel_magic), errp); + if (ret != 0) { + return; + } - if (ret != 0) { + channel_magic = be32_to_cpu(channel_magic); + if (channel_magic == QEMU_VM_FILE_MAGIC) { + channel = CH_MAIN; + } else if (channel_magic == MULTIFD_MAGIC) { + assert(migrate_multifd()); + channel = CH_MULTIFD; + } else if (!mis->from_src_file && + mis->state == MIGRATION_STATUS_POSTCOPY_PAUSED) { + /* reconnect main channel for postcopy recovery */ + channel = CH_MAIN; + } else { + error_setg(errp, "unknown channel magic: %u", channel_magic); + return; + } + } else if (mis->from_src_file && migrate_multifd()) { + /* + * Non-peekable channels like tls/file are processed as + * multifd channels when multifd is enabled. + */ + channel = CH_MULTIFD; + } else if (!mis->from_src_file) { + channel = CH_MAIN; + } else { + error_setg(errp, "non-peekable channel used without multifd"); return; } - - default_channel = (channel_magic == cpu_to_be32(QEMU_VM_FILE_MAGIC)); } else { - default_channel = !mis->from_src_file; + assert(migrate_postcopy_preempt()); + channel = CH_POSTCOPY; } if (multifd_recv_setup(errp) != 0) { return; } - if (default_channel) { + if (channel == CH_MAIN) { f = qemu_file_new_input(ioc); migration_incoming_setup(f); - } else { + } else if (channel == CH_MULTIFD) { /* Multiple connections */ - assert(migration_needs_multiple_sockets()); - if (migrate_multifd()) { - multifd_recv_new_channel(ioc, &local_err); - } else { - assert(migrate_postcopy_preempt()); - f = qemu_file_new_input(ioc); - postcopy_preempt_new_channel(mis, f); - } + multifd_recv_new_channel(ioc, &local_err); if (local_err) { error_propagate(errp, local_err); return; } + } else if (channel == CH_POSTCOPY) { + assert(!mis->postcopy_qemufile_dst); + f = qemu_file_new_input(ioc); + postcopy_preempt_new_channel(mis, f); + return; } - if (migration_should_start_incoming(default_channel)) { + if (migration_has_main_and_multifd_channels()) { /* If it's a recovery, we're done */ if (postcopy_try_recover()) { return; @@ -1094,18 +1109,13 @@ void migration_ioc_process_incoming(QIOChannel *ioc, Error **errp) */ bool migration_has_all_channels(void) { - MigrationIncomingState *mis = migration_incoming_get_current(); - - if (!mis->from_src_file) { + if (!migration_has_main_and_multifd_channels()) { return false; } - if (migrate_multifd()) { - return multifd_recv_all_channels_created(); - } - - if (migrate_postcopy_preempt()) { - return mis->postcopy_qemufile_dst != NULL; + MigrationIncomingState *mis = migration_incoming_get_current(); + if (migrate_postcopy_preempt() && !mis->postcopy_qemufile_dst) { + return false; } return true; From 1d481116015428c02f7e3635f9bc0b88b0978fdc Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 11 Apr 2025 17:15:30 +0530 Subject: [PATCH 0590/2760] migration: Add save_postcopy_prepare() savevm handler Add a savevm handler for a module to opt-in sending extra sections right before postcopy starts, and before VM is stopped. RAM will start to use this new savevm handler in the next patch to do flush and sync for multifd pages. Note that we choose to do it before VM stopped because the current only potential user is not sensitive to VM status, so doing it before VM is stopped is preferred to enlarge any postcopy downtime. It is still a bit unfortunate that we need to introduce such a new savevm handler just for the only use case, however it's so far the cleanest. Signed-off-by: Peter Xu Signed-off-by: Prasad Pandit Reviewed-by: Fabiano Rosas Message-ID: <20250411114534.3370816-4-ppandit@redhat.com> Signed-off-by: Fabiano Rosas --- include/migration/register.h | 15 +++++++++++++++ migration/migration.c | 4 ++++ migration/savevm.c | 33 +++++++++++++++++++++++++++++++++ migration/savevm.h | 1 + 4 files changed, 53 insertions(+) diff --git a/include/migration/register.h b/include/migration/register.h index c041ce32f2..b79dc81b8d 100644 --- a/include/migration/register.h +++ b/include/migration/register.h @@ -189,6 +189,21 @@ typedef struct SaveVMHandlers { /* This runs outside the BQL! */ + /** + * @save_postcopy_prepare + * + * This hook will be invoked on the source side right before switching + * to postcopy (before VM stopped). + * + * @f: QEMUFile where to send the data + * @opaque: Data pointer passed to register_savevm_live() + * @errp: Error** used to report error message + * + * Returns: true if succeeded, false if error occured. When false is + * returned, @errp must be set. + */ + bool (*save_postcopy_prepare)(QEMUFile *f, void *opaque, Error **errp); + /** * @state_pending_estimate * diff --git a/migration/migration.c b/migration/migration.c index f18cadcc5e..4697732bef 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -2727,6 +2727,10 @@ static int postcopy_start(MigrationState *ms, Error **errp) } } + if (!qemu_savevm_state_postcopy_prepare(ms->to_dst_file, errp)) { + return -1; + } + trace_postcopy_start(); bql_lock(); trace_postcopy_start_set_run(); diff --git a/migration/savevm.c b/migration/savevm.c index 0c12e373b4..006514c3e3 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -1523,6 +1523,39 @@ void qemu_savevm_state_complete_postcopy(QEMUFile *f) qemu_fflush(f); } +bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp) +{ + SaveStateEntry *se; + bool ret; + + QTAILQ_FOREACH(se, &savevm_state.handlers, entry) { + if (!se->ops || !se->ops->save_postcopy_prepare) { + continue; + } + + if (se->ops->is_active) { + if (!se->ops->is_active(se->opaque)) { + continue; + } + } + + trace_savevm_section_start(se->idstr, se->section_id); + + save_section_header(f, se, QEMU_VM_SECTION_PART); + ret = se->ops->save_postcopy_prepare(f, se->opaque, errp); + save_section_footer(f, se); + + trace_savevm_section_end(se->idstr, se->section_id, ret); + + if (!ret) { + assert(*errp); + return false; + } + } + + return true; +} + int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy) { int64_t start_ts_each, end_ts_each; diff --git a/migration/savevm.h b/migration/savevm.h index 138c39a7f9..2d5e9c7166 100644 --- a/migration/savevm.h +++ b/migration/savevm.h @@ -45,6 +45,7 @@ void qemu_savevm_state_pending_exact(uint64_t *must_precopy, void qemu_savevm_state_pending_estimate(uint64_t *must_precopy, uint64_t *can_postcopy); int qemu_savevm_state_complete_precopy_iterable(QEMUFile *f, bool in_postcopy); +bool qemu_savevm_state_postcopy_prepare(QEMUFile *f, Error **errp); void qemu_savevm_send_ping(QEMUFile *f, uint32_t value); void qemu_savevm_send_open_return_path(QEMUFile *f); int qemu_savevm_send_packaged(QEMUFile *f, const uint8_t *buf, size_t len); From ad8d82ffbb8b8034f58a570911e6e9c6328c9384 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Fri, 11 Apr 2025 17:15:31 +0530 Subject: [PATCH 0591/2760] migration/ram: Implement save_postcopy_prepare() Implement save_postcopy_prepare(), preparing for the enablement of both multifd and postcopy. Signed-off-by: Peter Xu Signed-off-by: Prasad Pandit Reviewed-by: Fabiano Rosas Message-ID: <20250411114534.3370816-5-ppandit@redhat.com> Signed-off-by: Fabiano Rosas --- migration/ram.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/migration/ram.c b/migration/ram.c index 1181a99cf6..a749e4a421 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -4398,6 +4398,42 @@ static int ram_resume_prepare(MigrationState *s, void *opaque) return 0; } +static bool ram_save_postcopy_prepare(QEMUFile *f, void *opaque, Error **errp) +{ + int ret; + + if (migrate_multifd()) { + /* + * When multifd is enabled, source QEMU needs to make sure all the + * pages queued before postcopy starts have been flushed. + * + * The load of these pages must happen before switching to postcopy. + * It's because loading of guest pages (so far) in multifd recv + * threads is still non-atomic, so the load cannot happen with vCPUs + * running on the destination side. + * + * This flush and sync will guarantee that those pages are loaded + * _before_ postcopy starts on the destination. The rationale is, + * this happens before VM stops (and before source QEMU sends all + * the rest of the postcopy messages). So when the destination QEMU + * receives the postcopy messages, it must have received the sync + * message on the main channel (either RAM_SAVE_FLAG_MULTIFD_FLUSH, + * or RAM_SAVE_FLAG_EOS), and such message would guarantee that + * all previous guest pages queued in the multifd channels are + * completely loaded. + */ + ret = multifd_ram_flush_and_sync(f); + if (ret < 0) { + error_setg(errp, "%s: multifd flush and sync failed", __func__); + return false; + } + } + + qemu_put_be64(f, RAM_SAVE_FLAG_EOS); + + return true; +} + void postcopy_preempt_shutdown_file(MigrationState *s) { qemu_put_be64(s->postcopy_qemufile_src, RAM_SAVE_FLAG_EOS); @@ -4417,6 +4453,7 @@ static SaveVMHandlers savevm_ram_handlers = { .load_setup = ram_load_setup, .load_cleanup = ram_load_cleanup, .resume_prepare = ram_resume_prepare, + .save_postcopy_prepare = ram_save_postcopy_prepare, }; static void ram_mig_ram_block_resized(RAMBlockNotifier *n, void *host, From 115cec9d663c1a2f5a73df4a5ca02b3a676e8a2a Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Fri, 11 Apr 2025 17:15:33 +0530 Subject: [PATCH 0592/2760] tests/qtest/migration: consolidate set capabilities Migration capabilities are set in multiple '.start_hook' functions for various tests. Instead, consolidate setting capabilities in 'migrate_start_set_capabilities()' function which is called from the 'migrate_start()' function. While simplifying the capabilities setting, it helps to declutter the qtest sources. Suggested-by: Fabiano Rosas Signed-off-by: Prasad Pandit Reviewed-by: Fabiano Rosas Message-ID: <20250411114534.3370816-7-ppandit@redhat.com> [fix open brace] Signed-off-by: Fabiano Rosas --- tests/qtest/migration/compression-tests.c | 22 +++++-- tests/qtest/migration/cpr-tests.c | 6 +- tests/qtest/migration/file-tests.c | 58 ++++++++---------- tests/qtest/migration/framework.c | 75 +++++++++++++++-------- tests/qtest/migration/framework.h | 9 ++- tests/qtest/migration/misc-tests.c | 4 +- tests/qtest/migration/postcopy-tests.c | 8 ++- tests/qtest/migration/precopy-tests.c | 29 +++++---- tests/qtest/migration/tls-tests.c | 23 ++++++- 9 files changed, 150 insertions(+), 84 deletions(-) diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c index 8b58401b84..41e79f031b 100644 --- a/tests/qtest/migration/compression-tests.c +++ b/tests/qtest/migration/compression-tests.c @@ -35,6 +35,9 @@ static void test_multifd_tcp_zstd(void) { MigrateCommon args = { .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd, }; test_precopy_common(&args); @@ -56,6 +59,9 @@ static void test_multifd_tcp_qatzip(void) { MigrateCommon args = { .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip, }; test_precopy_common(&args); @@ -74,6 +80,9 @@ static void test_multifd_tcp_qpl(void) { MigrateCommon args = { .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .start_hook = migrate_hook_start_precopy_tcp_multifd_qpl, }; test_precopy_common(&args); @@ -92,6 +101,9 @@ static void test_multifd_tcp_uadk(void) { MigrateCommon args = { .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .start_hook = migrate_hook_start_precopy_tcp_multifd_uadk, }; test_precopy_common(&args); @@ -103,10 +115,6 @@ migrate_hook_start_xbzrle(QTestState *from, QTestState *to) { migrate_set_parameter_int(from, "xbzrle-cache-size", 33554432); - - migrate_set_capability(from, "xbzrle", true); - migrate_set_capability(to, "xbzrle", true); - return NULL; } @@ -118,6 +126,9 @@ static void test_precopy_unix_xbzrle(void) .listen_uri = uri, .start_hook = migrate_hook_start_xbzrle, .iterations = 2, + .start = { + .caps[MIGRATION_CAPABILITY_XBZRLE] = true, + }, /* * XBZRLE needs pages to be modified when doing the 2nd+ round * iteration to have real data pushed to the stream. @@ -146,6 +157,9 @@ static void test_multifd_tcp_zlib(void) { MigrateCommon args = { .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .start_hook = migrate_hook_start_precopy_tcp_multifd_zlib, }; test_precopy_common(&args); diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index 4758841824..5536e14610 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -24,9 +24,6 @@ static void *migrate_hook_start_mode_reboot(QTestState *from, QTestState *to) migrate_set_parameter_str(from, "mode", "cpr-reboot"); migrate_set_parameter_str(to, "mode", "cpr-reboot"); - migrate_set_capability(from, "x-ignore-shared", true); - migrate_set_capability(to, "x-ignore-shared", true); - return NULL; } @@ -39,6 +36,9 @@ static void test_mode_reboot(void) .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_mode_reboot, + .start = { + .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true, + }, }; test_file_common(&args, true); diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c index f260e2871d..4d78ce0855 100644 --- a/tests/qtest/migration/file-tests.c +++ b/tests/qtest/migration/file-tests.c @@ -107,15 +107,6 @@ static void test_precopy_file_offset_bad(void) test_file_common(&args, false); } -static void *migrate_hook_start_mapped_ram(QTestState *from, - QTestState *to) -{ - migrate_set_capability(from, "mapped-ram", true); - migrate_set_capability(to, "mapped-ram", true); - - return NULL; -} - static void test_precopy_file_mapped_ram_live(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, @@ -123,7 +114,9 @@ static void test_precopy_file_mapped_ram_live(void) MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", - .start_hook = migrate_hook_start_mapped_ram, + .start = { + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + }, }; test_file_common(&args, false); @@ -136,26 +129,14 @@ static void test_precopy_file_mapped_ram(void) MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", - .start_hook = migrate_hook_start_mapped_ram, + .start = { + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + }, }; test_file_common(&args, true); } -static void *migrate_hook_start_multifd_mapped_ram(QTestState *from, - QTestState *to) -{ - migrate_hook_start_mapped_ram(from, to); - - migrate_set_parameter_int(from, "multifd-channels", 4); - migrate_set_parameter_int(to, "multifd-channels", 4); - - migrate_set_capability(from, "multifd", true); - migrate_set_capability(to, "multifd", true); - - return NULL; -} - static void test_multifd_file_mapped_ram_live(void) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, @@ -163,7 +144,10 @@ static void test_multifd_file_mapped_ram_live(void) MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", - .start_hook = migrate_hook_start_multifd_mapped_ram, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + }, }; test_file_common(&args, false); @@ -176,7 +160,10 @@ static void test_multifd_file_mapped_ram(void) MigrateCommon args = { .connect_uri = uri, .listen_uri = "defer", - .start_hook = migrate_hook_start_multifd_mapped_ram, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + }, }; test_file_common(&args, true); @@ -185,8 +172,6 @@ static void test_multifd_file_mapped_ram(void) static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from, QTestState *to) { - migrate_hook_start_multifd_mapped_ram(from, to); - migrate_set_parameter_bool(from, "direct-io", true); migrate_set_parameter_bool(to, "direct-io", true); @@ -201,6 +186,10 @@ static void test_multifd_file_mapped_ram_dio(void) .connect_uri = uri, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_dio, + .start = { + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; if (!probe_o_direct_support(tmpfs)) { @@ -246,7 +235,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset_dio(QTestState *from, fdset_add_fds(from, file, O_WRONLY, 2, true); fdset_add_fds(to, file, O_RDONLY, 2, true); - migrate_hook_start_multifd_mapped_ram(from, to); migrate_set_parameter_bool(from, "direct-io", true); migrate_set_parameter_bool(to, "direct-io", true); @@ -261,8 +249,6 @@ static void *migrate_hook_start_multifd_mapped_ram_fdset(QTestState *from, fdset_add_fds(from, file, O_WRONLY, 2, false); fdset_add_fds(to, file, O_RDONLY, 2, false); - migrate_hook_start_multifd_mapped_ram(from, to); - return NULL; } @@ -275,6 +261,10 @@ static void test_multifd_file_mapped_ram_fdset(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_fdset, .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, + .start = { + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; test_file_common(&args, true); @@ -289,6 +279,10 @@ static void test_multifd_file_mapped_ram_fdset_dio(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio, .end_hook = migrate_hook_end_multifd_mapped_ram_fdset, + .start = { + .caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; if (!probe_o_direct_support(tmpfs)) { diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index 10e1d04b58..e48b80a127 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -30,6 +30,7 @@ #define QEMU_VM_FILE_MAGIC 0x5145564d #define QEMU_ENV_SRC "QTEST_QEMU_BINARY_SRC" #define QEMU_ENV_DST "QTEST_QEMU_BINARY_DST" +#define MULTIFD_TEST_CHANNELS 4 unsigned start_address; unsigned end_address; @@ -207,6 +208,51 @@ static QList *migrate_start_get_qmp_capabilities(const MigrateStart *args) return capabilities; } +static void migrate_start_set_capabilities(QTestState *from, QTestState *to, + MigrateStart *args) +{ + /* + * MigrationCapability_lookup and MIGRATION_CAPABILITY_ constants + * are from qapi-types-migration.h. + */ + for (uint8_t i = 0; i < MIGRATION_CAPABILITY__MAX; i++) { + if (!args->caps[i]) { + continue; + } + if (from) { + migrate_set_capability(from, + MigrationCapability_lookup.array[i], true); + } + if (to) { + migrate_set_capability(to, + MigrationCapability_lookup.array[i], true); + } + } + + /* + * Always enable migration events. Libvirt always uses it, let's try + * to mimic as closer as that. + */ + migrate_set_capability(from, "events", true); + if (!args->defer_target_connect) { + migrate_set_capability(to, "events", true); + } + + /* + * Default number of channels should be fine for most + * tests. Individual tests can override by calling + * migrate_set_parameter() directly. + */ + if (args->caps[MIGRATION_CAPABILITY_MULTIFD]) { + migrate_set_parameter_int(from, "multifd-channels", + MULTIFD_TEST_CHANNELS); + migrate_set_parameter_int(to, "multifd-channels", + MULTIFD_TEST_CHANNELS); + } + + return; +} + int migrate_start(QTestState **from, QTestState **to, const char *uri, MigrateStart *args) { @@ -379,14 +425,7 @@ int migrate_start(QTestState **from, QTestState **to, const char *uri, unlink(shmem_path); } - /* - * Always enable migration events. Libvirt always uses it, let's try - * to mimic as closer as that. - */ - migrate_set_capability(*from, "events", true); - if (!args->defer_target_connect) { - migrate_set_capability(*to, "events", true); - } + migrate_start_set_capabilities(*from, *to, args); return 0; } @@ -432,6 +471,10 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, { QTestState *from, *to; + /* set postcopy capabilities */ + args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME] = true; + args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true; + if (migrate_start(&from, &to, "defer", &args->start)) { return -1; } @@ -440,17 +483,7 @@ static int migrate_postcopy_prepare(QTestState **from_ptr, args->postcopy_data = args->start_hook(from, to); } - migrate_set_capability(from, "postcopy-ram", true); - migrate_set_capability(to, "postcopy-ram", true); - migrate_set_capability(to, "postcopy-blocktime", true); - - if (args->postcopy_preempt) { - migrate_set_capability(from, "postcopy-preempt", true); - migrate_set_capability(to, "postcopy-preempt", true); - } - migrate_ensure_non_converge(from); - migrate_prepare_for_dirty_mem(from); qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," " 'arguments': { " @@ -948,15 +981,9 @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from, QTestState *to, const char *method) { - migrate_set_parameter_int(from, "multifd-channels", 16); - migrate_set_parameter_int(to, "multifd-channels", 16); - migrate_set_parameter_str(from, "multifd-compression", method); migrate_set_parameter_str(to, "multifd-compression", method); - migrate_set_capability(from, "multifd", true); - migrate_set_capability(to, "multifd", true); - /* Start incoming migration from the 1st socket */ migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index e4a11870f6..01e425e64e 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -12,6 +12,7 @@ #define TEST_FRAMEWORK_H #include "libqtest.h" +#include #define FILE_TEST_FILENAME "migfile" #define FILE_TEST_OFFSET 0x1000 @@ -120,6 +121,13 @@ typedef struct { /* Do not connect to target monitor and qtest sockets in qtest_init */ bool defer_target_connect; + + /* + * Migration capabilities to be set in both source and + * destination. For unilateral capabilities, use + * migration_set_capabilities(). + */ + bool caps[MIGRATION_CAPABILITY__MAX]; } MigrateStart; typedef enum PostcopyRecoveryFailStage { @@ -207,7 +215,6 @@ typedef struct { /* Postcopy specific fields */ void *postcopy_data; - bool postcopy_preempt; PostcopyRecoveryFailStage postcopy_recovery_fail_stage; } MigrateCommon; diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c index 2e612d9e38..54995256d8 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -98,6 +98,7 @@ static void test_ignore_shared(void) QTestState *from, *to; MigrateStart args = { .use_shmem = true, + .caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true, }; if (migrate_start(&from, &to, uri, &args)) { @@ -107,9 +108,6 @@ static void test_ignore_shared(void) migrate_ensure_non_converge(from); migrate_prepare_for_dirty_mem(from); - migrate_set_capability(from, "x-ignore-shared", true); - migrate_set_capability(to, "x-ignore-shared", true); - /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); diff --git a/tests/qtest/migration/postcopy-tests.c b/tests/qtest/migration/postcopy-tests.c index 982457bed1..483e3ff99f 100644 --- a/tests/qtest/migration/postcopy-tests.c +++ b/tests/qtest/migration/postcopy-tests.c @@ -39,7 +39,9 @@ static void test_postcopy_suspend(void) static void test_postcopy_preempt(void) { MigrateCommon args = { - .postcopy_preempt = true, + .start = { + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, }; test_postcopy_common(&args); @@ -73,7 +75,9 @@ static void test_postcopy_recovery_fail_reconnect(void) static void test_postcopy_preempt_recovery(void) { MigrateCommon args = { - .postcopy_preempt = true, + .start = { + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, }; test_postcopy_recovery_common(&args); diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index 565630dddf..87b0a7e8ef 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -170,23 +170,14 @@ static void test_precopy_tcp_plain(void) test_precopy_common(&args); } -static void *migrate_hook_start_switchover_ack(QTestState *from, QTestState *to) -{ - - migrate_set_capability(from, "return-path", true); - migrate_set_capability(to, "return-path", true); - - migrate_set_capability(from, "switchover-ack", true); - migrate_set_capability(to, "switchover-ack", true); - - return NULL; -} - static void test_precopy_tcp_switchover_ack(void) { MigrateCommon args = { .listen_uri = "tcp:127.0.0.1:0", - .start_hook = migrate_hook_start_switchover_ack, + .start = { + .caps[MIGRATION_CAPABILITY_RETURN_PATH] = true, + .caps[MIGRATION_CAPABILITY_SWITCHOVER_ACK] = true, + }, /* * Source VM must be running in order to consider the switchover ACK * when deciding to do switchover or not. @@ -455,6 +446,9 @@ static void test_multifd_tcp_uri_none(void) MigrateCommon args = { .listen_uri = "defer", .start_hook = migrate_hook_start_precopy_tcp_multifd, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, /* * Multifd is more complicated than most of the features, it * directly takes guest page buffers when sending, make sure @@ -470,6 +464,9 @@ static void test_multifd_tcp_zero_page_legacy(void) MigrateCommon args = { .listen_uri = "defer", .start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, /* * Multifd is more complicated than most of the features, it * directly takes guest page buffers when sending, make sure @@ -485,6 +482,9 @@ static void test_multifd_tcp_no_zero_page(void) MigrateCommon args = { .listen_uri = "defer", .start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, /* * Multifd is more complicated than most of the features, it * directly takes guest page buffers when sending, make sure @@ -501,6 +501,9 @@ static void test_multifd_tcp_channels_none(void) .listen_uri = "defer", .start_hook = migrate_hook_start_precopy_tcp_multifd, .live = true, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, .connect_channels = ("[ { 'channel-type': 'main'," " 'addr': { 'transport': 'socket'," " 'type': 'inet'," diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index 2cb4a44bcd..72f44defbb 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -375,9 +375,11 @@ static void test_postcopy_tls_psk(void) static void test_postcopy_preempt_tls_psk(void) { MigrateCommon args = { - .postcopy_preempt = true, .start_hook = migrate_hook_start_tls_psk_match, .end_hook = migrate_hook_end_tls_psk, + .start = { + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, }; test_postcopy_common(&args); @@ -397,9 +399,11 @@ static void test_postcopy_recovery_tls_psk(void) static void test_postcopy_preempt_all(void) { MigrateCommon args = { - .postcopy_preempt = true, .start_hook = migrate_hook_start_tls_psk_match, .end_hook = migrate_hook_end_tls_psk, + .start = { + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, }; test_postcopy_recovery_common(&args); @@ -631,6 +635,9 @@ static void test_multifd_tcp_tls_psk_match(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match, .end_hook = migrate_hook_end_tls_psk, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; test_precopy_common(&args); } @@ -640,6 +647,7 @@ static void test_multifd_tcp_tls_psk_mismatch(void) MigrateCommon args = { .start = { .hide_stderr = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch, @@ -656,6 +664,9 @@ static void test_multifd_tcp_tls_x509_default_host(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tls_x509_default_host, .end_hook = migrate_hook_end_tls_x509, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; test_precopy_common(&args); } @@ -666,6 +677,9 @@ static void test_multifd_tcp_tls_x509_override_host(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tls_x509_override_host, .end_hook = migrate_hook_end_tls_x509, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; test_precopy_common(&args); } @@ -688,6 +702,7 @@ static void test_multifd_tcp_tls_x509_mismatch_host(void) MigrateCommon args = { .start = { .hide_stderr = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host, @@ -703,6 +718,9 @@ static void test_multifd_tcp_tls_x509_allow_anon_client(void) .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client, .end_hook = migrate_hook_end_tls_x509, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, }; test_precopy_common(&args); } @@ -712,6 +730,7 @@ static void test_multifd_tcp_tls_x509_reject_anon_client(void) MigrateCommon args = { .start = { .hide_stderr = true, + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, }, .listen_uri = "defer", .start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client, From 20d82622812d888478d04a2d0d8575d70eb5d749 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 24 Apr 2025 18:07:05 -0400 Subject: [PATCH 0593/2760] migration/postcopy: Spatial locality page hint for preempt mode The preempt mode postcopy has been introduced for a while. From latency POV, it should always win the vanilla postcopy. However there's one thing missing when preempt mode is enabled right now, which is the spatial locality hint when there're page requests from the destination side. In vanilla postcopy, as long as a page request was unqueued, it will update the PSS of the precopy background stream, so that after a page request the background thread will move the pages after whatever was requested. It's pretty much a natural behavior when there's only one channel anyway, and one scanner to send the pages. Preempt mode didn't follow that, because preempt mode has its own channel and its own PSS (which doesn't linearly scan the guest memory, but dedicated to resolve page requested from destination). So the page request process and the background migration process are completely separate. This patch adds the hint explicitly for preempt mode. With that, whenever the preempt mode receives a page request on the source, it will service the remote page fault in the return path, then it'll provide a hint to the background thread so that we'll start sending the pages right after the requested ones in the background, assuming the follow up pages have a higher chance to be accessed later. NOTE: since the background migration thread and return path thread run completely concurrently, it doesn't always mean the hint will be applied every single time. For example, it's possible that the return path thread receives multiple page requests in a row without the background thread getting the chance to consume one. In such case, the preempt thread only provide the hint if the previous hint has been consumed. After all, there's no point queuing hints when we only have one linear scanner. This could measureably improve the simple sequential memory access pattern during postcopy (when preempt is on). For random accesses, I can measure a slight increase of remote page fault latency from ~500us -> ~600us, that could be a trade-off to have such hint mechanism, and after all that's still greatly improved comparing to vanilla postcopy on random (~10ms). The patch is verified by our QE team in a video streaming test case, to reduce the pause of the video from ~1min to a few seconds when switching over to postcopy with preempt mode. Reported-by: Xiaohui Li Tested-by: Xiaohui Li Reviewed-by: Juraj Marcin Link: https://lore.kernel.org/r/20250424220705.195544-1-peterx@redhat.com Signed-off-by: Peter Xu --- migration/ram.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index a749e4a421..e12913b43e 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -91,6 +91,36 @@ XBZRLECacheStats xbzrle_counters; +/* + * This structure locates a specific location of a guest page. In QEMU, + * it's described in a tuple of (ramblock, offset). + */ +struct PageLocation { + RAMBlock *block; + unsigned long offset; +}; +typedef struct PageLocation PageLocation; + +/** + * PageLocationHint: describes a hint to a page location + * + * @valid set if the hint is vaild and to be consumed + * @location: the hint content + * + * In postcopy preempt mode, the urgent channel may provide hints to the + * background channel, so that QEMU source can try to migrate whatever is + * right after the requested urgent pages. + * + * This is based on the assumption that the VM (already running on the + * destination side) tends to access the memory with spatial locality. + * This is also the default behavior of vanilla postcopy (preempt off). + */ +struct PageLocationHint { + bool valid; + PageLocation location; +}; +typedef struct PageLocationHint PageLocationHint; + /* used by the search for pages to send */ struct PageSearchStatus { /* The migration channel used for a specific host page */ @@ -395,6 +425,13 @@ struct RAMState { * RAM migration. */ unsigned int postcopy_bmap_sync_requested; + /* + * Page hint during postcopy when preempt mode is on. Return path + * thread sets it, while background migration thread consumes it. + * + * Protected by @bitmap_mutex. + */ + PageLocationHint page_hint; }; typedef struct RAMState RAMState; @@ -2019,6 +2056,21 @@ static void pss_host_page_finish(PageSearchStatus *pss) pss->host_page_start = pss->host_page_end = 0; } +static void ram_page_hint_update(RAMState *rs, PageSearchStatus *pss) +{ + PageLocationHint *hint = &rs->page_hint; + + /* If there's a pending hint not consumed, don't bother */ + if (hint->valid) { + return; + } + + /* Provide a hint to the background stream otherwise */ + hint->location.block = pss->block; + hint->location.offset = pss->page; + hint->valid = true; +} + /* * Send an urgent host page specified by `pss'. Need to be called with * bitmap_mutex held. @@ -2064,6 +2116,7 @@ out: /* For urgent requests, flush immediately if sent */ if (sent) { qemu_fflush(pss->pss_channel); + ram_page_hint_update(rs, pss); } return ret; } @@ -2151,6 +2204,30 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) return (res < 0 ? res : pages); } +static bool ram_page_hint_valid(RAMState *rs) +{ + /* There's only page hint during postcopy preempt mode */ + if (!postcopy_preempt_active()) { + return false; + } + + return rs->page_hint.valid; +} + +static void ram_page_hint_collect(RAMState *rs, RAMBlock **block, + unsigned long *page) +{ + PageLocationHint *hint = &rs->page_hint; + + assert(hint->valid); + + *block = hint->location.block; + *page = hint->location.offset; + + /* Mark the hint consumed */ + hint->valid = false; +} + /** * ram_find_and_save_block: finds a dirty page and sends it to f * @@ -2167,6 +2244,8 @@ static int ram_save_host_page(RAMState *rs, PageSearchStatus *pss) static int ram_find_and_save_block(RAMState *rs) { PageSearchStatus *pss = &rs->pss[RAM_CHANNEL_PRECOPY]; + unsigned long next_page; + RAMBlock *next_block; int pages = 0; /* No dirty page as there is zero RAM */ @@ -2186,7 +2265,14 @@ static int ram_find_and_save_block(RAMState *rs) rs->last_page = 0; } - pss_init(pss, rs->last_seen_block, rs->last_page); + if (ram_page_hint_valid(rs)) { + ram_page_hint_collect(rs, &next_block, &next_page); + } else { + next_block = rs->last_seen_block; + next_page = rs->last_page; + } + + pss_init(pss, next_block, next_page); while (true){ if (!get_queued_page(rs, pss)) { @@ -2319,6 +2405,13 @@ static void ram_save_cleanup(void *opaque) ram_state_cleanup(rsp); } +static void ram_page_hint_reset(PageLocationHint *hint) +{ + hint->location.block = NULL; + hint->location.offset = 0; + hint->valid = false; +} + static void ram_state_reset(RAMState *rs) { int i; @@ -2331,6 +2424,8 @@ static void ram_state_reset(RAMState *rs) rs->last_page = 0; rs->last_version = ram_list.version; rs->xbzrle_started = false; + + ram_page_hint_reset(&rs->page_hint); } #define MAX_WAIT 50 /* ms, half buffered_file limit */ From 0bafd6e9cbcdb1d857240f9f8c5df98a472b1b27 Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Wed, 2 Apr 2025 07:13:06 +0200 Subject: [PATCH 0594/2760] migration/rdma: Remove qemu_rdma_broken_ipv6_kernel I hit following error which testing migration in pure RoCE env: "-incoming rdma:[::]:8089: RDMA ERROR: You only have RoCE / iWARP devices in your systems and your management software has specified '[::]', but IPv6 over RoCE / iWARP is not supported in Linux.#012'." In our setup, we use rdma bind on ipv6 on target host, while connect from source with ipv4, remove the qemu_rdma_broken_ipv6_kernel, migration just work fine. Checking the git history, the function was added since introducing of rdma migration, which is more than 10 years ago. linux-rdma has improved support on RoCE/iWARP for ipv6 over past years. There are a few fixes back in 2016 seems related to the issue, eg: aeb76df46d11 ("IB/core: Set routable RoCE gid type for ipv4/ipv6 networks") other fixes back in 2018, eg: 052eac6eeb56 RDMA/cma: Update RoCE multicast routines to use net namespace 8d20a1f0ecd5 RDMA/cma: Fix rdma_cm raw IB path setting for RoCE 9327c7afdce3 RDMA/cma: Provide a function to set RoCE path record L2 parameters 5c181bda77f4 RDMA/cma: Set default GID type as RoCE when resolving RoCE route 3c7f67d1880d IB/cma: Fix default RoCE type setting be1d325a3358 IB/core: Set RoCEv2 MGID according to spec 63a5f483af0e IB/cma: Set default gid type to RoCEv2 So remove the outdated function and it's usage. Cc: Peter Xu Cc: Li Zhijian Cc: Yu Zhang Cc: Fabiano Rosas Cc: qemu-devel@nongnu.org Cc: linux-rdma@vger.kernel.org Cc: michael@flatgalaxy.com Signed-off-by: Jack Wang Tested-by: Li zhijian Reviewed-by: Michael Galaxy Link: https://lore.kernel.org/r/20250402051306.6509-1-jinpu.wang@ionos.com [peterx: some cosmetic changes] Signed-off-by: Peter Xu --- migration/rdma.c | 180 ++--------------------------------------------- 1 file changed, 4 insertions(+), 176 deletions(-) diff --git a/migration/rdma.c b/migration/rdma.c index 4875ca1987..2d839fce6c 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -767,149 +767,6 @@ static void qemu_rdma_dump_gid(const char *who, struct rdma_cm_id *id) trace_qemu_rdma_dump_gid(who, sgid, dgid); } -/* - * As of now, IPv6 over RoCE / iWARP is not supported by linux. - * We will try the next addrinfo struct, and fail if there are - * no other valid addresses to bind against. - * - * If user is listening on '[::]', then we will not have a opened a device - * yet and have no way of verifying if the device is RoCE or not. - * - * In this case, the source VM will throw an error for ALL types of - * connections (both IPv4 and IPv6) if the destination machine does not have - * a regular infiniband network available for use. - * - * The only way to guarantee that an error is thrown for broken kernels is - * for the management software to choose a *specific* interface at bind time - * and validate what time of hardware it is. - * - * Unfortunately, this puts the user in a fix: - * - * If the source VM connects with an IPv4 address without knowing that the - * destination has bound to '[::]' the migration will unconditionally fail - * unless the management software is explicitly listening on the IPv4 - * address while using a RoCE-based device. - * - * If the source VM connects with an IPv6 address, then we're OK because we can - * throw an error on the source (and similarly on the destination). - * - * But in mixed environments, this will be broken for a while until it is fixed - * inside linux. - * - * We do provide a *tiny* bit of help in this function: We can list all of the - * devices in the system and check to see if all the devices are RoCE or - * Infiniband. - * - * If we detect that we have a *pure* RoCE environment, then we can safely - * thrown an error even if the management software has specified '[::]' as the - * bind address. - * - * However, if there is are multiple hetergeneous devices, then we cannot make - * this assumption and the user just has to be sure they know what they are - * doing. - * - * Patches are being reviewed on linux-rdma. - */ -static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) -{ - /* This bug only exists in linux, to our knowledge. */ -#ifdef CONFIG_LINUX - struct ibv_port_attr port_attr; - - /* - * Verbs are only NULL if management has bound to '[::]'. - * - * Let's iterate through all the devices and see if there any pure IB - * devices (non-ethernet). - * - * If not, then we can safely proceed with the migration. - * Otherwise, there are no guarantees until the bug is fixed in linux. - */ - if (!verbs) { - int num_devices; - struct ibv_device **dev_list = ibv_get_device_list(&num_devices); - bool roce_found = false; - bool ib_found = false; - - for (int x = 0; x < num_devices; x++) { - verbs = ibv_open_device(dev_list[x]); - /* - * ibv_open_device() is not documented to set errno. If - * it does, it's somebody else's doc bug. If it doesn't, - * the use of errno below is wrong. - * TODO Find out whether ibv_open_device() sets errno. - */ - if (!verbs) { - if (errno == EPERM) { - continue; - } else { - error_setg_errno(errp, errno, - "could not open RDMA device context"); - return -1; - } - } - - if (ibv_query_port(verbs, 1, &port_attr)) { - ibv_close_device(verbs); - error_setg(errp, - "RDMA ERROR: Could not query initial IB port"); - return -1; - } - - if (port_attr.link_layer == IBV_LINK_LAYER_INFINIBAND) { - ib_found = true; - } else if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { - roce_found = true; - } - - ibv_close_device(verbs); - - } - - if (roce_found) { - if (ib_found) { - warn_report("migrations may fail:" - " IPv6 over RoCE / iWARP in linux" - " is broken. But since you appear to have a" - " mixed RoCE / IB environment, be sure to only" - " migrate over the IB fabric until the kernel " - " fixes the bug."); - } else { - error_setg(errp, "RDMA ERROR: " - "You only have RoCE / iWARP devices in your systems" - " and your management software has specified '[::]'" - ", but IPv6 over RoCE / iWARP is not supported in Linux."); - return -1; - } - } - - return 0; - } - - /* - * If we have a verbs context, that means that some other than '[::]' was - * used by the management software for binding. In which case we can - * actually warn the user about a potentially broken kernel. - */ - - /* IB ports start with 1, not 0 */ - if (ibv_query_port(verbs, 1, &port_attr)) { - error_setg(errp, "RDMA ERROR: Could not query initial IB port"); - return -1; - } - - if (port_attr.link_layer == IBV_LINK_LAYER_ETHERNET) { - error_setg(errp, "RDMA ERROR: " - "Linux kernel's RoCE / iWARP does not support IPv6 " - "(but patches on linux-rdma in progress)"); - return -1; - } - -#endif - - return 0; -} - /* * Figure out which RDMA device corresponds to the requested IP hostname * Also create the initial connection manager identifiers for opening @@ -917,7 +774,6 @@ static int qemu_rdma_broken_ipv6_kernel(struct ibv_context *verbs, Error **errp) */ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) { - Error *err = NULL; int ret; struct rdma_addrinfo *res; char port_str[16]; @@ -953,9 +809,8 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) goto err_resolve_get_addr; } - /* Try all addresses, saving the first error in @err */ + /* Try all addresses, exit loop on first success of resolving address */ for (struct rdma_addrinfo *e = res; e != NULL; e = e->ai_next) { - Error **local_errp = err ? NULL : &err; inet_ntop(e->ai_family, &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); @@ -964,25 +819,12 @@ static int qemu_rdma_resolve_host(RDMAContext *rdma, Error **errp) ret = rdma_resolve_addr(rdma->cm_id, NULL, e->ai_dst_addr, RDMA_RESOLVE_TIMEOUT_MS); if (ret >= 0) { - if (e->ai_family == AF_INET6) { - ret = qemu_rdma_broken_ipv6_kernel(rdma->cm_id->verbs, - local_errp); - if (ret < 0) { - continue; - } - } - error_free(err); goto route; } } rdma_freeaddrinfo(res); - if (err) { - error_propagate(errp, err); - } else { - error_setg(errp, "RDMA ERROR: could not resolve address %s", - rdma->host); - } + error_setg(errp, "RDMA ERROR: could not resolve address %s", rdma->host); goto err_resolve_get_addr; route: @@ -2611,7 +2453,6 @@ err_rdma_source_connect: static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) { - Error *err = NULL; int ret; struct rdma_cm_id *listen_id; char ip[40] = "unknown"; @@ -2661,9 +2502,8 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) goto err_dest_init_bind_addr; } - /* Try all addresses, saving the first error in @err */ + /* Try all addresses */ for (e = res; e != NULL; e = e->ai_next) { - Error **local_errp = err ? NULL : &err; inet_ntop(e->ai_family, &((struct sockaddr_in *) e->ai_dst_addr)->sin_addr, ip, sizeof ip); @@ -2672,24 +2512,12 @@ static int qemu_rdma_dest_init(RDMAContext *rdma, Error **errp) if (ret < 0) { continue; } - if (e->ai_family == AF_INET6) { - ret = qemu_rdma_broken_ipv6_kernel(listen_id->verbs, - local_errp); - if (ret < 0) { - continue; - } - } - error_free(err); break; } rdma_freeaddrinfo(res); if (!e) { - if (err) { - error_propagate(errp, err); - } else { - error_setg(errp, "RDMA ERROR: Error: could not rdma_bind_addr!"); - } + error_setg(errp, "RDMA ERROR: Error: could not rdma_bind_addr!"); goto err_dest_init_bind_addr; } From e674fedbd1fd9953bc30026670aba6779848280a Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 29 Apr 2025 17:21:39 +0200 Subject: [PATCH 0595/2760] scripts/vmstate-static-checker.py: Allow new name for ghes_addr_le field ghes_addr_le has been renamed to hw_error_le in commit 652f6d86cbb ("acpi/ghes: better name the offset of the hardware error firmware"). Adjust the checker script to allow that changed field name. Signed-off-by: Thomas Huth Reviewed-by: Peter Xu Link: https://lore.kernel.org/r/20250429152141.294380-3-thuth@redhat.com Signed-off-by: Peter Xu --- scripts/vmstate-static-checker.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py index 9c0e6b81f2..25aca839a0 100755 --- a/scripts/vmstate-static-checker.py +++ b/scripts/vmstate-static-checker.py @@ -42,6 +42,7 @@ def check_fields_match(name, s_field, d_field): # Some fields changed names between qemu versions. This list # is used to allow such changes in each section / description. changed_names = { + 'acpi-ghes': ['ghes_addr_le', 'hw_error_le'], 'apic': ['timer', 'timer_expiry'], 'e1000': ['dev', 'parent_obj'], 'ehci': ['dev', 'pcidev'], From 6f8e6aed81277ec14d5a5dcafdd00dadf7ac465c Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:35 +0800 Subject: [PATCH 0596/2760] rust/vmstate: Add support for field_exists checks Unfortunately, at present it's not possible to have a const "with_exist_check" method to append test_fn after vmstate_struct (due to error on "constant functions cannot evaluate destructors" for `F`). Before the vmstate builder, the only way to support "test_fn" is to extend vmstate_struct macro to add the such new optional member (and fortunately, Rust can still parse the current expansion!). Abstract the previous callback implementation of vmstate_validate into a separate macro, and moves it before vmstate_struct for vmstate_struct to call. Note that there's no need to add any extra flag for a new test_fn added in the VMStateField. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/vmstate.rs | 70 +++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 33 deletions(-) diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 1b2b12eadd..8c4a5bee3c 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -200,13 +200,14 @@ pub const fn vmstate_varray_flag(_: PhantomData) -> VMStateFlags /// and [`impl_vmstate_forward!`](crate::impl_vmstate_forward) help with this. #[macro_export] macro_rules! vmstate_of { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(,)?) => { + ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])? $(, $test_fn:expr)? $(,)?) => { $crate::bindings::VMStateField { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() .as_ptr() as *const ::std::os::raw::c_char, offset: $crate::offset_of!($struct_name, $field_name), $(num_offset: $crate::offset_of!($struct_name, $num),)? + $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? // The calls to `call_func_with_field!` are the magic that // computes most of the VMStateField from the type of the field. info: $crate::info_enum_to_ref!($crate::call_func_with_field!( @@ -435,6 +436,38 @@ macro_rules! vmstate_unused { }}; } +pub extern "C" fn rust_vms_test_field_exists FnCall<(&'a T, u8), bool>>( + opaque: *mut c_void, + version_id: c_int, +) -> bool { + // SAFETY: the opaque was passed as a reference to `T`. + let owner: &T = unsafe { &*(opaque.cast::()) }; + let version: u8 = version_id.try_into().unwrap(); + F::call((owner, version)) +} + +pub type VMSFieldExistCb = unsafe extern "C" fn( + opaque: *mut std::os::raw::c_void, + version_id: std::os::raw::c_int, +) -> bool; + +#[macro_export] +macro_rules! vmstate_exist_fn { + ($struct_name:ty, $test_fn:expr) => {{ + const fn test_cb_builder__ $crate::callbacks::FnCall<(&'a T, u8), bool>>( + _phantom: ::core::marker::PhantomData, + ) -> $crate::vmstate::VMSFieldExistCb { + let _: () = F::ASSERT_IS_SOME; + $crate::vmstate::rust_vms_test_field_exists:: + } + + const fn phantom__(_: &T) -> ::core::marker::PhantomData { + ::core::marker::PhantomData + } + Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn))) + }}; +} + // FIXME: including the `vmsd` field in a `const` is not possible without // the const_refs_static feature (stabilized in Rust 1.83.0). Without it, // it is not possible to use VMS_STRUCT in a transparent manner using @@ -445,7 +478,7 @@ macro_rules! vmstate_unused { #[doc(alias = "VMSTATE_STRUCT")] #[macro_export] macro_rules! vmstate_struct { - ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(,)?) => { + ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?, $vmsd:expr, $type:ty $(, $test_fn:expr)? $(,)?) => { $crate::bindings::VMStateField { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() @@ -458,6 +491,7 @@ macro_rules! vmstate_struct { size: ::core::mem::size_of::<$type>(), flags: $crate::bindings::VMStateFlags::VMS_STRUCT, vmsd: $vmsd, + $(field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn),)? ..$crate::zeroable::Zeroable::ZERO } $(.with_varray_flag_unchecked( $crate::call_func_with_field!( @@ -514,43 +548,13 @@ macro_rules! vmstate_fields { }} } -pub extern "C" fn rust_vms_test_field_exists FnCall<(&'a T, u8), bool>>( - opaque: *mut c_void, - version_id: c_int, -) -> bool { - let owner: &T = unsafe { &*(opaque.cast::()) }; - let version: u8 = version_id.try_into().unwrap(); - // SAFETY: the opaque was passed as a reference to `T`. - F::call((owner, version)) -} - -pub type VMSFieldExistCb = unsafe extern "C" fn( - opaque: *mut std::os::raw::c_void, - version_id: std::os::raw::c_int, -) -> bool; - #[doc(alias = "VMSTATE_VALIDATE")] #[macro_export] macro_rules! vmstate_validate { ($struct_name:ty, $test_name:expr, $test_fn:expr $(,)?) => { $crate::bindings::VMStateField { name: ::std::ffi::CStr::as_ptr($test_name), - field_exists: { - const fn test_cb_builder__< - T, - F: for<'a> $crate::callbacks::FnCall<(&'a T, u8), bool>, - >( - _phantom: ::core::marker::PhantomData, - ) -> $crate::vmstate::VMSFieldExistCb { - let _: () = F::ASSERT_IS_SOME; - $crate::vmstate::rust_vms_test_field_exists:: - } - - const fn phantom__(_: &T) -> ::core::marker::PhantomData { - ::core::marker::PhantomData - } - Some(test_cb_builder__::<$struct_name, _>(phantom__(&$test_fn))) - }, + field_exists: $crate::vmstate_exist_fn!($struct_name, $test_fn), flags: $crate::bindings::VMStateFlags( $crate::bindings::VMStateFlags::VMS_MUST_EXIST.0 | $crate::bindings::VMStateFlags::VMS_ARRAY.0, From 756ea88fff96252dd76cf388fb8678cb97dd2658 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 May 2025 09:45:38 +0200 Subject: [PATCH 0597/2760] vmstate: support varray for vmstate_clock! Make vmstate_struct and vmstate_clock more similar; they are basically the same thing, except for the clock case having a built-in VMStateDescription. Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/vmstate.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 8c4a5bee3c..9ae97c389c 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -507,7 +507,7 @@ macro_rules! vmstate_struct { #[doc(alias = "VMSTATE_CLOCK")] #[macro_export] macro_rules! vmstate_clock { - ($struct_name:ty, $field_name:ident) => {{ + ($struct_name:ty, $field_name:ident $([0 .. $num:ident $(* $factor:expr)?])?) => {{ $crate::bindings::VMStateField { name: ::core::concat!(::core::stringify!($field_name), "\0") .as_bytes() @@ -516,7 +516,7 @@ macro_rules! vmstate_clock { $crate::assert_field_type!( $struct_name, $field_name, - $crate::qom::Owned<$crate::qdev::Clock> + $crate::qom::Owned<$crate::qdev::Clock> $(, num = $num)? ); $crate::offset_of!($struct_name, $field_name) }, @@ -527,7 +527,14 @@ macro_rules! vmstate_clock { ), vmsd: unsafe { ::core::ptr::addr_of!($crate::bindings::vmstate_clock) }, ..$crate::zeroable::Zeroable::ZERO - } + } $(.with_varray_flag_unchecked( + $crate::call_func_with_field!( + $crate::vmstate::vmstate_varray_flag, + $struct_name, + $num + ) + ) + $(.with_varray_multiply($factor))?)? }}; } From fff99a88be34c82270c918b711f8fc3affd504d5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 2 May 2025 10:56:06 +0200 Subject: [PATCH 0598/2760] rust: assertions: Support index field wrapped in BqlCell Currently, if the `num` field of a varray is not a numeric type, such as being placed in a wrapper, the array variant of assert_field_type will fail the check. HPET currently wraps num_timers in BqlCell<>. Although BqlCell<> is not necessary from strictly speaking, it makes sense for vmstate to respect BqlCell. The failure of assert_field_type is because it cannot convert BqlCell into usize for use as the index. Use a constant 0 instead for the index, by avoiding $(...)? and extracting the common parts of assert_field_type! into an internal case. Commit message based on a patch by Zhao Liu . Link: https://lore.kernel.org/r/20250414144943.1112885-3-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/assertions.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/rust/qemu-api/src/assertions.rs b/rust/qemu-api/src/assertions.rs index eb12e9499a..a2d38c877d 100644 --- a/rust/qemu-api/src/assertions.rs +++ b/rust/qemu-api/src/assertions.rs @@ -78,33 +78,26 @@ macro_rules! assert_same_type { /// ``` #[macro_export] macro_rules! assert_field_type { - ($t:ty, $i:tt, $ti:ty) => { + (@internal $param_name:ident, $ti:ty, $t:ty, $($field:tt)*) => { const _: () = { #[allow(unused)] - fn assert_field_type(v: $t) { - fn types_must_be_equal(_: T) + fn assert_field_type($param_name: &$t) { + fn types_must_be_equal(_: &T) where T: $crate::assertions::EqType, { } - types_must_be_equal::<_, $ti>(v.$i); + types_must_be_equal::<_, $ti>(&$($field)*); } }; }; + ($t:ty, $i:tt, $ti:ty) => { + $crate::assert_field_type!(@internal v, $ti, $t, v.$i); + }; + ($t:ty, $i:tt, $ti:ty, num = $num:ident) => { - const _: () = { - #[allow(unused)] - fn assert_field_type(v: $t) { - fn types_must_be_equal(_: T) - where - T: $crate::assertions::EqType, - { - } - let index: usize = v.$num.try_into().unwrap(); - types_must_be_equal::<_, &$ti>(&v.$i[index]); - } - }; + $crate::assert_field_type!(@internal v, $ti, $t, v.$i[0]); }; } From cff1ec67509cacc2ea30d19ba61fa0ab0772e119 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:37 +0800 Subject: [PATCH 0599/2760] rust/vmstate_test: Test varray with num field wrapped in BqlCell Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-4-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/tests/vmstate_tests.rs | 41 ++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs index 8b93492a68..f7a93117e1 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -28,7 +28,7 @@ const FOO_ARRAY_MAX: usize = 3; // - VMSTATE_VARRAY_UINT16_UNSAFE // - VMSTATE_VARRAY_MULTIPLY #[repr(C)] -#[derive(qemu_api_macros::offsets)] +#[derive(Default, qemu_api_macros::offsets)] struct FooA { arr: [u8; FOO_ARRAY_MAX], num: u16, @@ -147,8 +147,9 @@ fn test_vmstate_varray_multiply() { // - VMSTATE_STRUCT_VARRAY_UINT8 // - (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32 // - VMSTATE_ARRAY +// - VMSTATE_STRUCT_VARRAY_UINT8 with BqlCell wrapper & test_fn #[repr(C)] -#[derive(qemu_api_macros::offsets)] +#[derive(Default, qemu_api_macros::offsets)] struct FooB { arr_a: [FooA; FOO_ARRAY_MAX], num_a: u8, @@ -158,6 +159,12 @@ struct FooB { val: bool, // FIXME: Use Timer array. Now we can't since it's hard to link savevm.c to test. arr_i64: [i64; FOO_ARRAY_MAX], + arr_a_wrap: [FooA; FOO_ARRAY_MAX], + num_a_wrap: BqlCell, +} + +fn validate_foob(_state: &FooB, _version_id: u8) -> bool { + true } static VMSTATE_FOOB: VMStateDescription = VMStateDescription { @@ -170,13 +177,14 @@ static VMSTATE_FOOB: VMStateDescription = VMStateDescription { vmstate_struct!(FooB, arr_a[0 .. num_a], &VMSTATE_FOOA, FooA).with_version_id(1), vmstate_struct!(FooB, arr_a_mul[0 .. num_a_mul * 32], &VMSTATE_FOOA, FooA).with_version_id(2), vmstate_of!(FooB, arr_i64), + vmstate_struct!(FooB, arr_a_wrap[0 .. num_a_wrap], &VMSTATE_FOOA, FooA, validate_foob), }, ..Zeroable::ZERO }; #[test] fn test_vmstate_bool_v() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; // 1st VMStateField ("val") in VMSTATE_FOOB (corresponding to VMSTATE_BOOL_V) assert_eq!( @@ -196,7 +204,7 @@ fn test_vmstate_bool_v() { #[test] fn test_vmstate_uint64() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; // 2nd VMStateField ("wrap") in VMSTATE_FOOB (corresponding to VMSTATE_U64) assert_eq!( @@ -216,7 +224,7 @@ fn test_vmstate_uint64() { #[test] fn test_vmstate_struct_varray_uint8() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; // 3rd VMStateField ("arr_a") in VMSTATE_FOOB (corresponding to // VMSTATE_STRUCT_VARRAY_UINT8) @@ -240,7 +248,7 @@ fn test_vmstate_struct_varray_uint8() { #[test] fn test_vmstate_struct_varray_uint32_multiply() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) @@ -266,7 +274,7 @@ fn test_vmstate_struct_varray_uint32_multiply() { #[test] fn test_vmstate_macro_array() { - let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 6) }; + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; // 5th VMStateField ("arr_i64") in VMSTATE_FOOB (corresponding to // VMSTATE_ARRAY) @@ -283,9 +291,26 @@ fn test_vmstate_macro_array() { assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_ARRAY); assert!(foo_fields[4].vmsd.is_null()); assert!(foo_fields[4].field_exists.is_none()); +} + +#[test] +fn test_vmstate_struct_varray_uint8_wrapper() { + let foo_fields: &[VMStateField] = unsafe { slice::from_raw_parts(VMSTATE_FOOB.fields, 7) }; + let mut foo_b: FooB = Default::default(); + let foo_b_p = std::ptr::addr_of_mut!(foo_b).cast::(); + + // 6th VMStateField ("arr_a_wrap") in VMSTATE_FOOB (corresponding to + // VMSTATE_STRUCT_VARRAY_UINT8). Other fields are checked in + // test_vmstate_struct_varray_uint8. + assert_eq!( + unsafe { CStr::from_ptr(foo_fields[5].name) }.to_bytes_with_nul(), + b"arr_a_wrap\0" + ); + assert_eq!(foo_fields[5].num_offset, 228); + assert!(unsafe { foo_fields[5].field_exists.unwrap()(foo_b_p, 0) }); // The last VMStateField in VMSTATE_FOOB. - assert_eq!(foo_fields[5].flags, VMStateFlags::VMS_END); + assert_eq!(foo_fields[6].flags, VMStateFlags::VMS_END); } // =========================== Test VMSTATE_FOOC =========================== From 8d9502b4e947a9cfcf1d1940cc70d1579b53ecaf Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:39 +0800 Subject: [PATCH 0600/2760] rust/timer: Define NANOSECONDS_PER_SECOND binding as u64 NANOSECONDS_PER_SECOND is often used in operations with get_ns(), which currently returns a u64. Therefore, define a new NANOSECONDS_PER_SECOND binding is with u64 type to eliminate unnecessary type conversions (from u32 to u64). Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-6-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/timer.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index f0b04ef95d..e769f8bc91 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -121,3 +121,5 @@ impl ClockType { pub const CLOCK_VIRTUAL: ClockType = ClockType { id: QEMUClockType::QEMU_CLOCK_VIRTUAL, }; + +pub const NANOSECONDS_PER_SECOND: u64 = 1000000000; From db46654af893abed53dce35ebab86056ac9b3004 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Mon, 14 Apr 2025 22:49:42 +0800 Subject: [PATCH 0601/2760] rust/hpet: Support migration Based on commit 1433e38cc8 ("hpet: do not overwrite properties on post_load"), add the basic migration support to Rust HPET. The current migration implementation introduces multiple unsafe callbacks. Before the vmstate builder, one possible cleanup approach is to wrap callbacks in the vmstate binding using a method similar to the vmstate_exist_fn macro. However, this approach would also create a lot of repetitive code (since vmstate has so many callbacks: pre_load, post_load, pre_save, post_save, needed and dev_unplug_pending). Although it would be cleaner, it would somewhat deviate from the path of the vmstate builder. Therefore, firstly focus on completing the functionality of HPET, and those current unsafe callbacks can at least clearly indicate the needed functionality of vmstate. The next step is to consider refactoring vmstate to move towards the vmstate builder direction. Additionally, update rust.rst about Rust HPET can support migration. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250414144943.1112885-9-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- docs/devel/rust.rst | 3 +- rust/hw/timer/hpet/src/hpet.rs | 146 ++++++++++++++++++++++++++++++++- 2 files changed, 146 insertions(+), 3 deletions(-) diff --git a/docs/devel/rust.rst b/docs/devel/rust.rst index 88bdec1eb2..3cc2841d4d 100644 --- a/docs/devel/rust.rst +++ b/docs/devel/rust.rst @@ -153,8 +153,7 @@ QEMU includes four crates: .. [#issues] The ``pl011`` crate is synchronized with ``hw/char/pl011.c`` as of commit 02b1f7f61928. The ``hpet`` crate is synchronized as of - commit f32352ff9e. Both are lacking tracing functionality; ``hpet`` - is also lacking support for migration. + commit 1433e38cc8. Both are lacking tracing functionality. This section explains how to work with them. diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index cbd2ed4f6b..12de2ba59a 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -4,6 +4,7 @@ use std::{ ffi::CStr, + os::raw::{c_int, c_void}, pin::Pin, ptr::{addr_of_mut, null_mut, NonNull}, slice::from_ref, @@ -25,7 +26,10 @@ use qemu_api::{ qom::{ObjectImpl, ObjectType, ParentField}, qom_isa, sysbus::{SysBusDevice, SysBusDeviceImpl}, - timer::{Timer, CLOCK_VIRTUAL}, + timer::{Timer, CLOCK_VIRTUAL, NANOSECONDS_PER_SECOND}, + vmstate::VMStateDescription, + vmstate_fields, vmstate_of, vmstate_struct, vmstate_subsections, vmstate_validate, + zeroable::Zeroable, }; use crate::fw_cfg::HPETFwConfig; @@ -561,6 +565,7 @@ pub struct HPETState { #[doc(alias = "timer")] timers: [BqlRefCell; HPET_MAX_TIMERS as usize], num_timers: BqlCell, + num_timers_save: BqlCell, /// Instance id (HPET timer block ID). hpet_id: BqlCell, @@ -839,6 +844,49 @@ impl HPETState { } } } + + fn pre_save(&self) -> i32 { + if self.is_hpet_enabled() { + self.counter.set(self.get_ticks()); + } + + /* + * The number of timers must match on source and destination, but it was + * also added to the migration stream. Check that it matches the value + * that was configured. + */ + self.num_timers_save.set(self.num_timers.get()); + 0 + } + + fn post_load(&self, _version_id: u8) -> i32 { + for timer in self.timers.iter().take(self.get_num_timers()) { + let mut t = timer.borrow_mut(); + + t.cmp64 = t.calculate_cmp64(t.get_state().counter.get(), t.cmp); + t.last = CLOCK_VIRTUAL.get_ns() - NANOSECONDS_PER_SECOND; + } + + // Recalculate the offset between the main counter and guest time + if !self.hpet_offset_saved { + self.hpet_offset + .set(ticks_to_ns(self.counter.get()) - CLOCK_VIRTUAL.get_ns()); + } + + 0 + } + + fn is_rtc_irq_level_needed(&self) -> bool { + self.rtc_irq_level.get() != 0 + } + + fn is_offset_needed(&self) -> bool { + self.is_hpet_enabled() && self.hpet_offset_saved + } + + fn validate_num_timers(&self, _version_id: u8) -> bool { + self.num_timers.get() == self.num_timers_save.get() + } } qom_isa!(HPETState: SysBusDevice, DeviceState, Object); @@ -895,11 +943,107 @@ qemu_api::declare_properties! { ), } +unsafe extern "C" fn hpet_rtc_irq_level_needed(opaque: *mut c_void) -> bool { + // SAFETY: + // the pointer is convertible to a reference + let state: &HPETState = unsafe { NonNull::new(opaque.cast::()).unwrap().as_ref() }; + state.is_rtc_irq_level_needed() +} + +unsafe extern "C" fn hpet_offset_needed(opaque: *mut c_void) -> bool { + // SAFETY: + // the pointer is convertible to a reference + let state: &HPETState = unsafe { NonNull::new(opaque.cast::()).unwrap().as_ref() }; + state.is_offset_needed() +} + +unsafe extern "C" fn hpet_pre_save(opaque: *mut c_void) -> c_int { + // SAFETY: + // the pointer is convertible to a reference + let state: &mut HPETState = + unsafe { NonNull::new(opaque.cast::()).unwrap().as_mut() }; + state.pre_save() as c_int +} + +unsafe extern "C" fn hpet_post_load(opaque: *mut c_void, version_id: c_int) -> c_int { + // SAFETY: + // the pointer is convertible to a reference + let state: &mut HPETState = + unsafe { NonNull::new(opaque.cast::()).unwrap().as_mut() }; + let version: u8 = version_id.try_into().unwrap(); + state.post_load(version) as c_int +} + +static VMSTATE_HPET_RTC_IRQ_LEVEL: VMStateDescription = VMStateDescription { + name: c_str!("hpet/rtc_irq_level").as_ptr(), + version_id: 1, + minimum_version_id: 1, + needed: Some(hpet_rtc_irq_level_needed), + fields: vmstate_fields! { + vmstate_of!(HPETState, rtc_irq_level), + }, + ..Zeroable::ZERO +}; + +static VMSTATE_HPET_OFFSET: VMStateDescription = VMStateDescription { + name: c_str!("hpet/offset").as_ptr(), + version_id: 1, + minimum_version_id: 1, + needed: Some(hpet_offset_needed), + fields: vmstate_fields! { + vmstate_of!(HPETState, hpet_offset), + }, + ..Zeroable::ZERO +}; + +static VMSTATE_HPET_TIMER: VMStateDescription = VMStateDescription { + name: c_str!("hpet_timer").as_ptr(), + version_id: 1, + minimum_version_id: 1, + fields: vmstate_fields! { + vmstate_of!(HPETTimer, index), + vmstate_of!(HPETTimer, config), + vmstate_of!(HPETTimer, cmp), + vmstate_of!(HPETTimer, fsb), + vmstate_of!(HPETTimer, period), + vmstate_of!(HPETTimer, wrap_flag), + vmstate_of!(HPETTimer, qemu_timer), + }, + ..Zeroable::ZERO +}; + +const VALIDATE_TIMERS_NAME: &CStr = c_str!("num_timers must match"); + +static VMSTATE_HPET: VMStateDescription = VMStateDescription { + name: c_str!("hpet").as_ptr(), + version_id: 2, + minimum_version_id: 1, + pre_save: Some(hpet_pre_save), + post_load: Some(hpet_post_load), + fields: vmstate_fields! { + vmstate_of!(HPETState, config), + vmstate_of!(HPETState, int_status), + vmstate_of!(HPETState, counter), + vmstate_of!(HPETState, num_timers_save).with_version_id(2), + vmstate_validate!(HPETState, VALIDATE_TIMERS_NAME, HPETState::validate_num_timers), + vmstate_struct!(HPETState, timers[0 .. num_timers], &VMSTATE_HPET_TIMER, BqlRefCell, HPETState::validate_num_timers).with_version_id(0), + }, + subsections: vmstate_subsections! { + VMSTATE_HPET_RTC_IRQ_LEVEL, + VMSTATE_HPET_OFFSET, + }, + ..Zeroable::ZERO +}; + impl DeviceImpl for HPETState { fn properties() -> &'static [Property] { &HPET_PROPERTIES } + fn vmsd() -> Option<&'static VMStateDescription> { + Some(&VMSTATE_HPET) + } + const REALIZE: Option = Some(Self::realize); } From 7c93067fe7e44f89a720fa5f0faf180697d5ac7e Mon Sep 17 00:00:00 2001 From: Magnus Kulke Date: Tue, 29 Apr 2025 11:33:19 +0200 Subject: [PATCH 0602/2760] target/i386/emulate: remove rflags leftovers Fixes: c901905ea670 ("target/i386/emulate: remove flags_mask") In c901905ea670 rflags have been removed from `x86_decode`, but there were some leftovers. Signed-off-by: Magnus Kulke Link: https://lore.kernel.org/r/20250429093319.5010-1-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_decode.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/target/i386/emulate/x86_decode.c b/target/i386/emulate/x86_decode.c index 7fee219687..7efa2f570e 100644 --- a/target/i386/emulate/x86_decode.c +++ b/target/i386/emulate/x86_decode.c @@ -1408,7 +1408,7 @@ struct decode_tbl _2op_inst[] = { }; struct decode_x87_tbl invl_inst_x87 = {0x0, 0, 0, 0, 0, false, false, NULL, - NULL, decode_invalid, 0}; + NULL, decode_invalid}; struct decode_x87_tbl _x87_inst[] = { {0xd8, 0, 3, X86_DECODE_CMD_FADD, 10, false, false, @@ -1456,8 +1456,7 @@ struct decode_x87_tbl _x87_inst[] = { decode_x87_modrm_st0, NULL, decode_d9_4}, {0xd9, 4, 0, X86_DECODE_CMD_INVL, 4, false, false, decode_x87_modrm_bytep, NULL, NULL}, - {0xd9, 5, 3, X86_DECODE_CMD_FLDxx, 10, false, false, NULL, NULL, NULL, - RFLAGS_MASK_NONE}, + {0xd9, 5, 3, X86_DECODE_CMD_FLDxx, 10, false, false, NULL, NULL, NULL}, {0xd9, 5, 0, X86_DECODE_CMD_FLDCW, 2, false, false, decode_x87_modrm_bytep, NULL, NULL}, @@ -1478,20 +1477,17 @@ struct decode_x87_tbl _x87_inst[] = { decode_x87_modrm_st0, NULL}, {0xda, 3, 3, X86_DECODE_CMD_FCMOV, 10, false, false, decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, - {0xda, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, - RFLAGS_MASK_NONE}, + {0xda, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL}, {0xda, 4, 0, X86_DECODE_CMD_FSUB, 4, false, false, decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, {0xda, 5, 3, X86_DECODE_CMD_FUCOM, 10, false, true, decode_x87_modrm_st0, decode_decode_x87_modrm_st0, NULL}, {0xda, 5, 0, X86_DECODE_CMD_FSUB, 4, true, false, decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, - {0xda, 6, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, - RFLAGS_MASK_NONE}, + {0xda, 6, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL}, {0xda, 6, 0, X86_DECODE_CMD_FDIV, 4, false, false, decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, - {0xda, 7, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, - RFLAGS_MASK_NONE}, + {0xda, 7, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL}, {0xda, 7, 0, X86_DECODE_CMD_FDIV, 4, true, false, decode_x87_modrm_st0, decode_x87_modrm_intp, NULL}, @@ -1511,8 +1507,7 @@ struct decode_x87_tbl _x87_inst[] = { decode_x87_modrm_intp, NULL, NULL}, {0xdb, 4, 3, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, decode_db_4}, - {0xdb, 4, 0, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL, - RFLAGS_MASK_NONE}, + {0xdb, 4, 0, X86_DECODE_CMD_INVL, 10, false, false, NULL, NULL, NULL}, {0xdb, 5, 3, X86_DECODE_CMD_FUCOMI, 10, false, false, decode_x87_modrm_st0, decode_x87_modrm_st0, NULL}, {0xdb, 5, 0, X86_DECODE_CMD_FLD, 10, false, false, From 785f945bd5ace415419d0fe4944fa5fce1bc1865 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Tue, 29 Apr 2025 06:24:51 +0000 Subject: [PATCH 0603/2760] target/i386/hvf: fix a compilation error Include exec/target_page.h to fix the following build error. x86_64-softmmu.a.p/target_i386_hvf_hvf.c.o -c ../target/i386/hvf/hvf.c ../target/i386/hvf/hvf.c:139:49: error: use of undeclared identifier 'TARGET_PAGE_SIZE' 139 | uint64_t dirty_page_start = gpa & ~(TARGET_PAGE_SIZE - 1u); | ^ ../target/i386/hvf/hvf.c:141:45: error: use of undeclared identifier 'TARGET_PAGE_SIZE' 141 | hv_vm_protect(dirty_page_start, TARGET_PAGE_SIZE, | ^ Signed-off-by: Wei Liu Link: https://lore.kernel.org/r/aBBws1ikCDfyC0RI@liuwe-devbox-ubuntu-v2.tail21d00.ts.net Signed-off-by: Paolo Bonzini --- target/i386/hvf/hvf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/i386/hvf/hvf.c b/target/i386/hvf/hvf.c index 23ebf2550a..99e37a33e5 100644 --- a/target/i386/hvf/hvf.c +++ b/target/i386/hvf/hvf.c @@ -76,6 +76,7 @@ #include "qemu/main-loop.h" #include "qemu/accel.h" #include "target/i386/cpu.h" +#include "exec/target_page.h" static Error *invtsc_mig_blocker; From e54ef98c8a80d16158bab4341d9a898701270528 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 13 Feb 2025 19:37:07 +0100 Subject: [PATCH 0604/2760] target/i386: do not trigger IRQ shadow for LSS Because LSS need not trigger an IRQ shadow, gen_movl_seg can't just use the destination register to decide whether to inhibit IRQs. Add an argument. Cc: qemu-stable@nongnu.org Signed-off-by: Paolo Bonzini --- target/i386/tcg/emit.c.inc | 4 ++-- target/i386/tcg/translate.c | 27 ++++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/target/i386/tcg/emit.c.inc b/target/i386/tcg/emit.c.inc index e3166e70a5..1a7fab9333 100644 --- a/target/i386/tcg/emit.c.inc +++ b/target/i386/tcg/emit.c.inc @@ -342,7 +342,7 @@ static void gen_writeback(DisasContext *s, X86DecodedInsn *decode, int opn, TCGv break; case X86_OP_SEG: /* Note that gen_movl_seg takes care of interrupt shadow and TF. */ - gen_movl_seg(s, op->n, s->T0); + gen_movl_seg(s, op->n, v, op->n == R_SS); break; case X86_OP_INT: if (op->has_ea) { @@ -2382,7 +2382,7 @@ static void gen_lxx_seg(DisasContext *s, X86DecodedInsn *decode, int seg) gen_op_ld_v(s, MO_16, s->T1, s->A0); /* load the segment here to handle exceptions properly */ - gen_movl_seg(s, seg, s->T1); + gen_movl_seg(s, seg, s->T1, false); } static void gen_LDS(DisasContext *s, X86DecodedInsn *decode) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index 8a641951cd..a4e935b043 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2026,27 +2026,32 @@ static void gen_op_movl_seg_real(DisasContext *s, X86Seg seg_reg, TCGv seg) /* move SRC to seg_reg and compute if the CPU state may change. Never call this function with seg_reg == R_CS */ -static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src) +static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit_irq) { if (PE(s) && !VM86(s)) { TCGv_i32 sel = tcg_temp_new_i32(); tcg_gen_trunc_tl_i32(sel, src); gen_helper_load_seg(tcg_env, tcg_constant_i32(seg_reg), sel); - /* abort translation because the addseg value may change or - because ss32 may change. For R_SS, translation must always - stop as a special handling must be done to disable hardware - interrupts for the next instruction */ - if (seg_reg == R_SS) { - s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; - } else if (CODE32(s) && seg_reg < R_FS) { + + /* For move to DS/ES/SS, the addseg or ss32 flags may change. */ + if (CODE32(s) && seg_reg < R_FS) { s->base.is_jmp = DISAS_EOB_NEXT; } } else { gen_op_movl_seg_real(s, seg_reg, src); - if (seg_reg == R_SS) { - s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; - } + } + + /* + * For MOV or POP to SS (but not LSS) translation must always + * stop as a special handling must be done to disable hardware + * interrupts for the next instruction. + * + * DISAS_EOB_INHIBIT_IRQ is a superset of DISAS_EOB_NEXT which + * might have been set above. + */ + if (inhibit_irq) { + s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; } } From 1e94ddc6854431064c94a7d8f2f2886def285829 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 15 Jul 2024 10:35:06 +0200 Subject: [PATCH 0605/2760] target/i386: do not block singlestep for STI STI will trigger a singlestep exception even if it has inhibit-IRQ behavior. Do not suppress single-step for all IRQ-inhibiting instructions, instead special case MOV SS and POP SS. Cc: qemu-stable@nongnu.org Fixes: f0f0136abba ("target/i386: no single-step exception after MOV or POP SS", 2024-05-25) Signed-off-by: Paolo Bonzini --- target/i386/tcg/translate.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c index a4e935b043..ed43c95c1d 100644 --- a/target/i386/tcg/translate.c +++ b/target/i386/tcg/translate.c @@ -2047,11 +2047,15 @@ static void gen_movl_seg(DisasContext *s, X86Seg seg_reg, TCGv src, bool inhibit * stop as a special handling must be done to disable hardware * interrupts for the next instruction. * + * This is the last instruction, so it's okay to overwrite + * HF_TF_MASK; the next TB will start with the flag set. + * * DISAS_EOB_INHIBIT_IRQ is a superset of DISAS_EOB_NEXT which * might have been set above. */ if (inhibit_irq) { s->base.is_jmp = DISAS_EOB_INHIBIT_IRQ; + s->flags &= ~HF_TF_MASK; } } @@ -2302,7 +2306,7 @@ gen_eob(DisasContext *s, int mode) if (mode == DISAS_EOB_RECHECK_TF) { gen_helper_rechecking_single_step(tcg_env); tcg_gen_exit_tb(NULL, 0); - } else if ((s->flags & HF_TF_MASK) && mode != DISAS_EOB_INHIBIT_IRQ) { + } else if (s->flags & HF_TF_MASK) { gen_helper_single_step(tcg_env); } else if (mode == DISAS_JUMP && /* give irqs a chance to happen */ From 8dc4f981004f17efe2d28f26b180f618f24f46de Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Fri, 2 May 2025 11:55:24 +0200 Subject: [PATCH 0606/2760] hw/char/serial: Remove unused prog_if compat property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property was added to preserve previous value when this was fixed in version 2.1 but the last machine using it was already removed when adding diva-gsp leaving this property unused and unnecessary. Signed-off-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Helge Deller Link: https://lore.kernel.org/r/20250502095524.DE1F355D264@zero.eik.bme.hu Signed-off-by: Paolo Bonzini --- hw/char/diva-gsp.c | 6 ++---- hw/char/serial-pci-multi.c | 7 ++----- hw/char/serial-pci.c | 10 ++-------- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/hw/char/diva-gsp.c b/hw/char/diva-gsp.c index 60f933191d..e1f0713cb7 100644 --- a/hw/char/diva-gsp.c +++ b/hw/char/diva-gsp.c @@ -51,7 +51,6 @@ typedef struct PCIDivaSerialState { SerialState state[PCI_SERIAL_MAX_PORTS]; uint32_t level[PCI_SERIAL_MAX_PORTS]; qemu_irq *irqs; - uint8_t prog_if; bool disable; } PCIDivaSerialState; @@ -124,8 +123,8 @@ static void diva_pci_realize(PCIDevice *dev, Error **errp) size_t i, offset = 0; size_t portmask = di.omask; - pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; - pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */ + pci->dev.config[PCI_INTERRUPT_PIN] = 1; memory_region_init(&pci->membar, OBJECT(pci), "serial_ports", 4096); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &pci->membar); pci->irqs = qemu_allocate_irqs(multi_serial_irq_mux, pci, di.nports); @@ -178,7 +177,6 @@ static const Property diva_serial_properties[] = { DEFINE_PROP_CHR("chardev2", PCIDivaSerialState, state[1].chr), DEFINE_PROP_CHR("chardev3", PCIDivaSerialState, state[2].chr), DEFINE_PROP_CHR("chardev4", PCIDivaSerialState, state[3].chr), - DEFINE_PROP_UINT8("prog_if", PCIDivaSerialState, prog_if, 0x02), DEFINE_PROP_UINT32("subvendor", PCIDivaSerialState, subvendor, PCI_DEVICE_ID_HP_DIVA_TOSCA1), }; diff --git a/hw/char/serial-pci-multi.c b/hw/char/serial-pci-multi.c index fb184c2e6d..13df272691 100644 --- a/hw/char/serial-pci-multi.c +++ b/hw/char/serial-pci-multi.c @@ -46,7 +46,6 @@ typedef struct PCIMultiSerialState { SerialState state[PCI_SERIAL_MAX_PORTS]; uint32_t level[PCI_SERIAL_MAX_PORTS]; IRQState irqs[PCI_SERIAL_MAX_PORTS]; - uint8_t prog_if; } PCIMultiSerialState; static void multi_serial_pci_exit(PCIDevice *dev) @@ -97,8 +96,8 @@ static void multi_serial_pci_realize(PCIDevice *dev, Error **errp) SerialState *s; size_t i, nports = multi_serial_get_port_count(pc); - pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; - pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */ + pci->dev.config[PCI_INTERRUPT_PIN] = 1; memory_region_init(&pci->iobar, OBJECT(pci), "multiserial", 8 * nports); pci_register_bar(&pci->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &pci->iobar); @@ -133,7 +132,6 @@ static const VMStateDescription vmstate_pci_multi_serial = { static const Property multi_2x_serial_pci_properties[] = { DEFINE_PROP_CHR("chardev1", PCIMultiSerialState, state[0].chr), DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), - DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), }; static const Property multi_4x_serial_pci_properties[] = { @@ -141,7 +139,6 @@ static const Property multi_4x_serial_pci_properties[] = { DEFINE_PROP_CHR("chardev2", PCIMultiSerialState, state[1].chr), DEFINE_PROP_CHR("chardev3", PCIMultiSerialState, state[2].chr), DEFINE_PROP_CHR("chardev4", PCIMultiSerialState, state[3].chr), - DEFINE_PROP_UINT8("prog_if", PCIMultiSerialState, prog_if, 0x02), }; static void multi_2x_serial_pci_class_initfn(ObjectClass *klass, diff --git a/hw/char/serial-pci.c b/hw/char/serial-pci.c index 8707e81914..46efabc4cb 100644 --- a/hw/char/serial-pci.c +++ b/hw/char/serial-pci.c @@ -38,7 +38,6 @@ struct PCISerialState { PCIDevice dev; SerialState state; - uint8_t prog_if; }; #define TYPE_PCI_SERIAL "pci-serial" @@ -53,8 +52,8 @@ static void serial_pci_realize(PCIDevice *dev, Error **errp) return; } - pci->dev.config[PCI_CLASS_PROG] = pci->prog_if; - pci->dev.config[PCI_INTERRUPT_PIN] = 0x01; + pci->dev.config[PCI_CLASS_PROG] = 2; /* 16550 compatible */ + pci->dev.config[PCI_INTERRUPT_PIN] = 1; s->irq = pci_allocate_irq(&pci->dev); memory_region_init_io(&s->io, OBJECT(pci), &serial_io_ops, s, "serial", 8); @@ -81,10 +80,6 @@ static const VMStateDescription vmstate_pci_serial = { } }; -static const Property serial_pci_properties[] = { - DEFINE_PROP_UINT8("prog_if", PCISerialState, prog_if, 0x02), -}; - static void serial_pci_class_initfn(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -96,7 +91,6 @@ static void serial_pci_class_initfn(ObjectClass *klass, const void *data) pc->revision = 1; pc->class_id = PCI_CLASS_COMMUNICATION_SERIAL; dc->vmsd = &vmstate_pci_serial; - device_class_set_props(dc, serial_pci_properties); set_bit(DEVICE_CATEGORY_INPUT, dc->categories); } From ffd5a60e9b67e14f7bac7ea29300ea46a944e508 Mon Sep 17 00:00:00 2001 From: Stefan Zabka Date: Fri, 2 May 2025 23:27:48 +0200 Subject: [PATCH 0607/2760] rust: centralize config in workspace root This commit bundles common config option in the workspace root and applies them through .workspace = true Signed-off-by: Stefan Zabka Link: https://lore.kernel.org/r/20250502212748.124953-1-git@zabka.it Signed-off-by: Paolo Bonzini --- rust/Cargo.toml | 7 +++++++ rust/hw/char/pl011/Cargo.toml | 11 ++++++----- rust/hw/timer/hpet/Cargo.toml | 9 ++++++--- rust/qemu-api-macros/Cargo.toml | 11 ++++++----- rust/qemu-api/Cargo.toml | 15 +++++++-------- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ab1185a814..5ace47c69b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -7,6 +7,13 @@ members = [ "hw/timer/hpet", ] +[workspace.package] +edition = "2021" +homepage = "https://www.qemu.org" +license = "GPL-2.0-or-later" +repository = "https://gitlab.com/qemu-project/qemu/" +rust-version = "1.63.0" + [workspace.lints.rust] unexpected_cfgs = { level = "deny", check-cfg = [ 'cfg(MESON)', 'cfg(HAVE_GLIB_WITH_ALIGNED_ALLOC)', diff --git a/rust/hw/char/pl011/Cargo.toml b/rust/hw/char/pl011/Cargo.toml index f2296cad58..a1f431ab4a 100644 --- a/rust/hw/char/pl011/Cargo.toml +++ b/rust/hw/char/pl011/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "pl011" version = "0.1.0" -edition = "2021" authors = ["Manos Pitsidianakis "] -license = "GPL-2.0-or-later" description = "pl011 device model for QEMU" resolver = "2" publish = false -keywords = [] -categories = [] -rust-version = "1.63.0" + +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true [lib] crate-type = ["staticlib"] diff --git a/rust/hw/timer/hpet/Cargo.toml b/rust/hw/timer/hpet/Cargo.toml index 147f216e72..6f07502784 100644 --- a/rust/hw/timer/hpet/Cargo.toml +++ b/rust/hw/timer/hpet/Cargo.toml @@ -1,11 +1,14 @@ [package] name = "hpet" version = "0.1.0" -edition = "2021" authors = ["Zhao Liu "] -license = "GPL-2.0-or-later" description = "IA-PC High Precision Event Timer emulation in Rust" -rust-version = "1.63.0" + +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true [lib] crate-type = ["staticlib"] diff --git a/rust/qemu-api-macros/Cargo.toml b/rust/qemu-api-macros/Cargo.toml index 89dee1cfb3..0cd40c8e16 100644 --- a/rust/qemu-api-macros/Cargo.toml +++ b/rust/qemu-api-macros/Cargo.toml @@ -1,15 +1,16 @@ [package] name = "qemu_api_macros" version = "0.1.0" -edition = "2021" authors = ["Manos Pitsidianakis "] -license = "GPL-2.0-or-later" description = "Rust bindings for QEMU - Utility macros" resolver = "2" publish = false -keywords = [] -categories = [] -rust-version = "1.63.0" + +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true [lib] proc-macro = true diff --git a/rust/qemu-api/Cargo.toml b/rust/qemu-api/Cargo.toml index 57747bc934..ca1b04269f 100644 --- a/rust/qemu-api/Cargo.toml +++ b/rust/qemu-api/Cargo.toml @@ -1,18 +1,17 @@ [package] name = "qemu_api" version = "0.1.0" -edition = "2021" authors = ["Manos Pitsidianakis "] -license = "GPL-2.0-or-later" -readme = "README.md" -homepage = "https://www.qemu.org" description = "Rust bindings for QEMU" -repository = "https://gitlab.com/qemu-project/qemu/" +readme = "README.md" resolver = "2" publish = false -keywords = [] -categories = [] -rust-version = "1.63.0" + +edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true [dependencies] qemu_api_macros = { path = "../qemu-api-macros" } From 03f50d7ee756eecbd4481c3008b5e01e999729c7 Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Sat, 3 May 2025 00:47:29 +0300 Subject: [PATCH 0608/2760] monitor: don't wake up qmp_dispatcher_co coroutine upon cleanup Since the commit 3e6bed61 ("monitor: cleanup detection of qmp_dispatcher_co shutting down"), coroutine pointer qmp_dispatcher_co is set to NULL upon cleanup. If a QMP command is sent after monitor_cleanup() (e.g. after shutdown), this may lead to SEGFAULT on aio_co_wake(NULL). As mentioned in the comment inside monitor_cleanup(), the intention is to allow incoming requests while shutting down, but simply leave them without any response. Let's do exactly that, and if qmp_dispatcher_co coroutine pointer has already been set to NULL, let's simply skip the aio_co_wake() part. Signed-off-by: Andrey Drobyshev Link: https://lore.kernel.org/r/20250502214729.928380-2-andrey.drobyshev@virtuozzo.com Signed-off-by: Paolo Bonzini --- monitor/qmp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monitor/qmp.c b/monitor/qmp.c index 2f46cf9e49..cb99a12d94 100644 --- a/monitor/qmp.c +++ b/monitor/qmp.c @@ -356,7 +356,8 @@ void qmp_dispatcher_co_wake(void) /* Write request before reading qmp_dispatcher_co_busy. */ smp_mb__before_rmw(); - if (!qatomic_xchg(&qmp_dispatcher_co_busy, true)) { + if (!qatomic_xchg(&qmp_dispatcher_co_busy, true) && + qatomic_read(&qmp_dispatcher_co)) { aio_co_wake(qmp_dispatcher_co); } } From ba27ba302a264117c8b8427f944ced1bed17c438 Mon Sep 17 00:00:00 2001 From: Troy Lee Date: Mon, 17 Mar 2025 14:59:38 +0800 Subject: [PATCH 0609/2760] hw/arm: ast27x0: Wire up EHCI controllers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST27x0 has 4 EHCI controllers, where each CPU and I/O die has 2 instances. This patch use existing TYPE_PLATFORM_EHCI. After wiring up the EHCI controller, the ast2700a1-evb can find up to 4 USB EHCI interfaces. ehci-platform 12061000.usb: EHCI Host Controller ehci-platform 12061000.usb: new USB bus registered, assigned bus number 2 ehci-platform 12063000.usb: EHCI Host Controller ehci-platform 12063000.usb: new USB bus registered, assigned bus number 3 ehci-platform 12061000.usb: irq 88, io mem 0x12061000 ehci-platform 12063000.usb: irq 90, io mem 0x12063000 ehci-platform 14121000.usb: EHCI Host Controller ehci-platform 14123000.usb: EHCI Host Controller ehci-platform 12061000.usb: USB 2.0 started, EHCI 1.00 ehci-platform 14121000.usb: new USB bus registered, assigned bus number 5 ehci-platform 14123000.usb: new USB bus registered, assigned bus number 6 ehci-platform 14121000.usb: irq 91, io mem 0x14121000 ehci-platform 14123000.usb: irq 92, io mem 0x14123000 ehci-platform 12063000.usb: USB 2.0 started, EHCI 1.00 usb usb2: Manufacturer: Linux 6.6.78-dirty-bafd2830c17c-gbafd2830c17c-dirty ehci_hcd usb usb3: Manufacturer: Linux 6.6.78-dirty-bafd2830c17c-gbafd2830c17c-dirty ehci_hcd ehci-platform 14121000.usb: USB 2.0 started, EHCI 1.00 usb usb5: Manufacturer: Linux 6.6.78-dirty-bafd2830c17c-gbafd2830c17c-dirty ehci_hcd ehci-platform 14123000.usb: USB 2.0 started, EHCI 1.00 usb usb6: Manufacturer: Linux 6.6.78-dirty-bafd2830c17c-gbafd2830c17c-dirty ehci_hcd Note that, AST27x0A0 only has 2 EHCI controllers due to hw issue. Signed-off-by: Troy Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250317065938.1902272-2-troy_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 28 ++++++++++++++++++++++++++++ include/hw/arm/aspeed_soc.h | 4 +++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 63a366f7e8..ea4a611b90 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -25,6 +25,8 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_SRAM] = 0x10000000, + [ASPEED_DEV_EHCI1] = 0x12061000, + [ASPEED_DEV_EHCI2] = 0x12063000, [ASPEED_DEV_HACE] = 0x12070000, [ASPEED_DEV_EMMC] = 0x12090000, [ASPEED_DEV_INTC] = 0x12100000, @@ -47,6 +49,8 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_ETH2] = 0x14060000, [ASPEED_DEV_ETH3] = 0x14070000, [ASPEED_DEV_SDHCI] = 0x14080000, + [ASPEED_DEV_EHCI3] = 0x14121000, + [ASPEED_DEV_EHCI4] = 0x14123000, [ASPEED_DEV_ADC] = 0x14C00000, [ASPEED_DEV_SCUIO] = 0x14C02000, [ASPEED_DEV_GPIO] = 0x14C0B000, @@ -91,6 +95,8 @@ static const int aspeed_soc_ast2700a0_irqmap[] = { [ASPEED_DEV_TIMER7] = 22, [ASPEED_DEV_TIMER8] = 23, [ASPEED_DEV_DP] = 28, + [ASPEED_DEV_EHCI1] = 33, + [ASPEED_DEV_EHCI2] = 37, [ASPEED_DEV_LPC] = 128, [ASPEED_DEV_IBT] = 128, [ASPEED_DEV_KCS] = 128, @@ -137,6 +143,8 @@ static const int aspeed_soc_ast2700a1_irqmap[] = { [ASPEED_DEV_TIMER7] = 22, [ASPEED_DEV_TIMER8] = 23, [ASPEED_DEV_DP] = 28, + [ASPEED_DEV_EHCI1] = 33, + [ASPEED_DEV_EHCI2] = 37, [ASPEED_DEV_LPC] = 192, [ASPEED_DEV_IBT] = 192, [ASPEED_DEV_KCS] = 192, @@ -212,6 +220,8 @@ static const int ast2700_gic132_gic196_intcmap[] = { [ASPEED_DEV_UART10] = 16, [ASPEED_DEV_UART11] = 17, [ASPEED_DEV_UART12] = 18, + [ASPEED_DEV_EHCI3] = 28, + [ASPEED_DEV_EHCI4] = 29, }; /* GICINT 133 */ @@ -434,6 +444,11 @@ static void aspeed_soc_ast2700_init(Object *obj) object_initialize_child(obj, "spi[*]", &s->spi[i], typename); } + for (i = 0; i < sc->ehcis_num; i++) { + object_initialize_child(obj, "ehci[*]", &s->ehci[i], + TYPE_PLATFORM_EHCI); + } + snprintf(typename, sizeof(typename), "aspeed.sdmc-%s", socname); object_initialize_child(obj, "sdmc", &s->sdmc, typename); object_property_add_alias(obj, "ram-size", OBJECT(&s->sdmc), @@ -709,6 +724,17 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base); } + /* EHCI */ + for (i = 0; i < sc->ehcis_num; i++) { + if (!sysbus_realize(SYS_BUS_DEVICE(&s->ehci[i]), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->ehci[i]), 0, + sc->memmap[ASPEED_DEV_EHCI1 + i]); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->ehci[i]), 0, + aspeed_soc_get_irq(s, ASPEED_DEV_EHCI1 + i)); + } + /* * SDMC - SDRAM Memory Controller * The SDMC controller is unlocked at SPL stage. @@ -900,6 +926,7 @@ static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data) sc->silicon_rev = AST2700_A0_SILICON_REV; sc->sram_size = 0x20000; sc->spis_num = 3; + sc->ehcis_num = 2; sc->wdts_num = 8; sc->macs_num = 1; sc->uarts_num = 13; @@ -927,6 +954,7 @@ static void aspeed_soc_ast2700a1_class_init(ObjectClass *oc, const void *data) sc->silicon_rev = AST2700_A1_SILICON_REV; sc->sram_size = 0x20000; sc->spis_num = 3; + sc->ehcis_num = 4; sc->wdts_num = 8; sc->macs_num = 3; sc->uarts_num = 13; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index f069d17d16..c1e80c8908 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -43,7 +43,7 @@ #include "hw/intc/arm_gicv3.h" #define ASPEED_SPIS_NUM 3 -#define ASPEED_EHCIS_NUM 2 +#define ASPEED_EHCIS_NUM 4 #define ASPEED_WDTS_NUM 8 #define ASPEED_CPUS_NUM 4 #define ASPEED_MACS_NUM 4 @@ -192,6 +192,8 @@ enum { ASPEED_DEV_SPI2, ASPEED_DEV_EHCI1, ASPEED_DEV_EHCI2, + ASPEED_DEV_EHCI3, + ASPEED_DEV_EHCI4, ASPEED_DEV_VIC, ASPEED_DEV_INTC, ASPEED_DEV_INTCIO, From 47cdaa46f3f2c6710911543f2ec836eeb624969e Mon Sep 17 00:00:00 2001 From: Joe Komlodi Date: Tue, 22 Apr 2025 00:27:47 +0000 Subject: [PATCH 0610/2760] hw/ssi/aspeed_smc: Allow 64-bit wide flash accesses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cde3247651dc998da5dc1005148302a90d72f21f fixed atomicity for LDRD, which ends up making accesses 64-bits wide. However, the AST2600 bootloader can sometimes compile with LDRD instructions, which causes the acceses to fail when accessing the memory-mapped SPI flash. To fix this, increase the MMIO region valid access size to allow for 64-bit accesses. Signed-off-by: Joe Komlodi Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250422002747.2593465-1-komlodi@google.com Signed-off-by: Cédric Le Goater --- hw/ssi/aspeed_smc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/ssi/aspeed_smc.c b/hw/ssi/aspeed_smc.c index 0d38f95c7a..614528b8ef 100644 --- a/hw/ssi/aspeed_smc.c +++ b/hw/ssi/aspeed_smc.c @@ -359,7 +359,7 @@ static const MemoryRegionOps aspeed_smc_flash_default_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, - .max_access_size = 4, + .max_access_size = 8, }, }; @@ -670,7 +670,7 @@ static const MemoryRegionOps aspeed_smc_flash_ops = { .endianness = DEVICE_LITTLE_ENDIAN, .valid = { .min_access_size = 1, - .max_access_size = 4, + .max_access_size = 8, }, }; From 9b671ea9bd88e8ad14325eac4240850792458136 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 09:40:05 +0800 Subject: [PATCH 0611/2760] tests/functional/aspeed: Update test ASPEED SDK v09.06 for AST2500 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423014008.147542-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_arm_aspeed_ast2500.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/test_arm_aspeed_ast2500.py b/tests/functional/test_arm_aspeed_ast2500.py index a3b44572fc..6923fe8701 100755 --- a/tests/functional/test_arm_aspeed_ast2500.py +++ b/tests/functional/test_arm_aspeed_ast2500.py @@ -37,14 +37,14 @@ class AST2500Machine(AspeedTest): self.do_test_arm_aspeed_buildroot_poweroff() - ASSET_SDK_V806_AST2500 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2500-default-obmc.tar.gz', - 'e1755f3cadff69190438c688d52dd0f0d399b70a1e14b1d3d5540fc4851d38ca') + ASSET_SDK_V906_AST2500 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2500-default-obmc.tar.gz', + '542db84645b4efd8aed50385d7f4dd1caff379a987032311cfa7b563a3addb2a') def test_arm_ast2500_evb_sdk(self): self.set_machine('ast2500-evb') - self.archive_extract(self.ASSET_SDK_V806_AST2500) + self.archive_extract(self.ASSET_SDK_V906_AST2500) self.do_test_arm_aspeed_sdk_start( self.scratch_file("ast2500-default", "image-bmc")) From 88bff6d5b2955d4b629a664c21cb7d91ff8a236c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 09:40:06 +0800 Subject: [PATCH 0612/2760] tests/functional/aspeed: Update test ASPEED SDK v09.06 for AST2600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update test for AST2600 production revision A3. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423014008.147542-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_arm_aspeed_ast2600.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/functional/test_arm_aspeed_ast2600.py b/tests/functional/test_arm_aspeed_ast2600.py index 5ef52f0659..fdae4c939d 100755 --- a/tests/functional/test_arm_aspeed_ast2600.py +++ b/tests/functional/test_arm_aspeed_ast2600.py @@ -97,26 +97,27 @@ class AST2600Machine(AspeedTest): self.do_test_arm_aspeed_buildroot_poweroff() - ASSET_SDK_V806_AST2600_A2 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v08.06/ast2600-a2-obmc.tar.gz', - '9083506135f622d5e7351fcf7d4e1c7125cee5ba16141220c0ba88931f3681a4') + ASSET_SDK_V906_AST2600 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2600-default-obmc.tar.gz', + '768d76e247896ad78c154b9cff4f766da2ce65f217d620b286a4a03a8a4f68f5') def test_arm_ast2600_evb_sdk(self): self.set_machine('ast2600-evb') - self.archive_extract(self.ASSET_SDK_V806_AST2600_A2) + self.archive_extract(self.ASSET_SDK_V906_AST2600) self.vm.add_args('-device', 'tmp105,bus=aspeed.i2c.bus.5,address=0x4d,id=tmp-test') self.vm.add_args('-device', 'ds1338,bus=aspeed.i2c.bus.5,address=0x32') self.do_test_arm_aspeed_sdk_start( - self.scratch_file("ast2600-a2", "image-bmc")) + self.scratch_file("ast2600-default", "image-bmc")) - self.wait_for_console_pattern('ast2600-a2 login:') + self.wait_for_console_pattern('ast2600-default login:') exec_command_and_wait_for_pattern(self, 'root', 'Password:') - exec_command_and_wait_for_pattern(self, '0penBmc', 'root@ast2600-a2:~#') + exec_command_and_wait_for_pattern(self, '0penBmc', + 'root@ast2600-default:~#') exec_command_and_wait_for_pattern(self, 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-5/device/new_device', From 53f3285e11876aae97d4240d944d45a4fe6c4597 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 09:40:07 +0800 Subject: [PATCH 0613/2760] tests/functional/aspeed: Update test ASPEED SDK v03.00 for AST1030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423014008.147542-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_arm_aspeed_ast1030.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/functional/test_arm_aspeed_ast1030.py b/tests/functional/test_arm_aspeed_ast1030.py index d45d9f7c1c..77037f0179 100755 --- a/tests/functional/test_arm_aspeed_ast1030.py +++ b/tests/functional/test_arm_aspeed_ast1030.py @@ -12,17 +12,17 @@ from qemu_test import exec_command_and_wait_for_pattern class AST1030Machine(LinuxKernelTest): - ASSET_ZEPHYR_1_04 = Asset( + ASSET_ZEPHYR_3_00 = Asset( ('https://github.com/AspeedTech-BMC' - '/zephyr/releases/download/v00.01.04/ast1030-evb-demo.zip'), - '4ac6210adcbc61294927918707c6762483fd844dde5e07f3ba834ad1f91434d3') + '/zephyr/releases/download/v00.03.00/ast1030-evb-demo.zip'), + '37fe3ecd4a1b9d620971a15b96492a81093435396eeac69b6f3e384262ff555f') - def test_ast1030_zephyros_1_04(self): + def test_ast1030_zephyros_3_00(self): self.set_machine('ast1030-evb') kernel_name = "ast1030-evb-demo/zephyr.elf" kernel_file = self.archive_extract( - self.ASSET_ZEPHYR_1_04, member=kernel_name) + self.ASSET_ZEPHYR_3_00, member=kernel_name) self.vm.set_console() self.vm.add_args('-kernel', kernel_file, '-nographic') From 8bc296c9b1122916166c021492c470c522e0fd16 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 15:23:37 +0800 Subject: [PATCH 0614/2760] hw/arm/aspeed_ast27x0: Rename variable sram_name to name in ast2700 realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The variable "sram_name" was only used for naming the SRAM memory region. Rename it to "name" for consistency with similar code and avoid unnecessary new local variable declarations. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Tested-by: Nabih Estefan Link: https://lore.kernel.org/qemu-devel/20250423072350.541742-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index ea4a611b90..2e21c3a98f 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -592,7 +592,7 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); AspeedINTCClass *ic = ASPEED_INTC_GET_CLASS(&a->intc[0]); AspeedINTCClass *icio = ASPEED_INTC_GET_CLASS(&a->intc[1]); - g_autofree char *sram_name = NULL; + g_autofree char *name = NULL; qemu_irq irq; /* Default boot region (SPI memory or ROMs) */ @@ -664,9 +664,9 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) } /* SRAM */ - sram_name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index); - if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, - errp)) { + name = g_strdup_printf("aspeed.sram.%d", CPU(&a->cpu[0])->cpu_index); + if (!memory_region_init_ram(&s->sram, OBJECT(s), name, sc->sram_size, + errp)) { return; } memory_region_add_subregion(s->memory, From 80c734ce92e3b68cdb8e82dfd094b3ba23900f17 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 15:23:43 +0800 Subject: [PATCH 0615/2760] tests/functional/aspeed: Move I2C test into shared helper for AST2700 reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move the I2C test case into a common helper function (do_ast2700_i2c_test) so it can be reused across multiple AST2700-based test cases. This reduces duplication and improves maintainability. Signed-off-by: Jamin Lin Reviewed-by: Nabih Estefan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072350.541742-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_aarch64_aspeed.py | 28 +++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index c7f3b3b319..4b6851db2a 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -18,6 +18,8 @@ class AST2x00MachineSDK(QemuSystemTest): def do_test_aarch64_aspeed_sdk_start(self, image): self.require_netdev('user') self.vm.set_console() + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', '-net', 'nic', '-net', 'user', '-snapshot') @@ -35,6 +37,17 @@ class AST2x00MachineSDK(QemuSystemTest): 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.05/ast2700-default-obmc.tar.gz', 'c1f4496aec06743c812a6e9a1a18d032f34d62f3ddb6956e924fef62aa2046a5') + def do_ast2700_i2c_test(self): + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ', + 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d') + exec_command_and_wait_for_pattern(self, + 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0') + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000) + exec_command_and_wait_for_pattern(self, + 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000') + def start_ast2700_test(self, name): num_cpu = 4 uboot_size = os.path.getsize(self.scratch_file(name, @@ -73,8 +86,6 @@ class AST2x00MachineSDK(QemuSystemTest): f'loader,addr=0x430000000,cpu-num={i}') self.vm.add_args('-smp', str(num_cpu)) - self.vm.add_args('-device', - 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) @@ -83,28 +94,19 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - exec_command_and_wait_for_pattern(self, - 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ', - 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d') - exec_command_and_wait_for_pattern(self, - 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0') - self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', - property='temperature', value=18000) - exec_command_and_wait_for_pattern(self, - 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000') - def test_aarch64_ast2700_evb_sdk_v09_05(self): self.set_machine('ast2700-evb') self.archive_extract(self.ASSET_SDK_V905_AST2700) self.start_ast2700_test('ast2700-a0-default') + self.do_ast2700_i2c_test() def test_aarch64_ast2700a1_evb_sdk_v09_05(self): self.set_machine('ast2700a1-evb') self.archive_extract(self.ASSET_SDK_V905_AST2700A1) self.start_ast2700_test('ast2700-default') - + self.do_ast2700_i2c_test() if __name__ == '__main__': QemuSystemTest.main() From b2a7c02a9a6d350005f722ca3df50df20d7f051e Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 15:23:44 +0800 Subject: [PATCH 0616/2760] tests/functional/aspeed: Update test ASPEED SDK v09.06 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072350.541742-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_aarch64_aspeed.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index 4b6851db2a..b6e2be1f82 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -29,13 +29,13 @@ class AST2x00MachineSDK(QemuSystemTest): wait_for_console_pattern(self, '## Loading kernel from FIT Image') wait_for_console_pattern(self, 'Starting kernel ...') - ASSET_SDK_V905_AST2700 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.05/ast2700-a0-default-obmc.tar.gz', - 'cfbbd1cce72f2a3b73b9080c41eecdadebb7077fba4f7806d72ac99f3e84b74a') + ASSET_SDK_V906_AST2700 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-a0-default-obmc.tar.gz', + '7247b6f19dbfb700686f8d9f723ac23f3eb229226c0589cb9b06b80d1b61f3cb') - ASSET_SDK_V905_AST2700A1 = Asset( - 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.05/ast2700-default-obmc.tar.gz', - 'c1f4496aec06743c812a6e9a1a18d032f34d62f3ddb6956e924fef62aa2046a5') + ASSET_SDK_V906_AST2700A1 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-default-obmc.tar.gz', + 'f1d53e0be8a404ecce3e105f72bc50fa4e090ad13160ffa91b10a6e0233a9dc6') def do_ast2700_i2c_test(self): exec_command_and_wait_for_pattern(self, @@ -94,17 +94,17 @@ class AST2x00MachineSDK(QemuSystemTest): exec_command_and_wait_for_pattern(self, 'root', 'Password:') exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - def test_aarch64_ast2700_evb_sdk_v09_05(self): + def test_aarch64_ast2700_evb_sdk_v09_06(self): self.set_machine('ast2700-evb') - self.archive_extract(self.ASSET_SDK_V905_AST2700) + self.archive_extract(self.ASSET_SDK_V906_AST2700) self.start_ast2700_test('ast2700-a0-default') self.do_ast2700_i2c_test() - def test_aarch64_ast2700a1_evb_sdk_v09_05(self): + def test_aarch64_ast2700a1_evb_sdk_v09_06(self): self.set_machine('ast2700a1-evb') - self.archive_extract(self.ASSET_SDK_V905_AST2700A1) + self.archive_extract(self.ASSET_SDK_V906_AST2700A1) self.start_ast2700_test('ast2700-default') self.do_ast2700_i2c_test() From af93cef791b5976b9b6d977da36e25999a6cebe1 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Wed, 23 Apr 2025 15:23:45 +0800 Subject: [PATCH 0617/2760] tests/functional/aspeed: extract boot and login sequence into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extracted repeated boot and login steps into a new helper function. No change in functional behavior. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250423072350.541742-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_aarch64_aspeed.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index b6e2be1f82..1e1f3f9ece 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -25,10 +25,15 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.launch() + def verify_openbmc_boot_and_login(self, name): wait_for_console_pattern(self, 'U-Boot 2023.10') wait_for_console_pattern(self, '## Loading kernel from FIT Image') wait_for_console_pattern(self, 'Starting kernel ...') + wait_for_console_pattern(self, f'{name} login:') + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') + ASSET_SDK_V906_AST2700 = Asset( 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-a0-default-obmc.tar.gz', '7247b6f19dbfb700686f8d9f723ac23f3eb229226c0589cb9b06b80d1b61f3cb') @@ -89,16 +94,12 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) - wait_for_console_pattern(self, f'{name} login:') - - exec_command_and_wait_for_pattern(self, 'root', 'Password:') - exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') - def test_aarch64_ast2700_evb_sdk_v09_06(self): self.set_machine('ast2700-evb') self.archive_extract(self.ASSET_SDK_V906_AST2700) self.start_ast2700_test('ast2700-a0-default') + self.verify_openbmc_boot_and_login('ast2700-a0-default') self.do_ast2700_i2c_test() def test_aarch64_ast2700a1_evb_sdk_v09_06(self): @@ -106,6 +107,7 @@ class AST2x00MachineSDK(QemuSystemTest): self.archive_extract(self.ASSET_SDK_V906_AST2700A1) self.start_ast2700_test('ast2700-default') + self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test() if __name__ == '__main__': From 2e143da2fbd92d9c3ae2d7a315efca5c6af24e69 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 24 Apr 2025 15:51:29 +0800 Subject: [PATCH 0618/2760] hw/arm/aspeed_ast27x0 Introduce vbootrom memory region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new vbootrom memory region. The region is mapped at address "0x00000000" and has a size of 128KB, identical to the SRAM region size. This memory region is intended for loading a vbootrom image file as part of the boot process. The vbootrom registered in the SoC's address space using the ASPEED_DEV_VBOOTROM index. Signed-off-by: Jamin Lin Reviewed-by: Nabih Estefan Tested-by: Nabih Estefan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424075135.3715128-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 9 +++++++++ include/hw/arm/aspeed_soc.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 2e21c3a98f..a289e65e49 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -24,6 +24,7 @@ #include "qemu/log.h" static const hwaddr aspeed_soc_ast2700_memmap[] = { + [ASPEED_DEV_VBOOTROM] = 0x00000000, [ASPEED_DEV_SRAM] = 0x10000000, [ASPEED_DEV_EHCI1] = 0x12061000, [ASPEED_DEV_EHCI2] = 0x12063000, @@ -672,6 +673,14 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(s->memory, sc->memmap[ASPEED_DEV_SRAM], &s->sram); + /* VBOOTROM */ + if (!memory_region_init_ram(&s->vbootrom, OBJECT(s), "aspeed.vbootrom", + 0x20000, errp)) { + return; + } + memory_region_add_subregion(s->memory, + sc->memmap[ASPEED_DEV_VBOOTROM], &s->vbootrom); + /* SCU */ if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { return; diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index c1e80c8908..4dcb1010dc 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -59,6 +59,7 @@ struct AspeedSoCState { MemoryRegion sram; MemoryRegion spi_boot_container; MemoryRegion spi_boot; + MemoryRegion vbootrom; AddressSpace dram_as; AspeedRtcState rtc; AspeedTimerCtrlState timerctrl; @@ -169,6 +170,7 @@ struct AspeedSoCClass { const char *aspeed_soc_cpu_type(AspeedSoCClass *sc); enum { + ASPEED_DEV_VBOOTROM, ASPEED_DEV_SPI_BOOT, ASPEED_DEV_IOMEM, ASPEED_DEV_UART0, From ee447054404ed8bbdea0eece888da354afe38d97 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 24 Apr 2025 15:51:31 +0800 Subject: [PATCH 0619/2760] hw/arm/aspeed: Add support for loading vbootrom image via "-bios" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce "aspeed_load_vbootrom()" to support loading a virtual boot ROM image into the vbootrom memory region, using the "-bios" command-line option. Introduce a new "vbootrom" field in the AspeedMachineClass to indicate whether a machine supports the virtual boot ROM region. Set this field to true by default for the AST2700-A0 and AST2700-A1 EVB machines. Signed-off-by: Jamin Lin Reviewed-by: Nabih Estefan Tested-by: Nabih Estefan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424075135.3715128-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed.c | 36 ++++++++++++++++++++++++++++++++++++ include/hw/arm/aspeed.h | 1 + 2 files changed, 37 insertions(+) diff --git a/hw/arm/aspeed.c b/hw/arm/aspeed.c index 20f418fb63..d0b333646e 100644 --- a/hw/arm/aspeed.c +++ b/hw/arm/aspeed.c @@ -27,6 +27,7 @@ #include "system/reset.h" #include "hw/loader.h" #include "qemu/error-report.h" +#include "qemu/datadir.h" #include "qemu/units.h" #include "hw/qdev-clock.h" #include "system/system.h" @@ -305,6 +306,33 @@ static void aspeed_install_boot_rom(AspeedMachineState *bmc, BlockBackend *blk, rom_size, &error_abort); } +#define VBOOTROM_FILE_NAME "ast27x0_bootrom.bin" + +/* + * This function locates the vbootrom image file specified via the command line + * using the -bios option. It loads the specified image into the vbootrom + * memory region and handles errors if the file cannot be found or loaded. + */ +static void aspeed_load_vbootrom(AspeedMachineState *bmc, const char *bios_name, + Error **errp) +{ + g_autofree char *filename = NULL; + AspeedSoCState *soc = bmc->soc; + int ret; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!filename) { + error_setg(errp, "Could not find vbootrom image '%s'", bios_name); + return; + } + + ret = load_image_mr(filename, &soc->vbootrom); + if (ret < 0) { + error_setg(errp, "Failed to load vbootrom image '%s'", bios_name); + return; + } +} + void aspeed_board_init_flashes(AspeedSMCState *s, const char *flashtype, unsigned int count, int unit0) { @@ -380,6 +408,7 @@ static void aspeed_machine_init(MachineState *machine) AspeedMachineClass *amc = ASPEED_MACHINE_GET_CLASS(machine); AspeedSoCClass *sc; int i; + const char *bios_name = NULL; DriveInfo *emmc0 = NULL; bool boot_emmc; @@ -482,6 +511,11 @@ static void aspeed_machine_init(MachineState *machine) } } + if (amc->vbootrom) { + bios_name = machine->firmware ?: VBOOTROM_FILE_NAME; + aspeed_load_vbootrom(bmc, bios_name, &error_abort); + } + arm_load_kernel(ARM_CPU(first_cpu), machine, &aspeed_board_binfo); } @@ -1701,6 +1735,7 @@ static void aspeed_machine_ast2700a0_evb_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON; amc->uart_default = ASPEED_DEV_UART12; amc->i2c_init = ast2700_evb_i2c_init; + amc->vbootrom = true; mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); @@ -1722,6 +1757,7 @@ static void aspeed_machine_ast2700a1_evb_class_init(ObjectClass *oc, amc->macs_mask = ASPEED_MAC0_ON | ASPEED_MAC1_ON | ASPEED_MAC2_ON; amc->uart_default = ASPEED_DEV_UART12; amc->i2c_init = ast2700_evb_i2c_init; + amc->vbootrom = true; mc->auto_create_sdcard = true; mc->default_ram_size = 1 * GiB; aspeed_machine_class_init_cpus_defaults(mc); diff --git a/include/hw/arm/aspeed.h b/include/hw/arm/aspeed.h index 9cae45a1c9..973277bea6 100644 --- a/include/hw/arm/aspeed.h +++ b/include/hw/arm/aspeed.h @@ -40,6 +40,7 @@ struct AspeedMachineClass { void (*i2c_init)(AspeedMachineState *bmc); uint32_t uart_default; bool sdhci_wp_inverted; + bool vbootrom; }; From 9e3d7afd7da40c9a1ba1a6b4e1103037f3a77da8 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 24 Apr 2025 15:51:32 +0800 Subject: [PATCH 0620/2760] tests/functional/aspeed: Add to test vbootrom for AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the AST2700 functional test to boot using the vbootrom image instead of manually loading boot components with -device loader. The boot ROM binary is now passed via the -bios option, using the image located in pc-bios/ast27x0_bootrom.bin. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424075135.3715128-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/functional/test_aarch64_aspeed.py | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed.py index 1e1f3f9ece..d02dc7991c 100755 --- a/tests/functional/test_aarch64_aspeed.py +++ b/tests/functional/test_aarch64_aspeed.py @@ -25,6 +25,18 @@ class AST2x00MachineSDK(QemuSystemTest): self.vm.launch() + def verify_vbootrom_firmware_flow(self): + wait_for_console_pattern(self, 'Found valid FIT image') + wait_for_console_pattern(self, '[uboot] loading') + wait_for_console_pattern(self, 'done') + wait_for_console_pattern(self, '[fdt] loading') + wait_for_console_pattern(self, 'done') + wait_for_console_pattern(self, '[tee] loading') + wait_for_console_pattern(self, 'done') + wait_for_console_pattern(self, '[atf] loading') + wait_for_console_pattern(self, 'done') + wait_for_console_pattern(self, 'Jumping to BL31 (Trusted Firmware-A)') + def verify_openbmc_boot_and_login(self, name): wait_for_console_pattern(self, 'U-Boot 2023.10') wait_for_console_pattern(self, '## Loading kernel from FIT Image') @@ -94,6 +106,11 @@ class AST2x00MachineSDK(QemuSystemTest): self.do_test_aarch64_aspeed_sdk_start( self.scratch_file(name, 'image-bmc')) + def start_ast2700_test_vbootrom(self, name): + self.vm.add_args('-bios', 'ast27x0_bootrom.bin') + self.do_test_aarch64_aspeed_sdk_start( + self.scratch_file(name, 'image-bmc')) + def test_aarch64_ast2700_evb_sdk_v09_06(self): self.set_machine('ast2700-evb') @@ -110,5 +127,14 @@ class AST2x00MachineSDK(QemuSystemTest): self.verify_openbmc_boot_and_login('ast2700-default') self.do_ast2700_i2c_test() + def test_aarch64_ast2700a1_evb_sdk_vbootrom_v09_06(self): + self.set_machine('ast2700a1-evb') + + self.archive_extract(self.ASSET_SDK_V906_AST2700A1) + self.start_ast2700_test_vbootrom('ast2700-default') + self.verify_vbootrom_firmware_flow() + self.verify_openbmc_boot_and_login('ast2700-default') + self.do_ast2700_i2c_test() + if __name__ == '__main__': QemuSystemTest.main() From 3eb01cfe9b85cd64255f6ef93346a3de17fa9632 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 24 Apr 2025 15:51:33 +0800 Subject: [PATCH 0621/2760] docs/system/arm/aspeed: move AST2700 content to new section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Moved AST2700-related content from the general Aspeed board list into a dedicated section for Aspeed 2700 family boards. Improves clarity and readability. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424075135.3715128-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 70 ++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 97fd6a0e7f..08a33b7008 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -1,12 +1,11 @@ -Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) +Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) ================================================================================================================================================================================================================================================================================================================================================================================================================== The QEMU Aspeed machines model BMCs of various OpenPOWER systems and Aspeed evaluation boards. They are based on different releases of the Aspeed SoC : the AST2400 integrating an ARM926EJ-S CPU (400MHz), the AST2500 with an ARM1176JZS CPU (800MHz), the AST2600 -with dual cores ARM Cortex-A7 CPUs (1.2GHz) and more recently the AST2700 -with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz) +with dual cores ARM Cortex-A7 CPUs (1.2GHz). The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C, etc. @@ -39,10 +38,6 @@ AST2600 SoC based machines : - ``qcom-dc-scm-v1-bmc`` Qualcomm DC-SCM V1 BMC - ``qcom-firework-bmc`` Qualcomm Firework BMC -AST2700 SoC based machines : - -- ``ast2700-evb`` Aspeed AST2700 Evaluation board (Cortex-A35) - Supported devices ----------------- @@ -247,6 +242,67 @@ under Linux), use : -M ast2500-evb,bmc-console=uart3 +Aspeed 2700 family boards (``ast2700-evb``) +================================================================== + +The QEMU Aspeed machines model BMCs of Aspeed evaluation boards. +They are based on different releases of the Aspeed SoC : +the AST2700 with quad cores ARM Cortex-A35 64 bits CPUs (1.6GHz). + +The SoC comes with RAM, Gigabit ethernet, USB, SD/MMC, USB, SPI, I2C, +etc. + +AST2700 SoC based machines : + +- ``ast2700-evb`` Aspeed AST2700 Evaluation board (Cortex-A35) + +Supported devices +----------------- + * Interrupt Controller + * Timer Controller + * RTC Controller + * I2C Controller + * System Control Unit (SCU) + * SRAM mapping + * X-DMA Controller (basic interface) + * Static Memory Controller (SMC or FMC) - Only SPI Flash support + * SPI Memory Controller + * USB 2.0 Controller + * SD/MMC storage controllers + * SDRAM controller (dummy interface for basic settings and training) + * Watchdog Controller + * GPIO Controller (Master only) + * UART + * Ethernet controllers + * Front LEDs (PCA9552 on I2C bus) + * LPC Peripheral Controller (a subset of subdevices are supported) + * Hash/Crypto Engine (HACE) - Hash support only. TODO: Crypto + * ADC + * eMMC Boot Controller (dummy) + * PECI Controller (minimal) + * I3C Controller + * Internal Bridge Controller (SLI dummy) + +Missing devices +--------------- + * Coprocessor support + * PWM and Fan Controller + * Slave GPIO Controller + * Super I/O Controller + * PCI-Express 1 Controller + * Graphic Display Controller + * MCTP Controller + * Mailbox Controller + * Virtual UART + * eSPI Controller + +Boot options +------------ + +Images can be downloaded from the ASPEED Forked OpenBMC GitHub release repository : + + https://github.com/AspeedTech-BMC/openbmc/releases + Booting the ast2700-evb machine ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From d2b857ef9a997237ebedda53c3db50b264baf4fc Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 24 Apr 2025 15:51:34 +0800 Subject: [PATCH 0622/2760] docs/system/arm/aspeed: Support vbootrom for AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using the vbootrom image support and the boot ROM binary is now passed via the -bios option, using the image located in pc-bios/ast27x0_bootrom.bin. Signed-off-by: Jamin Lin Reviewed-by: Nabih Estefan Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250424075135.3715128-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 08a33b7008..014545f444 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -306,7 +306,14 @@ Images can be downloaded from the ASPEED Forked OpenBMC GitHub release repositor Booting the ast2700-evb machine ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Boot the AST2700 machine from the flash image, use an MTD drive : +Boot the AST2700 machine from the flash image. + +There are two supported methods for booting the AST2700 machine with a flash image: + +Manual boot using ``-device loader``: + +It causes all 4 CPU cores to start execution from address ``0x430000000``, which +corresponds to the BL31 image load address. .. code-block:: bash @@ -326,6 +333,26 @@ Boot the AST2700 machine from the flash image, use an MTD drive : -drive file=${IMGDIR}/image-bmc,format=raw,if=mtd \ -nographic +Boot using a virtual boot ROM (``-bios``): + +If users do not specify the ``-bios option``, QEMU will attempt to load the +default vbootrom image ``ast27x0_bootrom.bin`` from either the current working +directory or the ``pc-bios`` directory within the QEMU source tree. + +.. code-block:: bash + + $ qemu-system-aarch64 -M ast2700-evb \ + -drive file=image-bmc,format=raw,if=mtd \ + -nographic + +The ``-bios`` option allows users to specify a custom path for the vbootrom +image to be loaded during boot. This will load the vbootrom image from the +specified path in the ${HOME} directory. + +.. code-block:: bash + + -bios ${HOME}/ast27x0_bootrom.bin + Aspeed minibmc family boards (``ast1030-evb``) ================================================================== From 91064bea6b2d747a981cb3bd2904e56f443e6c67 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:37 +0800 Subject: [PATCH 0623/2760] aspeed: ast27x0: Map unimplemented devices in SoC memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Maps following unimplemented devices in SoC memory - dpmcu - iomem - iomem0 - iomem1 - ltpi Iomem, Iomem0 and Iomem1 include unimplemented controllers in the memory ranges 0x0 - 0x1000000, 0x120000000 - 0x121000000 and 0x14000000 - 0x141000000. For instance: - USB hub at 0x12010000 - eSPI at 0x14C5000 - PWM at 0x140C0000 DPMCU stands for Display Port MCU controller. LTPI is used to connect to AST1700. AST1700 is an I/O expander that supports the DC-SCM 2.1 LTPI protocol. It provides AST2700 with additional GPIO, UART, I3C, and other interfaces. Signed-off-by: Steven Lee Change-Id: Iae4db49a4818af3e2c43c16a27fc76329d2405d6 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-2-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 52 ++++++++++++++++++++++++++++++++----- include/hw/arm/aspeed_soc.h | 6 +++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index a289e65e49..21769669df 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -23,9 +23,17 @@ #include "qobject/qlist.h" #include "qemu/log.h" +#define AST2700_SOC_IO_SIZE 0x01000000 +#define AST2700_SOC_IOMEM_SIZE 0x01000000 +#define AST2700_SOC_DPMCU_SIZE 0x00040000 +#define AST2700_SOC_LTPI_SIZE 0x01000000 + static const hwaddr aspeed_soc_ast2700_memmap[] = { + [ASPEED_DEV_IOMEM] = 0x00000000, [ASPEED_DEV_VBOOTROM] = 0x00000000, [ASPEED_DEV_SRAM] = 0x10000000, + [ASPEED_DEV_DPMCU] = 0x11000000, + [ASPEED_DEV_IOMEM0] = 0x12000000, [ASPEED_DEV_EHCI1] = 0x12061000, [ASPEED_DEV_EHCI2] = 0x12063000, [ASPEED_DEV_HACE] = 0x12070000, @@ -39,6 +47,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_TIMER1] = 0x12C10000, [ASPEED_DEV_SLI] = 0x12C17000, [ASPEED_DEV_UART4] = 0X12C1A000, + [ASPEED_DEV_IOMEM1] = 0x14000000, [ASPEED_DEV_FMC] = 0x14000000, [ASPEED_DEV_SPI0] = 0x14010000, [ASPEED_DEV_SPI1] = 0x14020000, @@ -73,6 +82,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_UART12] = 0X14C33B00, [ASPEED_DEV_WDT] = 0x14C37000, [ASPEED_DEV_SPI_BOOT] = 0x100000000, + [ASPEED_DEV_LTPI] = 0x300000000, [ASPEED_DEV_SDRAM] = 0x400000000, }; @@ -507,6 +517,16 @@ static void aspeed_soc_ast2700_init(Object *obj) snprintf(typename, sizeof(typename), "aspeed.hace-%s", socname); object_initialize_child(obj, "hace", &s->hace, typename); + object_initialize_child(obj, "dpmcu", &s->dpmcu, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "ltpi", &s->ltpi, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "iomem", &s->iomem, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "iomem0", &s->iomem0, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "iomem1", &s->iomem1, + TYPE_UNIMPLEMENTED_DEVICE); } /* @@ -542,8 +562,11 @@ static bool aspeed_soc_ast2700_gic_realize(DeviceState *dev, Error **errp) if (!sysbus_realize(gicbusdev, errp)) { return false; } - sysbus_mmio_map(gicbusdev, 0, sc->memmap[ASPEED_GIC_DIST]); - sysbus_mmio_map(gicbusdev, 1, sc->memmap[ASPEED_GIC_REDIST]); + + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 0, + sc->memmap[ASPEED_GIC_DIST]); + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->gic), 1, + sc->memmap[ASPEED_GIC_REDIST]); for (i = 0; i < sc->num_cpus; i++) { DeviceState *cpudev = DEVICE(&a->cpu[i]); @@ -911,11 +934,26 @@ static void aspeed_soc_ast2700_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(SYS_BUS_DEVICE(&s->hace), 0, aspeed_soc_get_irq(s, ASPEED_DEV_HACE)); - create_unimplemented_device("ast2700.dpmcu", 0x11000000, 0x40000); - create_unimplemented_device("ast2700.iomem0", 0x12000000, 0x01000000); - create_unimplemented_device("ast2700.iomem1", 0x14000000, 0x01000000); - create_unimplemented_device("ast2700.ltpi", 0x30000000, 0x1000000); - create_unimplemented_device("ast2700.io", 0x0, 0x4000000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->dpmcu), + "aspeed.dpmcu", + sc->memmap[ASPEED_DEV_DPMCU], + AST2700_SOC_DPMCU_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->ltpi), + "aspeed.ltpi", + sc->memmap[ASPEED_DEV_LTPI], + AST2700_SOC_LTPI_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem), + "aspeed.io", + sc->memmap[ASPEED_DEV_IOMEM], + AST2700_SOC_IO_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem0), + "aspeed.iomem0", + sc->memmap[ASPEED_DEV_IOMEM0], + AST2700_SOC_IOMEM_SIZE); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->iomem1), + "aspeed.iomem1", + sc->memmap[ASPEED_DEV_IOMEM1], + AST2700_SOC_IOMEM_SIZE); } static void aspeed_soc_ast2700a0_class_init(ObjectClass *oc, const void *data) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 4dcb1010dc..5fcfd2fe2e 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -91,6 +91,8 @@ struct AspeedSoCState { SerialMM uart[ASPEED_UARTS_NUM]; Clock *sysclk; UnimplementedDeviceState iomem; + UnimplementedDeviceState iomem0; + UnimplementedDeviceState iomem1; UnimplementedDeviceState video; UnimplementedDeviceState emmc_boot_controller; UnimplementedDeviceState dpmcu; @@ -98,6 +100,7 @@ struct AspeedSoCState { UnimplementedDeviceState espi; UnimplementedDeviceState udc; UnimplementedDeviceState sgpiom; + UnimplementedDeviceState ltpi; UnimplementedDeviceState jtag[ASPEED_JTAG_NUM]; AspeedAPB2OPBState fsi[2]; }; @@ -173,6 +176,9 @@ enum { ASPEED_DEV_VBOOTROM, ASPEED_DEV_SPI_BOOT, ASPEED_DEV_IOMEM, + ASPEED_DEV_IOMEM0, + ASPEED_DEV_IOMEM1, + ASPEED_DEV_LTPI, ASPEED_DEV_UART0, ASPEED_DEV_UART1, ASPEED_DEV_UART2, From 78110f821aa0c372bb8141ce8ec9f543f8660c36 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:38 +0800 Subject: [PATCH 0624/2760] aspeed: ast27x0: Correct hex notation for device addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrected the hexadecimal notation for several device addresses in the aspeed_soc_ast2700_memmap array by changing the uppercase 'X' to lowercase 'x'. Signed-off-by: Steven Lee Change-Id: I45426e18ea8e68d7ccdf9b60c4ea235c4da33cc3 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-3-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 21769669df..1974a25766 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -46,7 +46,7 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_RTC] = 0x12C0F000, [ASPEED_DEV_TIMER1] = 0x12C10000, [ASPEED_DEV_SLI] = 0x12C17000, - [ASPEED_DEV_UART4] = 0X12C1A000, + [ASPEED_DEV_UART4] = 0x12C1A000, [ASPEED_DEV_IOMEM1] = 0x14000000, [ASPEED_DEV_FMC] = 0x14000000, [ASPEED_DEV_SPI0] = 0x14010000, @@ -67,19 +67,19 @@ static const hwaddr aspeed_soc_ast2700_memmap[] = { [ASPEED_DEV_I2C] = 0x14C0F000, [ASPEED_DEV_INTCIO] = 0x14C18000, [ASPEED_DEV_SLIIO] = 0x14C1E000, - [ASPEED_DEV_VUART] = 0X14C30000, - [ASPEED_DEV_UART0] = 0X14C33000, - [ASPEED_DEV_UART1] = 0X14C33100, - [ASPEED_DEV_UART2] = 0X14C33200, - [ASPEED_DEV_UART3] = 0X14C33300, - [ASPEED_DEV_UART5] = 0X14C33400, - [ASPEED_DEV_UART6] = 0X14C33500, - [ASPEED_DEV_UART7] = 0X14C33600, - [ASPEED_DEV_UART8] = 0X14C33700, - [ASPEED_DEV_UART9] = 0X14C33800, - [ASPEED_DEV_UART10] = 0X14C33900, - [ASPEED_DEV_UART11] = 0X14C33A00, - [ASPEED_DEV_UART12] = 0X14C33B00, + [ASPEED_DEV_VUART] = 0x14C30000, + [ASPEED_DEV_UART0] = 0x14C33000, + [ASPEED_DEV_UART1] = 0x14C33100, + [ASPEED_DEV_UART2] = 0x14C33200, + [ASPEED_DEV_UART3] = 0x14C33300, + [ASPEED_DEV_UART5] = 0x14C33400, + [ASPEED_DEV_UART6] = 0x14C33500, + [ASPEED_DEV_UART7] = 0x14C33600, + [ASPEED_DEV_UART8] = 0x14C33700, + [ASPEED_DEV_UART9] = 0x14C33800, + [ASPEED_DEV_UART10] = 0x14C33900, + [ASPEED_DEV_UART11] = 0x14C33A00, + [ASPEED_DEV_UART12] = 0x14C33B00, [ASPEED_DEV_WDT] = 0x14C37000, [ASPEED_DEV_SPI_BOOT] = 0x100000000, [ASPEED_DEV_LTPI] = 0x300000000, From 8872b6717c37001e8f2e6c4ed0af20b1811d8f58 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:39 +0800 Subject: [PATCH 0625/2760] hw/intc/aspeed: Add support for AST2700 SSP INTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Define new types for ast2700ssp INTC and INTCIO - Add register definitions for SSP INTC and INTCIO - Implement write handlers for SSP INTC and INTCIO - Register new types in aspeed_intc_register_types The design of the SSP INTC and INTCIO controllers is similar to AST2700, with the following differences: - AST2700 Support GICINT128 to GICINT136 in INTC The INTCIO GIC_192_201 has 10 output pins, mapped as follows: Bit 0 -> GIC 192 Bit 1 -> GIC 193 Bit 2 -> GIC 194 Bit 3 -> GIC 195 Bit 4 -> GIC 196 - AST2700-ssp Support SSPINT128 to SSPINT136 in INTC The INTCIO SSPINT_160_169 has 10 output pins, mapped as follows: Bit 0 -> SSPINT 160 Bit 1 -> SSPINT 161 Bit 2 -> SSPINT 162 Bit 3 -> SSPINT 163 Bit 4 -> SSPINT 164 Signed-off-by: Steven Lee Change-Id: Ib8cb0e264505cef48e17f173e057f3b2d1ea35c4 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-4-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/intc/aspeed_intc.c | 211 ++++++++++++++++++++++++++++++++++ include/hw/intc/aspeed_intc.h | 3 + 2 files changed, 214 insertions(+) diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index be7f516a3b..e889246951 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -62,6 +62,50 @@ REG32(GICINT196_STATUS, 0x44) REG32(GICINT197_EN, 0x50) REG32(GICINT197_STATUS, 0x54) +/* + * SSP INTC Registers + */ +REG32(SSPINT128_EN, 0x2000) +REG32(SSPINT128_STATUS, 0x2004) +REG32(SSPINT129_EN, 0x2100) +REG32(SSPINT129_STATUS, 0x2104) +REG32(SSPINT130_EN, 0x2200) +REG32(SSPINT130_STATUS, 0x2204) +REG32(SSPINT131_EN, 0x2300) +REG32(SSPINT131_STATUS, 0x2304) +REG32(SSPINT132_EN, 0x2400) +REG32(SSPINT132_STATUS, 0x2404) +REG32(SSPINT133_EN, 0x2500) +REG32(SSPINT133_STATUS, 0x2504) +REG32(SSPINT134_EN, 0x2600) +REG32(SSPINT134_STATUS, 0x2604) +REG32(SSPINT135_EN, 0x2700) +REG32(SSPINT135_STATUS, 0x2704) +REG32(SSPINT136_EN, 0x2800) +REG32(SSPINT136_STATUS, 0x2804) +REG32(SSPINT137_EN, 0x2900) +REG32(SSPINT137_STATUS, 0x2904) +REG32(SSPINT138_EN, 0x2A00) +REG32(SSPINT138_STATUS, 0x2A04) +REG32(SSPINT160_169_EN, 0x2B00) +REG32(SSPINT160_169_STATUS, 0x2B04) + +/* + * SSP INTCIO Registers + */ +REG32(SSPINT160_EN, 0x180) +REG32(SSPINT160_STATUS, 0x184) +REG32(SSPINT161_EN, 0x190) +REG32(SSPINT161_STATUS, 0x194) +REG32(SSPINT162_EN, 0x1A0) +REG32(SSPINT162_STATUS, 0x1A4) +REG32(SSPINT163_EN, 0x1B0) +REG32(SSPINT163_STATUS, 0x1B4) +REG32(SSPINT164_EN, 0x1C0) +REG32(SSPINT164_STATUS, 0x1C4) +REG32(SSPINT165_EN, 0x1D0) +REG32(SSPINT165_STATUS, 0x1D4) + static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic, uint32_t reg) { @@ -450,6 +494,50 @@ static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data, } } +static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedINTCState *s = ASPEED_INTC(opaque); + const char *name = object_get_typename(OBJECT(s)); + uint32_t reg = offset >> 2; + + trace_aspeed_intc_write(name, offset, size, data); + + switch (reg) { + case R_SSPINT128_EN: + case R_SSPINT129_EN: + case R_SSPINT130_EN: + case R_SSPINT131_EN: + case R_SSPINT132_EN: + case R_SSPINT133_EN: + case R_SSPINT134_EN: + case R_SSPINT135_EN: + case R_SSPINT136_EN: + case R_SSPINT160_169_EN: + aspeed_intc_enable_handler(s, offset, data); + break; + case R_SSPINT128_STATUS: + case R_SSPINT129_STATUS: + case R_SSPINT130_STATUS: + case R_SSPINT131_STATUS: + case R_SSPINT132_STATUS: + case R_SSPINT133_STATUS: + case R_SSPINT134_STATUS: + case R_SSPINT135_STATUS: + case R_SSPINT136_STATUS: + aspeed_intc_status_handler(s, offset, data); + break; + case R_SSPINT160_169_STATUS: + aspeed_intc_status_handler_multi_outpins(s, offset, data); + break; + default: + s->regs[reg] = data; + break; + } + + return; +} + static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset, unsigned int size) { @@ -496,6 +584,39 @@ static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data, } } +static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedINTCState *s = ASPEED_INTC(opaque); + const char *name = object_get_typename(OBJECT(s)); + uint32_t reg = offset >> 2; + + trace_aspeed_intc_write(name, offset, size, data); + + switch (reg) { + case R_SSPINT160_EN: + case R_SSPINT161_EN: + case R_SSPINT162_EN: + case R_SSPINT163_EN: + case R_SSPINT164_EN: + case R_SSPINT165_EN: + aspeed_intc_enable_handler(s, offset, data); + break; + case R_SSPINT160_STATUS: + case R_SSPINT161_STATUS: + case R_SSPINT162_STATUS: + case R_SSPINT163_STATUS: + case R_SSPINT164_STATUS: + case R_SSPINT165_STATUS: + aspeed_intc_status_handler(s, offset, data); + break; + default: + s->regs[reg] = data; + break; + } + + return; +} static const MemoryRegionOps aspeed_intc_ops = { .read = aspeed_intc_read, @@ -517,6 +638,26 @@ static const MemoryRegionOps aspeed_intcio_ops = { } }; +static const MemoryRegionOps aspeed_ssp_intc_ops = { + .read = aspeed_intc_read, + .write = aspeed_ssp_intc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +static const MemoryRegionOps aspeed_ssp_intcio_ops = { + .read = aspeed_intcio_read, + .write = aspeed_ssp_intcio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + static void aspeed_intc_instance_init(Object *obj) { AspeedINTCState *s = ASPEED_INTC(obj); @@ -674,11 +815,81 @@ static const TypeInfo aspeed_2700_intcio_info = { .class_init = aspeed_2700_intcio_class_init, }; +static AspeedINTCIRQ aspeed_2700ssp_intc_irqs[ASPEED_INTC_MAX_INPINS] = { + {0, 0, 10, R_SSPINT160_169_EN, R_SSPINT160_169_STATUS}, + {1, 10, 1, R_SSPINT128_EN, R_SSPINT128_STATUS}, + {2, 11, 1, R_SSPINT129_EN, R_SSPINT129_STATUS}, + {3, 12, 1, R_SSPINT130_EN, R_SSPINT130_STATUS}, + {4, 13, 1, R_SSPINT131_EN, R_SSPINT131_STATUS}, + {5, 14, 1, R_SSPINT132_EN, R_SSPINT132_STATUS}, + {6, 15, 1, R_SSPINT133_EN, R_SSPINT133_STATUS}, + {7, 16, 1, R_SSPINT134_EN, R_SSPINT134_STATUS}, + {8, 17, 1, R_SSPINT135_EN, R_SSPINT135_STATUS}, + {9, 18, 1, R_SSPINT136_EN, R_SSPINT136_STATUS}, +}; + +static void aspeed_2700ssp_intc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); + + dc->desc = "ASPEED 2700 SSP INTC Controller"; + aic->num_lines = 32; + aic->num_inpins = 10; + aic->num_outpins = 19; + aic->mem_size = 0x4000; + aic->nr_regs = 0x2B08 >> 2; + aic->reg_offset = 0x0; + aic->reg_ops = &aspeed_ssp_intc_ops; + aic->irq_table = aspeed_2700ssp_intc_irqs; + aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intc_irqs); +} + +static const TypeInfo aspeed_2700ssp_intc_info = { + .name = TYPE_ASPEED_2700SSP_INTC, + .parent = TYPE_ASPEED_INTC, + .class_init = aspeed_2700ssp_intc_class_init, +}; + +static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = { + {0, 0, 1, R_SSPINT160_EN, R_SSPINT160_STATUS}, + {1, 1, 1, R_SSPINT161_EN, R_SSPINT161_STATUS}, + {2, 2, 1, R_SSPINT162_EN, R_SSPINT162_STATUS}, + {3, 3, 1, R_SSPINT163_EN, R_SSPINT163_STATUS}, + {4, 4, 1, R_SSPINT164_EN, R_SSPINT164_STATUS}, + {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS}, +}; + +static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); + + dc->desc = "ASPEED 2700 SSP INTC IO Controller"; + aic->num_lines = 32; + aic->num_inpins = 6; + aic->num_outpins = 6; + aic->mem_size = 0x400; + aic->nr_regs = 0x1d8 >> 2; + aic->reg_offset = 0; + aic->reg_ops = &aspeed_ssp_intcio_ops; + aic->irq_table = aspeed_2700ssp_intcio_irqs; + aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intcio_irqs); +} + +static const TypeInfo aspeed_2700ssp_intcio_info = { + .name = TYPE_ASPEED_2700SSP_INTCIO, + .parent = TYPE_ASPEED_INTC, + .class_init = aspeed_2700ssp_intcio_class_init, +}; + static void aspeed_intc_register_types(void) { type_register_static(&aspeed_intc_info); type_register_static(&aspeed_2700_intc_info); type_register_static(&aspeed_2700_intcio_info); + type_register_static(&aspeed_2700ssp_intc_info); + type_register_static(&aspeed_2700ssp_intcio_info); } type_init(aspeed_intc_register_types); diff --git a/include/hw/intc/aspeed_intc.h b/include/hw/intc/aspeed_intc.h index 3727ba24be..746f159bf3 100644 --- a/include/hw/intc/aspeed_intc.h +++ b/include/hw/intc/aspeed_intc.h @@ -15,6 +15,9 @@ #define TYPE_ASPEED_INTC "aspeed.intc" #define TYPE_ASPEED_2700_INTC TYPE_ASPEED_INTC "-ast2700" #define TYPE_ASPEED_2700_INTCIO TYPE_ASPEED_INTC "io-ast2700" +#define TYPE_ASPEED_2700SSP_INTC TYPE_ASPEED_INTC "-ast2700ssp" +#define TYPE_ASPEED_2700SSP_INTCIO TYPE_ASPEED_INTC "io-ast2700ssp" + OBJECT_DECLARE_TYPE(AspeedINTCState, AspeedINTCClass, ASPEED_INTC) #define ASPEED_INTC_MAX_INPINS 10 From c528f10dce8eeaabe97f216d6488a6b8509b7067 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:40 +0800 Subject: [PATCH 0626/2760] hw/intc/aspeed: Add support for AST2700 TSP INTC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Define new types for ast2700tsp INTC and INTCIO - Add register definitions for TSP INTC and INTCIO - Implement write handlers for TSP INTC and INTCIO - Register new types in aspeed_intc_register_types The design of the TSP INTC and INTCIO controllers is similar to AST2700, with the following differences: - AST2700 Support GICINT128 to GICINT136 in INTC The INTCIO GIC_192_201 has 10 output pins, mapped as follows: Bit 0 -> GIC 192 Bit 1 -> GIC 193 Bit 2 -> GIC 194 Bit 3 -> GIC 195 Bit 4 -> GIC 196 - AST2700-tsp Support TSPINT128 to TSPINT136 in INTC The INTCIO TSPINT_160_169 has 10 output pins, mapped as follows: Bit 0 -> TSPINT 160 Bit 1 -> TSPINT 161 Bit 2 -> TSPINT 162 Bit 3 -> TSPINT 163 Bit 4 -> TSPINT 164 Signed-off-by: Steven Lee Change-Id: I3f3aca4b90129640369cf4a92deb4b9a12df5b70 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-5-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/intc/aspeed_intc.c | 209 +++++++++++++++++++++++++++++++++- include/hw/intc/aspeed_intc.h | 2 + 2 files changed, 209 insertions(+), 2 deletions(-) diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index e889246951..33fcbe729c 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -106,6 +106,51 @@ REG32(SSPINT164_STATUS, 0x1C4) REG32(SSPINT165_EN, 0x1D0) REG32(SSPINT165_STATUS, 0x1D4) +/* + * TSP INTC Registers + */ +REG32(TSPINT128_EN, 0x3000) +REG32(TSPINT128_STATUS, 0x3004) +REG32(TSPINT129_EN, 0x3100) +REG32(TSPINT129_STATUS, 0x3104) +REG32(TSPINT130_EN, 0x3200) +REG32(TSPINT130_STATUS, 0x3204) +REG32(TSPINT131_EN, 0x3300) +REG32(TSPINT131_STATUS, 0x3304) +REG32(TSPINT132_EN, 0x3400) +REG32(TSPINT132_STATUS, 0x3404) +REG32(TSPINT133_EN, 0x3500) +REG32(TSPINT133_STATUS, 0x3504) +REG32(TSPINT134_EN, 0x3600) +REG32(TSPINT134_STATUS, 0x3604) +REG32(TSPINT135_EN, 0x3700) +REG32(TSPINT135_STATUS, 0x3704) +REG32(TSPINT136_EN, 0x3800) +REG32(TSPINT136_STATUS, 0x3804) +REG32(TSPINT137_EN, 0x3900) +REG32(TSPINT137_STATUS, 0x3904) +REG32(TSPINT138_EN, 0x3A00) +REG32(TSPINT138_STATUS, 0x3A04) +REG32(TSPINT160_169_EN, 0x3B00) +REG32(TSPINT160_169_STATUS, 0x3B04) + +/* + * TSP INTCIO Registers + */ + +REG32(TSPINT160_EN, 0x200) +REG32(TSPINT160_STATUS, 0x204) +REG32(TSPINT161_EN, 0x210) +REG32(TSPINT161_STATUS, 0x214) +REG32(TSPINT162_EN, 0x220) +REG32(TSPINT162_STATUS, 0x224) +REG32(TSPINT163_EN, 0x230) +REG32(TSPINT163_STATUS, 0x234) +REG32(TSPINT164_EN, 0x240) +REG32(TSPINT164_STATUS, 0x244) +REG32(TSPINT165_EN, 0x250) +REG32(TSPINT165_STATUS, 0x254) + static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic, uint32_t reg) { @@ -534,8 +579,48 @@ static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data, s->regs[reg] = data; break; } +} - return; +static void aspeed_tsp_intc_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedINTCState *s = ASPEED_INTC(opaque); + const char *name = object_get_typename(OBJECT(s)); + uint32_t reg = offset >> 2; + + trace_aspeed_intc_write(name, offset, size, data); + + switch (reg) { + case R_TSPINT128_EN: + case R_TSPINT129_EN: + case R_TSPINT130_EN: + case R_TSPINT131_EN: + case R_TSPINT132_EN: + case R_TSPINT133_EN: + case R_TSPINT134_EN: + case R_TSPINT135_EN: + case R_TSPINT136_EN: + case R_TSPINT160_169_EN: + aspeed_intc_enable_handler(s, offset, data); + break; + case R_TSPINT128_STATUS: + case R_TSPINT129_STATUS: + case R_TSPINT130_STATUS: + case R_TSPINT131_STATUS: + case R_TSPINT132_STATUS: + case R_TSPINT133_STATUS: + case R_TSPINT134_STATUS: + case R_TSPINT135_STATUS: + case R_TSPINT136_STATUS: + aspeed_intc_status_handler(s, offset, data); + break; + case R_TSPINT160_169_STATUS: + aspeed_intc_status_handler_multi_outpins(s, offset, data); + break; + default: + s->regs[reg] = data; + break; + } } static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset, @@ -614,8 +699,38 @@ static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data, s->regs[reg] = data; break; } +} - return; +static void aspeed_tsp_intcio_write(void *opaque, hwaddr offset, uint64_t data, + unsigned size) +{ + AspeedINTCState *s = ASPEED_INTC(opaque); + const char *name = object_get_typename(OBJECT(s)); + uint32_t reg = offset >> 2; + + trace_aspeed_intc_write(name, offset, size, data); + + switch (reg) { + case R_TSPINT160_EN: + case R_TSPINT161_EN: + case R_TSPINT162_EN: + case R_TSPINT163_EN: + case R_TSPINT164_EN: + case R_TSPINT165_EN: + aspeed_intc_enable_handler(s, offset, data); + break; + case R_TSPINT160_STATUS: + case R_TSPINT161_STATUS: + case R_TSPINT162_STATUS: + case R_TSPINT163_STATUS: + case R_TSPINT164_STATUS: + case R_TSPINT165_STATUS: + aspeed_intc_status_handler(s, offset, data); + break; + default: + s->regs[reg] = data; + break; + } } static const MemoryRegionOps aspeed_intc_ops = { @@ -658,6 +773,26 @@ static const MemoryRegionOps aspeed_ssp_intcio_ops = { } }; +static const MemoryRegionOps aspeed_tsp_intc_ops = { + .read = aspeed_intc_read, + .write = aspeed_tsp_intc_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + +static const MemoryRegionOps aspeed_tsp_intcio_ops = { + .read = aspeed_intcio_read, + .write = aspeed_tsp_intcio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + } +}; + static void aspeed_intc_instance_init(Object *obj) { AspeedINTCState *s = ASPEED_INTC(obj); @@ -883,6 +1018,74 @@ static const TypeInfo aspeed_2700ssp_intcio_info = { .class_init = aspeed_2700ssp_intcio_class_init, }; +static AspeedINTCIRQ aspeed_2700tsp_intc_irqs[ASPEED_INTC_MAX_INPINS] = { + {0, 0, 10, R_TSPINT160_169_EN, R_TSPINT160_169_STATUS}, + {1, 10, 1, R_TSPINT128_EN, R_TSPINT128_STATUS}, + {2, 11, 1, R_TSPINT129_EN, R_TSPINT129_STATUS}, + {3, 12, 1, R_TSPINT130_EN, R_TSPINT130_STATUS}, + {4, 13, 1, R_TSPINT131_EN, R_TSPINT131_STATUS}, + {5, 14, 1, R_TSPINT132_EN, R_TSPINT132_STATUS}, + {6, 15, 1, R_TSPINT133_EN, R_TSPINT133_STATUS}, + {7, 16, 1, R_TSPINT134_EN, R_TSPINT134_STATUS}, + {8, 17, 1, R_TSPINT135_EN, R_TSPINT135_STATUS}, + {9, 18, 1, R_TSPINT136_EN, R_TSPINT136_STATUS}, +}; + +static void aspeed_2700tsp_intc_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); + + dc->desc = "ASPEED 2700 TSP INTC Controller"; + aic->num_lines = 32; + aic->num_inpins = 10; + aic->num_outpins = 19; + aic->mem_size = 0x4000; + aic->nr_regs = 0x3B08 >> 2; + aic->reg_offset = 0; + aic->reg_ops = &aspeed_tsp_intc_ops; + aic->irq_table = aspeed_2700tsp_intc_irqs; + aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intc_irqs); +} + +static const TypeInfo aspeed_2700tsp_intc_info = { + .name = TYPE_ASPEED_2700TSP_INTC, + .parent = TYPE_ASPEED_INTC, + .class_init = aspeed_2700tsp_intc_class_init, +}; + +static AspeedINTCIRQ aspeed_2700tsp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = { + {0, 0, 1, R_TSPINT160_EN, R_TSPINT160_STATUS}, + {1, 1, 1, R_TSPINT161_EN, R_TSPINT161_STATUS}, + {2, 2, 1, R_TSPINT162_EN, R_TSPINT162_STATUS}, + {3, 3, 1, R_TSPINT163_EN, R_TSPINT163_STATUS}, + {4, 4, 1, R_TSPINT164_EN, R_TSPINT164_STATUS}, + {5, 5, 1, R_TSPINT165_EN, R_TSPINT165_STATUS}, +}; + +static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass, const void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); + + dc->desc = "ASPEED 2700 TSP INTC IO Controller"; + aic->num_lines = 32; + aic->num_inpins = 6; + aic->num_outpins = 6; + aic->mem_size = 0x400; + aic->nr_regs = 0x258 >> 2; + aic->reg_offset = 0x0; + aic->reg_ops = &aspeed_tsp_intcio_ops; + aic->irq_table = aspeed_2700tsp_intcio_irqs; + aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intcio_irqs); +} + +static const TypeInfo aspeed_2700tsp_intcio_info = { + .name = TYPE_ASPEED_2700TSP_INTCIO, + .parent = TYPE_ASPEED_INTC, + .class_init = aspeed_2700tsp_intcio_class_init, +}; + static void aspeed_intc_register_types(void) { type_register_static(&aspeed_intc_info); @@ -890,6 +1093,8 @@ static void aspeed_intc_register_types(void) type_register_static(&aspeed_2700_intcio_info); type_register_static(&aspeed_2700ssp_intc_info); type_register_static(&aspeed_2700ssp_intcio_info); + type_register_static(&aspeed_2700tsp_intc_info); + type_register_static(&aspeed_2700tsp_intcio_info); } type_init(aspeed_intc_register_types); diff --git a/include/hw/intc/aspeed_intc.h b/include/hw/intc/aspeed_intc.h index 746f159bf3..51288384a5 100644 --- a/include/hw/intc/aspeed_intc.h +++ b/include/hw/intc/aspeed_intc.h @@ -17,6 +17,8 @@ #define TYPE_ASPEED_2700_INTCIO TYPE_ASPEED_INTC "io-ast2700" #define TYPE_ASPEED_2700SSP_INTC TYPE_ASPEED_INTC "-ast2700ssp" #define TYPE_ASPEED_2700SSP_INTCIO TYPE_ASPEED_INTC "io-ast2700ssp" +#define TYPE_ASPEED_2700TSP_INTC TYPE_ASPEED_INTC "-ast2700tsp" +#define TYPE_ASPEED_2700TSP_INTCIO TYPE_ASPEED_INTC "io-ast2700tsp" OBJECT_DECLARE_TYPE(AspeedINTCState, AspeedINTCClass, ASPEED_INTC) From 541da2604fe157d9db5995808097230a9f966b4a Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:41 +0800 Subject: [PATCH 0627/2760] hw/arm/aspeed_ast27x0-ssp: Introduce AST27x0 A1 SSP SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2700 SSP (Secondary Service Processor) is a Cortex-M4 coprocessor. This patch adds support for A1 SSP with the following updates: - Introduce Aspeed27x0SSPSoCState structure in aspeed_soc.h - Define memory map and IRQ map for AST27x0 A1 SSP SoC - Implement initialization and realization functions - Add support for UART, INTC, and SCU devices - Map unimplemented devices for IPC and SCUIO The IRQ mapping is similar to AST2700 CA35 SoC, featuring a two-level interrupt controller. Difference from AST2700: - AST2700 - Support GICINT128 to GICINT136 in INTC - The INTCIO GIC_192_201 has 10 output pins, mapped as follows: Bit 0 -> GIC 192 Bit 1 -> GIC 193 Bit 2 -> GIC 194 Bit 3 -> GIC 195 Bit 4 -> GIC 196 - AST2700-ssp - Support SSPINT128 to SSPINT136 in INTC - The INTCIO SSPINT_160_169 has 10 output pins, mapped as follows: Bit 0 -> SSPINT 160 Bit 1 -> SSPINT 161 Bit 2 -> SSPINT 162 Bit 3 -> SSPINT 163 Bit 4 -> SSPINT 164 Signed-off-by: Steven Lee Change-Id: I924bf1a657f1e83f9e16d6673713f4a06ecdb496 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-6-steven_lee@aspeedtech.com [ clg: removed local 'Error* err' in aspeed_soc_ast27x0ssp_realize() ] Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-ssp.c | 294 ++++++++++++++++++++++++++++++++++++ hw/arm/meson.build | 1 + include/hw/arm/aspeed_soc.h | 14 ++ 3 files changed, 309 insertions(+) create mode 100644 hw/arm/aspeed_ast27x0-ssp.c diff --git a/hw/arm/aspeed_ast27x0-ssp.c b/hw/arm/aspeed_ast27x0-ssp.c new file mode 100644 index 0000000000..80ec5996c1 --- /dev/null +++ b/hw/arm/aspeed_ast27x0-ssp.c @@ -0,0 +1,294 @@ +/* + * ASPEED Ast27x0 SSP SoC + * + * Copyright (C) 2025 ASPEED Technology Inc. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-clock.h" +#include "hw/misc/unimp.h" +#include "hw/arm/aspeed_soc.h" + +#define AST2700_SSP_RAM_SIZE (32 * MiB) + +static const hwaddr aspeed_soc_ast27x0ssp_memmap[] = { + [ASPEED_DEV_SRAM] = 0x00000000, + [ASPEED_DEV_INTC] = 0x72100000, + [ASPEED_DEV_SCU] = 0x72C02000, + [ASPEED_DEV_SCUIO] = 0x74C02000, + [ASPEED_DEV_UART0] = 0x74C33000, + [ASPEED_DEV_UART1] = 0x74C33100, + [ASPEED_DEV_UART2] = 0x74C33200, + [ASPEED_DEV_UART3] = 0x74C33300, + [ASPEED_DEV_UART4] = 0x72C1A000, + [ASPEED_DEV_INTCIO] = 0x74C18000, + [ASPEED_DEV_IPC0] = 0x72C1C000, + [ASPEED_DEV_IPC1] = 0x74C39000, + [ASPEED_DEV_UART5] = 0x74C33400, + [ASPEED_DEV_UART6] = 0x74C33500, + [ASPEED_DEV_UART7] = 0x74C33600, + [ASPEED_DEV_UART8] = 0x74C33700, + [ASPEED_DEV_UART9] = 0x74C33800, + [ASPEED_DEV_UART10] = 0x74C33900, + [ASPEED_DEV_UART11] = 0x74C33A00, + [ASPEED_DEV_UART12] = 0x74C33B00, + [ASPEED_DEV_TIMER1] = 0x72C10000, +}; + +static const int aspeed_soc_ast27x0ssp_irqmap[] = { + [ASPEED_DEV_SCU] = 12, + [ASPEED_DEV_UART0] = 164, + [ASPEED_DEV_UART1] = 164, + [ASPEED_DEV_UART2] = 164, + [ASPEED_DEV_UART3] = 164, + [ASPEED_DEV_UART4] = 8, + [ASPEED_DEV_UART5] = 164, + [ASPEED_DEV_UART6] = 164, + [ASPEED_DEV_UART7] = 164, + [ASPEED_DEV_UART8] = 164, + [ASPEED_DEV_UART9] = 164, + [ASPEED_DEV_UART10] = 164, + [ASPEED_DEV_UART11] = 164, + [ASPEED_DEV_UART12] = 164, + [ASPEED_DEV_TIMER1] = 16, +}; + +/* SSPINT 164 */ +static const int ast2700_ssp132_ssp164_intcmap[] = { + [ASPEED_DEV_UART0] = 7, + [ASPEED_DEV_UART1] = 8, + [ASPEED_DEV_UART2] = 9, + [ASPEED_DEV_UART3] = 10, + [ASPEED_DEV_UART5] = 11, + [ASPEED_DEV_UART6] = 12, + [ASPEED_DEV_UART7] = 13, + [ASPEED_DEV_UART8] = 14, + [ASPEED_DEV_UART9] = 15, + [ASPEED_DEV_UART10] = 16, + [ASPEED_DEV_UART11] = 17, + [ASPEED_DEV_UART12] = 18, +}; + +struct nvic_intc_irq_info { + int irq; + int intc_idx; + int orgate_idx; + const int *ptr; +}; + +static struct nvic_intc_irq_info ast2700_ssp_intcmap[] = { + {160, 1, 0, NULL}, + {161, 1, 1, NULL}, + {162, 1, 2, NULL}, + {163, 1, 3, NULL}, + {164, 1, 4, ast2700_ssp132_ssp164_intcmap}, + {165, 1, 5, NULL}, + {166, 1, 6, NULL}, + {167, 1, 7, NULL}, + {168, 1, 8, NULL}, + {169, 1, 9, NULL}, + {128, 0, 1, NULL}, + {129, 0, 2, NULL}, + {130, 0, 3, NULL}, + {131, 0, 4, NULL}, + {132, 0, 5, ast2700_ssp132_ssp164_intcmap}, + {133, 0, 6, NULL}, + {134, 0, 7, NULL}, + {135, 0, 8, NULL}, + {136, 0, 9, NULL}, +}; + +static qemu_irq aspeed_soc_ast27x0ssp_get_irq(AspeedSoCState *s, int dev) +{ + Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(s); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + + int or_idx; + int idx; + int i; + + for (i = 0; i < ARRAY_SIZE(ast2700_ssp_intcmap); i++) { + if (sc->irqmap[dev] == ast2700_ssp_intcmap[i].irq) { + assert(ast2700_ssp_intcmap[i].ptr); + or_idx = ast2700_ssp_intcmap[i].orgate_idx; + idx = ast2700_ssp_intcmap[i].intc_idx; + return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]), + ast2700_ssp_intcmap[i].ptr[dev]); + } + } + + return qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[dev]); +} + +static void aspeed_soc_ast27x0ssp_init(Object *obj) +{ + Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(obj); + AspeedSoCState *s = ASPEED_SOC(obj); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i; + + object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M); + object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU); + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); + + for (i = 0; i < sc->uarts_num; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM); + } + + object_initialize_child(obj, "intc0", &a->intc[0], + TYPE_ASPEED_2700SSP_INTC); + object_initialize_child(obj, "intc1", &a->intc[1], + TYPE_ASPEED_2700SSP_INTCIO); + + object_initialize_child(obj, "timerctrl", &s->timerctrl, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "ipc0", &a->ipc[0], + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "ipc1", &a->ipc[1], + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "scuio", &a->scuio, + TYPE_UNIMPLEMENTED_DEVICE); +} + +static void aspeed_soc_ast27x0ssp_realize(DeviceState *dev_soc, Error **errp) +{ + Aspeed27x0SSPSoCState *a = ASPEED27X0SSP_SOC(dev_soc); + AspeedSoCState *s = ASPEED_SOC(dev_soc); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + DeviceState *armv7m; + g_autofree char *sram_name = NULL; + int i; + + if (!clock_has_source(s->sysclk)) { + error_setg(errp, "sysclk clock must be wired up by the board code"); + return; + } + + /* AST27X0 SSP Core */ + armv7m = DEVICE(&a->armv7m); + qdev_prop_set_uint32(armv7m, "num-irq", 256); + qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); + qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); + object_property_set_link(OBJECT(&a->armv7m), "memory", + OBJECT(s->memory), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&a->armv7m), &error_abort); + + sram_name = g_strdup_printf("aspeed.dram.%d", + CPU(a->armv7m.cpu)->cpu_index); + + if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, + errp)) { + return; + } + memory_region_add_subregion(s->memory, + sc->memmap[ASPEED_DEV_SRAM], + &s->sram); + + /* SCU */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + + /* INTC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { + return; + } + + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0, + sc->memmap[ASPEED_DEV_INTC]); + + /* INTCIO */ + if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[1]), errp)) { + return; + } + + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0, + sc->memmap[ASPEED_DEV_INTCIO]); + + /* irq source orgates -> INTC0 */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_inpins; i++) { + qdev_connect_gpio_out(DEVICE(&a->intc[0].orgates[i]), 0, + qdev_get_gpio_in(DEVICE(&a->intc[0]), i)); + } + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_outpins; i++) { + assert(i < ARRAY_SIZE(ast2700_ssp_intcmap)); + sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[0]), i, + qdev_get_gpio_in(DEVICE(&a->armv7m), + ast2700_ssp_intcmap[i].irq)); + } + /* irq source orgates -> INTCIO */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_inpins; i++) { + qdev_connect_gpio_out(DEVICE(&a->intc[1].orgates[i]), 0, + qdev_get_gpio_in(DEVICE(&a->intc[1]), i)); + } + /* INTCIO -> INTC */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_outpins; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[1]), i, + qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i)); + } + /* UART */ + if (!aspeed_soc_uart_realize(s, errp)) { + return; + } + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl), + "aspeed.timerctrl", + sc->memmap[ASPEED_DEV_TIMER1], 0x200); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]), + "aspeed.ipc0", + sc->memmap[ASPEED_DEV_IPC0], 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]), + "aspeed.ipc1", + sc->memmap[ASPEED_DEV_IPC1], 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio), + "aspeed.scuio", + sc->memmap[ASPEED_DEV_SCUIO], 0x1000); +} + +static void aspeed_soc_ast27x0ssp_class_init(ObjectClass *klass, const void *data) +{ + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO: cortex-m4f */ + NULL + }; + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); + + /* Reason: The Aspeed SoC can only be instantiated from a board */ + dc->user_creatable = false; + dc->realize = aspeed_soc_ast27x0ssp_realize; + + sc->valid_cpu_types = valid_cpu_types; + sc->silicon_rev = AST2700_A1_SILICON_REV; + sc->sram_size = AST2700_SSP_RAM_SIZE; + sc->spis_num = 0; + sc->ehcis_num = 0; + sc->wdts_num = 0; + sc->macs_num = 0; + sc->uarts_num = 13; + sc->uarts_base = ASPEED_DEV_UART0; + sc->irqmap = aspeed_soc_ast27x0ssp_irqmap; + sc->memmap = aspeed_soc_ast27x0ssp_memmap; + sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast27x0ssp_get_irq; +} + +static const TypeInfo aspeed_soc_ast27x0ssp_types[] = { + { + .name = TYPE_ASPEED27X0SSP_SOC, + .parent = TYPE_ASPEED_SOC, + .instance_size = sizeof(Aspeed27x0SSPSoCState), + .instance_init = aspeed_soc_ast27x0ssp_init, + .class_init = aspeed_soc_ast27x0ssp_class_init, + }, +}; + +DEFINE_TYPES(aspeed_soc_ast27x0ssp_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 09b1cfe5b5..39b74a89ed 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -44,6 +44,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_soc_common.c', 'aspeed_ast2400.c', 'aspeed_ast2600.c', + 'aspeed_ast27x0-ssp.c', 'aspeed_ast10x0.c', 'aspeed_eeprom.c', 'fby35.c')) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 5fcfd2fe2e..32be90bc35 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -146,6 +146,18 @@ struct Aspeed10x0SoCState { ARMv7MState armv7m; }; +struct Aspeed27x0SSPSoCState { + AspeedSoCState parent; + AspeedINTCState intc[2]; + UnimplementedDeviceState ipc[2]; + UnimplementedDeviceState scuio; + + ARMv7MState armv7m; +}; + +#define TYPE_ASPEED27X0SSP_SOC "aspeed27x0ssp-soc" +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SSPSoCState, ASPEED27X0SSP_SOC) + #define TYPE_ASPEED10X0_SOC "aspeed10x0-soc" OBJECT_DECLARE_SIMPLE_TYPE(Aspeed10x0SoCState, ASPEED10X0_SOC) @@ -259,6 +271,8 @@ enum { ASPEED_DEV_SLIIO, ASPEED_GIC_DIST, ASPEED_GIC_REDIST, + ASPEED_DEV_IPC0, + ASPEED_DEV_IPC1, }; qemu_irq aspeed_soc_get_irq(AspeedSoCState *s, int dev); From 2d64e6a009e1efbf6d9ae63a3dc5d35f356641e7 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:42 +0800 Subject: [PATCH 0628/2760] hw/arm/aspeed_ast27x0-tsp: Introduce AST27x0 A1 TSP SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AST2700 TSP(Tertiary Service Processor) is a Cortex-M4 coprocessor The patch adds support for TSP with following update: - Introduce Aspeed27x0TSPSoCState structure in aspeed_soc.h - Implement initialization and realization functions - Add support for UART, INTC, and SCU devices - Map unimplemented devices for IPC and SCUIO - Defined memory map and IRQ maps for AST27x0 A1 TSP SoC The IRQ mapping is similar to AST2700 CA35 SoC, featuring a two-level interrupt controller. Difference from AST2700: - AST2700 - Support GICINT128 to GICINT136 in INTC - The INTCIO GIC_192_201 has 10 output pins, mapped as follows: Bit 0 -> GIC 192 Bit 1 -> GIC 193 Bit 2 -> GIC 194 Bit 3 -> GIC 195 Bit 4 -> GIC 196 - AST2700-tsp - Support TSPINT128 to TSPINT136 in INTC - The INTCIO TSPINT_160_169 has 10 output pins, mapped as follows: Bit 0 -> TSPINT 160 Bit 1 -> TSPINT 161 Bit 2 -> TSPINT 162 Bit 3 -> TSPINT 163 Bit 4 -> TSPINT 164 Signed-off-by: Steven Lee Change-Id: I69eec2b68b26ef04187b2922c5f2e584b9076c66 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-7-steven_lee@aspeedtech.com [ clg: removed local 'Error* err' in aspeed_soc_ast27x0tsp_realize() ] Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-tsp.c | 294 ++++++++++++++++++++++++++++++++++++ hw/arm/meson.build | 1 + include/hw/arm/aspeed_soc.h | 12 ++ 3 files changed, 307 insertions(+) create mode 100644 hw/arm/aspeed_ast27x0-tsp.c diff --git a/hw/arm/aspeed_ast27x0-tsp.c b/hw/arm/aspeed_ast27x0-tsp.c new file mode 100644 index 0000000000..4e0efaef07 --- /dev/null +++ b/hw/arm/aspeed_ast27x0-tsp.c @@ -0,0 +1,294 @@ +/* + * ASPEED Ast27x0 TSP SoC + * + * Copyright (C) 2025 ASPEED Technology Inc. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/qdev-clock.h" +#include "hw/misc/unimp.h" +#include "hw/arm/aspeed_soc.h" + +#define AST2700_TSP_RAM_SIZE (32 * MiB) + +static const hwaddr aspeed_soc_ast27x0tsp_memmap[] = { + [ASPEED_DEV_SRAM] = 0x00000000, + [ASPEED_DEV_INTC] = 0x72100000, + [ASPEED_DEV_SCU] = 0x72C02000, + [ASPEED_DEV_SCUIO] = 0x74C02000, + [ASPEED_DEV_UART0] = 0x74C33000, + [ASPEED_DEV_UART1] = 0x74C33100, + [ASPEED_DEV_UART2] = 0x74C33200, + [ASPEED_DEV_UART3] = 0x74C33300, + [ASPEED_DEV_UART4] = 0x72C1A000, + [ASPEED_DEV_INTCIO] = 0x74C18000, + [ASPEED_DEV_IPC0] = 0x72C1C000, + [ASPEED_DEV_IPC1] = 0x74C39000, + [ASPEED_DEV_UART5] = 0x74C33400, + [ASPEED_DEV_UART6] = 0x74C33500, + [ASPEED_DEV_UART7] = 0x74C33600, + [ASPEED_DEV_UART8] = 0x74C33700, + [ASPEED_DEV_UART9] = 0x74C33800, + [ASPEED_DEV_UART10] = 0x74C33900, + [ASPEED_DEV_UART11] = 0x74C33A00, + [ASPEED_DEV_UART12] = 0x74C33B00, + [ASPEED_DEV_TIMER1] = 0x72C10000, +}; + +static const int aspeed_soc_ast27x0tsp_irqmap[] = { + [ASPEED_DEV_SCU] = 12, + [ASPEED_DEV_UART0] = 164, + [ASPEED_DEV_UART1] = 164, + [ASPEED_DEV_UART2] = 164, + [ASPEED_DEV_UART3] = 164, + [ASPEED_DEV_UART4] = 8, + [ASPEED_DEV_UART5] = 164, + [ASPEED_DEV_UART6] = 164, + [ASPEED_DEV_UART7] = 164, + [ASPEED_DEV_UART8] = 164, + [ASPEED_DEV_UART9] = 164, + [ASPEED_DEV_UART10] = 164, + [ASPEED_DEV_UART11] = 164, + [ASPEED_DEV_UART12] = 164, + [ASPEED_DEV_TIMER1] = 16, +}; + +/* TSPINT 164 */ +static const int ast2700_tsp132_tsp164_intcmap[] = { + [ASPEED_DEV_UART0] = 7, + [ASPEED_DEV_UART1] = 8, + [ASPEED_DEV_UART2] = 9, + [ASPEED_DEV_UART3] = 10, + [ASPEED_DEV_UART5] = 11, + [ASPEED_DEV_UART6] = 12, + [ASPEED_DEV_UART7] = 13, + [ASPEED_DEV_UART8] = 14, + [ASPEED_DEV_UART9] = 15, + [ASPEED_DEV_UART10] = 16, + [ASPEED_DEV_UART11] = 17, + [ASPEED_DEV_UART12] = 18, +}; + +struct nvic_intc_irq_info { + int irq; + int intc_idx; + int orgate_idx; + const int *ptr; +}; + +static struct nvic_intc_irq_info ast2700_tsp_intcmap[] = { + {160, 1, 0, NULL}, + {161, 1, 1, NULL}, + {162, 1, 2, NULL}, + {163, 1, 3, NULL}, + {164, 1, 4, ast2700_tsp132_tsp164_intcmap}, + {165, 1, 5, NULL}, + {166, 1, 6, NULL}, + {167, 1, 7, NULL}, + {168, 1, 8, NULL}, + {169, 1, 9, NULL}, + {128, 0, 1, NULL}, + {129, 0, 2, NULL}, + {130, 0, 3, NULL}, + {131, 0, 4, NULL}, + {132, 0, 5, ast2700_tsp132_tsp164_intcmap}, + {133, 0, 6, NULL}, + {134, 0, 7, NULL}, + {135, 0, 8, NULL}, + {136, 0, 9, NULL}, +}; + +static qemu_irq aspeed_soc_ast27x0tsp_get_irq(AspeedSoCState *s, int dev) +{ + Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(s); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + + int or_idx; + int idx; + int i; + + for (i = 0; i < ARRAY_SIZE(ast2700_tsp_intcmap); i++) { + if (sc->irqmap[dev] == ast2700_tsp_intcmap[i].irq) { + assert(ast2700_tsp_intcmap[i].ptr); + or_idx = ast2700_tsp_intcmap[i].orgate_idx; + idx = ast2700_tsp_intcmap[i].intc_idx; + return qdev_get_gpio_in(DEVICE(&a->intc[idx].orgates[or_idx]), + ast2700_tsp_intcmap[i].ptr[dev]); + } + } + + return qdev_get_gpio_in(DEVICE(&a->armv7m), sc->irqmap[dev]); +} + +static void aspeed_soc_ast27x0tsp_init(Object *obj) +{ + Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(obj); + AspeedSoCState *s = ASPEED_SOC(obj); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + int i; + + object_initialize_child(obj, "armv7m", &a->armv7m, TYPE_ARMV7M); + object_initialize_child(obj, "scu", &s->scu, TYPE_ASPEED_2700_SCU); + s->sysclk = qdev_init_clock_in(DEVICE(s), "sysclk", NULL, NULL, 0); + qdev_prop_set_uint32(DEVICE(&s->scu), "silicon-rev", sc->silicon_rev); + + for (i = 0; i < sc->uarts_num; i++) { + object_initialize_child(obj, "uart[*]", &s->uart[i], TYPE_SERIAL_MM); + } + + object_initialize_child(obj, "intc0", &a->intc[0], + TYPE_ASPEED_2700TSP_INTC); + object_initialize_child(obj, "intc1", &a->intc[1], + TYPE_ASPEED_2700TSP_INTCIO); + + object_initialize_child(obj, "timerctrl", &s->timerctrl, + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "ipc0", &a->ipc[0], + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "ipc1", &a->ipc[1], + TYPE_UNIMPLEMENTED_DEVICE); + object_initialize_child(obj, "scuio", &a->scuio, + TYPE_UNIMPLEMENTED_DEVICE); +} + +static void aspeed_soc_ast27x0tsp_realize(DeviceState *dev_soc, Error **errp) +{ + Aspeed27x0TSPSoCState *a = ASPEED27X0TSP_SOC(dev_soc); + AspeedSoCState *s = ASPEED_SOC(dev_soc); + AspeedSoCClass *sc = ASPEED_SOC_GET_CLASS(s); + DeviceState *armv7m; + g_autofree char *sram_name = NULL; + int i; + + if (!clock_has_source(s->sysclk)) { + error_setg(errp, "sysclk clock must be wired up by the board code"); + return; + } + + /* AST27X0 TSP Core */ + armv7m = DEVICE(&a->armv7m); + qdev_prop_set_uint32(armv7m, "num-irq", 256); + qdev_prop_set_string(armv7m, "cpu-type", aspeed_soc_cpu_type(sc)); + qdev_connect_clock_in(armv7m, "cpuclk", s->sysclk); + object_property_set_link(OBJECT(&a->armv7m), "memory", + OBJECT(s->memory), &error_abort); + sysbus_realize(SYS_BUS_DEVICE(&a->armv7m), &error_abort); + + sram_name = g_strdup_printf("aspeed.dram.%d", + CPU(a->armv7m.cpu)->cpu_index); + + if (!memory_region_init_ram(&s->sram, OBJECT(s), sram_name, sc->sram_size, + errp)) { + return; + } + memory_region_add_subregion(s->memory, + sc->memmap[ASPEED_DEV_SRAM], + &s->sram); + + /* SCU */ + if (!sysbus_realize(SYS_BUS_DEVICE(&s->scu), errp)) { + return; + } + aspeed_mmio_map(s, SYS_BUS_DEVICE(&s->scu), 0, sc->memmap[ASPEED_DEV_SCU]); + + /* INTC */ + if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[0]), errp)) { + return; + } + + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[0]), 0, + sc->memmap[ASPEED_DEV_INTC]); + + /* INTCIO */ + if (!sysbus_realize(SYS_BUS_DEVICE(&a->intc[1]), errp)) { + return; + } + + aspeed_mmio_map(s, SYS_BUS_DEVICE(&a->intc[1]), 0, + sc->memmap[ASPEED_DEV_INTCIO]); + + /* irq source orgates -> INTC */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_inpins; i++) { + qdev_connect_gpio_out(DEVICE(&a->intc[0].orgates[i]), 0, + qdev_get_gpio_in(DEVICE(&a->intc[0]), i)); + } + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[0])->num_outpins; i++) { + assert(i < ARRAY_SIZE(ast2700_tsp_intcmap)); + sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[0]), i, + qdev_get_gpio_in(DEVICE(&a->armv7m), + ast2700_tsp_intcmap[i].irq)); + } + /* irq source orgates -> INTC */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_inpins; i++) { + qdev_connect_gpio_out(DEVICE(&a->intc[1].orgates[i]), 0, + qdev_get_gpio_in(DEVICE(&a->intc[1]), i)); + } + /* INTCIO -> INTC */ + for (i = 0; i < ASPEED_INTC_GET_CLASS(&a->intc[1])->num_outpins; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&a->intc[1]), i, + qdev_get_gpio_in(DEVICE(&a->intc[0].orgates[0]), i)); + } + /* UART */ + if (!aspeed_soc_uart_realize(s, errp)) { + return; + } + + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&s->timerctrl), + "aspeed.timerctrl", + sc->memmap[ASPEED_DEV_TIMER1], 0x200); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[0]), + "aspeed.ipc0", + sc->memmap[ASPEED_DEV_IPC0], 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->ipc[1]), + "aspeed.ipc1", + sc->memmap[ASPEED_DEV_IPC1], 0x1000); + aspeed_mmio_map_unimplemented(s, SYS_BUS_DEVICE(&a->scuio), + "aspeed.scuio", + sc->memmap[ASPEED_DEV_SCUIO], 0x1000); +} + +static void aspeed_soc_ast27x0tsp_class_init(ObjectClass *klass, const void *data) +{ + static const char * const valid_cpu_types[] = { + ARM_CPU_TYPE_NAME("cortex-m4"), /* TODO cortex-m4f */ + NULL + }; + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedSoCClass *sc = ASPEED_SOC_CLASS(dc); + + /* Reason: The Aspeed SoC can only be instantiated from a board */ + dc->user_creatable = false; + dc->realize = aspeed_soc_ast27x0tsp_realize; + + sc->valid_cpu_types = valid_cpu_types; + sc->silicon_rev = AST2700_A1_SILICON_REV; + sc->sram_size = AST2700_TSP_RAM_SIZE; + sc->spis_num = 0; + sc->ehcis_num = 0; + sc->wdts_num = 0; + sc->macs_num = 0; + sc->uarts_num = 13; + sc->uarts_base = ASPEED_DEV_UART0; + sc->irqmap = aspeed_soc_ast27x0tsp_irqmap; + sc->memmap = aspeed_soc_ast27x0tsp_memmap; + sc->num_cpus = 1; + sc->get_irq = aspeed_soc_ast27x0tsp_get_irq; +} + +static const TypeInfo aspeed_soc_ast27x0tsp_types[] = { + { + .name = TYPE_ASPEED27X0TSP_SOC, + .parent = TYPE_ASPEED_SOC, + .instance_size = sizeof(Aspeed27x0TSPSoCState), + .instance_init = aspeed_soc_ast27x0tsp_init, + .class_init = aspeed_soc_ast27x0tsp_class_init, + }, +}; + +DEFINE_TYPES(aspeed_soc_ast27x0tsp_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 39b74a89ed..98c5631506 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -45,6 +45,7 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_ast2400.c', 'aspeed_ast2600.c', 'aspeed_ast27x0-ssp.c', + 'aspeed_ast27x0-tsp.c', 'aspeed_ast10x0.c', 'aspeed_eeprom.c', 'fby35.c')) diff --git a/include/hw/arm/aspeed_soc.h b/include/hw/arm/aspeed_soc.h index 32be90bc35..217ef0eafd 100644 --- a/include/hw/arm/aspeed_soc.h +++ b/include/hw/arm/aspeed_soc.h @@ -158,6 +158,18 @@ struct Aspeed27x0SSPSoCState { #define TYPE_ASPEED27X0SSP_SOC "aspeed27x0ssp-soc" OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0SSPSoCState, ASPEED27X0SSP_SOC) +struct Aspeed27x0TSPSoCState { + AspeedSoCState parent; + AspeedINTCState intc[2]; + UnimplementedDeviceState ipc[2]; + UnimplementedDeviceState scuio; + + ARMv7MState armv7m; +}; + +#define TYPE_ASPEED27X0TSP_SOC "aspeed27x0tsp-soc" +OBJECT_DECLARE_SIMPLE_TYPE(Aspeed27x0TSPSoCState, ASPEED27X0TSP_SOC) + #define TYPE_ASPEED10X0_SOC "aspeed10x0-soc" OBJECT_DECLARE_SIMPLE_TYPE(Aspeed10x0SoCState, ASPEED10X0_SOC) From a74faf35efc5befb95d57041c9321a90a0edbb6d Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:43 +0800 Subject: [PATCH 0629/2760] hw/arm: Introduce ASPEED AST2700 A1 full core machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added new machine type `ast2700fc` with full core support. - Defined `Ast2700FCState` structure for the new machine type. - Implemented initialization functions for CA35, SSP, and TSP components. - Updated `ast2700fc_types` to include the new machine type. - Set machine class properties for `ast2700fc`. Test Step: - Download ast2700-default-obmc.tar.gz from AspeedTech-BMC OpenBmc release page. - Run the following QEMU command: ``` IMGDIR=~/path/to/image UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin) ./qemu-system-aarch64 -machine ast2700fc \ -device loader,force-raw=on,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin \ -device loader,force-raw=on,addr=$((0x400000000 + ${UBOOT_SIZE})),file=${IMGDIR}/u-boot.dtb \ -device loader,force-raw=on,addr=0x430000000,file=${IMGDIR}/bl31.bin \ -device loader,force-raw=on,addr=0x430080000,file=${IMGDIR}/tee-raw.bin \ -device loader,cpu-num=0,addr=0x430000000 \ -device loader,cpu-num=1,addr=0x430000000 \ -device loader,cpu-num=2,addr=0x430000000 \ -device loader,cpu-num=3,addr=0x430000000 \ -device loader,file=${IMGDIR}/ast2700-ssp.elf,cpu-num=4 \ -device loader,file=${IMGDIR}/ast2700-tsp.elf,cpu-num=5 \ -drive file=${IMGDIR}/image-bmc,if=mtd,format=raw \ -serial pty -serial pty -serial pty \ -snapshot \ -S -nographic ``` - After starting QEMU, serial devices will be redirected: char device redirected to /dev/pts/51 (label serial0) char device redirected to /dev/pts/52 (label serial1) char device redirected to /dev/pts/53 (label serial2) - serial0 is the console for the four Cortex-A35 primary processors, serial1 and serial2 are the consoles for the two Cortex-M4 coprocessors. - Connect to the consoles using a terminal emulator. Signed-off-by: Steven Lee Change-Id: I32447b9372a78eb53a07135afef59c2a19202328 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-8-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 192 +++++++++++++++++++++++++++++++++++++ hw/arm/meson.build | 4 +- 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 hw/arm/aspeed_ast27x0-fc.c diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c new file mode 100644 index 0000000000..125a3ade40 --- /dev/null +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -0,0 +1,192 @@ +/* + * ASPEED SoC 2700 family + * + * Copyright (C) 2025 ASPEED Technology Inc. + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/units.h" +#include "qapi/error.h" +#include "system/block-backend.h" +#include "system/system.h" +#include "hw/arm/aspeed.h" +#include "hw/boards.h" +#include "hw/qdev-clock.h" +#include "hw/arm/aspeed_soc.h" +#include "hw/loader.h" +#include "hw/arm/boot.h" +#include "hw/block/flash.h" + + +#define TYPE_AST2700A1FC MACHINE_TYPE_NAME("ast2700fc") +OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700A1FC); + +static struct arm_boot_info ast2700fc_board_info = { + .board_id = -1, /* device-tree-only board */ +}; + +struct Ast2700FCState { + MachineState parent_obj; + + MemoryRegion ca35_memory; + MemoryRegion ca35_dram; + MemoryRegion ssp_memory; + MemoryRegion tsp_memory; + + Clock *ssp_sysclk; + Clock *tsp_sysclk; + + Aspeed27x0SoCState ca35; + Aspeed27x0SSPSoCState ssp; + Aspeed27x0TSPSoCState tsp; + + bool mmio_exec; +}; + +#define AST2700FC_BMC_RAM_SIZE (2 * GiB) +#define AST2700FC_CM4_DRAM_SIZE (32 * MiB) + +#define AST2700FC_HW_STRAP1 0x000000C0 +#define AST2700FC_HW_STRAP2 0x00000003 +#define AST2700FC_FMC_MODEL "w25q01jvq" +#define AST2700FC_SPI_MODEL "w25q512jv" + +static void ast2700fc_ca35_init(MachineState *machine) +{ + Ast2700FCState *s = AST2700A1FC(machine); + AspeedSoCState *soc; + AspeedSoCClass *sc; + + object_initialize_child(OBJECT(s), "ca35", &s->ca35, "ast2700-a1"); + soc = ASPEED_SOC(&s->ca35); + sc = ASPEED_SOC_GET_CLASS(soc); + + memory_region_init(&s->ca35_memory, OBJECT(&s->ca35), "ca35-memory", + UINT64_MAX); + + if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram", + AST2700FC_BMC_RAM_SIZE, &error_abort)) { + return; + } + if (!object_property_set_link(OBJECT(&s->ca35), "memory", + OBJECT(&s->ca35_memory), + &error_abort)) { + return; + }; + if (!object_property_set_link(OBJECT(&s->ca35), "dram", + OBJECT(&s->ca35_dram), &error_abort)) { + return; + } + if (!object_property_set_int(OBJECT(&s->ca35), "ram-size", + AST2700FC_BMC_RAM_SIZE, &error_abort)) { + return; + } + if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1", + AST2700FC_HW_STRAP1, &error_abort)) { + return; + } + if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap2", + AST2700FC_HW_STRAP2, &error_abort)) { + return; + } + aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0)); + if (!qdev_realize(DEVICE(&s->ca35), NULL, &error_abort)) { + return; + } + + /* + * AST2700 EVB has a LM75 temperature sensor on I2C bus 0 at address 0x4d. + */ + i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "tmp105", 0x4d); + + aspeed_board_init_flashes(&soc->fmc, AST2700FC_FMC_MODEL, 2, 0); + aspeed_board_init_flashes(&soc->spi[0], AST2700FC_SPI_MODEL, 1, 2); + + ast2700fc_board_info.ram_size = machine->ram_size; + ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM]; + + arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info); +} + +static void ast2700fc_ssp_init(MachineState *machine) +{ + AspeedSoCState *soc; + Ast2700FCState *s = AST2700A1FC(machine); + s->ssp_sysclk = clock_new(OBJECT(s), "SSP_SYSCLK"); + clock_set_hz(s->ssp_sysclk, 200000000ULL); + + object_initialize_child(OBJECT(s), "ssp", &s->ssp, TYPE_ASPEED27X0SSP_SOC); + memory_region_init(&s->ssp_memory, OBJECT(&s->ssp), "ssp-memory", + UINT64_MAX); + + qdev_connect_clock_in(DEVICE(&s->ssp), "sysclk", s->ssp_sysclk); + if (!object_property_set_link(OBJECT(&s->ssp), "memory", + OBJECT(&s->ssp_memory), &error_abort)) { + return; + } + + soc = ASPEED_SOC(&s->ssp); + aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART4, serial_hd(1)); + if (!qdev_realize(DEVICE(&s->ssp), NULL, &error_abort)) { + return; + } +} + +static void ast2700fc_tsp_init(MachineState *machine) +{ + AspeedSoCState *soc; + Ast2700FCState *s = AST2700A1FC(machine); + s->tsp_sysclk = clock_new(OBJECT(s), "TSP_SYSCLK"); + clock_set_hz(s->tsp_sysclk, 200000000ULL); + + object_initialize_child(OBJECT(s), "tsp", &s->tsp, TYPE_ASPEED27X0TSP_SOC); + memory_region_init(&s->tsp_memory, OBJECT(&s->tsp), "tsp-memory", + UINT64_MAX); + + qdev_connect_clock_in(DEVICE(&s->tsp), "sysclk", s->tsp_sysclk); + if (!object_property_set_link(OBJECT(&s->tsp), "memory", + OBJECT(&s->tsp_memory), &error_abort)) { + return; + } + + soc = ASPEED_SOC(&s->tsp); + aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART7, serial_hd(2)); + if (!qdev_realize(DEVICE(&s->tsp), NULL, &error_abort)) { + return; + } +} + +static void ast2700fc_init(MachineState *machine) +{ + ast2700fc_ca35_init(machine); + ast2700fc_ssp_init(machine); + ast2700fc_tsp_init(machine); +} + +static void ast2700fc_class_init(ObjectClass *oc, const void *data) +{ + MachineClass *mc = MACHINE_CLASS(oc); + + mc->alias = "ast2700fc"; + mc->desc = "ast2700 full core support"; + mc->init = ast2700fc_init; + mc->no_floppy = 1; + mc->no_cdrom = 1; + mc->min_cpus = mc->max_cpus = mc->default_cpus = 6; +} + +static const TypeInfo ast2700fc_types[] = { + { + .name = MACHINE_TYPE_NAME("ast2700fc"), + .parent = TYPE_MACHINE, + .class_init = ast2700fc_class_init, + .instance_size = sizeof(Ast2700FCState), + }, +}; + +DEFINE_TYPES(ast2700fc_types) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 98c5631506..5098795f61 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -49,7 +49,9 @@ arm_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_ast10x0.c', 'aspeed_eeprom.c', 'fby35.c')) -arm_common_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files('aspeed_ast27x0.c')) +arm_common_ss.add(when: ['CONFIG_ASPEED_SOC', 'TARGET_AARCH64'], if_true: files( + 'aspeed_ast27x0.c', + 'aspeed_ast27x0-fc.c',)) arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2.c')) arm_common_ss.add(when: 'CONFIG_MPS2', if_true: files('mps2-tz.c')) arm_common_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-soc.c')) From 81c74475433c69f6a4d67fcba463622c63667807 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Mon, 5 May 2025 11:06:18 +0800 Subject: [PATCH 0630/2760] tests/function/aspeed: Add functional test for ast2700fc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce a new test suite for ast2700fc machine. Rename the original test_aarch64_aspeed.py to test_aarch64_aspeed_ast2700.py. Signed-off-by: Steven Lee Change-Id: I3855f55c9f6e5cca1270c179445f549f8d81f36c Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250505030618.3612042-1-steven_lee@aspeedtech.com [ clg: Added new tests in meson.build ] Signed-off-by: Cédric Le Goater --- tests/functional/meson.build | 6 +- ...peed.py => test_aarch64_aspeed_ast2700.py} | 0 .../test_aarch64_aspeed_ast2700fc.py | 135 ++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) rename tests/functional/{test_aarch64_aspeed.py => test_aarch64_aspeed_ast2700.py} (100%) create mode 100755 tests/functional/test_aarch64_aspeed_ast2700fc.py diff --git a/tests/functional/meson.build b/tests/functional/meson.build index b317ad42c5..ab9df03b1f 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -11,7 +11,8 @@ endif # Timeouts for individual tests that can be slow e.g. with debugging enabled test_timeouts = { - 'aarch64_aspeed' : 600, + 'aarch64_aspeed_ast2700' : 600, + 'aarch64_aspeed_ast2700fc' : 600, 'aarch64_raspi4' : 480, 'aarch64_reverse_debug' : 180, 'aarch64_rme_virt' : 1200, @@ -79,7 +80,8 @@ tests_aarch64_system_quick = [ ] tests_aarch64_system_thorough = [ - 'aarch64_aspeed', + 'aarch64_aspeed_ast2700', + 'aarch64_aspeed_ast2700fc', 'aarch64_raspi3', 'aarch64_raspi4', 'aarch64_replay', diff --git a/tests/functional/test_aarch64_aspeed.py b/tests/functional/test_aarch64_aspeed_ast2700.py similarity index 100% rename from tests/functional/test_aarch64_aspeed.py rename to tests/functional/test_aarch64_aspeed_ast2700.py diff --git a/tests/functional/test_aarch64_aspeed_ast2700fc.py b/tests/functional/test_aarch64_aspeed_ast2700fc.py new file mode 100755 index 0000000000..b85370e182 --- /dev/null +++ b/tests/functional/test_aarch64_aspeed_ast2700fc.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +# +# Functional test that boots the ASPEED SoCs with firmware +# +# Copyright (C) 2022 ASPEED Technology Inc +# +# SPDX-License-Identifier: GPL-2.0-or-later + +import os + +from qemu_test import QemuSystemTest, Asset +from qemu_test import wait_for_console_pattern +from qemu_test import exec_command_and_wait_for_pattern + + +class AST2x00MachineSDK(QemuSystemTest): + + def do_test_aarch64_aspeed_sdk_start(self, image): + self.require_netdev('user') + self.vm.set_console() + self.vm.add_args('-device', + 'tmp105,bus=aspeed.i2c.bus.1,address=0x4d,id=tmp-test') + self.vm.add_args('-drive', 'file=' + image + ',if=mtd,format=raw', + '-net', 'nic', '-net', 'user', '-snapshot') + + self.vm.launch() + + def verify_openbmc_boot_and_login(self, name): + wait_for_console_pattern(self, 'U-Boot 2023.10') + wait_for_console_pattern(self, '## Loading kernel from FIT Image') + wait_for_console_pattern(self, 'Starting kernel ...') + + wait_for_console_pattern(self, f'{name} login:') + exec_command_and_wait_for_pattern(self, 'root', 'Password:') + exec_command_and_wait_for_pattern(self, '0penBmc', f'root@{name}:~#') + + ASSET_SDK_V906_AST2700 = Asset( + 'https://github.com/AspeedTech-BMC/openbmc/releases/download/v09.06/ast2700-default-obmc.tar.gz', + 'f1d53e0be8a404ecce3e105f72bc50fa4e090ad13160ffa91b10a6e0233a9dc6') + + def do_ast2700_i2c_test(self): + exec_command_and_wait_for_pattern(self, + 'echo lm75 0x4d > /sys/class/i2c-dev/i2c-1/device/new_device ', + 'i2c i2c-1: new_device: Instantiated device lm75 at 0x4d') + exec_command_and_wait_for_pattern(self, + 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '0') + self.vm.cmd('qom-set', path='/machine/peripheral/tmp-test', + property='temperature', value=18000) + exec_command_and_wait_for_pattern(self, + 'cat /sys/bus/i2c/devices/1-004d/hwmon/hwmon*/temp1_input', '18000') + + def do_ast2700fc_ssp_test(self): + self.vm.shutdown() + self.vm.set_console(console_index=1) + self.vm.launch() + + exec_command_and_wait_for_pattern(self, '\012', 'ssp:~$') + exec_command_and_wait_for_pattern(self, 'version', + 'Zephyr version 3.7.1') + exec_command_and_wait_for_pattern(self, 'md 72c02000 1', + '[72c02000] 06010103') + + def do_ast2700fc_tsp_test(self): + self.vm.shutdown() + self.vm.set_console(console_index=2) + self.vm.launch() + + exec_command_and_wait_for_pattern(self, '\012', 'tsp:~$') + exec_command_and_wait_for_pattern(self, 'version', + 'Zephyr version 3.7.1') + exec_command_and_wait_for_pattern(self, 'md 72c02000 1', + '[72c02000] 06010103') + + def start_ast2700fc_test(self, name): + ca35_core = 4 + uboot_size = os.path.getsize(self.scratch_file(name, + 'u-boot-nodtb.bin')) + uboot_dtb_load_addr = hex(0x400000000 + uboot_size) + + load_images_list = [ + { + 'addr': '0x400000000', + 'file': self.scratch_file(name, + 'u-boot-nodtb.bin') + }, + { + 'addr': str(uboot_dtb_load_addr), + 'file': self.scratch_file(name, 'u-boot.dtb') + }, + { + 'addr': '0x430000000', + 'file': self.scratch_file(name, 'bl31.bin') + }, + { + 'addr': '0x430080000', + 'file': self.scratch_file(name, 'optee', + 'tee-raw.bin') + } + ] + + for load_image in load_images_list: + addr = load_image['addr'] + file = load_image['file'] + self.vm.add_args('-device', + f'loader,force-raw=on,addr={addr},file={file}') + + for i in range(ca35_core): + self.vm.add_args('-device', + f'loader,addr=0x430000000,cpu-num={i}') + + load_elf_list = { + 'ssp': self.scratch_file(name, 'zephyr-aspeed-ssp.elf'), + 'tsp': self.scratch_file(name, 'zephyr-aspeed-tsp.elf') + } + + for cpu_num, key in enumerate(load_elf_list, start=4): + file = load_elf_list[key] + self.vm.add_args('-device', + f'loader,file={file},cpu-num={cpu_num}') + + self.do_test_aarch64_aspeed_sdk_start( + self.scratch_file(name, 'image-bmc')) + + def test_aarch64_ast2700fc_sdk_v09_06(self): + self.set_machine('ast2700fc') + + self.archive_extract(self.ASSET_SDK_V906_AST2700) + self.start_ast2700fc_test('ast2700-default') + self.verify_openbmc_boot_and_login('ast2700-default') + self.do_ast2700_i2c_test() + self.do_ast2700fc_ssp_test() + self.do_ast2700fc_tsp_test() + +if __name__ == '__main__': + QemuSystemTest.main() From f32ef57f7de98ec36da52b0a13bd5d18ac4bd583 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 2 May 2025 18:34:45 +0800 Subject: [PATCH 0631/2760] docs: Add support for ast2700fc machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Updated Aspeed family boards list to include `ast2700fc`. - Added boot instructions for the `ast2700fc` machine. - Detailed the configuration and loading of firmware for the Cortex-A35 and Cortex-M4 processors. Signed-off-by: Steven Lee Change-Id: Id41312e9c7cf79bc55c6f24a87a7ad9993dc7261 Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250502103449.3091642-10-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 69 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 014545f444..58a8020eec 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -1,5 +1,5 @@ -Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) -================================================================================================================================================================================================================================================================================================================================================================================================================== +Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``ast2700fc``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) +================================================================================================================================================================================================================================================================================================================================================================================================================================= The QEMU Aspeed machines model BMCs of various OpenPOWER systems and Aspeed evaluation boards. They are based on different releases of the @@ -255,6 +255,7 @@ etc. AST2700 SoC based machines : - ``ast2700-evb`` Aspeed AST2700 Evaluation board (Cortex-A35) +- ``ast2700fc`` Aspeed AST2700 Evaluation board (Cortex-A35 + Cortex-M4) Supported devices ----------------- @@ -285,7 +286,6 @@ Supported devices Missing devices --------------- - * Coprocessor support * PWM and Fan Controller * Slave GPIO Controller * Super I/O Controller @@ -353,6 +353,69 @@ specified path in the ${HOME} directory. -bios ${HOME}/ast27x0_bootrom.bin +Booting the ast2700fc machine +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +AST2700 features four Cortex-A35 primary processors and two Cortex-M4 coprocessors. +**ast2700-evb** machine focuses on emulating the four Cortex-A35 primary processors, +**ast2700fc** machine extends **ast2700-evb** by adding support for the two Cortex-M4 coprocessors. + +Steps to boot the AST2700fc machine: + +1. Ensure you have the following AST2700A1 binaries available in a directory + + * u-boot-nodtb.bin + * u-boot.dtb + * bl31.bin + * optee/tee-raw.bin + * image-bmc + * zephyr-aspeed-ssp.elf (for SSP firmware, CPU 5) + * zephyr-aspeed-tsp.elf (for TSP firmware, CPU 6) + +2. Execute the following command to start ``ast2700fc`` machine: + +.. code-block:: bash + + IMGDIR=ast2700-default + UBOOT_SIZE=$(stat --format=%s -L ${IMGDIR}/u-boot-nodtb.bin) + + $ qemu-system-aarch64 -M ast2700fc \ + -device loader,force-raw=on,addr=0x400000000,file=${IMGDIR}/u-boot-nodtb.bin \ + -device loader,force-raw=on,addr=$((0x400000000 + ${UBOOT_SIZE})),file=${IMGDIR}/u-boot.dtb \ + -device loader,force-raw=on,addr=0x430000000,file=${IMGDIR}/bl31.bin \ + -device loader,force-raw=on,addr=0x430080000,file=${IMGDIR}/optee/tee-raw.bin \ + -device loader,cpu-num=0,addr=0x430000000 \ + -device loader,cpu-num=1,addr=0x430000000 \ + -device loader,cpu-num=2,addr=0x430000000 \ + -device loader,cpu-num=3,addr=0x430000000 \ + -drive file=${IMGDIR}/image-bmc,if=mtd,format=raw \ + -device loader,file=${IMGDIR}/zephyr-aspeed-ssp.elf,cpu-num=4 \ + -device loader,file=${IMGDIR}/zephyr-aspeed-tsp.elf,cpu-num=5 \ + -serial pty -serial pty -serial pty \ + -snapshot \ + -S -nographic + +After launching QEMU, serial devices will be automatically redirected. +Example output: + +.. code-block:: bash + + char device redirected to /dev/pts/55 (label serial0) + char device redirected to /dev/pts/56 (label serial1) + char device redirected to /dev/pts/57 (label serial2) + +- serial0: Console for the four Cortex-A35 primary processors. +- serial1 and serial2: Consoles for the two Cortex-M4 coprocessors. + +Use ``tio`` or another terminal emulator to connect to the consoles: + +.. code-block:: bash + + $ tio /dev/pts/55 + $ tio /dev/pts/56 + $ tio /dev/pts/57 + + Aspeed minibmc family boards (``ast1030-evb``) ================================================================== From 61da38db70affd925226ce1e8a61d761c20d045b Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Fri, 7 Mar 2025 10:22:56 +0100 Subject: [PATCH 0632/2760] 9pfs: fix concurrent v9fs_reclaim_fd() calls Even though this function is serialized to be always called from main thread, v9fs_reclaim_fd() is dispatching the coroutine to a worker thread in between via its v9fs_co_*() calls, hence leading to the situation where v9fs_reclaim_fd() is effectively executed multiple times simultaniously, which renders its LRU algorithm useless and causes high latency. Fix this by adding a simple boolean variable to ensure this function is only called once at a time. No synchronization needed for this boolean variable as this function is only entered and returned on main thread. Fixes: 7a46274529c ('hw/9pfs: Add file descriptor reclaim support') Signed-off-by: Christian Schoenebeck Reviewed-by: Greg Kurz Message-Id: <5c622067efd66dd4ee5eca740dcf263f41db20b2.1741339452.git.qemu_oss@crudebyte.com> --- hw/9pfs/9p.c | 10 ++++++++++ hw/9pfs/9p.h | 1 + 2 files changed, 11 insertions(+) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 7cad2bce62..4f9c2dde9c 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -435,6 +435,12 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) GHashTableIter iter; gpointer fid; + /* prevent multiple coroutines running this function simultaniously */ + if (s->reclaiming) { + return; + } + s->reclaiming = true; + g_hash_table_iter_init(&iter, s->fids); QSLIST_HEAD(, V9fsFidState) reclaim_list = @@ -510,6 +516,8 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) */ put_fid(pdu, f); } + + s->reclaiming = false; } /* @@ -4324,6 +4332,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t, s->ctx.fst = &fse->fst; fsdev_throttle_init(s->ctx.fst); + s->reclaiming = false; + rc = 0; out: if (rc) { diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 5e041e1f60..259ad32ed1 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -362,6 +362,7 @@ struct V9fsState { uint64_t qp_ndevices; /* Amount of entries in qpd_table. */ uint16_t qp_affix_next; uint64_t qp_fullpath_next; + bool reclaiming; }; /* 9p2000.L open flags */ From 89f7b4da7662ecc6840ffb0846045f03f9714bc6 Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Fri, 7 Mar 2025 10:23:02 +0100 Subject: [PATCH 0633/2760] 9pfs: fix FD leak and reduce latency of v9fs_reclaim_fd() This patch fixes two different bugs in v9fs_reclaim_fd(): 1. Reduce latency: This function calls v9fs_co_close() and v9fs_co_closedir() in a loop. Each one of the calls adds two thread hops (between main thread and a fs driver background thread). Each thread hop adds latency, which sums up in function's loop to a significant duration. Reduce overall latency by open coding what v9fs_co_close() and v9fs_co_closedir() do, executing those and the loop itself altogether in only one background thread block, hence reducing the total amount of thread hops to only two. 2. Fix file descriptor leak: The existing code called v9fs_co_close() and v9fs_co_closedir() to close file descriptors. Both functions check right at the beginning if the 9p request was cancelled: if (v9fs_request_cancelled(pdu)) { return -EINTR; } So if client sent a 'Tflush' message, v9fs_co_close() / v9fs_co_closedir() returned without having closed the file descriptor and v9fs_reclaim_fd() subsequently freed the FID without its file descriptor being closed, hence leaking those file descriptors. This 2nd bug is fixed by this patch as well by open coding v9fs_co_close() and v9fs_co_closedir() inside of v9fs_reclaim_fd() and not performing the v9fs_request_cancelled(pdu) check there. Fixes: 7a46274529c ('hw/9pfs: Add file descriptor reclaim support') Fixes: bccacf6c792 ('hw/9pfs: Implement TFLUSH operation') Signed-off-by: Christian Schoenebeck Reviewed-by: Greg Kurz Message-Id: <5747469d3f039c53147e850b456943a1d4b5485c.1741339452.git.qemu_oss@crudebyte.com> --- hw/9pfs/9p.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 4f9c2dde9c..80b190ff5b 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -434,6 +434,8 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) V9fsFidState *f; GHashTableIter iter; gpointer fid; + int err; + int nclosed = 0; /* prevent multiple coroutines running this function simultaniously */ if (s->reclaiming) { @@ -446,10 +448,10 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) QSLIST_HEAD(, V9fsFidState) reclaim_list = QSLIST_HEAD_INITIALIZER(reclaim_list); + /* Pick FIDs to be closed, collect them on reclaim_list. */ while (g_hash_table_iter_next(&iter, &fid, (gpointer *) &f)) { /* - * Unlink fids cannot be reclaimed. Check - * for them and skip them. Also skip fids + * Unlinked fids cannot be reclaimed, skip those, and also skip fids * currently being operated on. */ if (f->ref || f->flags & FID_NON_RECLAIMABLE) { @@ -499,17 +501,26 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) } } /* - * Now close the fid in reclaim list. Free them if they - * are already clunked. + * Close the picked FIDs altogether on a background I/O driver thread. Do + * this all at once to keep latency (i.e. amount of thread hops between main + * thread <-> fs driver background thread) as low as possible. */ + v9fs_co_run_in_worker({ + QSLIST_FOREACH(f, &reclaim_list, reclaim_next) { + err = (f->fid_type == P9_FID_DIR) ? + s->ops->closedir(&s->ctx, &f->fs_reclaim) : + s->ops->close(&s->ctx, &f->fs_reclaim); + if (!err) { + /* total_open_fd must only be mutated on main thread */ + nclosed++; + } + } + }); + total_open_fd -= nclosed; + /* Free the closed FIDs. */ while (!QSLIST_EMPTY(&reclaim_list)) { f = QSLIST_FIRST(&reclaim_list); QSLIST_REMOVE(&reclaim_list, f, V9fsFidState, reclaim_next); - if (f->fid_type == P9_FID_FILE) { - v9fs_co_close(pdu, &f->fs_reclaim); - } else if (f->fid_type == P9_FID_DIR) { - v9fs_co_closedir(pdu, &f->fs_reclaim); - } /* * Now drop the fid reference, free it * if clunked. From 4f82ce8cd94f2601fb2b2e4cfe0cf5b44131817e Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 12 Mar 2025 16:29:27 +0100 Subject: [PATCH 0634/2760] 9pfs: local : Introduce local_fid_fd() helper Factor out duplicated code to a single helper. More users to come. Signed-off-by: Greg Kurz Reviewed-by: Christian Schoenebeck Message-Id: <20250312152933.383967-2-groug@kaod.org> Signed-off-by: Christian Schoenebeck --- hw/9pfs/9p-local.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 928523afcc..99b9560a52 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -766,16 +766,19 @@ out: return err; } +static int local_fid_fd(int fid_type, V9fsFidOpenState *fs) +{ + if (fid_type == P9_FID_DIR) { + return dirfd(fs->dir.stream); + } else { + return fs->fd; + } +} + static int local_fstat(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs, struct stat *stbuf) { - int err, fd; - - if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); - } else { - fd = fs->fd; - } + int err, fd = local_fid_fd(fid_type, fs); err = fstat(fd, stbuf); if (err) { @@ -1167,13 +1170,7 @@ out: static int local_fsync(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, int datasync) { - int fd; - - if (fid_type == P9_FID_DIR) { - fd = dirfd(fs->dir.stream); - } else { - fd = fs->fd; - } + int fd = local_fid_fd(fid_type, fs); if (datasync) { return qemu_fdatasync(fd); From f2bb367d2b265c6c0ead1e0d4a8f7c43310b3107 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 12 Mar 2025 16:29:28 +0100 Subject: [PATCH 0635/2760] 9pfs: Don't use file descriptors in core code v9fs_getattr() currently peeks into V9fsFidOpenState to know if a fid has a valid file descriptor or directory stream. Even though the fields are accessible, this is an implementation detail of the local backend that should not be manipulated directly by the server code. Abstract that with a new has_valid_file_handle() backend operation. Signed-off-by: Greg Kurz Reviewed-by: Christian Schoenebeck Message-Id: <20250312152933.383967-3-groug@kaod.org> Signed-off-by: Christian Schoenebeck --- fsdev/file-op-9p.h | 1 + hw/9pfs/9p-local.c | 8 ++++++++ hw/9pfs/9p-synth.c | 6 ++++++ hw/9pfs/9p.c | 9 ++++++--- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 4997677460..b815cea44e 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -164,6 +164,7 @@ struct FileOperations { int (*renameat)(FsContext *ctx, V9fsPath *olddir, const char *old_name, V9fsPath *newdir, const char *new_name); int (*unlinkat)(FsContext *ctx, V9fsPath *dir, const char *name, int flags); + bool (*has_valid_file_handle)(int fid_type, V9fsFidOpenState *fs); }; #endif diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 99b9560a52..b16132299f 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1572,6 +1572,13 @@ static int local_parse_opts(QemuOpts *opts, FsDriverEntry *fse, Error **errp) return 0; } +static bool local_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs) +{ + return + (fid_type == P9_FID_FILE && fs->fd != -1) || + (fid_type == P9_FID_DIR && fs->dir.stream != NULL); +} + FileOperations local_ops = { .parse_opts = local_parse_opts, .init = local_init, @@ -1609,4 +1616,5 @@ FileOperations local_ops = { .name_to_path = local_name_to_path, .renameat = local_renameat, .unlinkat = local_unlinkat, + .has_valid_file_handle = local_has_valid_file_handle, }; diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 2abaf3a291..be0492b400 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -615,6 +615,11 @@ static int synth_init(FsContext *ctx, Error **errp) return 0; } +static bool synth_has_valid_file_handle(int fid_type, V9fsFidOpenState *fs) +{ + return false; +} + FileOperations synth_ops = { .init = synth_init, .lstat = synth_lstat, @@ -650,4 +655,5 @@ FileOperations synth_ops = { .name_to_path = synth_name_to_path, .renameat = synth_renameat, .unlinkat = synth_unlinkat, + .has_valid_file_handle = synth_has_valid_file_handle, }; diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 80b190ff5b..4586822d24 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1593,6 +1593,11 @@ out_nofid: pdu_complete(pdu, err); } +static bool fid_has_valid_file_handle(V9fsState *s, V9fsFidState *fidp) +{ + return s->ops->has_valid_file_handle(fidp->fid_type, &fidp->fs); +} + static void coroutine_fn v9fs_getattr(void *opaque) { int32_t fid; @@ -1615,9 +1620,7 @@ static void coroutine_fn v9fs_getattr(void *opaque) retval = -ENOENT; goto out_nofid; } - if ((fidp->fid_type == P9_FID_FILE && fidp->fs.fd != -1) || - (fidp->fid_type == P9_FID_DIR && fidp->fs.dir.stream)) - { + if (fid_has_valid_file_handle(pdu->s, fidp)) { retval = v9fs_co_fstat(pdu, fidp, &stbuf); } else { retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf); From 0c798dd52355f3489b29bba0dfd7df0e24cfa1dd Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 12 Mar 2025 16:29:29 +0100 Subject: [PATCH 0636/2760] 9pfs: Introduce ftruncate file op Add an ftruncate operation to the fs driver and use if when a fid has a valid file descriptor. This is required to support more cases where the client wants to do an action on an unlinked file which it still has an open file decriptor for. Only 9P2000.L was considered. Signed-off-by: Greg Kurz Reviewed-by: Christian Schoenebeck Message-Id: <20250312152933.383967-4-groug@kaod.org> Signed-off-by: Christian Schoenebeck --- fsdev/file-op-9p.h | 2 ++ hw/9pfs/9p-local.c | 9 +++++++++ hw/9pfs/9p-synth.c | 8 ++++++++ hw/9pfs/9p.c | 6 +++++- hw/9pfs/cofs.c | 18 ++++++++++++++++++ hw/9pfs/coth.h | 2 ++ 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index b815cea44e..26ba1438c0 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -152,6 +152,8 @@ struct FileOperations { int (*fstat)(FsContext *, int, V9fsFidOpenState *, struct stat *); int (*rename)(FsContext *, const char *, const char *); int (*truncate)(FsContext *, V9fsPath *, off_t); + int (*ftruncate)(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, + off_t size); int (*fsync)(FsContext *, int, V9fsFidOpenState *, int); int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf); ssize_t (*lgetxattr)(FsContext *, V9fsPath *, diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index b16132299f..0b33da8d2a 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1042,6 +1042,14 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size) return ret; } +static int local_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, + off_t size) +{ + int fd = local_fid_fd(fid_type, fs); + + return ftruncate(fd, size); +} + static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) { char *dirpath = g_path_get_dirname(fs_path->data); @@ -1617,4 +1625,5 @@ FileOperations local_ops = { .renameat = local_renameat, .unlinkat = local_unlinkat, .has_valid_file_handle = local_has_valid_file_handle, + .ftruncate = local_ftruncate, }; diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index be0492b400..3d28afc4d0 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -356,6 +356,13 @@ static int synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset) return -1; } +static int synth_ftruncate(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, + off_t size) +{ + errno = ENOSYS; + return -1; +} + static int synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) { errno = EPERM; @@ -656,4 +663,5 @@ FileOperations synth_ops = { .renameat = synth_renameat, .unlinkat = synth_unlinkat, .has_valid_file_handle = synth_has_valid_file_handle, + .ftruncate = synth_ftruncate, }; diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index 4586822d24..c96f2d2d3d 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1752,7 +1752,11 @@ static void coroutine_fn v9fs_setattr(void *opaque) } } if (v9iattr.valid & (P9_ATTR_SIZE)) { - err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size); + if (fid_has_valid_file_handle(pdu->s, fidp)) { + err = v9fs_co_ftruncate(pdu, fidp, v9iattr.size); + } else { + err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size); + } if (err < 0) { goto out; } diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 67e3ae5c5c..893466fb1a 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -184,6 +184,24 @@ int coroutine_fn v9fs_co_truncate(V9fsPDU *pdu, V9fsPath *path, off_t size) return err; } +int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, off_t size) +{ + int err; + V9fsState *s = pdu->s; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + v9fs_co_run_in_worker( + { + err = s->ops->ftruncate(&s->ctx, fidp->fid_type, &fidp->fs, size); + if (err < 0) { + err = -errno; + } + }); + return err; +} + int coroutine_fn v9fs_co_mknod(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, uid_t uid, gid_t gid, dev_t dev, mode_t mode, struct stat *stbuf) diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 2c54249b35..62e922dc12 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -73,6 +73,8 @@ int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); +int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, + off_t size); int coroutine_fn v9fs_co_llistxattr(V9fsPDU *, V9fsPath *, void *, size_t); int coroutine_fn v9fs_co_lgetxattr(V9fsPDU *, V9fsPath *, V9fsString *, void *, size_t); From 371a269ff8ce561c28e4fa03bb49e4940f990637 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 12 Mar 2025 16:29:30 +0100 Subject: [PATCH 0637/2760] 9pfs: Introduce futimens file op Add an futimens operation to the fs driver and use if when a fid has a valid file descriptor. This is required to support more cases where the client wants to do an action on an unlinked file which it still has an open file decriptor for. Only 9P2000.L was considered. Signed-off-by: Greg Kurz Reviewed-by: Christian Schoenebeck Message-Id: <20250312152933.383967-5-groug@kaod.org> Signed-off-by: Christian Schoenebeck --- fsdev/file-op-9p.h | 2 ++ hw/9pfs/9p-local.c | 9 +++++++++ hw/9pfs/9p-synth.c | 8 ++++++++ hw/9pfs/9p-util.h | 1 + hw/9pfs/9p.c | 6 +++++- hw/9pfs/cofs.c | 19 +++++++++++++++++++ hw/9pfs/coth.h | 2 ++ 7 files changed, 46 insertions(+), 1 deletion(-) diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index 26ba1438c0..b9dae8c84c 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -129,6 +129,8 @@ struct FileOperations { int (*chown)(FsContext *, V9fsPath *, FsCred *); int (*mknod)(FsContext *, V9fsPath *, const char *, FsCred *); int (*utimensat)(FsContext *, V9fsPath *, const struct timespec *); + int (*futimens)(FsContext *ctx, int fid_type, V9fsFidOpenState *fs, + const struct timespec *times); int (*remove)(FsContext *, const char *); int (*symlink)(FsContext *, const char *, V9fsPath *, const char *, FsCred *); diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 0b33da8d2a..31e216227c 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -1100,6 +1100,14 @@ out: return ret; } +static int local_futimens(FsContext *s, int fid_type, V9fsFidOpenState *fs, + const struct timespec *times) +{ + int fd = local_fid_fd(fid_type, fs); + + return qemu_futimens(fd, times); +} + static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, int flags) { @@ -1626,4 +1634,5 @@ FileOperations local_ops = { .unlinkat = local_unlinkat, .has_valid_file_handle = local_has_valid_file_handle, .ftruncate = local_ftruncate, + .futimens = local_futimens, }; diff --git a/hw/9pfs/9p-synth.c b/hw/9pfs/9p-synth.c index 3d28afc4d0..9cd1884224 100644 --- a/hw/9pfs/9p-synth.c +++ b/hw/9pfs/9p-synth.c @@ -424,6 +424,13 @@ static int synth_utimensat(FsContext *fs_ctx, V9fsPath *path, return 0; } +static int synth_futimens(FsContext *fs_ctx, int fid_type, V9fsFidOpenState *fs, + const struct timespec *buf) +{ + errno = ENOSYS; + return -1; +} + static int synth_remove(FsContext *ctx, const char *path) { errno = EPERM; @@ -664,4 +671,5 @@ FileOperations synth_ops = { .unlinkat = synth_unlinkat, .has_valid_file_handle = synth_has_valid_file_handle, .ftruncate = synth_ftruncate, + .futimens = synth_futimens, }; diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 7bc4ec8e85..a1924fe3f0 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -103,6 +103,7 @@ static inline int errno_to_dotl(int err) { #define qemu_renameat renameat #define qemu_utimensat utimensat #define qemu_unlinkat unlinkat +#define qemu_futimens futimens static inline void close_preserve_errno(int fd) { diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index c96f2d2d3d..b22df3aa2b 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -1727,7 +1727,11 @@ static void coroutine_fn v9fs_setattr(void *opaque) } else { times[1].tv_nsec = UTIME_OMIT; } - err = v9fs_co_utimensat(pdu, &fidp->path, times); + if (fid_has_valid_file_handle(pdu->s, fidp)) { + err = v9fs_co_futimens(pdu, fidp, times); + } else { + err = v9fs_co_utimensat(pdu, &fidp->path, times); + } if (err < 0) { goto out; } diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 893466fb1a..12fa8c9fe9 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -139,6 +139,25 @@ int coroutine_fn v9fs_co_utimensat(V9fsPDU *pdu, V9fsPath *path, return err; } +int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp, + struct timespec times[2]) +{ + int err; + V9fsState *s = pdu->s; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + v9fs_co_run_in_worker( + { + err = s->ops->futimens(&s->ctx, fidp->fid_type, &fidp->fs, times); + if (err < 0) { + err = -errno; + } + }); + return err; +} + int coroutine_fn v9fs_co_chown(V9fsPDU *pdu, V9fsPath *path, uid_t uid, gid_t gid) { diff --git a/hw/9pfs/coth.h b/hw/9pfs/coth.h index 62e922dc12..7906fa7782 100644 --- a/hw/9pfs/coth.h +++ b/hw/9pfs/coth.h @@ -71,6 +71,8 @@ int coroutine_fn v9fs_co_statfs(V9fsPDU *, V9fsPath *, struct statfs *); int coroutine_fn v9fs_co_lstat(V9fsPDU *, V9fsPath *, struct stat *); int coroutine_fn v9fs_co_chmod(V9fsPDU *, V9fsPath *, mode_t); int coroutine_fn v9fs_co_utimensat(V9fsPDU *, V9fsPath *, struct timespec [2]); +int coroutine_fn v9fs_co_futimens(V9fsPDU *pdu, V9fsFidState *fidp, + struct timespec times[2]); int coroutine_fn v9fs_co_chown(V9fsPDU *, V9fsPath *, uid_t, gid_t); int coroutine_fn v9fs_co_truncate(V9fsPDU *, V9fsPath *, off_t); int coroutine_fn v9fs_co_ftruncate(V9fsPDU *pdu, V9fsFidState *fidp, From 4719a2d59176a6c850e2b4f1af44cecd25430fce Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Wed, 12 Mar 2025 16:29:31 +0100 Subject: [PATCH 0638/2760] tests/9p: add 'Tsetattr' request to test client Add and implement functions to 9pfs test client for sending a 9p2000.L 'Tsetattr' request and receiving its 'Rsetattr' response counterpart. Signed-off-by: Christian Schoenebeck Signed-off-by: Greg Kurz Message-Id: <20250312152933.383967-6-groug@kaod.org> --- tests/qtest/libqos/virtio-9p-client.c | 49 +++++++++++++++++++++++++++ tests/qtest/libqos/virtio-9p-client.h | 34 +++++++++++++++++++ tests/qtest/virtio-9p-test.c | 1 + 3 files changed, 84 insertions(+) diff --git a/tests/qtest/libqos/virtio-9p-client.c b/tests/qtest/libqos/virtio-9p-client.c index 98b77db51d..6ab4501c6e 100644 --- a/tests/qtest/libqos/virtio-9p-client.c +++ b/tests/qtest/libqos/virtio-9p-client.c @@ -557,6 +557,55 @@ void v9fs_rgetattr(P9Req *req, v9fs_attr *attr) v9fs_req_free(req); } +/* + * size[4] Tsetattr tag[2] fid[4] valid[4] mode[4] uid[4] gid[4] size[8] + * atime_sec[8] atime_nsec[8] mtime_sec[8] mtime_nsec[8] + */ +TSetAttrRes v9fs_tsetattr(TSetAttrOpt opt) +{ + P9Req *req; + uint32_t err; + + g_assert(opt.client); + + req = v9fs_req_init( + opt.client, 4/*fid*/ + 4/*valid*/ + 4/*mode*/ + 4/*uid*/ + 4/*gid*/ + + 8/*size*/ + 8/*atime_sec*/ + 8/*atime_nsec*/ + 8/*mtime_sec*/ + + 8/*mtime_nsec*/, P9_TSETATTR, opt.tag + ); + v9fs_uint32_write(req, opt.fid); + v9fs_uint32_write(req, (uint32_t) opt.attr.valid); + v9fs_uint32_write(req, opt.attr.mode); + v9fs_uint32_write(req, opt.attr.uid); + v9fs_uint32_write(req, opt.attr.gid); + v9fs_uint64_write(req, opt.attr.size); + v9fs_uint64_write(req, opt.attr.atime_sec); + v9fs_uint64_write(req, opt.attr.atime_nsec); + v9fs_uint64_write(req, opt.attr.mtime_sec); + v9fs_uint64_write(req, opt.attr.mtime_nsec); + v9fs_req_send(req); + + if (!opt.requestOnly) { + v9fs_req_wait_for_reply(req, NULL); + if (opt.expectErr) { + v9fs_rlerror(req, &err); + g_assert_cmpint(err, ==, opt.expectErr); + } else { + v9fs_rsetattr(req); + } + req = NULL; /* request was freed */ + } + + return (TSetAttrRes) { .req = req }; +} + +/* size[4] Rsetattr tag[2] */ +void v9fs_rsetattr(P9Req *req) +{ + v9fs_req_recv(req, P9_RSETATTR); + v9fs_req_free(req); +} + /* size[4] Treaddir tag[2] fid[4] offset[8] count[4] */ TReadDirRes v9fs_treaddir(TReadDirOpt opt) { diff --git a/tests/qtest/libqos/virtio-9p-client.h b/tests/qtest/libqos/virtio-9p-client.h index 78228eb97d..e3221a3104 100644 --- a/tests/qtest/libqos/virtio-9p-client.h +++ b/tests/qtest/libqos/virtio-9p-client.h @@ -65,6 +65,16 @@ typedef struct v9fs_attr { #define P9_GETATTR_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ #define P9_GETATTR_ALL 0x00003fffULL /* Mask for ALL fields */ +#define P9_SETATTR_MODE 0x00000001UL +#define P9_SETATTR_UID 0x00000002UL +#define P9_SETATTR_GID 0x00000004UL +#define P9_SETATTR_SIZE 0x00000008UL +#define P9_SETATTR_ATIME 0x00000010UL +#define P9_SETATTR_MTIME 0x00000020UL +#define P9_SETATTR_CTIME 0x00000040UL +#define P9_SETATTR_ATIME_SET 0x00000080UL +#define P9_SETATTR_MTIME_SET 0x00000100UL + struct V9fsDirent { v9fs_qid qid; uint64_t offset; @@ -182,6 +192,28 @@ typedef struct TGetAttrRes { P9Req *req; } TGetAttrRes; +/* options for 'Tsetattr' 9p request */ +typedef struct TSetAttrOpt { + /* 9P client being used (mandatory) */ + QVirtio9P *client; + /* user supplied tag number being returned with response (optional) */ + uint16_t tag; + /* file ID of file/dir whose attributes shall be modified (required) */ + uint32_t fid; + /* new attribute values to be set by 9p server */ + v9fs_attr attr; + /* only send Tsetattr request but not wait for a reply? (optional) */ + bool requestOnly; + /* do we expect an Rlerror response, if yes which error code? (optional) */ + uint32_t expectErr; +} TSetAttrOpt; + +/* result of 'Tsetattr' 9p request */ +typedef struct TSetAttrRes { + /* if requestOnly was set: request object for further processing */ + P9Req *req; +} TSetAttrRes; + /* options for 'Treaddir' 9p request */ typedef struct TReadDirOpt { /* 9P client being used (mandatory) */ @@ -470,6 +502,8 @@ TWalkRes v9fs_twalk(TWalkOpt opt); void v9fs_rwalk(P9Req *req, uint16_t *nwqid, v9fs_qid **wqid); TGetAttrRes v9fs_tgetattr(TGetAttrOpt); void v9fs_rgetattr(P9Req *req, v9fs_attr *attr); +TSetAttrRes v9fs_tsetattr(TSetAttrOpt opt); +void v9fs_rsetattr(P9Req *req); TReadDirRes v9fs_treaddir(TReadDirOpt); void v9fs_rreaddir(P9Req *req, uint32_t *count, uint32_t *nentries, struct V9fsDirent **entries); diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index ab3a12c816..f515a9bb15 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -20,6 +20,7 @@ #define tversion(...) v9fs_tversion((TVersionOpt) __VA_ARGS__) #define tattach(...) v9fs_tattach((TAttachOpt) __VA_ARGS__) #define tgetattr(...) v9fs_tgetattr((TGetAttrOpt) __VA_ARGS__) +#define tsetattr(...) v9fs_tsetattr((TSetAttrOpt) __VA_ARGS__) #define treaddir(...) v9fs_treaddir((TReadDirOpt) __VA_ARGS__) #define tlopen(...) v9fs_tlopen((TLOpenOpt) __VA_ARGS__) #define twrite(...) v9fs_twrite((TWriteOpt) __VA_ARGS__) From 610dc187e52605c8ea8d14c5e7d8e7384f8af290 Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Wed, 12 Mar 2025 16:29:32 +0100 Subject: [PATCH 0639/2760] tests/9p: Test `Tsetattr` can truncate unlinked file Enhance the `use-after-unlink` test with a new check for the case where the client wants to alter the size of an unlinked file for which it still has an active fid. Suggested-by: Christian Schoenebeck Signed-off-by: Greg Kurz Reviewed-by: Christian Schoenebeck Message-Id: <20250312152933.383967-7-groug@kaod.org> Signed-off-by: Christian Schoenebeck --- tests/qtest/virtio-9p-test.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/qtest/virtio-9p-test.c b/tests/qtest/virtio-9p-test.c index f515a9bb15..ac38ccf595 100644 --- a/tests/qtest/virtio-9p-test.c +++ b/tests/qtest/virtio-9p-test.c @@ -736,6 +736,20 @@ static void fs_use_after_unlink(void *obj, void *data, .data = buf }).count; g_assert_cmpint(count, ==, write_count); + + /* truncate file to (arbitrarily chosen) size 2001 */ + tsetattr({ + .client = v9p, .fid = fid_file, .attr = (v9fs_attr) { + .valid = P9_SETATTR_SIZE, + .size = 2001 + } + }); + /* truncate apparently succeeded, let's double-check the size */ + tgetattr({ + .client = v9p, .fid = fid_file, .request_mask = P9_GETATTR_BASIC, + .rgetattr.attr = &attr + }); + g_assert_cmpint(attr.size, ==, 2001); } static void cleanup_9p_local_driver(void *data) From cdafeda35709ddf8cd982a7eb653c2a5028c8074 Mon Sep 17 00:00:00 2001 From: Christian Schoenebeck Date: Thu, 20 Mar 2025 13:16:20 +0100 Subject: [PATCH 0640/2760] 9pfs: fix 'total_open_fd' decrementation According to 'man 2 close' errors returned by close() should only be used for either diagnostic purposes or for catching data loss due to a previous write error, as an error result of close() usually indicates a deferred error of a previous write operation. Therefore not decrementing 'total_open_fd' on a close() error is wrong and would yield in a higher open file descriptor count than actually the case, leading to 9p server reclaiming open file descriptors too soon. Based-on: <20250312152933.383967-7-groug@kaod.org> Signed-off-by: Christian Schoenebeck Reviewed-by: Greg Kurz Message-Id: --- hw/9pfs/9p.c | 10 +++++++++- hw/9pfs/codir.c | 7 ++++++- hw/9pfs/cofile.c | 7 ++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c index b22df3aa2b..8b001b9112 100644 --- a/hw/9pfs/9p.c +++ b/hw/9pfs/9p.c @@ -510,7 +510,15 @@ void coroutine_fn v9fs_reclaim_fd(V9fsPDU *pdu) err = (f->fid_type == P9_FID_DIR) ? s->ops->closedir(&s->ctx, &f->fs_reclaim) : s->ops->close(&s->ctx, &f->fs_reclaim); - if (!err) { + + /* 'man 2 close' suggests to ignore close() errors except of EBADF */ + if (unlikely(err && errno == EBADF)) { + /* + * unexpected case as FIDs were picked above by having a valid + * file descriptor + */ + error_report("9pfs: v9fs_reclaim_fd() WARNING: close() failed with EBADF"); + } else { /* total_open_fd must only be mutated on main thread */ nclosed++; } diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 2068a4779d..bce7dd96e9 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -20,6 +20,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "qemu/error-report.h" #include "coth.h" #include "9p-xattr.h" #include "9p-util.h" @@ -353,7 +354,11 @@ int coroutine_fn v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs) err = -errno; } }); - if (!err) { + /* 'man 2 close' suggests to ignore close() errors except of EBADF */ + if (unlikely(err && errno == EBADF)) { + /* unexpected case as we should have checked for a valid file handle */ + error_report("9pfs: WARNING: v9fs_co_closedir() failed with EBADF"); + } else { total_open_fd--; } return err; diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 71174c3e4a..6e775c8e41 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -20,6 +20,7 @@ #include "fsdev/qemu-fsdev.h" #include "qemu/thread.h" #include "qemu/main-loop.h" +#include "qemu/error-report.h" #include "coth.h" int coroutine_fn v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, @@ -197,7 +198,11 @@ int coroutine_fn v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) err = -errno; } }); - if (!err) { + /* 'man 2 close' suggests to ignore close() errors except of EBADF */ + if (unlikely(err && errno == EBADF)) { + /* unexpected case as we should have checked for a valid file handle */ + error_report("9pfs: WARNING: v9fs_co_close() failed with EBADF"); + } else { total_open_fd--; } return err; From d551b822f7ac329c763267659950992849d7e735 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 15:33:05 -0700 Subject: [PATCH 0641/2760] accel/tcg: Use vaddr in cpu_loop.h Use vaddr instead of abi_ptr or target_ulong for a guest address. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 2 +- bsd-user/signal.c | 4 ++-- include/user/cpu_loop.h | 12 +++++------- linux-user/signal.c | 4 ++-- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 68e01fc584..e1f4c4eacf 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -126,7 +126,7 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) * guest, we'd end up in an infinite loop of retrying the faulting access. */ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, - uintptr_t host_pc, abi_ptr guest_addr) + uintptr_t host_pc, vaddr guest_addr) { switch (page_unprotect(cpu, guest_addr, host_pc)) { case 0: diff --git a/bsd-user/signal.c b/bsd-user/signal.c index 1aa0fd79d6..dadcc037dc 100644 --- a/bsd-user/signal.c +++ b/bsd-user/signal.c @@ -1030,7 +1030,7 @@ void process_pending_signals(CPUArchState *env) ts->in_sigsuspend = false; } -void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, +void cpu_loop_exit_sigsegv(CPUState *cpu, vaddr addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; @@ -1046,7 +1046,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, cpu_loop_exit_restore(cpu, ra); } -void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, +void cpu_loop_exit_sigbus(CPUState *cpu, vaddr addr, MMUAccessType access_type, uintptr_t ra) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; diff --git a/include/user/cpu_loop.h b/include/user/cpu_loop.h index 589c66543f..ad8a1d711f 100644 --- a/include/user/cpu_loop.h +++ b/include/user/cpu_loop.h @@ -20,11 +20,9 @@ #ifndef USER_CPU_LOOP_H #define USER_CPU_LOOP_H -#include "exec/abi_ptr.h" +#include "exec/vaddr.h" #include "exec/mmu-access-type.h" -#include "exec/log.h" -#include "exec/target_long.h" -#include "special-errno.h" + /** * adjust_signal_pc: @@ -46,7 +44,7 @@ MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write); * Return true if the write fault has been handled, and should be re-tried. */ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, - uintptr_t host_pc, abi_ptr guest_addr); + uintptr_t host_pc, vaddr guest_addr); /** * cpu_loop_exit_sigsegv: @@ -59,7 +57,7 @@ bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, * Use the TCGCPUOps hook to record cpu state, do guest operating system * specific things to raise SIGSEGV, and jump to the main cpu loop. */ -G_NORETURN void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, +G_NORETURN void cpu_loop_exit_sigsegv(CPUState *cpu, vaddr addr, MMUAccessType access_type, bool maperr, uintptr_t ra); @@ -73,7 +71,7 @@ G_NORETURN void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, * Use the TCGCPUOps hook to record cpu state, do guest operating system * specific things to raise SIGBUS, and jump to the main cpu loop. */ -G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, +G_NORETURN void cpu_loop_exit_sigbus(CPUState *cpu, vaddr addr, MMUAccessType access_type, uintptr_t ra); diff --git a/linux-user/signal.c b/linux-user/signal.c index 4dafc2c3a2..cd0e7398aa 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -750,7 +750,7 @@ void force_sigsegv(int oldsig) } #endif -void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, +void cpu_loop_exit_sigsegv(CPUState *cpu, vaddr addr, MMUAccessType access_type, bool maperr, uintptr_t ra) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; @@ -766,7 +766,7 @@ void cpu_loop_exit_sigsegv(CPUState *cpu, target_ulong addr, cpu_loop_exit_restore(cpu, ra); } -void cpu_loop_exit_sigbus(CPUState *cpu, target_ulong addr, +void cpu_loop_exit_sigbus(CPUState *cpu, vaddr addr, MMUAccessType access_type, uintptr_t ra) { const TCGCPUOps *tcg_ops = cpu->cc->tcg_ops; From 9b74d403b30e64256b4b94cbc01c76a0382ca5e8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 16:54:31 -0700 Subject: [PATCH 0642/2760] accel/tcg: Move user-only tlb_vaddr_to_host out of line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At the same time, fix a mis-match between user and system by using vaddr not abi_ptr for the address parameter. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 6 ++++++ include/accel/tcg/cpu-ldst.h | 8 -------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index e1f4c4eacf..adc5296ba5 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -850,6 +850,12 @@ void *probe_access(CPUArchState *env, vaddr addr, int size, return size ? g2h(env_cpu(env), addr) : NULL; } +void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr, + MMUAccessType access_type, int mmu_idx) +{ + return g2h(env_cpu(env), addr); +} + tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, void **hostp) { diff --git a/include/accel/tcg/cpu-ldst.h b/include/accel/tcg/cpu-ldst.h index 44a62b54da..00e6419e13 100644 --- a/include/accel/tcg/cpu-ldst.h +++ b/include/accel/tcg/cpu-ldst.h @@ -515,15 +515,7 @@ static inline uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) * Otherwise (TLB entry is for an I/O access, guest software * TLB fill required, etc) return NULL. */ -#ifdef CONFIG_USER_ONLY -static inline void *tlb_vaddr_to_host(CPUArchState *env, abi_ptr addr, - MMUAccessType access_type, int mmu_idx) -{ - return g2h(env_cpu(env), addr); -} -#else void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr, MMUAccessType access_type, int mmu_idx); -#endif #endif /* ACCEL_TCG_CPU_LDST_H */ From a21959a8a835783b556d4a1d18aaa2fad4b7ea62 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 17:09:28 -0700 Subject: [PATCH 0643/2760] accel/tcg: Move tlb_vaddr_to_host declaration to probe.h This is a probing function, not a load/store function. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/accel/tcg/cpu-ldst.h | 16 ---------------- include/accel/tcg/probe.h | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/accel/tcg/cpu-ldst.h b/include/accel/tcg/cpu-ldst.h index 00e6419e13..0de7f5eaa6 100644 --- a/include/accel/tcg/cpu-ldst.h +++ b/include/accel/tcg/cpu-ldst.h @@ -502,20 +502,4 @@ static inline uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr addr) return cpu_ldq_code_mmu(env, addr, oi, 0); } -/** - * tlb_vaddr_to_host: - * @env: CPUArchState - * @addr: guest virtual address to look up - * @access_type: 0 for read, 1 for write, 2 for execute - * @mmu_idx: MMU index to use for lookup - * - * Look up the specified guest virtual index in the TCG softmmu TLB. - * If we can translate a host virtual address suitable for direct RAM - * access, without causing a guest exception, then return it. - * Otherwise (TLB entry is for an I/O access, guest software - * TLB fill required, etc) return NULL. - */ -void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr, - MMUAccessType access_type, int mmu_idx); - #endif /* ACCEL_TCG_CPU_LDST_H */ diff --git a/include/accel/tcg/probe.h b/include/accel/tcg/probe.h index 177bd1608d..dd9ecbbdf1 100644 --- a/include/accel/tcg/probe.h +++ b/include/accel/tcg/probe.h @@ -103,4 +103,20 @@ int probe_access_full_mmu(CPUArchState *env, vaddr addr, int size, #endif /* !CONFIG_USER_ONLY */ +/** + * tlb_vaddr_to_host: + * @env: CPUArchState + * @addr: guest virtual address to look up + * @access_type: 0 for read, 1 for write, 2 for execute + * @mmu_idx: MMU index to use for lookup + * + * Look up the specified guest virtual index in the TCG softmmu TLB. + * If we can translate a host virtual address suitable for direct RAM + * access, without causing a guest exception, then return it. + * Otherwise (TLB entry is for an I/O access, guest software + * TLB fill required, etc) return NULL. + */ +void *tlb_vaddr_to_host(CPUArchState *env, vaddr addr, + MMUAccessType access_type, int mmu_idx); + #endif From b5555a077f7a2e655b0a4aec9328d70497a7dd65 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 17:17:56 -0700 Subject: [PATCH 0644/2760] accel/tcg: Use target_long_bits() in cputlb.c Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 5b6d6f7975..35c467aace 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" +#include "qemu/target-info.h" #include "accel/tcg/cpu-ops.h" #include "accel/tcg/iommu.h" #include "accel/tcg/probe.h" @@ -771,19 +772,19 @@ void tlb_flush_range_by_mmuidx(CPUState *cpu, vaddr addr, assert_cpu_is_self(cpu); + /* If no page bits are significant, this devolves to tlb_flush. */ + if (bits < TARGET_PAGE_BITS) { + tlb_flush_by_mmuidx(cpu, idxmap); + return; + } /* * If all bits are significant, and len is small, * this devolves to tlb_flush_page. */ - if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { + if (len <= TARGET_PAGE_SIZE && bits >= target_long_bits()) { tlb_flush_page_by_mmuidx(cpu, addr, idxmap); return; } - /* If no page bits are significant, this devolves to tlb_flush. */ - if (bits < TARGET_PAGE_BITS) { - tlb_flush_by_mmuidx(cpu, idxmap); - return; - } /* This should already be page aligned */ d.addr = addr & TARGET_PAGE_MASK; @@ -809,19 +810,19 @@ void tlb_flush_range_by_mmuidx_all_cpus_synced(CPUState *src_cpu, TLBFlushRangeData d, *p; CPUState *dst_cpu; + /* If no page bits are significant, this devolves to tlb_flush. */ + if (bits < TARGET_PAGE_BITS) { + tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap); + return; + } /* * If all bits are significant, and len is small, * this devolves to tlb_flush_page. */ - if (bits >= TARGET_LONG_BITS && len <= TARGET_PAGE_SIZE) { + if (len <= TARGET_PAGE_SIZE && bits >= target_long_bits()) { tlb_flush_page_by_mmuidx_all_cpus_synced(src_cpu, addr, idxmap); return; } - /* If no page bits are significant, this devolves to tlb_flush. */ - if (bits < TARGET_PAGE_BITS) { - tlb_flush_by_mmuidx_all_cpus_synced(src_cpu, idxmap); - return; - } /* This should already be page aligned */ d.addr = addr & TARGET_PAGE_MASK; From 4b2de658f13df52ccbf41c3399ab4f7adbcc6080 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 17:26:28 -0700 Subject: [PATCH 0645/2760] accel/tcg: Use vaddr for plugin_{load,store}_cb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid the use of abi_ptr within ldst_common.c.inc. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/ldst_common.c.inc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accel/tcg/ldst_common.c.inc b/accel/tcg/ldst_common.c.inc index 9791a4e9ef..57f3e06192 100644 --- a/accel/tcg/ldst_common.c.inc +++ b/accel/tcg/ldst_common.c.inc @@ -123,7 +123,7 @@ void helper_st_i128(CPUArchState *env, uint64_t addr, Int128 val, MemOpIdx oi) * Load helpers for cpu_ldst.h */ -static void plugin_load_cb(CPUArchState *env, abi_ptr addr, +static void plugin_load_cb(CPUArchState *env, vaddr addr, uint64_t value_low, uint64_t value_high, MemOpIdx oi) @@ -193,7 +193,7 @@ Int128 cpu_ld16_mmu(CPUArchState *env, vaddr addr, * Store helpers for cpu_ldst.h */ -static void plugin_store_cb(CPUArchState *env, abi_ptr addr, +static void plugin_store_cb(CPUArchState *env, vaddr addr, uint64_t value_low, uint64_t value_high, MemOpIdx oi) From 0566f364f79c452af99f437a7784397b03775c72 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 17:31:43 -0700 Subject: [PATCH 0646/2760] accel/tcg: Build cputlb.c once MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 3 ++- accel/tcg/meson.build | 5 +---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 35c467aace..5f6d7c601c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -25,7 +25,8 @@ #include "accel/tcg/probe.h" #include "exec/page-protection.h" #include "system/memory.h" -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" +#include "accel/tcg/cpu-mmu-index.h" #include "exec/cputlb.h" #include "exec/tb-flush.h" #include "system/ram_addr.h" diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index d6bd304add..9b86051b82 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -25,15 +25,12 @@ tcg_specific_ss = ss.source_set() tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) -specific_ss.add(when: ['CONFIG_SYSTEM_ONLY', 'CONFIG_TCG'], if_true: files( - 'cputlb.c', -)) - libuser_ss.add(files( 'user-exec-stub.c', )) libsystem_ss.add(files( + 'cputlb.c', 'icount-common.c', 'monitor.c', 'tcg-accel-ops.c', From 30da476066d6470e1064eb564e348af945a1a656 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 18:07:47 -0700 Subject: [PATCH 0647/2760] include/user: Convert GUEST_ADDR_MAX to a variable Remove GUEST_ADDR_MAX and add guest_addr_max. Initialize it in *-user/main.c, after reserved_va. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 4 ++-- bsd-user/main.c | 8 ++++++++ include/user/guest-host.h | 27 +++++++-------------------- linux-user/main.c | 8 ++++++++ 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index adc5296ba5..f674fd875e 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -500,7 +500,7 @@ void page_set_flags(vaddr start, vaddr last, int flags) guest address space. If this assert fires, it probably indicates a missing call to h2g_valid. */ assert(start <= last); - assert(last <= GUEST_ADDR_MAX); + assert(last <= guest_addr_max); /* Only set PAGE_ANON with new mappings. */ assert(!(flags & PAGE_ANON) || (flags & PAGE_RESET)); assert_memory_lock(); @@ -621,7 +621,7 @@ vaddr page_find_range_empty(vaddr min, vaddr max, vaddr len, vaddr align) vaddr len_m1, align_m1; assert(min <= max); - assert(max <= GUEST_ADDR_MAX); + assert(max <= guest_addr_max); assert(len != 0); assert(is_power_of_2(align)); assert_memory_lock(); diff --git a/bsd-user/main.c b/bsd-user/main.c index fa7645a56e..603fc80ba7 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -89,6 +89,7 @@ bool have_guest_base; #endif unsigned long reserved_va; +unsigned long guest_addr_max; const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX; const char *qemu_uname_release; @@ -500,6 +501,13 @@ int main(int argc, char **argv) /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */ reserved_va = max_reserved_va; } + if (reserved_va != 0) { + guest_addr_max = reserved_va; + } else if (MIN(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) { + guest_addr_max = UINT32_MAX; + } else { + guest_addr_max = ~0ul; + } if (getenv("QEMU_STRACE")) { do_strace = 1; diff --git a/include/user/guest-host.h b/include/user/guest-host.h index 8d2079bbbb..8e10d36948 100644 --- a/include/user/guest-host.h +++ b/include/user/guest-host.h @@ -23,23 +23,11 @@ extern unsigned long reserved_va; /* - * Limit the guest addresses as best we can. - * - * When not using -R reserved_va, we cannot really limit the guest - * to less address space than the host. For 32-bit guests, this - * acts as a sanity check that we're not giving the guest an address - * that it cannot even represent. For 64-bit guests... the address - * might not be what the real kernel would give, but it is at least - * representable in the guest. - * - * TODO: Improve address allocation to avoid this problem, and to - * avoid setting bits at the top of guest addresses that might need - * to be used for tags. + * The last byte of the guest address space. + * If reserved_va is non-zero, guest_addr_max matches. + * If reserved_va is zero, guest_addr_max equals the full guest space. */ -#define GUEST_ADDR_MAX_ \ - ((MIN_CONST(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) ? \ - UINT32_MAX : ~0ul) -#define GUEST_ADDR_MAX (reserved_va ? : GUEST_ADDR_MAX_) +extern unsigned long guest_addr_max; #ifndef TARGET_TAGGED_ADDRESSES static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x) @@ -61,17 +49,16 @@ static inline void *g2h(CPUState *cs, abi_ptr x) static inline bool guest_addr_valid_untagged(abi_ulong x) { - return x <= GUEST_ADDR_MAX; + return x <= guest_addr_max; } static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) { - return len - 1 <= GUEST_ADDR_MAX && start <= GUEST_ADDR_MAX - len + 1; + return len - 1 <= guest_addr_max && start <= guest_addr_max - len + 1; } #define h2g_valid(x) \ - (HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS || \ - (uintptr_t)(x) - guest_base <= GUEST_ADDR_MAX) + ((uintptr_t)(x) - guest_base <= guest_addr_max) #define h2g_nocheck(x) ({ \ uintptr_t __ret = (uintptr_t)(x) - guest_base; \ diff --git a/linux-user/main.c b/linux-user/main.c index 4af7f49f38..5ac5b55dc6 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -122,6 +122,7 @@ static const char *last_log_filename; #endif unsigned long reserved_va; +unsigned long guest_addr_max; static void usage(int exitcode); @@ -858,6 +859,13 @@ int main(int argc, char **argv, char **envp) /* MAX_RESERVED_VA + 1 is a large power of 2, so is aligned. */ reserved_va = max_reserved_va; } + if (reserved_va != 0) { + guest_addr_max = reserved_va; + } else if (MIN(TARGET_VIRT_ADDR_SPACE_BITS, TARGET_ABI_BITS) <= 32) { + guest_addr_max = UINT32_MAX; + } else { + guest_addr_max = ~0ul; + } /* * Temporarily disable From 7804c84a56f9265813eb87db0bdae063279af030 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 18:20:04 -0700 Subject: [PATCH 0648/2760] include/user: Use vaddr in guest-host.h Replace abi_ptr and abi_ulong with vaddr. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/user/guest-host.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/user/guest-host.h b/include/user/guest-host.h index 8e10d36948..0656f2e356 100644 --- a/include/user/guest-host.h +++ b/include/user/guest-host.h @@ -8,7 +8,7 @@ #ifndef USER_GUEST_HOST_H #define USER_GUEST_HOST_H -#include "user/abitypes.h" +#include "exec/vaddr.h" #include "user/guest-base.h" #include "cpu.h" @@ -30,29 +30,29 @@ extern unsigned long reserved_va; extern unsigned long guest_addr_max; #ifndef TARGET_TAGGED_ADDRESSES -static inline abi_ptr cpu_untagged_addr(CPUState *cs, abi_ptr x) +static inline vaddr cpu_untagged_addr(CPUState *cs, vaddr x) { return x; } #endif /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ -static inline void *g2h_untagged(abi_ptr x) +static inline void *g2h_untagged(vaddr x) { return (void *)((uintptr_t)(x) + guest_base); } -static inline void *g2h(CPUState *cs, abi_ptr x) +static inline void *g2h(CPUState *cs, vaddr x) { return g2h_untagged(cpu_untagged_addr(cs, x)); } -static inline bool guest_addr_valid_untagged(abi_ulong x) +static inline bool guest_addr_valid_untagged(vaddr x) { return x <= guest_addr_max; } -static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) +static inline bool guest_range_valid_untagged(vaddr start, vaddr len) { return len - 1 <= guest_addr_max && start <= guest_addr_max - len + 1; } @@ -62,7 +62,7 @@ static inline bool guest_range_valid_untagged(abi_ulong start, abi_ulong len) #define h2g_nocheck(x) ({ \ uintptr_t __ret = (uintptr_t)(x) - guest_base; \ - (abi_ptr)__ret; \ + (vaddr)__ret; \ }) #define h2g(x) ({ \ From 2c0b261fcd259f0e027633c744d279d255b4ff49 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 18:46:41 -0700 Subject: [PATCH 0649/2760] accel/tcg: Move TARGET_TAGGED_ADDRESSES to TCGCPUOps.untagged_addr Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- include/accel/tcg/cpu-ops.h | 7 +++++++ include/user/guest-host.h | 8 +++++--- target/arm/cpu-param.h | 7 +------ target/arm/cpu.c | 27 ++++++++++++++++++++++++++- target/arm/cpu.h | 32 +------------------------------- 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 23cd6af0b2..cd22e5d5b9 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -157,6 +157,13 @@ struct TCGCPUOps { */ void (*record_sigbus)(CPUState *cpu, vaddr addr, MMUAccessType access_type, uintptr_t ra); + + /** + * untagged_addr: Remove an ignored tag from an address + * @cpu: cpu context + * @addr: tagged guest address + */ + vaddr (*untagged_addr)(CPUState *cs, vaddr addr); #else /** @do_interrupt: Callback for interrupt handling. */ void (*do_interrupt)(CPUState *cpu); diff --git a/include/user/guest-host.h b/include/user/guest-host.h index 0656f2e356..8f7ef75896 100644 --- a/include/user/guest-host.h +++ b/include/user/guest-host.h @@ -10,7 +10,7 @@ #include "exec/vaddr.h" #include "user/guest-base.h" -#include "cpu.h" +#include "accel/tcg/cpu-ops.h" /* * If non-zero, the guest virtual address space is a contiguous subset @@ -29,12 +29,14 @@ extern unsigned long reserved_va; */ extern unsigned long guest_addr_max; -#ifndef TARGET_TAGGED_ADDRESSES static inline vaddr cpu_untagged_addr(CPUState *cs, vaddr x) { + const TCGCPUOps *tcg_ops = cs->cc->tcg_ops; + if (tcg_ops->untagged_addr) { + return tcg_ops->untagged_addr(cs, x); + } return x; } -#endif /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ static inline void *g2h_untagged(vaddr x) diff --git a/target/arm/cpu-param.h b/target/arm/cpu-param.h index 5c5bc8a009..8b46c7c570 100644 --- a/target/arm/cpu-param.h +++ b/target/arm/cpu-param.h @@ -17,14 +17,9 @@ #endif #ifdef CONFIG_USER_ONLY -# ifdef TARGET_AARCH64 -# define TARGET_TAGGED_ADDRESSES -# ifdef __FreeBSD__ -# define TARGET_PAGE_BITS 12 -# else +# if defined(TARGET_AARCH64) && defined(CONFIG_LINUX) /* Allow user-only to vary page size from 4k */ # define TARGET_PAGE_BITS_VARY -# endif # else # define TARGET_PAGE_BITS 12 # endif diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 2020aec54a..45cb6fd7ee 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2671,7 +2671,31 @@ static const char *arm_gdb_get_core_xml_file(CPUState *cs) return "arm-core.xml"; } -#ifndef CONFIG_USER_ONLY +#ifdef CONFIG_USER_ONLY +/** + * aarch64_untagged_addr: + * + * Remove any address tag from @x. This is explicitly related to the + * linux syscall TIF_TAGGED_ADDR setting, not TBI in general. + * + * There should be a better place to put this, but we need this in + * include/exec/cpu_ldst.h, and not some place linux-user specific. + * + * Note that arm-*-user will never set tagged_addr_enable. + */ +static vaddr aarch64_untagged_addr(CPUState *cs, vaddr x) +{ + CPUARMState *env = cpu_env(cs); + if (env->tagged_addr_enable) { + /* + * TBI is enabled for userspace but not kernelspace addresses. + * Only clear the tag if bit 55 is clear. + */ + x &= sextract64(x, 0, 56); + } + return x; +} +#else #include "hw/core/sysemu-cpu-ops.h" static const struct SysemuCPUOps arm_sysemu_ops = { @@ -2702,6 +2726,7 @@ static const TCGCPUOps arm_tcg_ops = { #ifdef CONFIG_USER_ONLY .record_sigsegv = arm_cpu_record_sigsegv, .record_sigbus = arm_cpu_record_sigbus, + .untagged_addr = aarch64_untagged_addr, #else .tlb_fill_align = arm_cpu_tlb_fill_align, .cpu_exec_interrupt = arm_cpu_exec_interrupt, diff --git a/target/arm/cpu.h b/target/arm/cpu.h index be4449ca06..23720b2b17 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -783,12 +783,9 @@ typedef struct CPUArchState { #else /* CONFIG_USER_ONLY */ /* For usermode syscall translation. */ bool eabi; -#endif /* CONFIG_USER_ONLY */ - -#ifdef TARGET_TAGGED_ADDRESSES /* Linux syscall tagged address support */ bool tagged_addr_enable; -#endif +#endif /* CONFIG_USER_ONLY */ } CPUARMState; static inline void set_feature(CPUARMState *env, int feature) @@ -3217,34 +3214,7 @@ extern const uint64_t pred_esz_masks[5]; #define TAG_GRANULE (1 << LOG2_TAG_GRANULE) #ifdef CONFIG_USER_ONLY - #define TARGET_PAGE_DATA_SIZE (TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1)) - -#ifdef TARGET_TAGGED_ADDRESSES -/** - * cpu_untagged_addr: - * @cs: CPU context - * @x: tagged address - * - * Remove any address tag from @x. This is explicitly related to the - * linux syscall TIF_TAGGED_ADDR setting, not TBI in general. - * - * There should be a better place to put this, but we need this in - * include/exec/cpu_ldst.h, and not some place linux-user specific. - */ -static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x) -{ - CPUARMState *env = cpu_env(cs); - if (env->tagged_addr_enable) { - /* - * TBI is enabled for userspace but not kernelspace addresses. - * Only clear the tag if bit 55 is clear. - */ - x &= sextract64(x, 0, 56); - } - return x; -} -#endif /* TARGET_TAGGED_ADDRESSES */ #endif /* CONFIG_USER_ONLY */ #endif From 964080d3563f1211b70051c8ea5add752586da09 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 20:23:59 -0700 Subject: [PATCH 0650/2760] accel/tcg: Remove TARGET_PAGE_DATA_SIZE This macro is used by only one target, and even then under unusual conditions -- AArch64 with mmap's PROT_MTE flag. Since page size for aarch64-linux-user is variable, the per-page data size is also variable. Since page_reset_target_data via target_munmap does not have ready access to CPUState, simply pass in the size from the first allocation and remember that. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 26 ++++++++++++++++---------- include/user/page-protection.h | 8 +++++--- target/arm/cpu.h | 4 ---- target/arm/tcg/mte_helper.c | 4 ++-- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index f674fd875e..46b1e97c30 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -870,7 +870,6 @@ tb_page_addr_t get_page_addr_code_hostp(CPUArchState *env, vaddr addr, return addr; } -#ifdef TARGET_PAGE_DATA_SIZE /* * Allocate chunks of target data together. For the only current user, * if we allocate one hunk per page, we have overhead of 40/128 or 40%. @@ -886,10 +885,16 @@ typedef struct TargetPageDataNode { } TargetPageDataNode; static IntervalTreeRoot targetdata_root; +static size_t target_page_data_size; void page_reset_target_data(vaddr start, vaddr last) { IntervalTreeNode *n, *next; + size_t size = target_page_data_size; + + if (likely(size == 0)) { + return; + } assert_memory_lock(); @@ -920,17 +925,22 @@ void page_reset_target_data(vaddr start, vaddr last) n_last = MIN(last, n->last); p_len = (n_last + 1 - n_start) >> TARGET_PAGE_BITS; - memset(t->data + p_ofs * TARGET_PAGE_DATA_SIZE, 0, - p_len * TARGET_PAGE_DATA_SIZE); + memset(t->data + p_ofs * size, 0, p_len * size); } } -void *page_get_target_data(vaddr address) +void *page_get_target_data(vaddr address, size_t size) { IntervalTreeNode *n; TargetPageDataNode *t; vaddr page, region, p_ofs; + /* Remember the size from the first call, and it should be constant. */ + if (unlikely(target_page_data_size != size)) { + assert(target_page_data_size == 0); + target_page_data_size = size; + } + page = address & TARGET_PAGE_MASK; region = address & TBD_MASK; @@ -945,8 +955,7 @@ void *page_get_target_data(vaddr address) mmap_lock(); n = interval_tree_iter_first(&targetdata_root, page, page); if (!n) { - t = g_malloc0(sizeof(TargetPageDataNode) - + TPD_PAGES * TARGET_PAGE_DATA_SIZE); + t = g_malloc0(sizeof(TargetPageDataNode) + TPD_PAGES * size); n = &t->itree; n->start = region; n->last = region | ~TBD_MASK; @@ -957,11 +966,8 @@ void *page_get_target_data(vaddr address) t = container_of(n, TargetPageDataNode, itree); p_ofs = (page - region) >> TARGET_PAGE_BITS; - return t->data + p_ofs * TARGET_PAGE_DATA_SIZE; + return t->data + p_ofs * size; } -#else -void page_reset_target_data(vaddr start, vaddr last) { } -#endif /* TARGET_PAGE_DATA_SIZE */ /* The system-mode versions of these helpers are in cputlb.c. */ diff --git a/include/user/page-protection.h b/include/user/page-protection.h index 86143212fd..4bde664e4a 100644 --- a/include/user/page-protection.h +++ b/include/user/page-protection.h @@ -73,18 +73,20 @@ bool page_check_range_empty(vaddr start, vaddr last); vaddr page_find_range_empty(vaddr min, vaddr max, vaddr len, vaddr align); /** - * page_get_target_data(address) + * page_get_target_data * @address: guest virtual address + * @size: per-page size * - * Return TARGET_PAGE_DATA_SIZE bytes of out-of-band data to associate + * Return @size bytes of out-of-band data to associate * with the guest page at @address, allocating it if necessary. The * caller should already have verified that the address is valid. + * The value of @size must be the same for every call. * * The memory will be freed when the guest page is deallocated, * e.g. with the munmap system call. */ __attribute__((returns_nonnull)) -void *page_get_target_data(vaddr address); +void *page_get_target_data(vaddr address, size_t size); typedef int (*walk_memory_regions_fn)(void *, vaddr, vaddr, int); int walk_memory_regions(void *, walk_memory_regions_fn); diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 23720b2b17..6ed6409cb7 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -3213,8 +3213,4 @@ extern const uint64_t pred_esz_masks[5]; #define LOG2_TAG_GRANULE 4 #define TAG_GRANULE (1 << LOG2_TAG_GRANULE) -#ifdef CONFIG_USER_ONLY -#define TARGET_PAGE_DATA_SIZE (TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1)) -#endif /* CONFIG_USER_ONLY */ - #endif diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index 13d7ac0097..0efc18a181 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -37,7 +37,6 @@ #include "qemu/guest-random.h" #include "mte_helper.h" - static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) { if (exclude == 0xffff) { @@ -63,6 +62,7 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, bool probe, uintptr_t ra) { #ifdef CONFIG_USER_ONLY + const size_t page_data_size = TARGET_PAGE_SIZE >> (LOG2_TAG_GRANULE + 1); uint64_t clean_ptr = useronly_clean_ptr(ptr); int flags = page_get_flags(clean_ptr); uint8_t *tags; @@ -83,7 +83,7 @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, return NULL; } - tags = page_get_target_data(clean_ptr); + tags = page_get_target_data(clean_ptr, page_data_size); index = extract32(ptr, LOG2_TAG_GRANULE + 1, TARGET_PAGE_BITS - LOG2_TAG_GRANULE - 1); From 03c981e7d63eaa03e6b7c4b9ef59b45b0b985876 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 20:30:22 -0700 Subject: [PATCH 0651/2760] accel/tcg: Avoid abi_ptr in user-exec.c In page_dump/dump_region, use guest_addr_max to check the size of the guest address space and size the output appropriately. This will change output with small values of -R reserved_va, but shouldn't affect anything else. Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/user-exec.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 46b1e97c30..085da0c036 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -29,6 +29,7 @@ #include "accel/tcg/helper-retaddr.h" #include "accel/tcg/probe.h" #include "user/cpu_loop.h" +#include "user/guest-host.h" #include "qemu/main-loop.h" #include "user/page-protection.h" #include "exec/page-protection.h" @@ -202,10 +203,19 @@ int walk_memory_regions(void *priv, walk_memory_regions_fn fn) static int dump_region(void *opaque, vaddr start, vaddr end, int prot) { FILE *f = opaque; + uint64_t mask; + int width; - fprintf(f, TARGET_ABI_FMT_ptr "-" TARGET_ABI_FMT_ptr - " " TARGET_ABI_FMT_ptr " %c%c%c\n", - (abi_ptr)start, (abi_ptr)end, (abi_ptr)(end - start), + if (guest_addr_max <= UINT32_MAX) { + mask = UINT32_MAX, width = 8; + } else { + mask = UINT64_MAX, width = 16; + } + + fprintf(f, "%0*" PRIx64 "-%0*" PRIx64 " %0*" PRIx64 " %c%c%c\n", + width, start & mask, + width, end & mask, + width, (end - start) & mask, ((prot & PAGE_READ) ? 'r' : '-'), ((prot & PAGE_WRITE) ? 'w' : '-'), ((prot & PAGE_EXEC) ? 'x' : '-')); @@ -215,10 +225,10 @@ static int dump_region(void *opaque, vaddr start, vaddr end, int prot) /* dump memory mappings */ void page_dump(FILE *f) { - const int length = sizeof(abi_ptr) * 2; + int width = guest_addr_max <= UINT32_MAX ? 8 : 16; fprintf(f, "%-*s %-*s %-*s %s\n", - length, "start", length, "end", length, "size", "prot"); + width, "start", width, "end", width, "size", "prot"); walk_memory_regions(f, dump_region); } @@ -1135,7 +1145,7 @@ static uint64_t do_ld8_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, return ret; } -static Int128 do_ld16_mmu(CPUState *cpu, abi_ptr addr, +static Int128 do_ld16_mmu(CPUState *cpu, vaddr addr, MemOpIdx oi, uintptr_t ra) { void *haddr; From 768cb76d14f1a50c00d60fbb1d393996c76645d8 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 30 Apr 2025 20:31:10 -0700 Subject: [PATCH 0652/2760] accel/tcg: Build user-exec.c once Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/meson.build | 5 +---- accel/tcg/user-exec.c | 5 ++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 9b86051b82..d6f533f9a1 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -21,11 +21,8 @@ endif libuser_ss.add_all(tcg_ss) libsystem_ss.add_all(tcg_ss) -tcg_specific_ss = ss.source_set() -tcg_specific_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c')) -specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_specific_ss) - libuser_ss.add(files( + 'user-exec.c', 'user-exec-stub.c', )) diff --git a/accel/tcg/user-exec.c b/accel/tcg/user-exec.c index 085da0c036..f25d80e2dc 100644 --- a/accel/tcg/user-exec.c +++ b/accel/tcg/user-exec.c @@ -19,13 +19,12 @@ #include "qemu/osdep.h" #include "accel/tcg/cpu-ops.h" #include "disas/disas.h" -#include "cpu.h" #include "exec/vaddr.h" #include "exec/tlb-flags.h" #include "tcg/tcg.h" #include "qemu/bitops.h" #include "qemu/rcu.h" -#include "accel/tcg/cpu-ldst.h" +#include "accel/tcg/cpu-ldst-common.h" #include "accel/tcg/helper-retaddr.h" #include "accel/tcg/probe.h" #include "user/cpu_loop.h" @@ -33,7 +32,7 @@ #include "qemu/main-loop.h" #include "user/page-protection.h" #include "exec/page-protection.h" -#include "exec/helper-proto.h" +#include "exec/helper-proto-common.h" #include "qemu/atomic128.h" #include "qemu/bswap.h" #include "qemu/int128.h" From 36ad84ecb26d6a28c78d079dc51063d972600592 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Mar 2025 09:34:41 +0800 Subject: [PATCH 0653/2760] hw/intc/loongarch_ipi: Add reset support Add reset support with ipi object, register reset callback and clear internal registers when virt machine resets. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/intc/loongarch_ipi.c | 29 +++++++++++++++++++++++++++++ include/hw/intc/loongarch_ipi.h | 1 + 2 files changed, 30 insertions(+) diff --git a/hw/intc/loongarch_ipi.c b/hw/intc/loongarch_ipi.c index 2f8bb57828..74372a2039 100644 --- a/hw/intc/loongarch_ipi.c +++ b/hw/intc/loongarch_ipi.c @@ -93,6 +93,32 @@ static void loongarch_ipi_realize(DeviceState *dev, Error **errp) } } +static void loongarch_ipi_reset_hold(Object *obj, ResetType type) +{ + int i; + LoongarchIPIClass *lic = LOONGARCH_IPI_GET_CLASS(obj); + LoongsonIPICommonState *lics = LOONGSON_IPI_COMMON(obj); + IPICore *core; + + if (lic->parent_phases.hold) { + lic->parent_phases.hold(obj, type); + } + + for (i = 0; i < lics->num_cpu; i++) { + core = lics->cpu + i; + /* IPI with targeted CPU available however not present */ + if (!core->cpu) { + continue; + } + + core->status = 0; + core->en = 0; + core->set = 0; + core->clear = 0; + memset(core->buf, 0, sizeof(core->buf)); + } +} + static void loongarch_ipi_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { @@ -145,10 +171,13 @@ static void loongarch_ipi_class_init(ObjectClass *klass, const void *data) LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); LoongarchIPIClass *lic = LOONGARCH_IPI_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass); device_class_set_parent_realize(dc, loongarch_ipi_realize, &lic->parent_realize); + resettable_class_set_parent_phases(rc, NULL, loongarch_ipi_reset_hold, + NULL, &lic->parent_phases); licc->get_iocsr_as = get_iocsr_as; licc->cpu_by_arch_id = loongarch_cpu_by_arch_id; hc->plug = loongarch_ipi_cpu_plug; diff --git a/include/hw/intc/loongarch_ipi.h b/include/hw/intc/loongarch_ipi.h index 923bf21ecb..a7c6bf85d3 100644 --- a/include/hw/intc/loongarch_ipi.h +++ b/include/hw/intc/loongarch_ipi.h @@ -21,6 +21,7 @@ struct LoongarchIPIState { struct LoongarchIPIClass { LoongsonIPICommonClass parent_class; DeviceRealize parent_realize; + ResettablePhases parent_phases; }; #endif From 86e4a64751a728aae24fa95d76d6c313aa82cf82 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Mar 2025 10:12:09 +0800 Subject: [PATCH 0654/2760] hw/intc/loongarch_extioi: Add reset support Add reset support with extioi irqchip, and register reset callback support with new API resettable_class_set_parent_phases(). Clear internal HW registers and SW state when virt machine resets. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/intc/loongarch_extioi_common.c | 41 +++++++++++++++++++++++ include/hw/intc/loongarch_extioi_common.h | 1 + 2 files changed, 42 insertions(+) diff --git a/hw/intc/loongarch_extioi_common.c b/hw/intc/loongarch_extioi_common.c index 9e1589060c..4a904b3bc1 100644 --- a/hw/intc/loongarch_extioi_common.c +++ b/hw/intc/loongarch_extioi_common.c @@ -108,6 +108,43 @@ static void loongarch_extioi_common_realize(DeviceState *dev, Error **errp) } } +static void loongarch_extioi_common_reset_hold(Object *obj, ResetType type) +{ + LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_GET_CLASS(obj); + LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(obj); + ExtIOICore *core; + int i; + + if (lecc->parent_phases.hold) { + lecc->parent_phases.hold(obj, type); + } + + /* Clear HW registers for the board */ + memset(s->nodetype, 0, sizeof(s->nodetype)); + memset(s->bounce, 0, sizeof(s->bounce)); + memset(s->isr, 0, sizeof(s->isr)); + memset(s->enable, 0, sizeof(s->enable)); + memset(s->ipmap, 0, sizeof(s->ipmap)); + memset(s->coremap, 0, sizeof(s->coremap)); + memset(s->sw_pending, 0, sizeof(s->sw_pending)); + memset(s->sw_ipmap, 0, sizeof(s->sw_ipmap)); + memset(s->sw_coremap, 0, sizeof(s->sw_coremap)); + + for (i = 0; i < s->num_cpu; i++) { + core = s->cpu + i; + /* EXTIOI with targeted CPU available however not present */ + if (!core->cpu) { + continue; + } + + /* Clear HW registers for CPUs */ + memset(core->coreisr, 0, sizeof(core->coreisr)); + memset(core->sw_isr, 0, sizeof(core->sw_isr)); + } + + s->status = 0; +} + static int loongarch_extioi_common_pre_save(void *opaque) { LoongArchExtIOICommonState *s = (LoongArchExtIOICommonState *)opaque; @@ -180,9 +217,13 @@ static void loongarch_extioi_common_class_init(ObjectClass *klass, DeviceClass *dc = DEVICE_CLASS(klass); LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_parent_realize(dc, loongarch_extioi_common_realize, &lecc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, + loongarch_extioi_common_reset_hold, + NULL, &lecc->parent_phases); device_class_set_props(dc, extioi_properties); dc->vmsd = &vmstate_loongarch_extioi; hc->plug = loongarch_extioi_cpu_plug; diff --git a/include/hw/intc/loongarch_extioi_common.h b/include/hw/intc/loongarch_extioi_common.h index 22d7880977..735bfee80a 100644 --- a/include/hw/intc/loongarch_extioi_common.h +++ b/include/hw/intc/loongarch_extioi_common.h @@ -94,6 +94,7 @@ struct LoongArchExtIOICommonClass { SysBusDeviceClass parent_class; DeviceRealize parent_realize; + ResettablePhases parent_phases; int (*pre_save)(void *s); int (*post_load)(void *s, int version_id); }; From bba709ff694cc6f844ca32d333b6be7adc7bd6b4 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Mar 2025 10:23:21 +0800 Subject: [PATCH 0655/2760] hw/intc/loongarch_extioi: Replace legacy reset callback with new api Replace legacy reset callback register device_class_set_legacy_reset() with new function resettable_class_set_parent_phases(). With new API, it will call reset callback of parent object and then itself. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/intc/loongarch_extioi.c | 12 ++++++++---- include/hw/intc/loongarch_extioi.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hw/intc/loongarch_extioi.c b/hw/intc/loongarch_extioi.c index f4fe961a98..7c38c4c9b7 100644 --- a/hw/intc/loongarch_extioi.c +++ b/hw/intc/loongarch_extioi.c @@ -377,11 +377,13 @@ static void loongarch_extioi_unrealize(DeviceState *dev) g_free(s->cpu); } -static void loongarch_extioi_reset(DeviceState *d) +static void loongarch_extioi_reset_hold(Object *obj, ResetType type) { - LoongArchExtIOICommonState *s = LOONGARCH_EXTIOI_COMMON(d); + LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_GET_CLASS(obj); - s->status = 0; + if (lec->parent_phases.hold) { + lec->parent_phases.hold(obj, type); + } } static int vmstate_extioi_post_load(void *opaque, int version_id) @@ -406,12 +408,14 @@ static void loongarch_extioi_class_init(ObjectClass *klass, const void *data) DeviceClass *dc = DEVICE_CLASS(klass); LoongArchExtIOIClass *lec = LOONGARCH_EXTIOI_CLASS(klass); LoongArchExtIOICommonClass *lecc = LOONGARCH_EXTIOI_COMMON_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_parent_realize(dc, loongarch_extioi_realize, &lec->parent_realize); device_class_set_parent_unrealize(dc, loongarch_extioi_unrealize, &lec->parent_unrealize); - device_class_set_legacy_reset(dc, loongarch_extioi_reset); + resettable_class_set_parent_phases(rc, NULL, loongarch_extioi_reset_hold, + NULL, &lec->parent_phases); lecc->post_load = vmstate_extioi_post_load; } diff --git a/include/hw/intc/loongarch_extioi.h b/include/hw/intc/loongarch_extioi.h index 351f18afcf..4a6ae903e9 100644 --- a/include/hw/intc/loongarch_extioi.h +++ b/include/hw/intc/loongarch_extioi.h @@ -22,6 +22,7 @@ struct LoongArchExtIOIClass { DeviceRealize parent_realize; DeviceUnrealize parent_unrealize; + ResettablePhases parent_phases; }; #endif /* LOONGARCH_EXTIOI_H */ From 5101435e6d784c6d5bb267ca019b721a028dbc47 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Mar 2025 11:57:31 +0800 Subject: [PATCH 0656/2760] hw/intc/loongarch_pch: Add reset support Add reset support with LoongArch pci irqchip, and register reset callback support with new API resettable_class_set_parent_phases(). Clear internal HW registers and SW state when virt machine resets. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/intc/loongarch_pic_common.c | 25 +++++++++++++++++++++++++ include/hw/intc/loongarch_pic_common.h | 1 + 2 files changed, 26 insertions(+) diff --git a/hw/intc/loongarch_pic_common.c b/hw/intc/loongarch_pic_common.c index fdb250c418..6dccacc741 100644 --- a/hw/intc/loongarch_pic_common.c +++ b/hw/intc/loongarch_pic_common.c @@ -44,6 +44,27 @@ static void loongarch_pic_common_realize(DeviceState *dev, Error **errp) } } +static void loongarch_pic_common_reset_hold(Object *obj, ResetType type) +{ + LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(obj); + int i; + + s->int_mask = UINT64_MAX; + s->htmsi_en = 0x0; + s->intedge = 0x0; + s->intclr = 0x0; + s->auto_crtl0 = 0x0; + s->auto_crtl1 = 0x0; + for (i = 0; i < 64; i++) { + s->route_entry[i] = 0x1; + s->htmsi_vector[i] = 0x0; + } + s->intirr = 0x0; + s->intisr = 0x0; + s->last_intirr = 0x0; + s->int_polarity = 0x0; +} + static const Property loongarch_pic_common_properties[] = { DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPICCommonState, irq_num, 0), }; @@ -76,9 +97,13 @@ static void loongarch_pic_common_class_init(ObjectClass *klass, { DeviceClass *dc = DEVICE_CLASS(klass); LoongArchPICCommonClass *lpcc = LOONGARCH_PIC_COMMON_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); device_class_set_parent_realize(dc, loongarch_pic_common_realize, &lpcc->parent_realize); + resettable_class_set_parent_phases(rc, NULL, + loongarch_pic_common_reset_hold, + NULL, &lpcc->parent_phases); device_class_set_props(dc, loongarch_pic_common_properties); dc->vmsd = &vmstate_loongarch_pic_common; } diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 43cce48978..d301377cd7 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -76,6 +76,7 @@ struct LoongArchPICCommonClass { SysBusDeviceClass parent_class; DeviceRealize parent_realize; + ResettablePhases parent_phases; int (*pre_save)(LoongArchPICCommonState *s); int (*post_load)(LoongArchPICCommonState *s, int version_id); }; From a41a74ca5323f4d30ac7eb48ec1d54a09fae5baa Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 7 Mar 2025 14:20:13 +0800 Subject: [PATCH 0657/2760] hw/intc/loongarch_pch: Replace legacy reset callback with new api Replace legacy reset callback register device_class_set_legacy_reset() with new function resettable_class_set_parent_phases(). With new API, it will call reset callback of parent object. The internal state has been cleared in parent object LOONGARCH_PIC_COMMON, here parent_phases.hold() is directly called. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 24 +++++++----------------- include/hw/intc/loongarch_pch_pic.h | 1 + 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 6c2b6de3f0..834096265a 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -354,25 +354,13 @@ static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static void loongarch_pch_pic_reset(DeviceState *d) +static void loongarch_pic_reset_hold(Object *obj, ResetType type) { - LoongArchPICCommonState *s = LOONGARCH_PIC_COMMON(d); - int i; + LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(obj); - s->int_mask = -1; - s->htmsi_en = 0x0; - s->intedge = 0x0; - s->intclr = 0x0; - s->auto_crtl0 = 0x0; - s->auto_crtl1 = 0x0; - for (i = 0; i < 64; i++) { - s->route_entry[i] = 0x1; - s->htmsi_vector[i] = 0x0; + if (lpc->parent_phases.hold) { + lpc->parent_phases.hold(obj, type); } - s->intirr = 0x0; - s->intisr = 0x0; - s->last_intirr = 0x0; - s->int_polarity = 0x0; } static void loongarch_pic_realize(DeviceState *dev, Error **errp) @@ -408,8 +396,10 @@ static void loongarch_pic_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); LoongarchPICClass *lpc = LOONGARCH_PIC_CLASS(klass); + ResettableClass *rc = RESETTABLE_CLASS(klass); - device_class_set_legacy_reset(dc, loongarch_pch_pic_reset); + resettable_class_set_parent_phases(rc, NULL, loongarch_pic_reset_hold, + NULL, &lpc->parent_phases); device_class_set_parent_realize(dc, loongarch_pic_realize, &lpc->parent_realize); } diff --git a/include/hw/intc/loongarch_pch_pic.h b/include/hw/intc/loongarch_pch_pic.h index 481cc58aed..839a59a43b 100644 --- a/include/hw/intc/loongarch_pch_pic.h +++ b/include/hw/intc/loongarch_pch_pic.h @@ -22,6 +22,7 @@ struct LoongarchPICClass { LoongArchPICCommonClass parent_class; DeviceRealize parent_realize; + ResettablePhases parent_phases; }; #endif /* HW_LOONGARCH_PCH_PIC_H */ From 73047c825e25a18127dddb89eff0c0bf97a26aed Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 25 Apr 2025 10:05:04 +0800 Subject: [PATCH 0658/2760] hw/loongarch/virt: Get physical entry address with elf file With load_elf() api, image load low address and high address is converted to physical address if parameter translate_fn is provided. However executing entry address is still virtual address. Here convert entry address into physical address, since MMU is disabled when system power on, the first PC instruction should be physical address. Signed-off-by: Bibo Mao Reviewed-by: Richard Henderson Tested-by: Song Gao --- hw/loongarch/boot.c | 1 + tests/tcg/loongarch64/system/kernel.ld | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index 354cf458c8..0324d6adcb 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -245,6 +245,7 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) &kernel_entry, &kernel_low, &kernel_high, NULL, ELFDATA2LSB, EM_LOONGARCH, 1, 0); + kernel_entry = cpu_loongarch_virt_to_phys(NULL, kernel_entry); if (kernel_size < 0) { kernel_size = load_loongarch_linux_image(info->kernel_filename, &kernel_entry, &kernel_low, diff --git a/tests/tcg/loongarch64/system/kernel.ld b/tests/tcg/loongarch64/system/kernel.ld index f1a7c0168c..56d8588f1a 100644 --- a/tests/tcg/loongarch64/system/kernel.ld +++ b/tests/tcg/loongarch64/system/kernel.ld @@ -3,7 +3,7 @@ ENTRY(_start) SECTIONS { /* Linux kernel legacy start address. */ - . = 0x9000000000200000; + . = 0x200000; _text = .; .text : { *(.text) From d0897c6970b3717fe707c8d5a807fe2baf836ddd Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Fri, 28 Feb 2025 09:44:12 +0800 Subject: [PATCH 0659/2760] hw/loongarch/virt: Replace RSDT with XSDT table XSDT table is introduced in ACPI Specification 5.0, it supports 64-bit address in the table. There is LoongArch system support from ACPI Specification 6.4 and later, XSDT is supported by LoongArch system. Here replace RSDT with XSDT table. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/loongarch/virt-acpi-build.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hw/loongarch/virt-acpi-build.c b/hw/loongarch/virt-acpi-build.c index fced6c445a..073b6de75c 100644 --- a/hw/loongarch/virt-acpi-build.c +++ b/hw/loongarch/virt-acpi-build.c @@ -514,7 +514,7 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(machine); GArray *table_offsets; AcpiFadtData fadt_data; - unsigned facs, rsdt, dsdt; + unsigned facs, xsdt, dsdt; uint8_t *u; GArray *tables_blob = tables->table_data; @@ -600,17 +600,17 @@ static void acpi_build(AcpiBuildTables *tables, MachineState *machine) } /* RSDT is pointed to by RSDP */ - rsdt = tables_blob->len; - build_rsdt(tables_blob, tables->linker, table_offsets, + xsdt = tables_blob->len; + build_xsdt(tables_blob, tables->linker, table_offsets, lvms->oem_id, lvms->oem_table_id); /* RSDP is in FSEG memory, so allocate it separately */ { AcpiRsdpData rsdp_data = { - .revision = 0, + .revision = 2, .oem_id = lvms->oem_id, - .xsdt_tbl_offset = NULL, - .rsdt_tbl_offset = &rsdt, + .xsdt_tbl_offset = &xsdt, + .rsdt_tbl_offset = NULL, }; build_rsdp(tables->rsdp, tables->linker, &rsdp_data); } From 445c9c645befa759b95b21108447704ab328ae03 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 4 Mar 2025 14:59:17 +0800 Subject: [PATCH 0660/2760] hw/loongarch/virt: Allow user to customize OEM ID and OEM table ID On LoongArch virt machine, the default OEM ID and OEM table ID is "BOCHS " and "BXPC ". Here property x-oem-id and x-oem-table-id is added on virt machine to set customized OEM ID and OEM table ID. Signed-off-by: Bibo Mao Reviewed-by: Song Gao --- hw/loongarch/virt.c | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index 779544fada..7ad7fb68ff 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -773,6 +773,48 @@ static void virt_set_acpi(Object *obj, Visitor *v, const char *name, visit_type_OnOffAuto(v, name, &lvms->acpi, errp); } +static char *virt_get_oem_id(Object *obj, Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + + return g_strdup(lvms->oem_id); +} + +static void virt_set_oem_id(Object *obj, const char *value, Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + size_t len = strlen(value); + + if (len > 6) { + error_setg(errp, + "User specified oem-id value is bigger than 6 bytes in size"); + return; + } + + strncpy(lvms->oem_id, value, 6); +} + +static char *virt_get_oem_table_id(Object *obj, Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + + return g_strdup(lvms->oem_table_id); +} + +static void virt_set_oem_table_id(Object *obj, const char *value, + Error **errp) +{ + LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); + size_t len = strlen(value); + + if (len > 8) { + error_setg(errp, + "User specified oem-table-id value is bigger than 8 bytes in size"); + return; + } + strncpy(lvms->oem_table_id, value, 8); +} + static void virt_initfn(Object *obj) { LoongArchVirtMachineState *lvms = LOONGARCH_VIRT_MACHINE(obj); @@ -1177,6 +1219,22 @@ static void virt_class_init(ObjectClass *oc, const void *data) #ifdef CONFIG_TPM machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); #endif + object_class_property_add_str(oc, "x-oem-id", + virt_get_oem_id, + virt_set_oem_id); + object_class_property_set_description(oc, "x-oem-id", + "Override the default value of field OEMID " + "in ACPI table header." + "The string may be up to 6 bytes in size"); + + + object_class_property_add_str(oc, "x-oem-table-id", + virt_get_oem_table_id, + virt_set_oem_table_id); + object_class_property_set_description(oc, "x-oem-table-id", + "Override the default value of field OEM Table ID " + "in ACPI table header." + "The string may be up to 8 bytes in size"); } static const TypeInfo virt_machine_types[] = { From bb5101aadc1675790983c7911092dd9abeec4651 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:43 +0800 Subject: [PATCH 0661/2760] ui/dmabuf: extend QemuDmaBuf to support multi-plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mesa/radeonsi is going to support explicit modifier which may export a multi-plane texture. For example, texture with DCC enabled (a compressed format) has two planes, one with compressed data, the other with meta data for compression. v2: * change API qemu_dmabuf_get_fd/offset/stride to qemu_dmabuf_get_fds/offsets/strides. * change API qemu_dmabuf_dup_fd to qemu_dmabuf_dup_fds. * add an extra arg to these API for the length of the array. Reviewed-by: Marc-André Lureau Signed-off-by: Qiang Yu [ Fix style ] Signed-off-by: Marc-André Lureau Message-ID: <20250327025848.46962-2-yuq825@gmail.com> --- hw/display/vhost-user-gpu.c | 6 ++- hw/display/virtio-gpu-udmabuf.c | 6 ++- hw/vfio/display.c | 7 +-- include/ui/dmabuf.h | 20 ++++---- ui/dbus-listener.c | 10 ++-- ui/dmabuf.c | 82 +++++++++++++++++++++++---------- ui/egl-helpers.c | 4 +- ui/spice-display.c | 4 +- 8 files changed, 90 insertions(+), 49 deletions(-) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 06c4e7e190..a367daac82 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -249,6 +249,8 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) case VHOST_USER_GPU_DMABUF_SCANOUT: { VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout; int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr); + uint32_t offset = 0; + uint32_t stride = m->fd_stride; uint64_t modifier = 0; QemuDmaBuf *dmabuf; @@ -282,10 +284,10 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) } dmabuf = qemu_dmabuf_new(m->width, m->height, - m->fd_stride, 0, 0, + &offset, &stride, 0, 0, m->fd_width, m->fd_height, m->fd_drm_fourcc, modifier, - fd, false, m->fd_flags & + &fd, 1, false, m->fd_flags & VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP); dpy_gl_scanout_dmabuf(con, dmabuf); diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 0510577475..01b0024ead 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -176,16 +176,18 @@ static VGPUDMABuf struct virtio_gpu_rect *r) { VGPUDMABuf *dmabuf; + uint32_t offset = 0; if (res->dmabuf_fd < 0) { return NULL; } dmabuf = g_new0(VGPUDMABuf, 1); - dmabuf->buf = qemu_dmabuf_new(r->width, r->height, fb->stride, + dmabuf->buf = qemu_dmabuf_new(r->width, r->height, + &offset, &fb->stride, r->x, r->y, fb->width, fb->height, qemu_pixman_to_drm_format(fb->format), - 0, res->dmabuf_fd, true, false); + 0, &res->dmabuf_fd, 1, true, false); dmabuf->scanout_id = scanout_id; QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next); diff --git a/hw/vfio/display.c b/hw/vfio/display.c index f3e6581f15..9c6f5aa265 100644 --- a/hw/vfio/display.c +++ b/hw/vfio/display.c @@ -213,6 +213,7 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev, struct vfio_device_gfx_plane_info plane; VFIODMABuf *dmabuf; int fd, ret; + uint32_t offset = 0; memset(&plane, 0, sizeof(plane)); plane.argsz = sizeof(plane); @@ -245,10 +246,10 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev, dmabuf = g_new0(VFIODMABuf, 1); dmabuf->dmabuf_id = plane.dmabuf_id; - dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height, - plane.stride, 0, 0, plane.width, + dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height, &offset, + &plane.stride, 0, 0, plane.width, plane.height, plane.drm_format, - plane.drm_format_mod, fd, false, false); + plane.drm_format_mod, &fd, 1, false, false); if (plane_type == DRM_PLANE_TYPE_CURSOR) { vfio_display_update_cursor(dmabuf, &plane); diff --git a/include/ui/dmabuf.h b/include/ui/dmabuf.h index dc74ba895a..3decdca497 100644 --- a/include/ui/dmabuf.h +++ b/include/ui/dmabuf.h @@ -10,24 +10,29 @@ #ifndef DMABUF_H #define DMABUF_H +#define DMABUF_MAX_PLANES 4 + typedef struct QemuDmaBuf QemuDmaBuf; QemuDmaBuf *qemu_dmabuf_new(uint32_t width, uint32_t height, - uint32_t stride, uint32_t x, - uint32_t y, uint32_t backing_width, - uint32_t backing_height, uint32_t fourcc, - uint64_t modifier, int dmabuf_fd, + const uint32_t *offset, const uint32_t *stride, + uint32_t x, uint32_t y, + uint32_t backing_width, uint32_t backing_height, + uint32_t fourcc, uint64_t modifier, + const int32_t *dmabuf_fd, uint32_t num_planes, bool allow_fences, bool y0_top); void qemu_dmabuf_free(QemuDmaBuf *dmabuf); G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuDmaBuf, qemu_dmabuf_free); -int qemu_dmabuf_get_fd(QemuDmaBuf *dmabuf); -int qemu_dmabuf_dup_fd(QemuDmaBuf *dmabuf); +const int *qemu_dmabuf_get_fds(QemuDmaBuf *dmabuf, int *nfds); +void qemu_dmabuf_dup_fds(QemuDmaBuf *dmabuf, int *fds, int nfds); void qemu_dmabuf_close(QemuDmaBuf *dmabuf); uint32_t qemu_dmabuf_get_width(QemuDmaBuf *dmabuf); uint32_t qemu_dmabuf_get_height(QemuDmaBuf *dmabuf); -uint32_t qemu_dmabuf_get_stride(QemuDmaBuf *dmabuf); +const uint32_t *qemu_dmabuf_get_offsets(QemuDmaBuf *dmabuf, int *noffsets); +const uint32_t *qemu_dmabuf_get_strides(QemuDmaBuf *dmabuf, int *nstrides); +uint32_t qemu_dmabuf_get_num_planes(QemuDmaBuf *dmabuf); uint32_t qemu_dmabuf_get_fourcc(QemuDmaBuf *dmabuf); uint64_t qemu_dmabuf_get_modifier(QemuDmaBuf *dmabuf); uint32_t qemu_dmabuf_get_texture(QemuDmaBuf *dmabuf); @@ -44,6 +49,5 @@ void qemu_dmabuf_set_texture(QemuDmaBuf *dmabuf, uint32_t texture); void qemu_dmabuf_set_fence_fd(QemuDmaBuf *dmabuf, int32_t fence_fd); void qemu_dmabuf_set_sync(QemuDmaBuf *dmabuf, void *sync); void qemu_dmabuf_set_draw_submitted(QemuDmaBuf *dmabuf, bool draw_submitted); -void qemu_dmabuf_set_fd(QemuDmaBuf *dmabuf, int32_t fd); #endif diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 51244c9240..65373d519c 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -299,7 +299,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, uint64_t modifier; bool y0_top; - fd = qemu_dmabuf_get_fd(dmabuf); + fd = qemu_dmabuf_get_fds(dmabuf, NULL)[0]; fd_list = g_unix_fd_list_new(); if (g_unix_fd_list_append(fd_list, fd, &err) != 0) { error_report("Failed to setup dmabuf fdlist: %s", err->message); @@ -310,7 +310,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl, width = qemu_dmabuf_get_width(dmabuf); height = qemu_dmabuf_get_height(dmabuf); - stride = qemu_dmabuf_get_stride(dmabuf); + stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; fourcc = qemu_dmabuf_get_fourcc(dmabuf); modifier = qemu_dmabuf_get_modifier(dmabuf); y0_top = qemu_dmabuf_get_y0_top(dmabuf); @@ -505,7 +505,7 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl, #ifdef CONFIG_GBM g_autoptr(QemuDmaBuf) dmabuf = NULL; int fd; - uint32_t stride, fourcc; + uint32_t offset = 0, stride, fourcc; uint64_t modifier; assert(tex_id); @@ -515,8 +515,8 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl, error_report("%s: failed to get fd for texture", __func__); return; } - dmabuf = qemu_dmabuf_new(w, h, stride, x, y, backing_width, - backing_height, fourcc, modifier, fd, + dmabuf = qemu_dmabuf_new(w, h, &offset, &stride, x, y, backing_width, + backing_height, fourcc, modifier, &fd, 1, false, backing_y_0_top); dbus_scanout_dmabuf(dcl, dmabuf); diff --git a/ui/dmabuf.c b/ui/dmabuf.c index df7a09703f..7433a268f0 100644 --- a/ui/dmabuf.c +++ b/ui/dmabuf.c @@ -11,10 +11,12 @@ #include "ui/dmabuf.h" struct QemuDmaBuf { - int fd; + int fd[DMABUF_MAX_PLANES]; uint32_t width; uint32_t height; - uint32_t stride; + uint32_t offset[DMABUF_MAX_PLANES]; + uint32_t stride[DMABUF_MAX_PLANES]; + uint32_t num_planes; uint32_t fourcc; uint64_t modifier; uint32_t texture; @@ -30,28 +32,33 @@ struct QemuDmaBuf { }; QemuDmaBuf *qemu_dmabuf_new(uint32_t width, uint32_t height, - uint32_t stride, uint32_t x, - uint32_t y, uint32_t backing_width, - uint32_t backing_height, uint32_t fourcc, - uint64_t modifier, int32_t dmabuf_fd, + const uint32_t *offset, const uint32_t *stride, + uint32_t x, uint32_t y, + uint32_t backing_width, uint32_t backing_height, + uint32_t fourcc, uint64_t modifier, + const int32_t *dmabuf_fd, uint32_t num_planes, bool allow_fences, bool y0_top) { QemuDmaBuf *dmabuf; + assert(num_planes > 0 && num_planes <= DMABUF_MAX_PLANES); + dmabuf = g_new0(QemuDmaBuf, 1); dmabuf->width = width; dmabuf->height = height; - dmabuf->stride = stride; + memcpy(dmabuf->offset, offset, num_planes * sizeof(*offset)); + memcpy(dmabuf->stride, stride, num_planes * sizeof(*stride)); dmabuf->x = x; dmabuf->y = y; dmabuf->backing_width = backing_width; dmabuf->backing_height = backing_height; dmabuf->fourcc = fourcc; dmabuf->modifier = modifier; - dmabuf->fd = dmabuf_fd; + memcpy(dmabuf->fd, dmabuf_fd, num_planes * sizeof(*dmabuf_fd)); dmabuf->allow_fences = allow_fences; dmabuf->y0_top = y0_top; dmabuf->fence_fd = -1; + dmabuf->num_planes = num_planes; return dmabuf; } @@ -65,31 +72,40 @@ void qemu_dmabuf_free(QemuDmaBuf *dmabuf) g_free(dmabuf); } -int qemu_dmabuf_get_fd(QemuDmaBuf *dmabuf) +const int *qemu_dmabuf_get_fds(QemuDmaBuf *dmabuf, int *nfds) { assert(dmabuf != NULL); + if (nfds) { + *nfds = ARRAY_SIZE(dmabuf->fd); + } + return dmabuf->fd; } -int qemu_dmabuf_dup_fd(QemuDmaBuf *dmabuf) +void qemu_dmabuf_dup_fds(QemuDmaBuf *dmabuf, int *fds, int nfds) { - assert(dmabuf != NULL); + int i; - if (dmabuf->fd >= 0) { - return dup(dmabuf->fd); - } else { - return -1; + assert(dmabuf != NULL); + assert(nfds >= dmabuf->num_planes); + + for (i = 0; i < dmabuf->num_planes; i++) { + fds[i] = dmabuf->fd[i] >= 0 ? dup(dmabuf->fd[i]) : -1; } } void qemu_dmabuf_close(QemuDmaBuf *dmabuf) { + int i; + assert(dmabuf != NULL); - if (dmabuf->fd >= 0) { - close(dmabuf->fd); - dmabuf->fd = -1; + for (i = 0; i < dmabuf->num_planes; i++) { + if (dmabuf->fd[i] >= 0) { + close(dmabuf->fd[i]); + dmabuf->fd[i] = -1; + } } } @@ -107,13 +123,35 @@ uint32_t qemu_dmabuf_get_height(QemuDmaBuf *dmabuf) return dmabuf->height; } -uint32_t qemu_dmabuf_get_stride(QemuDmaBuf *dmabuf) +const uint32_t *qemu_dmabuf_get_offsets(QemuDmaBuf *dmabuf, int *noffsets) { assert(dmabuf != NULL); + if (noffsets) { + *noffsets = ARRAY_SIZE(dmabuf->offset); + } + + return dmabuf->offset; +} + +const uint32_t *qemu_dmabuf_get_strides(QemuDmaBuf *dmabuf, int *nstrides) +{ + assert(dmabuf != NULL); + + if (nstrides) { + *nstrides = ARRAY_SIZE(dmabuf->stride); + } + return dmabuf->stride; } +uint32_t qemu_dmabuf_get_num_planes(QemuDmaBuf *dmabuf) +{ + assert(dmabuf != NULL); + + return dmabuf->num_planes; +} + uint32_t qemu_dmabuf_get_fourcc(QemuDmaBuf *dmabuf) { assert(dmabuf != NULL); @@ -221,9 +259,3 @@ void qemu_dmabuf_set_draw_submitted(QemuDmaBuf *dmabuf, bool draw_submitted) assert(dmabuf != NULL); dmabuf->draw_submitted = draw_submitted; } - -void qemu_dmabuf_set_fd(QemuDmaBuf *dmabuf, int32_t fd) -{ - assert(dmabuf != NULL); - dmabuf->fd = fd; -} diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index d591159480..d194d004b7 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -323,9 +323,9 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf); attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT; - attrs[i++] = qemu_dmabuf_get_fd(dmabuf); + attrs[i++] = qemu_dmabuf_get_fds(dmabuf, NULL)[0]; attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; - attrs[i++] = qemu_dmabuf_get_stride(dmabuf); + attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attrs[i++] = 0; #ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT diff --git a/ui/spice-display.c b/ui/spice-display.c index c794ae0649..40547edb5e 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -1075,10 +1075,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, stride, fourcc, false); } } else { - stride = qemu_dmabuf_get_stride(dmabuf); + stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; fourcc = qemu_dmabuf_get_fourcc(dmabuf); y_0_top = qemu_dmabuf_get_y0_top(dmabuf); - fd = qemu_dmabuf_dup_fd(dmabuf); + qemu_dmabuf_dup_fds(dmabuf, &fd, 1); trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, width, height); /* note: spice server will close the fd, so hand over a dup */ From 806c861dc6b92019765aed09a016db460cd345fb Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:44 +0800 Subject: [PATCH 0662/2760] ui/egl: require EGL_EXT_image_dma_buf_import_modifiers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's used already, just check it explicitly. Reviewed-by: Marc-André Lureau Signed-off-by: Qiang Yu Message-ID: <20250327025848.46962-3-yuq825@gmail.com> --- ui/egl-helpers.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index d194d004b7..432863d702 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -257,6 +257,11 @@ int egl_rendernode_init(const char *rendernode, DisplayGLMode mode) error_report("egl: EGL_MESA_image_dma_buf_export not supported"); goto err; } + if (!epoxy_has_egl_extension(qemu_egl_display, + "EGL_EXT_image_dma_buf_import_modifiers")) { + error_report("egl: EGL_EXT_image_dma_buf_import_modifiers not supported"); + goto err; + } qemu_egl_rn_ctx = qemu_egl_init_ctx(); if (!qemu_egl_rn_ctx) { @@ -308,7 +313,7 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) EGLImageKHR image = EGL_NO_IMAGE_KHR; EGLint attrs[64]; int i = 0; - uint64_t modifier; + uint64_t modifier = qemu_dmabuf_get_modifier(dmabuf); uint32_t texture = qemu_dmabuf_get_texture(dmabuf); if (texture != 0) { @@ -328,15 +333,12 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attrs[i++] = 0; -#ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT - modifier = qemu_dmabuf_get_modifier(dmabuf); if (modifier) { attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; attrs[i++] = (modifier >> 0) & 0xffffffff; attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; attrs[i++] = (modifier >> 32) & 0xffffffff; } -#endif attrs[i++] = EGL_NONE; image = eglCreateImageKHR(qemu_egl_display, From ac70568902c3fb77516d93b169cddd0bcaabfb4e Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:45 +0800 Subject: [PATCH 0663/2760] ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0 is used as DRM_FORMAT_MOD_LINEAR already. Reviewed-by: Marc-André Lureau Signed-off-by: Qiang Yu Message-ID: <20250327025848.46962-4-yuq825@gmail.com> --- hw/display/vhost-user-gpu.c | 3 ++- hw/display/virtio-gpu-udmabuf.c | 4 +++- ui/egl-helpers.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index a367daac82..43d4c08a2e 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -18,6 +18,7 @@ #include "chardev/char-fe.h" #include "qapi/error.h" #include "migration/blocker.h" +#include "standard-headers/drm/drm_fourcc.h" typedef enum VhostUserGpuRequest { VHOST_USER_GPU_NONE = 0, @@ -251,7 +252,7 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg) int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr); uint32_t offset = 0; uint32_t stride = m->fd_stride; - uint64_t modifier = 0; + uint64_t modifier = DRM_FORMAT_MOD_INVALID; QemuDmaBuf *dmabuf; if (m->scanout_id >= g->parent_obj.conf.max_outputs) { diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c index 01b0024ead..d804f321aa 100644 --- a/hw/display/virtio-gpu-udmabuf.c +++ b/hw/display/virtio-gpu-udmabuf.c @@ -25,6 +25,7 @@ #include #include "qemu/memfd.h" #include "standard-headers/linux/udmabuf.h" +#include "standard-headers/drm/drm_fourcc.h" static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res) { @@ -187,7 +188,8 @@ static VGPUDMABuf &offset, &fb->stride, r->x, r->y, fb->width, fb->height, qemu_pixman_to_drm_format(fb->format), - 0, &res->dmabuf_fd, 1, true, false); + DRM_FORMAT_MOD_INVALID, &res->dmabuf_fd, + 1, true, false); dmabuf->scanout_id = scanout_id; QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next); diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 432863d702..8c0e394d2b 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -23,6 +23,7 @@ #include "system/system.h" #include "qapi/error.h" #include "trace.h" +#include "standard-headers/drm/drm_fourcc.h" EGLDisplay *qemu_egl_display; EGLConfig qemu_egl_config; @@ -333,7 +334,7 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; attrs[i++] = 0; - if (modifier) { + if (modifier != DRM_FORMAT_MOD_INVALID) { attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; attrs[i++] = (modifier >> 0) & 0xffffffff; attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; From 0e15d0b92700000db66e19c68ad2d50aace860d8 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:46 +0800 Subject: [PATCH 0664/2760] ui/egl: support multi-plane dmabuf when egl export/import MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: * use new dmabuf API and check length Reviewed-by: Marc-André Lureau Signed-off-by: Qiang Yu [ Fix style ] Signed-off-by: Marc-André Lureau Message-ID: <20250327025848.46962-5-yuq825@gmail.com> --- include/ui/egl-helpers.h | 5 ++- ui/dbus-listener.c | 19 +++++---- ui/egl-helpers.c | 92 ++++++++++++++++++++++++++++++---------- ui/spice-display.c | 60 +++++++++++++++++--------- 4 files changed, 124 insertions(+), 52 deletions(-) diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index 4b8c0d2281..fb80e15142 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -46,8 +46,9 @@ extern int qemu_egl_rn_fd; extern struct gbm_device *qemu_egl_rn_gbm_dev; int egl_rendernode_init(const char *rendernode, DisplayGLMode mode); -int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc, - EGLuint64KHR *modifier); +bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset, + EGLint *stride, EGLint *fourcc, int *num_planes, + EGLuint64KHR *modifier); void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf); void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf); diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 65373d519c..90147972cd 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -504,19 +504,22 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl, backing_width, backing_height, x, y, w, h); #ifdef CONFIG_GBM g_autoptr(QemuDmaBuf) dmabuf = NULL; - int fd; - uint32_t offset = 0, stride, fourcc; + int fd[DMABUF_MAX_PLANES], num_planes; + uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc; uint64_t modifier; assert(tex_id); - fd = egl_get_fd_for_texture(tex_id, (EGLint *)&stride, (EGLint *)&fourcc, - &modifier); - if (fd < 0) { - error_report("%s: failed to get fd for texture", __func__); + if (!egl_dmabuf_export_texture(tex_id, fd, (EGLint *)offset, (EGLint *)stride, + (EGLint *)&fourcc, &num_planes, &modifier)) { + error_report("%s: failed to export dmabuf for texture", __func__); return; } - dmabuf = qemu_dmabuf_new(w, h, &offset, &stride, x, y, backing_width, - backing_height, fourcc, modifier, &fd, 1, + if (num_planes > 1) { + error_report("%s: does not support multi-plane dmabuf", __func__); + return; + } + dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width, + backing_height, fourcc, modifier, fd, num_planes, false, backing_y_0_top); dbus_scanout_dmabuf(dcl, dmabuf); diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 8c0e394d2b..9cda2bbbee 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -283,44 +283,86 @@ err: return -1; } -int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc, - EGLuint64KHR *modifier) +bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset, + EGLint *stride, EGLint *fourcc, int *num_planes, + EGLuint64KHR *modifier) { EGLImageKHR image; - EGLint num_planes, fd; + EGLuint64KHR modifiers[DMABUF_MAX_PLANES]; image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(), EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)(unsigned long)tex_id, NULL); if (!image) { - return -1; + return false; } eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc, - &num_planes, modifier); - if (num_planes != 1) { - eglDestroyImageKHR(qemu_egl_display, image); - return -1; - } - eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL); + num_planes, modifiers); + eglExportDMABUFImageMESA(qemu_egl_display, image, fd, stride, offset); eglDestroyImageKHR(qemu_egl_display, image); - return fd; + /* Only first modifier matters. */ + if (modifier) { + *modifier = modifiers[0]; + } + + return true; } void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) { EGLImageKHR image = EGL_NO_IMAGE_KHR; EGLint attrs[64]; - int i = 0; + int i = 0, j; uint64_t modifier = qemu_dmabuf_get_modifier(dmabuf); uint32_t texture = qemu_dmabuf_get_texture(dmabuf); + int nfds, noffsets, nstrides; + const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds); + const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets); + const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides); + uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf); + + EGLint fd_attrs[] = { + EGL_DMA_BUF_PLANE0_FD_EXT, + EGL_DMA_BUF_PLANE1_FD_EXT, + EGL_DMA_BUF_PLANE2_FD_EXT, + EGL_DMA_BUF_PLANE3_FD_EXT, + }; + EGLint offset_attrs[] = { + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + EGL_DMA_BUF_PLANE1_OFFSET_EXT, + EGL_DMA_BUF_PLANE2_OFFSET_EXT, + EGL_DMA_BUF_PLANE3_OFFSET_EXT, + }; + EGLint stride_attrs[] = { + EGL_DMA_BUF_PLANE0_PITCH_EXT, + EGL_DMA_BUF_PLANE1_PITCH_EXT, + EGL_DMA_BUF_PLANE2_PITCH_EXT, + EGL_DMA_BUF_PLANE3_PITCH_EXT, + }; + EGLint modifier_lo_attrs[] = { + EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT, + }; + EGLint modifier_hi_attrs[] = { + EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, + EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT, + EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT, + EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT, + }; if (texture != 0) { return; } + assert(nfds >= num_planes); + assert(noffsets >= num_planes); + assert(nstrides >= num_planes); + attrs[i++] = EGL_WIDTH; attrs[i++] = qemu_dmabuf_get_backing_width(dmabuf); attrs[i++] = EGL_HEIGHT; @@ -328,18 +370,22 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf) attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT; attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf); - attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT; - attrs[i++] = qemu_dmabuf_get_fds(dmabuf, NULL)[0]; - attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; - attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; - attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT; - attrs[i++] = 0; - if (modifier != DRM_FORMAT_MOD_INVALID) { - attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; - attrs[i++] = (modifier >> 0) & 0xffffffff; - attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; - attrs[i++] = (modifier >> 32) & 0xffffffff; + for (j = 0; j < num_planes; j++) { + attrs[i++] = fd_attrs[j]; + /* fd[1-3] may be -1 if using a joint buffer for all planes */ + attrs[i++] = fds[j] >= 0 ? fds[j] : fds[0]; + attrs[i++] = stride_attrs[j]; + attrs[i++] = strides[j]; + attrs[i++] = offset_attrs[j]; + attrs[i++] = offsets[j]; + if (modifier != DRM_FORMAT_MOD_INVALID) { + attrs[i++] = modifier_lo_attrs[j]; + attrs[i++] = (modifier >> 0) & 0xffffffff; + attrs[i++] = modifier_hi_attrs[j]; + attrs[i++] = (modifier >> 32) & 0xffffffff; + } } + attrs[i++] = EGL_NONE; image = eglCreateImageKHR(qemu_egl_display, diff --git a/ui/spice-display.c b/ui/spice-display.c index 40547edb5e..a9fee87a72 100644 --- a/ui/spice-display.c +++ b/ui/spice-display.c @@ -876,19 +876,24 @@ static void spice_gl_switch(DisplayChangeListener *dcl, struct DisplaySurface *new_surface) { SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - EGLint stride, fourcc; - int fd; if (ssd->ds) { surface_gl_destroy_texture(ssd->gls, ssd->ds); } ssd->ds = new_surface; if (ssd->ds) { + uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES]; + int fd[DMABUF_MAX_PLANES], num_planes, fourcc; + surface_gl_create_texture(ssd->gls, ssd->ds); - fd = egl_get_fd_for_texture(ssd->ds->texture, - &stride, &fourcc, - NULL); - if (fd < 0) { + if (!egl_dmabuf_export_texture(ssd->ds->texture, fd, (EGLint *)offset, + (EGLint *)stride, &fourcc, &num_planes, NULL)) { + surface_gl_destroy_texture(ssd->gls, ssd->ds); + return; + } + + if (num_planes > 1) { + fprintf(stderr, "%s: does not support multi-plane texture\n", __func__); surface_gl_destroy_texture(ssd->gls, ssd->ds); return; } @@ -899,10 +904,10 @@ static void spice_gl_switch(DisplayChangeListener *dcl, fourcc); /* note: spice server will close the fd */ - spice_qxl_gl_scanout(&ssd->qxl, fd, + spice_qxl_gl_scanout(&ssd->qxl, fd[0], surface_width(ssd->ds), surface_height(ssd->ds), - stride, fourcc, false); + stride[0], fourcc, false); ssd->have_surface = true; ssd->have_scanout = false; @@ -941,20 +946,24 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl, void *d3d_tex2d) { SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl); - EGLint stride = 0, fourcc = 0; - int fd = -1; + EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0; + int fd[DMABUF_MAX_PLANES], num_planes; assert(tex_id); - fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc, NULL); - if (fd < 0) { - fprintf(stderr, "%s: failed to get fd for texture\n", __func__); + if (!egl_dmabuf_export_texture(tex_id, fd, offset, stride, &fourcc, + &num_planes, NULL)) { + fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__); + return; + } + if (num_planes > 1) { + fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__); return; } trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc); /* note: spice server will close the fd */ - spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height, - stride, fourcc, y_0_top); + spice_qxl_gl_scanout(&ssd->qxl, fd[0], backing_width, backing_height, + stride[0], fourcc, y_0_top); qemu_spice_gl_monitor_config(ssd, x, y, w, h); ssd->have_surface = false; ssd->have_scanout = true; @@ -1064,15 +1073,28 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl, /* dest framebuffer */ if (ssd->blit_fb.width != width || ssd->blit_fb.height != height) { + int fds[DMABUF_MAX_PLANES], num_planes; + uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES]; + trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, width, height); egl_fb_destroy(&ssd->blit_fb); egl_fb_setup_new_tex(&ssd->blit_fb, width, height); - fd = egl_get_fd_for_texture(ssd->blit_fb.texture, - &stride, &fourcc, NULL); - spice_qxl_gl_scanout(&ssd->qxl, fd, width, height, - stride, fourcc, false); + if (!egl_dmabuf_export_texture(ssd->blit_fb.texture, fds, + (EGLint *)offsets, (EGLint *)strides, + &fourcc, &num_planes, NULL)) { + fprintf(stderr, + "%s: failed to export dmabuf for texture\n", __func__); + return; + } + if (num_planes > 1) { + fprintf(stderr, + "%s: does not support multi-plane dmabuf\n", __func__); + return; + } + spice_qxl_gl_scanout(&ssd->qxl, fds[0], width, height, + strides[0], fourcc, false); } } else { stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0]; From 10aaad0edc7ff827f91583cd537b6f11b77e6e79 Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:47 +0800 Subject: [PATCH 0665/2760] ui/dbus: change dbus ScanoutDMABUF interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To handle multi plane. v3: * rename interface * add x/y/backing_width/backing_height arg v2: * use new dmabuf API and check length Reviewed-by: Marc-André Lureau Signed-off-by: Qiang Yu Message-ID: <20250327025848.46962-6-yuq825@gmail.com> [ Fix style ] Signed-off-by: Marc-André Lureau --- ui/dbus-display1.xml | 45 +++++++++++++++++ ui/dbus-listener.c | 114 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 152 insertions(+), 7 deletions(-) diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index 72deefa455..4a41a7e0f3 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -614,6 +614,51 @@ + + + + + + + + + + + + + + + + + + + + + + loongarch_pch_pic_ops loongarch_pch_pic_low_readw --> loongarch_pch_pic_read loongarch_pch_pic_low_writew --> loongarch_pch_pic_write Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-3-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 26 +++++++------------------- include/hw/intc/loongarch_pic_common.h | 2 +- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index c06ef0df3f..076b984d93 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -230,18 +230,6 @@ static void loongarch_pch_pic_write(void *opaque, hwaddr addr, } } -static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, - unsigned size) -{ - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - loongarch_pch_pic_write(opaque, addr, value, size); -} - static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, unsigned size) { @@ -270,9 +258,9 @@ static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, loongarch_pch_pic_write(opaque, addr, data, size); } -static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { - .read = loongarch_pch_pic_low_readw, - .write = loongarch_pch_pic_low_writew, +static const MemoryRegionOps loongarch_pch_pic_ops = { + .read = loongarch_pch_pic_read, + .write = loongarch_pch_pic_write, .valid = { .min_access_size = 4, .max_access_size = 8, @@ -336,15 +324,15 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) qdev_init_gpio_out(dev, s->parent_irq, s->irq_num); qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); - memory_region_init_io(&s->iomem32_low, OBJECT(dev), - &loongarch_pch_pic_reg32_low_ops, - s, PCH_PIC_NAME(.reg32_part1), 0x100); + memory_region_init_io(&s->iomem, OBJECT(dev), + &loongarch_pch_pic_ops, + s, TYPE_LOONGARCH_PIC, 0x100); memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops, s, PCH_PIC_NAME(.reg8), 0x2a0); memory_region_init_io(&s->iomem32_high, OBJECT(dev), &loongarch_pch_pic_reg32_high_ops, s, PCH_PIC_NAME(.reg32_part2), 0xc60); - sysbus_init_mmio(sbd, &s->iomem32_low); + sysbus_init_mmio(sbd, &s->iomem); sysbus_init_mmio(sbd, &s->iomem8); sysbus_init_mmio(sbd, &s->iomem32_high); diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index 7a9a2bdd46..dc03056227 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -65,7 +65,7 @@ struct LoongArchPICCommonState { uint8_t route_entry[64]; /* 0x100 - 0x138 */ uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */ - MemoryRegion iomem32_low; + MemoryRegion iomem; MemoryRegion iomem32_high; MemoryRegion iomem8; unsigned int irq_num; From 2493ff01dc7c9b06a0579f6e66c3df69da4d5d23 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:53 +0800 Subject: [PATCH 0853/2760] hw/intc/loongarch_pch: Set flexible memory access size with iomem region The original iomem region only supports 4 bytes access size, set it ok with 1/2/4/8 bytes. Also unaligned memory access is not supported. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-4-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index 076b984d93..e9126a0c1f 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -262,12 +262,19 @@ static const MemoryRegionOps loongarch_pch_pic_ops = { .read = loongarch_pch_pic_read, .write = loongarch_pch_pic_write, .valid = { - .min_access_size = 4, + .min_access_size = 1, .max_access_size = 8, + /* + * PCH PIC device would not work correctly if the guest was doing + * unaligned access. This might not be a limitation on the real + * device but in practice there is no reason for a guest to access + * this device unaligned. + */ + .unaligned = false, }, .impl = { - .min_access_size = 4, - .max_access_size = 4, + .min_access_size = 1, + .max_access_size = 8, }, .endianness = DEVICE_LITTLE_ENDIAN, }; From f4881c67ba8a852687566610949d8e9ab0542a31 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Wed, 7 May 2025 10:37:54 +0800 Subject: [PATCH 0854/2760] hw/intc/loongarch_pch: Merge three memory region into one Since memory region iomem supports memory access size with 1/2/4/8, it can be used for memory region iomem8 and iomem32_high. Now remove memory region iomem8 and iomem32_high, merge them into iomem together. Signed-off-by: Bibo Mao Reviewed-by: Song Gao Message-Id: <20250507023754.1877445-5-maobibo@loongson.cn> Signed-off-by: Song Gao --- hw/intc/loongarch_pch_pic.c | 66 +------------------------- hw/loongarch/virt.c | 6 --- include/hw/intc/loongarch_pic_common.h | 2 - 3 files changed, 1 insertion(+), 73 deletions(-) diff --git a/hw/intc/loongarch_pch_pic.c b/hw/intc/loongarch_pch_pic.c index e9126a0c1f..cbba2fc284 100644 --- a/hw/intc/loongarch_pch_pic.c +++ b/hw/intc/loongarch_pch_pic.c @@ -230,34 +230,6 @@ static void loongarch_pch_pic_write(void *opaque, hwaddr addr, } } -static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, - unsigned size) -{ - addr += PCH_PIC_INT_STATUS; - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, - uint64_t value, unsigned size) -{ - addr += PCH_PIC_INT_STATUS; - loongarch_pch_pic_write(opaque, addr, value, size); -} - -static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, - unsigned size) -{ - addr += PCH_PIC_ROUTE_ENTRY; - return loongarch_pch_pic_read(opaque, addr, size); -} - -static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - addr += PCH_PIC_ROUTE_ENTRY; - loongarch_pch_pic_write(opaque, addr, data, size); -} - static const MemoryRegionOps loongarch_pch_pic_ops = { .read = loongarch_pch_pic_read, .write = loongarch_pch_pic_write, @@ -279,34 +251,6 @@ static const MemoryRegionOps loongarch_pch_pic_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { - .read = loongarch_pch_pic_high_readw, - .write = loongarch_pch_pic_high_writew, - .valid = { - .min_access_size = 4, - .max_access_size = 8, - }, - .impl = { - .min_access_size = 4, - .max_access_size = 4, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { - .read = loongarch_pch_pic_readb, - .write = loongarch_pch_pic_writeb, - .valid = { - .min_access_size = 1, - .max_access_size = 1, - }, - .impl = { - .min_access_size = 1, - .max_access_size = 1, - }, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - static void loongarch_pic_reset_hold(Object *obj, ResetType type) { LoongarchPICClass *lpc = LOONGARCH_PIC_GET_CLASS(obj); @@ -333,16 +277,8 @@ static void loongarch_pic_realize(DeviceState *dev, Error **errp) qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); memory_region_init_io(&s->iomem, OBJECT(dev), &loongarch_pch_pic_ops, - s, TYPE_LOONGARCH_PIC, 0x100); - memory_region_init_io(&s->iomem8, OBJECT(dev), &loongarch_pch_pic_reg8_ops, - s, PCH_PIC_NAME(.reg8), 0x2a0); - memory_region_init_io(&s->iomem32_high, OBJECT(dev), - &loongarch_pch_pic_reg32_high_ops, - s, PCH_PIC_NAME(.reg32_part2), 0xc60); + s, TYPE_LOONGARCH_PIC, VIRT_PCH_REG_SIZE); sysbus_init_mmio(sbd, &s->iomem); - sysbus_init_mmio(sbd, &s->iomem8); - sysbus_init_mmio(sbd, &s->iomem32_high); - } static void loongarch_pic_class_init(ObjectClass *klass, const void *data) diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c index ebcef0a92b..1b504047db 100644 --- a/hw/loongarch/virt.c +++ b/hw/loongarch/virt.c @@ -429,12 +429,6 @@ static void virt_irq_init(LoongArchVirtMachineState *lvms) sysbus_realize_and_unref(d, &error_fatal); memory_region_add_subregion(get_system_memory(), VIRT_IOAPIC_REG_BASE, sysbus_mmio_get_region(d, 0)); - memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_ROUTE_ENTRY, - sysbus_mmio_get_region(d, 1)); - memory_region_add_subregion(get_system_memory(), - VIRT_IOAPIC_REG_BASE + PCH_PIC_INT_STATUS, - sysbus_mmio_get_region(d, 2)); /* Connect pch_pic irqs to extioi */ for (i = 0; i < num; i++) { diff --git a/include/hw/intc/loongarch_pic_common.h b/include/hw/intc/loongarch_pic_common.h index dc03056227..9349a055d0 100644 --- a/include/hw/intc/loongarch_pic_common.h +++ b/include/hw/intc/loongarch_pic_common.h @@ -66,8 +66,6 @@ struct LoongArchPICCommonState { uint8_t htmsi_vector[64]; /* 0x200 - 0x238 */ MemoryRegion iomem; - MemoryRegion iomem32_high; - MemoryRegion iomem8; unsigned int irq_num; }; From a3d5f62254a48b7c260d5aa7bd8e8467a0bb8ea3 Mon Sep 17 00:00:00 2001 From: Xianglai Li Date: Tue, 6 May 2025 16:09:46 +0800 Subject: [PATCH 0855/2760] hw/loongarch/boot: Adjust the loading position of the initrd When only the -kernel parameter is used to load the elf kernel, the initrd is loaded in the ram. If the initrd size is too large, the loading fails, resulting in a VM startup failure. This patch first loads initrd near the kernel. When the nearby memory space of the kernel is insufficient, it tries to load it to the starting position of high memory. If there is still not enough, qemu will report an error and ask the user to increase the memory space for the virtual machine to boot. Signed-off-by: Xianglai Li Message-Id: <20250506080946.817092-1-lixianglai@loongson.cn> Signed-off-by: Song Gao --- hw/loongarch/boot.c | 52 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/hw/loongarch/boot.c b/hw/loongarch/boot.c index 0324d6adcb..9b6292eaa1 100644 --- a/hw/loongarch/boot.c +++ b/hw/loongarch/boot.c @@ -235,6 +235,45 @@ static int64_t load_loongarch_linux_image(const char *filename, return size; } +static ram_addr_t alloc_initrd_memory(struct loongarch_boot_info *info, + uint64_t advice_start, ssize_t rd_size) +{ + hwaddr base, ram_size, gap, low_end; + ram_addr_t initrd_end, initrd_start; + + base = VIRT_LOWMEM_BASE; + gap = VIRT_LOWMEM_SIZE; + initrd_start = advice_start; + initrd_end = initrd_start + rd_size; + + ram_size = info->ram_size; + low_end = base + MIN(ram_size, gap); + if (initrd_end <= low_end) { + return initrd_start; + } + + if (ram_size <= gap) { + error_report("The low memory too small for initial ram disk '%s'," + "You need to expand the ram", + info->initrd_filename); + exit(1); + } + + /* + * Try to load initrd in the high memory + */ + ram_size -= gap; + initrd_start = VIRT_HIGHMEM_BASE; + if (rd_size <= ram_size) { + return initrd_start; + } + + error_report("The high memory too small for initial ram disk '%s'," + "You need to expand the ram", + info->initrd_filename); + exit(1); +} + static int64_t load_kernel_info(struct loongarch_boot_info *info) { uint64_t kernel_entry, kernel_low, kernel_high; @@ -263,15 +302,10 @@ static int64_t load_kernel_info(struct loongarch_boot_info *info) initrd_size = get_image_size(info->initrd_filename); if (initrd_size > 0) { initrd_offset = ROUND_UP(kernel_high + 4 * kernel_size, 64 * KiB); - - if (initrd_offset + initrd_size > info->ram_size) { - error_report("memory too small for initial ram disk '%s'", - info->initrd_filename); - exit(1); - } - - initrd_size = load_image_targphys(info->initrd_filename, initrd_offset, - info->ram_size - initrd_offset); + initrd_offset = alloc_initrd_memory(info, initrd_offset, + initrd_size); + initrd_size = load_image_targphys(info->initrd_filename, + initrd_offset, initrd_size); } if (initrd_size == (target_ulong)-1) { From 98cbac128f1c38fa62becf5b89bc662c9218a780 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 5 Mar 2025 09:24:52 +0000 Subject: [PATCH 0856/2760] hw/cxl: Support aborting background commands As of 3.1 spec, background commands can be canceled with a new abort command. Implement the support, which is advertised in the CEL. No ad-hoc context undoing is necessary as all the command logic of the running bg command is done upon completion. Arbitrarily, the on-going background cmd will not be aborted if already at least 85% done; A mutex is introduced to stabilize mbox request cancel command vs the timer callback being fired scenarios (as well as reading the mbox registers). While some operations under critical regions may be unnecessary (irq notifying, cmd callbacks), this is not a path where performance is important, so simplicity is preferred. Tested-by: Ajay Joshi Reviewed-by: Ajay Joshi Signed-off-by: Davidlohr Bueso Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-2-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-device-utils.c | 14 ++++--- hw/cxl/cxl-mailbox-utils.c | 72 ++++++++++++++++++++++++++++++++---- hw/mem/cxl_type3.c | 8 +++- include/hw/cxl/cxl_device.h | 4 ++ include/hw/cxl/cxl_mailbox.h | 1 + 5 files changed, 86 insertions(+), 13 deletions(-) diff --git a/hw/cxl/cxl-device-utils.c b/hw/cxl/cxl-device-utils.c index 52ad1e4c3f..e150d74457 100644 --- a/hw/cxl/cxl-device-utils.c +++ b/hw/cxl/cxl-device-utils.c @@ -95,11 +95,15 @@ static uint64_t mailbox_reg_read(void *opaque, hwaddr offset, unsigned size) } if (offset == A_CXL_DEV_MAILBOX_STS) { uint64_t status_reg = cxl_dstate->mbox_reg_state64[offset / size]; - if (cci->bg.complete_pct) { - status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP, - 0); - cxl_dstate->mbox_reg_state64[offset / size] = status_reg; - } + int bgop; + + qemu_mutex_lock(&cci->bg.lock); + bgop = !(cci->bg.complete_pct == 100 || cci->bg.aborted); + + status_reg = FIELD_DP64(status_reg, CXL_DEV_MAILBOX_STS, BG_OP, + bgop); + cxl_dstate->mbox_reg_state64[offset / size] = status_reg; + qemu_mutex_unlock(&cci->bg.lock); } return cxl_dstate->mbox_reg_state64[offset / size]; default: diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 516c01d840..4401f446d9 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -56,6 +56,7 @@ enum { INFOSTAT = 0x00, #define IS_IDENTIFY 0x1 #define BACKGROUND_OPERATION_STATUS 0x2 + #define BACKGROUND_OPERATION_ABORT 0x5 EVENTS = 0x01, #define GET_RECORDS 0x0 #define CLEAR_RECORDS 0x1 @@ -636,6 +637,41 @@ static CXLRetCode cmd_infostat_bg_op_sts(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* + * CXL r3.1 Section 8.2.9.1.5: + * Request Abort Background Operation (Opcode 0005h) + */ +static CXLRetCode cmd_infostat_bg_op_abort(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + int bg_set = cci->bg.opcode >> 8; + int bg_cmd = cci->bg.opcode & 0xff; + const struct cxl_cmd *bg_c = &cci->cxl_cmd_set[bg_set][bg_cmd]; + + if (!(bg_c->effect & CXL_MBOX_BACKGROUND_OPERATION_ABORT)) { + return CXL_MBOX_REQUEST_ABORT_NOTSUP; + } + + qemu_mutex_lock(&cci->bg.lock); + if (cci->bg.runtime) { + /* operation is near complete, let it finish */ + if (cci->bg.complete_pct < 85) { + timer_del(cci->bg.timer); + cci->bg.ret_code = CXL_MBOX_ABORTED; + cci->bg.starttime = 0; + cci->bg.runtime = 0; + cci->bg.aborted = true; + } + } + qemu_mutex_unlock(&cci->bg.lock); + + return CXL_MBOX_SUCCESS; +} + #define CXL_FW_SLOTS 2 #define CXL_FW_SIZE 0x02000000 /* 32 mb */ @@ -2715,6 +2751,8 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd, } static const struct cxl_cmd cxl_cmd_set[256][256] = { + [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", + cmd_infostat_bg_op_abort, 0, 0 }, [EVENTS][GET_RECORDS] = { "EVENTS_GET_RECORDS", cmd_events_get_records, 1, 0 }, [EVENTS][CLEAR_RECORDS] = { "EVENTS_CLEAR_RECORDS", @@ -2727,9 +2765,11 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = { [FIRMWARE_UPDATE][GET_INFO] = { "FIRMWARE_UPDATE_GET_INFO", cmd_firmware_update_get_info, 0, 0 }, [FIRMWARE_UPDATE][TRANSFER] = { "FIRMWARE_UPDATE_TRANSFER", - cmd_firmware_update_transfer, ~0, CXL_MBOX_BACKGROUND_OPERATION }, + cmd_firmware_update_transfer, ~0, + CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT }, [FIRMWARE_UPDATE][ACTIVATE] = { "FIRMWARE_UPDATE_ACTIVATE", - cmd_firmware_update_activate, 2, CXL_MBOX_BACKGROUND_OPERATION }, + cmd_firmware_update_activate, 2, + CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT }, [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, CXL_MBOX_IMMEDIATE_POLICY_CHANGE }, @@ -2758,7 +2798,8 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = { [SANITIZE][OVERWRITE] = { "SANITIZE_OVERWRITE", cmd_sanitize_overwrite, 0, (CXL_MBOX_IMMEDIATE_DATA_CHANGE | CXL_MBOX_SECURITY_STATE_CHANGE | - CXL_MBOX_BACKGROUND_OPERATION)}, + CXL_MBOX_BACKGROUND_OPERATION | + CXL_MBOX_BACKGROUND_OPERATION_ABORT)}, [PERSISTENT_MEM][GET_SECURITY_STATE] = { "GET_SECURITY_STATE", cmd_get_security_state, 0, 0 }, [MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST", @@ -2771,7 +2812,8 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = { "MEDIA_AND_POISON_GET_SCAN_MEDIA_CAPABILITIES", cmd_media_get_scan_media_capabilities, 16, 0 }, [MEDIA_AND_POISON][SCAN_MEDIA] = { "MEDIA_AND_POISON_SCAN_MEDIA", - cmd_media_scan_media, 17, CXL_MBOX_BACKGROUND_OPERATION }, + cmd_media_scan_media, 17, + (CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT)}, [MEDIA_AND_POISON][GET_SCAN_MEDIA_RESULTS] = { "MEDIA_AND_POISON_GET_SCAN_MEDIA_RESULTS", cmd_media_get_scan_media_results, 0, 0 }, @@ -2795,6 +2837,8 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = { [INFOSTAT][IS_IDENTIFY] = { "IDENTIFY", cmd_infostat_identify, 0, 0 }, [INFOSTAT][BACKGROUND_OPERATION_STATUS] = { "BACKGROUND_OPERATION_STATUS", cmd_infostat_bg_op_sts, 0, 0 }, + [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", + cmd_infostat_bg_op_abort, 0, 0 }, [TIMESTAMP][GET] = { "TIMESTAMP_GET", cmd_timestamp_get, 0, 0 }, [TIMESTAMP][SET] = { "TIMESTAMP_SET", cmd_timestamp_set, 8, CXL_MBOX_IMMEDIATE_POLICY_CHANGE }, @@ -2881,6 +2925,7 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd, cci->bg.opcode = (set << 8) | cmd; cci->bg.complete_pct = 0; + cci->bg.aborted = false; cci->bg.ret_code = 0; now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); @@ -2894,10 +2939,12 @@ int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd, static void bg_timercb(void *opaque) { CXLCCI *cci = opaque; - uint64_t now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); - uint64_t total_time = cci->bg.starttime + cci->bg.runtime; + uint64_t now, total_time; - assert(cci->bg.runtime > 0); + qemu_mutex_lock(&cci->bg.lock); + + now = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL); + total_time = cci->bg.starttime + cci->bg.runtime; if (now >= total_time) { /* we are done */ uint16_t ret = CXL_MBOX_SUCCESS; @@ -2950,6 +2997,8 @@ static void bg_timercb(void *opaque) msi_notify(pdev, cxl_dstate->mbox_msi_n); } } + + qemu_mutex_unlock(&cci->bg.lock); } static void cxl_rebuild_cel(CXLCCI *cci) @@ -2978,12 +3027,21 @@ void cxl_init_cci(CXLCCI *cci, size_t payload_max) cci->bg.complete_pct = 0; cci->bg.starttime = 0; cci->bg.runtime = 0; + cci->bg.aborted = false; cci->bg.timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, bg_timercb, cci); + qemu_mutex_init(&cci->bg.lock); memset(&cci->fw, 0, sizeof(cci->fw)); cci->fw.active_slot = 1; cci->fw.slot[cci->fw.active_slot - 1] = true; + cci->initialized = true; +} + +void cxl_destroy_cci(CXLCCI *cci) +{ + qemu_mutex_destroy(&cci->bg.lock); + cci->initialized = false; } static void cxl_copy_cci_commands(CXLCCI *cci, const struct cxl_cmd (*cxl_cmds)[256]) diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index bba923f8ea..aacd078118 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -969,6 +969,7 @@ static void ct3_exit(PCIDevice *pci_dev) cxl_doe_cdat_release(cxl_cstate); msix_uninit_exclusive_bar(pci_dev); g_free(regs->special_ops); + cxl_destroy_cci(&ct3d->cci); if (ct3d->dc.host_dc) { cxl_destroy_dc_regions(ct3d); address_space_destroy(&ct3d->dc.host_dc_as); @@ -1224,12 +1225,17 @@ static void ct3d_reset(DeviceState *dev) * Bring up an endpoint to target with MCTP over VDM. * This device is emulating an MLD with single LD for now. */ + if (ct3d->vdm_fm_owned_ld_mctp_cci.initialized) { + cxl_destroy_cci(&ct3d->vdm_fm_owned_ld_mctp_cci); + } cxl_initialize_t3_fm_owned_ld_mctpcci(&ct3d->vdm_fm_owned_ld_mctp_cci, DEVICE(ct3d), DEVICE(ct3d), 512); /* Max payload made up */ + if (ct3d->ld0_cci.initialized) { + cxl_destroy_cci(&ct3d->ld0_cci); + } cxl_initialize_t3_ld_cci(&ct3d->ld0_cci, DEVICE(ct3d), DEVICE(ct3d), 512); /* Max payload made up */ - } static const Property ct3_props[] = { diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 3a0ee7e8e7..d21695507f 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -176,10 +176,12 @@ typedef struct CXLCCI { uint16_t opcode; uint16_t complete_pct; uint16_t ret_code; /* Current value of retcode */ + bool aborted; uint64_t starttime; /* set by each bg cmd, cleared by the bg_timer when complete */ uint64_t runtime; QEMUTimer *timer; + QemuMutex lock; /* serializes mbox abort vs timer cb */ } bg; /* firmware update */ @@ -201,6 +203,7 @@ typedef struct CXLCCI { DeviceState *d; /* Pointer to the device hosting the protocol conversion */ DeviceState *intf; + bool initialized; } CXLCCI; typedef struct cxl_device_state { @@ -316,6 +319,7 @@ void cxl_initialize_mailbox_t3(CXLCCI *cci, DeviceState *d, size_t payload_max); void cxl_initialize_mailbox_swcci(CXLCCI *cci, DeviceState *intf, DeviceState *d, size_t payload_max); void cxl_init_cci(CXLCCI *cci, size_t payload_max); +void cxl_destroy_cci(CXLCCI *cci); void cxl_add_cci_commands(CXLCCI *cci, const struct cxl_cmd (*cxl_cmd_set)[256], size_t payload_max); int cxl_process_cci_message(CXLCCI *cci, uint8_t set, uint8_t cmd, diff --git a/include/hw/cxl/cxl_mailbox.h b/include/hw/cxl/cxl_mailbox.h index beb048052e..9008402d1c 100644 --- a/include/hw/cxl/cxl_mailbox.h +++ b/include/hw/cxl/cxl_mailbox.h @@ -14,5 +14,6 @@ #define CXL_MBOX_IMMEDIATE_LOG_CHANGE (1 << 4) #define CXL_MBOX_SECURITY_STATE_CHANGE (1 << 5) #define CXL_MBOX_BACKGROUND_OPERATION (1 << 6) +#define CXL_MBOX_BACKGROUND_OPERATION_ABORT (1 << 7) #endif From 1000158f031818bf286454c8691da9b4f33c4d02 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 5 Mar 2025 09:24:53 +0000 Subject: [PATCH 0857/2760] hw/cxl: Support get/set mctp response payload size Add Get/Set Response Message Limit commands. Signed-off-by: Davidlohr Bueso Reviewed-by: Fan Ni Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-3-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 58 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 4401f446d9..bd25df033a 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -7,6 +7,8 @@ * COPYING file in the top-level directory. */ +#include + #include "qemu/osdep.h" #include "hw/pci/msi.h" #include "hw/pci/msix.h" @@ -56,6 +58,8 @@ enum { INFOSTAT = 0x00, #define IS_IDENTIFY 0x1 #define BACKGROUND_OPERATION_STATUS 0x2 + #define GET_RESPONSE_MSG_LIMIT 0x3 + #define SET_RESPONSE_MSG_LIMIT 0x4 #define BACKGROUND_OPERATION_ABORT 0x5 EVENTS = 0x01, #define GET_RECORDS 0x0 @@ -413,12 +417,58 @@ static CXLRetCode cmd_infostat_identify(const struct cxl_cmd *cmd, is_identify->component_type = 0x3; /* Type 3 */ } - /* TODO: Allow this to vary across different CCIs */ - is_identify->max_message_size = 9; /* 512 bytes - MCTP_CXL_MAILBOX_BYTES */ + is_identify->max_message_size = (uint8_t)log2(cci->payload_max); *len_out = sizeof(*is_identify); return CXL_MBOX_SUCCESS; } +/* CXL r3.1 section 8.2.9.1.3: Get Response Message Limit (Opcode 0003h) */ +static CXLRetCode cmd_get_response_msg_limit(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t rsp_limit; + } QEMU_PACKED *get_rsp_msg_limit = (void *)payload_out; + QEMU_BUILD_BUG_ON(sizeof(*get_rsp_msg_limit) != 1); + + get_rsp_msg_limit->rsp_limit = (uint8_t)log2(cci->payload_max); + + *len_out = sizeof(*get_rsp_msg_limit); + return CXL_MBOX_SUCCESS; +} + +/* CXL r3.1 section 8.2.9.1.4: Set Response Message Limit (Opcode 0004h) */ +static CXLRetCode cmd_set_response_msg_limit(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t rsp_limit; + } QEMU_PACKED *in = (void *)payload_in; + QEMU_BUILD_BUG_ON(sizeof(*in) != 1); + struct { + uint8_t rsp_limit; + } QEMU_PACKED *out = (void *)payload_out; + QEMU_BUILD_BUG_ON(sizeof(*out) != 1); + + if (in->rsp_limit < 8 || in->rsp_limit > 10) { + return CXL_MBOX_INVALID_INPUT; + } + + cci->payload_max = 1 << in->rsp_limit; + out->rsp_limit = in->rsp_limit; + + *len_out = sizeof(*out); + return CXL_MBOX_SUCCESS; +} + static void cxl_set_dsp_active_bm(PCIBus *b, PCIDevice *d, void *private) { @@ -3105,6 +3155,10 @@ void cxl_initialize_t3_ld_cci(CXLCCI *cci, DeviceState *d, DeviceState *intf, static const struct cxl_cmd cxl_cmd_set_t3_fm_owned_ld_mctp[256][256] = { [INFOSTAT][IS_IDENTIFY] = { "IDENTIFY", cmd_infostat_identify, 0, 0}, + [INFOSTAT][GET_RESPONSE_MSG_LIMIT] = { "GET_RESPONSE_MSG_LIMIT", + cmd_get_response_msg_limit, 0, 0 }, + [INFOSTAT][SET_RESPONSE_MSG_LIMIT] = { "SET_RESPONSE_MSG_LIMIT", + cmd_set_response_msg_limit, 1, 0 }, [LOGS][GET_SUPPORTED] = { "LOGS_GET_SUPPORTED", cmd_logs_get_supported, 0, 0 }, [LOGS][GET_LOG] = { "LOGS_GET_LOG", cmd_logs_get_log, 0x18, 0 }, From 77a8e9fe0ecb71b260d17f43221df5b18769b359 Mon Sep 17 00:00:00 2001 From: Vinayak Holikatti Date: Wed, 5 Mar 2025 09:24:54 +0000 Subject: [PATCH 0858/2760] hw/cxl/cxl-mailbox-utils: Add support for Media operations discovery commands cxl r3.2 (8.2.10.9.5.3) CXL spec 3.2 section 8.2.10.9.5.3 describes media operations commands. CXL devices supports media operations discovery command. Signed-off-by: Vinayak Holikatti Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-4-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 125 +++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index bd25df033a..79b35d1405 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -89,6 +89,7 @@ enum { SANITIZE = 0x44, #define OVERWRITE 0x0 #define SECURE_ERASE 0x1 + #define MEDIA_OPERATIONS 0x2 PERSISTENT_MEM = 0x45, #define GET_SECURITY_STATE 0x0 MEDIA_AND_POISON = 0x43, @@ -1705,6 +1706,126 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd, return CXL_MBOX_BG_STARTED; } +enum { + MEDIA_OP_CLASS_GENERAL = 0x0, + #define MEDIA_OP_GEN_SUBC_DISCOVERY 0x0 + MEDIA_OP_CLASS_SANITIZE = 0x1, + #define MEDIA_OP_SAN_SUBC_SANITIZE 0x0 + #define MEDIA_OP_SAN_SUBC_ZERO 0x1 +}; + +struct media_op_supported_list_entry { + uint8_t media_op_class; + uint8_t media_op_subclass; +}; + +struct media_op_discovery_out_pl { + uint64_t dpa_range_granularity; + uint16_t total_supported_operations; + uint16_t num_of_supported_operations; + struct media_op_supported_list_entry entry[]; +} QEMU_PACKED; + +static const struct media_op_supported_list_entry media_op_matrix[] = { + { MEDIA_OP_CLASS_GENERAL, MEDIA_OP_GEN_SUBC_DISCOVERY }, + { MEDIA_OP_CLASS_SANITIZE, MEDIA_OP_SAN_SUBC_SANITIZE }, + { MEDIA_OP_CLASS_SANITIZE, MEDIA_OP_SAN_SUBC_ZERO }, +}; + +static CXLRetCode media_operations_discovery(uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out) +{ + struct { + uint8_t media_operation_class; + uint8_t media_operation_subclass; + uint8_t rsvd[2]; + uint32_t dpa_range_count; + struct { + uint16_t start_index; + uint16_t num_ops; + } discovery_osa; + } QEMU_PACKED *media_op_in_disc_pl = (void *)payload_in; + struct media_op_discovery_out_pl *media_out_pl = + (struct media_op_discovery_out_pl *)payload_out; + int num_ops, start_index, i; + int count = 0; + + if (len_in < sizeof(*media_op_in_disc_pl)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + + num_ops = media_op_in_disc_pl->discovery_osa.num_ops; + start_index = media_op_in_disc_pl->discovery_osa.start_index; + + /* + * As per spec CXL r3.2 8.2.10.9.5.3 dpa_range_count should be zero and + * start index should not exceed the total number of entries for discovery + * sub class command. + */ + if (media_op_in_disc_pl->dpa_range_count || + start_index > ARRAY_SIZE(media_op_matrix)) { + return CXL_MBOX_INVALID_INPUT; + } + + media_out_pl->dpa_range_granularity = CXL_CACHE_LINE_SIZE; + media_out_pl->total_supported_operations = + ARRAY_SIZE(media_op_matrix); + if (num_ops > 0) { + for (i = start_index; i < start_index + num_ops; i++) { + media_out_pl->entry[count].media_op_class = + media_op_matrix[i].media_op_class; + media_out_pl->entry[count].media_op_subclass = + media_op_matrix[i].media_op_subclass; + count++; + if (count == num_ops) { + break; + } + } + } + + media_out_pl->num_of_supported_operations = count; + *len_out = sizeof(*media_out_pl) + count * sizeof(*media_out_pl->entry); + return CXL_MBOX_SUCCESS; +} + +static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t media_operation_class; + uint8_t media_operation_subclass; + uint8_t rsvd[2]; + uint32_t dpa_range_count; + } QEMU_PACKED *media_op_in_common_pl = (void *)payload_in; + uint8_t media_op_cl = 0; + uint8_t media_op_subclass = 0; + + if (len_in < sizeof(*media_op_in_common_pl)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + + media_op_cl = media_op_in_common_pl->media_operation_class; + media_op_subclass = media_op_in_common_pl->media_operation_subclass; + + switch (media_op_cl) { + case MEDIA_OP_CLASS_GENERAL: + if (media_op_subclass != MEDIA_OP_GEN_SUBC_DISCOVERY) { + return CXL_MBOX_UNSUPPORTED; + } + + return media_operations_discovery(payload_in, len_in, payload_out, + len_out); + default: + return CXL_MBOX_UNSUPPORTED; + } +} + static CXLRetCode cmd_get_security_state(const struct cxl_cmd *cmd, uint8_t *payload_in, size_t len_in, @@ -2850,6 +2971,10 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = { CXL_MBOX_SECURITY_STATE_CHANGE | CXL_MBOX_BACKGROUND_OPERATION | CXL_MBOX_BACKGROUND_OPERATION_ABORT)}, + [SANITIZE][MEDIA_OPERATIONS] = { "MEDIA_OPERATIONS", cmd_media_operations, + ~0, + (CXL_MBOX_IMMEDIATE_DATA_CHANGE | + CXL_MBOX_BACKGROUND_OPERATION)}, [PERSISTENT_MEM][GET_SECURITY_STATE] = { "GET_SECURITY_STATE", cmd_get_security_state, 0, 0 }, [MEDIA_AND_POISON][GET_POISON_LIST] = { "MEDIA_AND_POISON_GET_POISON_LIST", From 484df0704ea592ebd5993c15d63ea38f309ec6e0 Mon Sep 17 00:00:00 2001 From: Vinayak Holikatti Date: Wed, 5 Mar 2025 09:24:55 +0000 Subject: [PATCH 0859/2760] hw/cxl: factor out calculation of sanitize duration from cmd_santize_overwrite Move the code of calculation of sanitize duration into function for usability by other sanitize routines Estimate times based on: https://pmem.io/documents/NVDIMM_DSM_Interface-V1.8.pdf Signed-off-by: Davidlohr Bueso Signed-off-by: Vinayak Holikatti Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-5-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 63 ++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 79b35d1405..9f9d475678 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -1640,6 +1640,41 @@ static void __do_sanitization(CXLType3Dev *ct3d) cxl_discard_all_event_records(&ct3d->cxl_dstate); } +static int get_sanitize_duration(uint64_t total_mem) +{ + int secs = 0; + + if (total_mem <= 512) { + secs = 4; + } else if (total_mem <= 1024) { + secs = 8; + } else if (total_mem <= 2 * 1024) { + secs = 15; + } else if (total_mem <= 4 * 1024) { + secs = 30; + } else if (total_mem <= 8 * 1024) { + secs = 60; + } else if (total_mem <= 16 * 1024) { + secs = 2 * 60; + } else if (total_mem <= 32 * 1024) { + secs = 4 * 60; + } else if (total_mem <= 64 * 1024) { + secs = 8 * 60; + } else if (total_mem <= 128 * 1024) { + secs = 15 * 60; + } else if (total_mem <= 256 * 1024) { + secs = 30 * 60; + } else if (total_mem <= 512 * 1024) { + secs = 60 * 60; + } else if (total_mem <= 1024 * 1024) { + secs = 120 * 60; + } else { + secs = 240 * 60; /* max 4 hrs */ + } + + return secs; +} + /* * CXL r3.1 Section 8.2.9.9.5.1: Sanitize (Opcode 4400h) * @@ -1668,33 +1703,7 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd, int secs; total_mem = (ct3d->cxl_dstate.vmem_size + ct3d->cxl_dstate.pmem_size) >> 20; - if (total_mem <= 512) { - secs = 4; - } else if (total_mem <= 1024) { - secs = 8; - } else if (total_mem <= 2 * 1024) { - secs = 15; - } else if (total_mem <= 4 * 1024) { - secs = 30; - } else if (total_mem <= 8 * 1024) { - secs = 60; - } else if (total_mem <= 16 * 1024) { - secs = 2 * 60; - } else if (total_mem <= 32 * 1024) { - secs = 4 * 60; - } else if (total_mem <= 64 * 1024) { - secs = 8 * 60; - } else if (total_mem <= 128 * 1024) { - secs = 15 * 60; - } else if (total_mem <= 256 * 1024) { - secs = 30 * 60; - } else if (total_mem <= 512 * 1024) { - secs = 60 * 60; - } else if (total_mem <= 1024 * 1024) { - secs = 120 * 60; - } else { - secs = 240 * 60; /* max 4 hrs */ - } + secs = get_sanitize_duration(total_mem); /* EBUSY other bg cmds as of now */ cci->bg.runtime = secs * 1000UL; From 40ab4ed107757e1c5bdccc906e8a44cb4e2cb7a4 Mon Sep 17 00:00:00 2001 From: Vinayak Holikatti Date: Wed, 5 Mar 2025 09:24:56 +0000 Subject: [PATCH 0860/2760] hw/cxl/cxl-mailbox-utils: Media operations Sanitize and Write Zeros commands CXL r3.2(8.2.10.9.5.3) CXL spec 3.2 section 8.2.10.9.5.3 describes media operations commands. CXL devices supports media operations Sanitize and Write zero command. Signed-off-by: Vinayak Holikatti Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-6-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 204 ++++++++++++++++++++++++++++++++++++ include/hw/cxl/cxl_device.h | 4 + 2 files changed, 208 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 9f9d475678..2c6db70e5f 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -1715,6 +1715,131 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd, return CXL_MBOX_BG_STARTED; } +struct dpa_range_list_entry { + uint64_t starting_dpa; + uint64_t length; +} QEMU_PACKED; + +struct CXLSanitizeInfo { + uint32_t dpa_range_count; + uint8_t fill_value; + struct dpa_range_list_entry dpa_range_list[]; +} QEMU_PACKED; + +static uint64_t get_vmr_size(CXLType3Dev *ct3d, MemoryRegion **vmr) +{ + MemoryRegion *mr; + if (ct3d->hostvmem) { + mr = host_memory_backend_get_memory(ct3d->hostvmem); + if (vmr) { + *vmr = mr; + } + return memory_region_size(mr); + } + return 0; +} + +static uint64_t get_pmr_size(CXLType3Dev *ct3d, MemoryRegion **pmr) +{ + MemoryRegion *mr; + if (ct3d->hostpmem) { + mr = host_memory_backend_get_memory(ct3d->hostpmem); + if (pmr) { + *pmr = mr; + } + return memory_region_size(mr); + } + return 0; +} + +static uint64_t get_dc_size(CXLType3Dev *ct3d, MemoryRegion **dc_mr) +{ + MemoryRegion *mr; + if (ct3d->dc.host_dc) { + mr = host_memory_backend_get_memory(ct3d->dc.host_dc); + if (dc_mr) { + *dc_mr = mr; + } + return memory_region_size(mr); + } + return 0; +} + +static int validate_dpa_addr(CXLType3Dev *ct3d, uint64_t dpa_addr, + size_t length) +{ + uint64_t vmr_size, pmr_size, dc_size; + + if ((dpa_addr % CXL_CACHE_LINE_SIZE) || + (length % CXL_CACHE_LINE_SIZE) || + (length <= 0)) { + return -EINVAL; + } + + vmr_size = get_vmr_size(ct3d, NULL); + pmr_size = get_pmr_size(ct3d, NULL); + dc_size = get_dc_size(ct3d, NULL); + + if (dpa_addr + length > vmr_size + pmr_size + dc_size) { + return -EINVAL; + } + + if (dpa_addr > vmr_size + pmr_size) { + if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) { + return -ENODEV; + } + } + + return 0; +} + +static int sanitize_range(CXLType3Dev *ct3d, uint64_t dpa_addr, size_t length, + uint8_t fill_value) +{ + + uint64_t vmr_size, pmr_size; + AddressSpace *as = NULL; + MemTxAttrs mem_attrs = {}; + + vmr_size = get_vmr_size(ct3d, NULL); + pmr_size = get_pmr_size(ct3d, NULL); + + if (dpa_addr < vmr_size) { + as = &ct3d->hostvmem_as; + } else if (dpa_addr < vmr_size + pmr_size) { + as = &ct3d->hostpmem_as; + } else { + if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) { + return -ENODEV; + } + as = &ct3d->dc.host_dc_as; + } + + return address_space_set(as, dpa_addr, fill_value, length, mem_attrs); +} + +/* Perform the actual device zeroing */ +static void __do_sanitize(CXLType3Dev *ct3d) +{ + struct CXLSanitizeInfo *san_info = ct3d->media_op_sanitize; + int dpa_range_count = san_info->dpa_range_count; + int rc = 0; + int i; + + for (i = 0; i < dpa_range_count; i++) { + rc = sanitize_range(ct3d, san_info->dpa_range_list[i].starting_dpa, + san_info->dpa_range_list[i].length, + san_info->fill_value); + if (rc) { + goto exit; + } + } +exit: + g_free(ct3d->media_op_sanitize); + ct3d->media_op_sanitize = NULL; + return; +} + enum { MEDIA_OP_CLASS_GENERAL = 0x0, #define MEDIA_OP_GEN_SUBC_DISCOVERY 0x0 @@ -1799,6 +1924,65 @@ static CXLRetCode media_operations_discovery(uint8_t *payload_in, return CXL_MBOX_SUCCESS; } +static CXLRetCode media_operations_sanitize(CXLType3Dev *ct3d, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + uint8_t fill_value, + CXLCCI *cci) +{ + struct media_operations_sanitize { + uint8_t media_operation_class; + uint8_t media_operation_subclass; + uint8_t rsvd[2]; + uint32_t dpa_range_count; + struct dpa_range_list_entry dpa_range_list[]; + } QEMU_PACKED *media_op_in_sanitize_pl = (void *)payload_in; + uint32_t dpa_range_count = media_op_in_sanitize_pl->dpa_range_count; + uint64_t total_mem = 0; + size_t dpa_range_list_size; + int secs = 0, i; + + if (dpa_range_count == 0) { + return CXL_MBOX_SUCCESS; + } + + dpa_range_list_size = dpa_range_count * sizeof(struct dpa_range_list_entry); + if (len_in < (sizeof(*media_op_in_sanitize_pl) + dpa_range_list_size)) { + return CXL_MBOX_INVALID_PAYLOAD_LENGTH; + } + + for (i = 0; i < dpa_range_count; i++) { + uint64_t start_dpa = + media_op_in_sanitize_pl->dpa_range_list[i].starting_dpa; + uint64_t length = media_op_in_sanitize_pl->dpa_range_list[i].length; + + if (validate_dpa_addr(ct3d, start_dpa, length)) { + return CXL_MBOX_INVALID_INPUT; + } + total_mem += length; + } + ct3d->media_op_sanitize = g_malloc0(sizeof(struct CXLSanitizeInfo) + + dpa_range_list_size); + + ct3d->media_op_sanitize->dpa_range_count = dpa_range_count; + ct3d->media_op_sanitize->fill_value = fill_value; + memcpy(ct3d->media_op_sanitize->dpa_range_list, + media_op_in_sanitize_pl->dpa_range_list, + dpa_range_list_size); + secs = get_sanitize_duration(total_mem >> 20); + + /* EBUSY other bg cmds as of now */ + cci->bg.runtime = secs * 1000UL; + *len_out = 0; + /* + * media op sanitize is targeted so no need to disable media or + * clear event logs + */ + return CXL_MBOX_BG_STARTED; +} + static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd, uint8_t *payload_in, size_t len_in, @@ -1812,6 +1996,7 @@ static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd, uint8_t rsvd[2]; uint32_t dpa_range_count; } QEMU_PACKED *media_op_in_common_pl = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); uint8_t media_op_cl = 0; uint8_t media_op_subclass = 0; @@ -1830,6 +2015,19 @@ static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd, return media_operations_discovery(payload_in, len_in, payload_out, len_out); + case MEDIA_OP_CLASS_SANITIZE: + switch (media_op_subclass) { + case MEDIA_OP_SAN_SUBC_SANITIZE: + return media_operations_sanitize(ct3d, payload_in, len_in, + payload_out, len_out, 0xF, + cci); + case MEDIA_OP_SAN_SUBC_ZERO: + return media_operations_sanitize(ct3d, payload_in, len_in, + payload_out, len_out, 0, + cci); + default: + return CXL_MBOX_UNSUPPORTED; + } default: return CXL_MBOX_UNSUPPORTED; } @@ -3147,6 +3345,12 @@ static void bg_timercb(void *opaque) cxl_dev_enable_media(&ct3d->cxl_dstate); } break; + case 0x4402: /* Media Operations sanitize */ + { + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + __do_sanitize(ct3d); + } + break; case 0x4304: /* scan media */ { CXLType3Dev *ct3d = CXL_TYPE3(cci->d); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index d21695507f..3ec7be3809 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -540,6 +540,8 @@ typedef struct CXLSetFeatureInfo { size_t data_size; } CXLSetFeatureInfo; +struct CXLSanitizeInfo; + struct CXLType3Dev { /* Private */ PCIDevice parent_obj; @@ -606,6 +608,8 @@ struct CXLType3Dev { uint8_t num_regions; /* 0-8 regions */ CXLDCRegion regions[DCD_MAX_NUM_REGION]; } dc; + + struct CXLSanitizeInfo *media_op_sanitize; }; #define TYPE_CXL_TYPE3 "cxl-type3" From a3e0b1ff37e930095a417666ab3e12715394fb9b Mon Sep 17 00:00:00 2001 From: Sweta Kumari Date: Wed, 5 Mar 2025 09:24:57 +0000 Subject: [PATCH 0861/2760] hw/cxl/cxl-mailbox-utils: CXL CCI Get/Set alert config commands 1) get alert configuration(Opcode 4201h) 2) set alert configuration(Opcode 4202h) Signed-off-by: Sweta Kumari Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-7-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/cxl/cxl-mailbox-utils.c | 105 ++++++++++++++++++++++++++++++++++++ hw/mem/cxl_type3.c | 14 +++++ include/hw/cxl/cxl_device.h | 15 ++++++ 3 files changed, 134 insertions(+) diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 2c6db70e5f..299f232f26 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -28,6 +28,11 @@ #define CXL_DC_EVENT_LOG_SIZE 8 #define CXL_NUM_EXTENTS_SUPPORTED 512 #define CXL_NUM_TAGS_SUPPORTED 0 +#define CXL_ALERTS_LIFE_USED_WARN_THRESH (1 << 0) +#define CXL_ALERTS_OVER_TEMP_WARN_THRESH (1 << 1) +#define CXL_ALERTS_UNDER_TEMP_WARN_THRESH (1 << 2) +#define CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH (1 << 3) +#define CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH (1 << 4) /* * How to add a new command, example. The command set FOO, with cmd BAR. @@ -86,6 +91,9 @@ enum { #define GET_PARTITION_INFO 0x0 #define GET_LSA 0x2 #define SET_LSA 0x3 + HEALTH_INFO_ALERTS = 0x42, + #define GET_ALERT_CONFIG 0x1 + #define SET_ALERT_CONFIG 0x2 SANITIZE = 0x44, #define OVERWRITE 0x0 #define SECURE_ERASE 0x1 @@ -1610,6 +1618,97 @@ static CXLRetCode cmd_ccls_set_lsa(const struct cxl_cmd *cmd, return CXL_MBOX_SUCCESS; } +/* CXL r3.2 Section 8.2.10.9.3.2 Get Alert Configuration (Opcode 4201h) */ +static CXLRetCode cmd_get_alert_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLAlertConfig *out = (CXLAlertConfig *)payload_out; + + memcpy(out, &ct3d->alert_config, sizeof(ct3d->alert_config)); + *len_out = sizeof(ct3d->alert_config); + + return CXL_MBOX_SUCCESS; +} + +/* CXL r3.2 Section 8.2.10.9.3.3 Set Alert Configuration (Opcode 4202h) */ +static CXLRetCode cmd_set_alert_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLAlertConfig *alert_config = &ct3d->alert_config; + struct { + uint8_t valid_alert_actions; + uint8_t enable_alert_actions; + uint8_t life_used_warn_thresh; + uint8_t rsvd; + uint16_t over_temp_warn_thresh; + uint16_t under_temp_warn_thresh; + uint16_t cor_vmem_err_warn_thresh; + uint16_t cor_pmem_err_warn_thresh; + } QEMU_PACKED *in = (void *)payload_in; + + if (in->valid_alert_actions & CXL_ALERTS_LIFE_USED_WARN_THRESH) { + /* + * CXL r3.2 Table 8-149 The life used warning threshold shall be + * less than the life used critical alert value. + */ + if (in->life_used_warn_thresh >= + alert_config->life_used_crit_alert_thresh) { + return CXL_MBOX_INVALID_INPUT; + } + alert_config->life_used_warn_thresh = in->life_used_warn_thresh; + alert_config->enable_alerts |= CXL_ALERTS_LIFE_USED_WARN_THRESH; + } + + if (in->valid_alert_actions & CXL_ALERTS_OVER_TEMP_WARN_THRESH) { + /* + * CXL r3.2 Table 8-149 The Device Over-Temperature Warning Threshold + * shall be less than the the Device Over-Temperature Critical + * Alert Threshold. + */ + if (in->over_temp_warn_thresh >= + alert_config->over_temp_crit_alert_thresh) { + return CXL_MBOX_INVALID_INPUT; + } + alert_config->over_temp_warn_thresh = in->over_temp_warn_thresh; + alert_config->enable_alerts |= CXL_ALERTS_OVER_TEMP_WARN_THRESH; + } + + if (in->valid_alert_actions & CXL_ALERTS_UNDER_TEMP_WARN_THRESH) { + /* + * CXL r3.2 Table 8-149 The Device Under-Temperature Warning Threshold + * shall be higher than the the Device Under-Temperature Critical + * Alert Threshold. + */ + if (in->under_temp_warn_thresh <= + alert_config->under_temp_crit_alert_thresh) { + return CXL_MBOX_INVALID_INPUT; + } + alert_config->under_temp_warn_thresh = in->under_temp_warn_thresh; + alert_config->enable_alerts |= CXL_ALERTS_UNDER_TEMP_WARN_THRESH; + } + + if (in->valid_alert_actions & CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH) { + alert_config->cor_vmem_err_warn_thresh = in->cor_vmem_err_warn_thresh; + alert_config->enable_alerts |= CXL_ALERTS_COR_VMEM_ERR_WARN_THRESH; + } + + if (in->valid_alert_actions & CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH) { + alert_config->cor_pmem_err_warn_thresh = in->cor_pmem_err_warn_thresh; + alert_config->enable_alerts |= CXL_ALERTS_COR_PMEM_ERR_WARN_THRESH; + } + return CXL_MBOX_SUCCESS; +} + /* Perform the actual device zeroing */ static void __do_sanitization(CXLType3Dev *ct3d) { @@ -3173,6 +3272,12 @@ static const struct cxl_cmd cxl_cmd_set[256][256] = { [CCLS][GET_LSA] = { "CCLS_GET_LSA", cmd_ccls_get_lsa, 8, 0 }, [CCLS][SET_LSA] = { "CCLS_SET_LSA", cmd_ccls_set_lsa, ~0, CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | CXL_MBOX_IMMEDIATE_DATA_CHANGE }, + [HEALTH_INFO_ALERTS][GET_ALERT_CONFIG] = { + "HEALTH_INFO_ALERTS_GET_ALERT_CONFIG", + cmd_get_alert_config, 0, 0 }, + [HEALTH_INFO_ALERTS][SET_ALERT_CONFIG] = { + "HEALTH_INFO_ALERTS_SET_ALERT_CONFIG", + cmd_set_alert_config, 12, CXL_MBOX_IMMEDIATE_POLICY_CHANGE }, [SANITIZE][OVERWRITE] = { "SANITIZE_OVERWRITE", cmd_sanitize_overwrite, 0, (CXL_MBOX_IMMEDIATE_DATA_CHANGE | CXL_MBOX_SECURITY_STATE_CHANGE | diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c index aacd078118..94e7274912 100644 --- a/hw/mem/cxl_type3.c +++ b/hw/mem/cxl_type3.c @@ -843,6 +843,19 @@ static DOEProtocol doe_cdat_prot[] = { { } }; +/* Initialize CXL device alerts with default threshold values. */ +static void init_alert_config(CXLType3Dev *ct3d) +{ + ct3d->alert_config = (CXLAlertConfig) { + .life_used_crit_alert_thresh = 75, + .life_used_warn_thresh = 40, + .over_temp_crit_alert_thresh = 35, + .under_temp_crit_alert_thresh = 10, + .over_temp_warn_thresh = 25, + .under_temp_warn_thresh = 20 + }; +} + static void ct3_realize(PCIDevice *pci_dev, Error **errp) { ERRP_GUARD(); @@ -910,6 +923,7 @@ static void ct3_realize(PCIDevice *pci_dev, Error **errp) goto err_msix_uninit; } + init_alert_config(ct3d); pcie_cap_deverr_init(pci_dev); /* Leave a bit of room for expansion */ rc = pcie_aer_init(pci_dev, PCI_ERR_VER, 0x200, PCI_ERR_SIZEOF, errp); diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h index 3ec7be3809..ed6cd50c67 100644 --- a/include/hw/cxl/cxl_device.h +++ b/include/hw/cxl/cxl_device.h @@ -542,6 +542,19 @@ typedef struct CXLSetFeatureInfo { struct CXLSanitizeInfo; +typedef struct CXLAlertConfig { + uint8_t valid_alerts; + uint8_t enable_alerts; + uint8_t life_used_crit_alert_thresh; + uint8_t life_used_warn_thresh; + uint16_t over_temp_crit_alert_thresh; + uint16_t under_temp_crit_alert_thresh; + uint16_t over_temp_warn_thresh; + uint16_t under_temp_warn_thresh; + uint16_t cor_vmem_err_warn_thresh; + uint16_t cor_pmem_err_warn_thresh; +} QEMU_PACKED CXLAlertConfig; + struct CXLType3Dev { /* Private */ PCIDevice parent_obj; @@ -563,6 +576,8 @@ struct CXLType3Dev { CXLCCI vdm_fm_owned_ld_mctp_cci; CXLCCI ld0_cci; + CXLAlertConfig alert_config; + /* PCIe link characteristics */ PCIExpLinkSpeed speed; PCIExpLinkWidth width; From abde58f8644491503c058c2ff0775613f251c8e6 Mon Sep 17 00:00:00 2001 From: Yuquan Wang Date: Wed, 5 Mar 2025 09:24:59 +0000 Subject: [PATCH 0862/2760] docs/cxl: Add serial number for persistent-memdev Add serial number parameter in the cxl persistent examples. Signed-off-by: Yuquan Wang Signed-off-by: Jonathan Cameron Message-Id: <20250305092501.191929-9-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/system/devices/cxl.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/system/devices/cxl.rst b/docs/system/devices/cxl.rst index 882b036f5e..e307caf3f8 100644 --- a/docs/system/devices/cxl.rst +++ b/docs/system/devices/cxl.rst @@ -308,7 +308,7 @@ A very simple setup with just one directly attached CXL Type 3 Persistent Memory -object memory-backend-file,id=cxl-lsa1,share=on,mem-path=/tmp/lsa.raw,size=256M \ -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ - -device cxl-type3,bus=root_port13,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -device cxl-type3,bus=root_port13,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0,sn=0x1 \ -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G A very simple setup with just one directly attached CXL Type 3 Volatile Memory device:: @@ -349,13 +349,13 @@ the CXL Type3 device directly attached (no switches).:: -device pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1 \ -device pxb-cxl,bus_nr=222,bus=pcie.0,id=cxl.2 \ -device cxl-rp,port=0,bus=cxl.1,id=root_port13,chassis=0,slot=2 \ - -device cxl-type3,bus=root_port13,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0 \ + -device cxl-type3,bus=root_port13,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem0,sn=0x1 \ -device cxl-rp,port=1,bus=cxl.1,id=root_port14,chassis=0,slot=3 \ - -device cxl-type3,bus=root_port14,persistent-memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem1 \ + -device cxl-type3,bus=root_port14,persistent-memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem1,sn=0x2 \ -device cxl-rp,port=0,bus=cxl.2,id=root_port15,chassis=0,slot=5 \ - -device cxl-type3,bus=root_port15,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem2 \ + -device cxl-type3,bus=root_port15,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem2,sn=0x3 \ -device cxl-rp,port=1,bus=cxl.2,id=root_port16,chassis=0,slot=6 \ - -device cxl-type3,bus=root_port16,persistent-memdev=cxl-mem4,lsa=cxl-lsa4,id=cxl-pmem3 \ + -device cxl-type3,bus=root_port16,persistent-memdev=cxl-mem4,lsa=cxl-lsa4,id=cxl-pmem3,sn=0x4 \ -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.targets.1=cxl.2,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=8k An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave:: @@ -375,13 +375,13 @@ An example of 4 devices below a switch suitable for 1, 2 or 4 way interleave:: -device cxl-rp,port=1,bus=cxl.1,id=root_port1,chassis=0,slot=1 \ -device cxl-upstream,bus=root_port0,id=us0 \ -device cxl-downstream,port=0,bus=us0,id=swport0,chassis=0,slot=4 \ - -device cxl-type3,bus=swport0,persistent-memdev=cxl-mem0,lsa=cxl-lsa0,id=cxl-pmem0 \ + -device cxl-type3,bus=swport0,persistent-memdev=cxl-mem0,lsa=cxl-lsa0,id=cxl-pmem0,sn=0x1 \ -device cxl-downstream,port=1,bus=us0,id=swport1,chassis=0,slot=5 \ - -device cxl-type3,bus=swport1,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem1 \ + -device cxl-type3,bus=swport1,persistent-memdev=cxl-mem1,lsa=cxl-lsa1,id=cxl-pmem1,sn=0x2 \ -device cxl-downstream,port=2,bus=us0,id=swport2,chassis=0,slot=6 \ - -device cxl-type3,bus=swport2,persistent-memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem2 \ + -device cxl-type3,bus=swport2,persistent-memdev=cxl-mem2,lsa=cxl-lsa2,id=cxl-pmem2,sn=0x3 \ -device cxl-downstream,port=3,bus=us0,id=swport3,chassis=0,slot=7 \ - -device cxl-type3,bus=swport3,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3 \ + -device cxl-type3,bus=swport3,persistent-memdev=cxl-mem3,lsa=cxl-lsa3,id=cxl-pmem3,sn=0x4 \ -M cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=4G,cxl-fmw.0.interleave-granularity=4k Deprecations From 3a031e395dc65239d031890d038bc354af61dc35 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:50 +0900 Subject: [PATCH 0863/2760] hw/pci: Do not add ROM BAR for SR-IOV VF A SR-IOV VF cannot have a ROM BAR. Co-developed-by: Yui Washizu Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-1-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index fe38c4c028..6d9d3ce90f 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2522,6 +2522,14 @@ static void pci_add_option_rom(PCIDevice *pdev, bool is_default_rom, return; } + if (pci_is_vf(pdev)) { + if (pdev->rom_bar > 0) { + error_setg(errp, "ROM BAR cannot be enabled for SR-IOV VF"); + } + + return; + } + if (load_file || pdev->romsize == UINT32_MAX) { path = qemu_find_file(QEMU_FILE_TYPE_BIOS, pdev->romfile); if (path == NULL) { From a5745ac183e606937f22bfbf59a7f18e74f3c464 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:51 +0900 Subject: [PATCH 0864/2760] hw/pci: Fix SR-IOV VF number calculation pci_config_get_bar_addr() had a division by vf_stride. vf_stride needs to be non-zero when there are multiple VFs, but the specification does not prohibit to make it zero when there is only one VF. Do not perform the division for the first VF to avoid division by zero. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-2-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 6d9d3ce90f..039cf1e256 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1594,7 +1594,11 @@ static pcibus_t pci_config_get_bar_addr(PCIDevice *d, int reg, pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_OFFSET); uint16_t vf_stride = pci_get_word(pf->config + sriov_cap + PCI_SRIOV_VF_STRIDE); - uint32_t vf_num = (d->devfn - (pf->devfn + vf_offset)) / vf_stride; + uint32_t vf_num = d->devfn - (pf->devfn + vf_offset); + + if (vf_num) { + vf_num /= vf_stride; + } if (type & PCI_BASE_ADDRESS_MEM_TYPE_64) { new_addr = pci_get_quad(pf->config + bar); From 92b6ce3dba26bd3734b528bda7f9a9dee2ee7bb4 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:52 +0900 Subject: [PATCH 0865/2760] pcie_sriov: Ensure PF and VF are mutually exclusive A device cannot be a SR-IOV PF and a VF at the same time. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-3-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie_sriov.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 1eb4358256..109b2ebccc 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -42,6 +42,11 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, uint8_t *cfg = dev->config + offset; uint8_t *wmask; + if (pci_is_vf(dev)) { + error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); + return false; + } + if (total_vfs && (uint32_t)devfn + (uint32_t)(total_vfs - 1) * vf_stride >= PCI_DEVFN_MAX) { error_setg(errp, "VF addr overflows"); From d2f5bb7849e463646173564fdadf40e32a32bf6e Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:53 +0900 Subject: [PATCH 0866/2760] pcie_sriov: Check PCI Express for SR-IOV PF SR-IOV requires PCI Express. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-4-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie_sriov.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 109b2ebccc..a5b546abe8 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -42,6 +42,11 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, uint8_t *cfg = dev->config + offset; uint8_t *wmask; + if (!pci_is_express(dev)) { + error_setg(errp, "PCI Express is required for SR-IOV PF"); + return false; + } + if (pci_is_vf(dev)) { error_setg(errp, "a device cannot be a SR-IOV PF and a VF at the same time"); return false; From 19e55471d4e8a494cfda7470e701829e3a873bdc Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:54 +0900 Subject: [PATCH 0867/2760] pcie_sriov: Allow user to create SR-IOV device A user can create a SR-IOV device by specifying the PF with the sriov-pf property of the VFs. The VFs must be added before the PF. A user-creatable VF must have PCIDeviceClass::sriov_vf_user_creatable set. Such a VF cannot refer to the PF because it is created before the PF. A PF that user-creatable VFs can be attached calls pcie_sriov_pf_init_from_user_created_vfs() during realization and pcie_sriov_pf_exit() when exiting. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-5-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 62 +++++--- hw/pci/pcie_sriov.c | 288 ++++++++++++++++++++++++++++-------- include/hw/pci/pci_device.h | 6 +- include/hw/pci/pcie_sriov.h | 18 +++ 4 files changed, 291 insertions(+), 83 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 039cf1e256..de07096347 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -101,6 +101,7 @@ static const Property pci_props[] = { QEMU_PCIE_ARI_NEXTFN_1_BITNR, false), DEFINE_PROP_SIZE32("x-max-bounce-buffer-size", PCIDevice, max_bounce_buffer_size, DEFAULT_MAX_BOUNCE_BUFFER_SIZE), + DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf), DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present, QEMU_PCIE_EXT_TAG_BITNR, true), { .name = "busnr", .info = &prop_pci_busnr }, @@ -1112,13 +1113,8 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp) dev->config[PCI_HEADER_TYPE] |= PCI_HEADER_TYPE_MULTI_FUNCTION; } - /* - * With SR/IOV and ARI, a device at function 0 need not be a multifunction - * device, as it may just be a VF that ended up with function 0 in - * the legacy PCI interpretation. Avoid failing in such cases: - */ - if (pci_is_vf(dev) && - dev->exp.sriov_vf.pf->cap_present & QEMU_PCI_CAP_MULTIFUNCTION) { + /* SR/IOV is not handled here. */ + if (pci_is_vf(dev)) { return; } @@ -1151,7 +1147,8 @@ static void pci_init_multifunction(PCIBus *bus, PCIDevice *dev, Error **errp) } /* function 0 indicates single function, so function > 0 must be NULL */ for (func = 1; func < PCI_FUNC_MAX; ++func) { - if (bus->devices[PCI_DEVFN(slot, func)]) { + PCIDevice *device = bus->devices[PCI_DEVFN(slot, func)]; + if (device && !pci_is_vf(device)) { error_setg(errp, "PCI: %x.0 indicates single function, " "but %x.%x is already populated.", slot, slot, func); @@ -1439,6 +1436,7 @@ static void pci_qdev_unrealize(DeviceState *dev) pci_unregister_io_regions(pci_dev); pci_del_option_rom(pci_dev); + pcie_sriov_unregister_device(pci_dev); if (pc->exit) { pc->exit(pci_dev); @@ -1470,7 +1468,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, pcibus_t size = memory_region_size(memory); uint8_t hdr_type; - assert(!pci_is_vf(pci_dev)); /* VFs must use pcie_sriov_vf_register_bar */ assert(region_num >= 0); assert(region_num < PCI_NUM_REGIONS); assert(is_power_of_2(size)); @@ -1482,7 +1479,6 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, r = &pci_dev->io_regions[region_num]; assert(!r->size); - r->addr = PCI_BAR_UNMAPPED; r->size = size; r->type = type; r->memory = memory; @@ -1490,22 +1486,35 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num, ? pci_get_bus(pci_dev)->address_space_io : pci_get_bus(pci_dev)->address_space_mem; - wmask = ~(size - 1); - if (region_num == PCI_ROM_SLOT) { - /* ROM enable bit is writable */ - wmask |= PCI_ROM_ADDRESS_ENABLE; - } + if (pci_is_vf(pci_dev)) { + PCIDevice *pf = pci_dev->exp.sriov_vf.pf; + assert(!pf || type == pf->exp.sriov_pf.vf_bar_type[region_num]); - addr = pci_bar(pci_dev, region_num); - pci_set_long(pci_dev->config + addr, type); - - if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && - r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_set_quad(pci_dev->wmask + addr, wmask); - pci_set_quad(pci_dev->cmask + addr, ~0ULL); + r->addr = pci_bar_address(pci_dev, region_num, r->type, r->size); + if (r->addr != PCI_BAR_UNMAPPED) { + memory_region_add_subregion_overlap(r->address_space, + r->addr, r->memory, 1); + } } else { - pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); - pci_set_long(pci_dev->cmask + addr, 0xffffffff); + r->addr = PCI_BAR_UNMAPPED; + + wmask = ~(size - 1); + if (region_num == PCI_ROM_SLOT) { + /* ROM enable bit is writable */ + wmask |= PCI_ROM_ADDRESS_ENABLE; + } + + addr = pci_bar(pci_dev, region_num); + pci_set_long(pci_dev->config + addr, type); + + if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && + r->type & PCI_BASE_ADDRESS_MEM_TYPE_64) { + pci_set_quad(pci_dev->wmask + addr, wmask); + pci_set_quad(pci_dev->cmask + addr, ~0ULL); + } else { + pci_set_long(pci_dev->wmask + addr, wmask & 0xffffffff); + pci_set_long(pci_dev->cmask + addr, 0xffffffff); + } } } @@ -2272,6 +2281,11 @@ static void pci_qdev_realize(DeviceState *qdev, Error **errp) } } + if (!pcie_sriov_register_device(pci_dev, errp)) { + pci_qdev_unrealize(DEVICE(pci_dev)); + return; + } + /* * A PCIe Downstream Port that do not have ARI Forwarding enabled must * associate only Device 0 with the device attached to the bus diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index a5b546abe8..08f707e847 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -15,11 +15,12 @@ #include "hw/pci/pcie.h" #include "hw/pci/pci_bus.h" #include "hw/qdev-properties.h" -#include "qemu/error-report.h" #include "qemu/range.h" #include "qapi/error.h" #include "trace.h" +static GHashTable *pfs; + static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs) { for (uint16_t i = 0; i < total_vfs; i++) { @@ -31,13 +32,43 @@ static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs) dev->exp.sriov_pf.vf = NULL; } -bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, - const char *vfname, uint16_t vf_dev_id, - uint16_t init_vfs, uint16_t total_vfs, - uint16_t vf_offset, uint16_t vf_stride, - Error **errp) +static void register_vfs(PCIDevice *dev) +{ + uint16_t num_vfs; + uint16_t i; + uint16_t sriov_cap = dev->exp.sriov_cap; + + assert(sriov_cap > 0); + num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); + + trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn), num_vfs); + for (i = 0; i < num_vfs; i++) { + pci_set_enabled(dev->exp.sriov_pf.vf[i], true); + } + + pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_NUM_VF, 0); +} + +static void unregister_vfs(PCIDevice *dev) +{ + uint8_t *cfg = dev->config + dev->exp.sriov_cap; + uint16_t i; + + trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), + PCI_FUNC(dev->devfn)); + for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) { + pci_set_enabled(dev->exp.sriov_pf.vf[i], false); + } + + pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff); +} + +static bool pcie_sriov_pf_init_common(PCIDevice *dev, uint16_t offset, + uint16_t vf_dev_id, uint16_t init_vfs, + uint16_t total_vfs, uint16_t vf_offset, + uint16_t vf_stride, Error **errp) { - BusState *bus = qdev_get_parent_bus(&dev->qdev); int32_t devfn = dev->devfn + vf_offset; uint8_t *cfg = dev->config + offset; uint8_t *wmask; @@ -94,6 +125,28 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, qdev_prop_set_bit(&dev->qdev, "multifunction", true); + return true; +} + +bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset, + const char *vfname, uint16_t vf_dev_id, + uint16_t init_vfs, uint16_t total_vfs, + uint16_t vf_offset, uint16_t vf_stride, + Error **errp) +{ + BusState *bus = qdev_get_parent_bus(&dev->qdev); + int32_t devfn = dev->devfn + vf_offset; + + if (pfs && g_hash_table_contains(pfs, dev->qdev.id)) { + error_setg(errp, "attaching user-created SR-IOV VF unsupported"); + return false; + } + + if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, init_vfs, + total_vfs, vf_offset, vf_stride, errp)) { + return false; + } + dev->exp.sriov_pf.vf = g_new(PCIDevice *, total_vfs); for (uint16_t i = 0; i < total_vfs; i++) { @@ -123,7 +176,22 @@ void pcie_sriov_pf_exit(PCIDevice *dev) { uint8_t *cfg = dev->config + dev->exp.sriov_cap; - unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)); + if (dev->exp.sriov_pf.vf_user_created) { + uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); + uint16_t total_vfs = pci_get_word(dev->config + PCI_SRIOV_TOTAL_VF); + uint16_t vf_dev_id = pci_get_word(dev->config + PCI_SRIOV_VF_DID); + + unregister_vfs(dev); + + for (uint16_t i = 0; i < total_vfs; i++) { + dev->exp.sriov_pf.vf[i]->exp.sriov_vf.pf = NULL; + + pci_config_set_vendor_id(dev->exp.sriov_pf.vf[i]->config, ven_id); + pci_config_set_device_id(dev->exp.sriov_pf.vf[i]->config, vf_dev_id); + } + } else { + unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF)); + } } void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, @@ -156,69 +224,173 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, MemoryRegion *memory) { - PCIIORegion *r; - PCIBus *bus = pci_get_bus(dev); uint8_t type; - pcibus_t size = memory_region_size(memory); - assert(pci_is_vf(dev)); /* PFs must use pci_register_bar */ - assert(region_num >= 0); - assert(region_num < PCI_NUM_REGIONS); + assert(dev->exp.sriov_vf.pf); type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num]; - if (!is_power_of_2(size)) { - error_report("%s: PCI region size must be a power" - " of two - type=0x%x, size=0x%"FMT_PCIBUS, - __func__, type, size); - exit(1); - } - - r = &dev->io_regions[region_num]; - r->memory = memory; - r->address_space = - type & PCI_BASE_ADDRESS_SPACE_IO - ? bus->address_space_io - : bus->address_space_mem; - r->size = size; - r->type = type; - - r->addr = pci_bar_address(dev, region_num, r->type, r->size); - if (r->addr != PCI_BAR_UNMAPPED) { - memory_region_add_subregion_overlap(r->address_space, - r->addr, r->memory, 1); - } + return pci_register_bar(dev, region_num, type, memory); } -static void register_vfs(PCIDevice *dev) +static gint compare_vf_devfns(gconstpointer a, gconstpointer b) { - uint16_t num_vfs; - uint16_t i; - uint16_t sriov_cap = dev->exp.sriov_cap; - - assert(sriov_cap > 0); - num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF); - - trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn), num_vfs); - for (i = 0; i < num_vfs; i++) { - pci_set_enabled(dev->exp.sriov_pf.vf[i], true); - } - - pci_set_word(dev->wmask + sriov_cap + PCI_SRIOV_NUM_VF, 0); + return (*(PCIDevice **)a)->devfn - (*(PCIDevice **)b)->devfn; } -static void unregister_vfs(PCIDevice *dev) +int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, + uint16_t offset, + Error **errp) { - uint8_t *cfg = dev->config + dev->exp.sriov_cap; + GPtrArray *pf; + PCIDevice **vfs; + BusState *bus = qdev_get_parent_bus(DEVICE(dev)); + uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); + uint16_t vf_dev_id; + uint16_t vf_offset; + uint16_t vf_stride; uint16_t i; - trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn), - PCI_FUNC(dev->devfn)); - for (i = 0; i < pci_get_word(cfg + PCI_SRIOV_TOTAL_VF); i++) { - pci_set_enabled(dev->exp.sriov_pf.vf[i], false); + if (!pfs || !dev->qdev.id) { + return 0; } - pci_set_word(dev->wmask + dev->exp.sriov_cap + PCI_SRIOV_NUM_VF, 0xffff); + pf = g_hash_table_lookup(pfs, dev->qdev.id); + if (!pf) { + return 0; + } + + if (pf->len > UINT16_MAX) { + error_setg(errp, "too many VFs"); + return -1; + } + + g_ptr_array_sort(pf, compare_vf_devfns); + vfs = (void *)pf->pdata; + + if (vfs[0]->devfn <= dev->devfn) { + error_setg(errp, "a VF function number is less than the PF function number"); + return -1; + } + + vf_dev_id = pci_get_word(vfs[0]->config + PCI_DEVICE_ID); + vf_offset = vfs[0]->devfn - dev->devfn; + vf_stride = pf->len < 2 ? 0 : vfs[1]->devfn - vfs[0]->devfn; + + for (i = 0; i < pf->len; i++) { + if (bus != qdev_get_parent_bus(&vfs[i]->qdev)) { + error_setg(errp, "SR-IOV VF parent bus mismatches with PF"); + return -1; + } + + if (ven_id != pci_get_word(vfs[i]->config + PCI_VENDOR_ID)) { + error_setg(errp, "SR-IOV VF vendor ID mismatches with PF"); + return -1; + } + + if (vf_dev_id != pci_get_word(vfs[i]->config + PCI_DEVICE_ID)) { + error_setg(errp, "inconsistent SR-IOV VF device IDs"); + return -1; + } + + for (size_t j = 0; j < PCI_NUM_REGIONS; j++) { + if (vfs[i]->io_regions[j].size != vfs[0]->io_regions[j].size || + vfs[i]->io_regions[j].type != vfs[0]->io_regions[j].type) { + error_setg(errp, "inconsistent SR-IOV BARs"); + return -1; + } + } + + if (vfs[i]->devfn - vfs[0]->devfn != vf_stride * i) { + error_setg(errp, "inconsistent SR-IOV stride"); + return -1; + } + } + + if (!pcie_sriov_pf_init_common(dev, offset, vf_dev_id, pf->len, + pf->len, vf_offset, vf_stride, errp)) { + return -1; + } + + for (i = 0; i < pf->len; i++) { + vfs[i]->exp.sriov_vf.pf = dev; + vfs[i]->exp.sriov_vf.vf_number = i; + + /* set vid/did according to sr/iov spec - they are not used */ + pci_config_set_vendor_id(vfs[i]->config, 0xffff); + pci_config_set_device_id(vfs[i]->config, 0xffff); + } + + dev->exp.sriov_pf.vf = vfs; + dev->exp.sriov_pf.vf_user_created = true; + + for (i = 0; i < PCI_NUM_REGIONS; i++) { + PCIIORegion *region = &vfs[0]->io_regions[i]; + + if (region->size) { + pcie_sriov_pf_init_vf_bar(dev, i, region->type, region->size); + } + } + + return PCI_EXT_CAP_SRIOV_SIZEOF; +} + +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp) +{ + if (!dev->exp.sriov_pf.vf && dev->qdev.id && + pfs && g_hash_table_contains(pfs, dev->qdev.id)) { + error_setg(errp, "attaching user-created SR-IOV VF unsupported"); + return false; + } + + if (dev->sriov_pf) { + PCIDevice *pci_pf; + GPtrArray *pf; + + if (!PCI_DEVICE_GET_CLASS(dev)->sriov_vf_user_creatable) { + error_setg(errp, "user cannot create SR-IOV VF with this device type"); + return false; + } + + if (!pci_is_express(dev)) { + error_setg(errp, "PCI Express is required for SR-IOV VF"); + return false; + } + + if (!pci_qdev_find_device(dev->sriov_pf, &pci_pf)) { + error_setg(errp, "PCI device specified as SR-IOV PF already exists"); + return false; + } + + if (!pfs) { + pfs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + } + + pf = g_hash_table_lookup(pfs, dev->sriov_pf); + if (!pf) { + pf = g_ptr_array_new(); + g_hash_table_insert(pfs, g_strdup(dev->sriov_pf), pf); + } + + g_ptr_array_add(pf, dev); + } + + return true; +} + +void pcie_sriov_unregister_device(PCIDevice *dev) +{ + if (dev->sriov_pf && pfs) { + GPtrArray *pf = g_hash_table_lookup(pfs, dev->sriov_pf); + + if (pf) { + g_ptr_array_remove_fast(pf, dev); + + if (!pf->len) { + g_hash_table_remove(pfs, dev->sriov_pf); + g_ptr_array_free(pf, FALSE); + } + } + } } void pcie_sriov_config_write(PCIDevice *dev, uint32_t address, @@ -314,7 +486,7 @@ void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize) uint16_t pcie_sriov_vf_number(PCIDevice *dev) { - assert(pci_is_vf(dev)); + assert(dev->exp.sriov_vf.pf); return dev->exp.sriov_vf.vf_number; } diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h index 345b12eaac..e41d95b0b0 100644 --- a/include/hw/pci/pci_device.h +++ b/include/hw/pci/pci_device.h @@ -38,6 +38,8 @@ struct PCIDeviceClass { uint16_t subsystem_id; /* only for header type = 0 */ const char *romfile; /* rom bar */ + + bool sriov_vf_user_creatable; }; enum PCIReqIDType { @@ -177,6 +179,8 @@ struct PCIDevice { * realizing the device. */ uint32_t max_bounce_buffer_size; + + char *sriov_pf; }; static inline int pci_intx(PCIDevice *pci_dev) @@ -209,7 +213,7 @@ static inline int pci_is_express_downstream_port(const PCIDevice *d) static inline int pci_is_vf(const PCIDevice *d) { - return d->exp.sriov_vf.pf != NULL; + return d->sriov_pf || d->exp.sriov_vf.pf != NULL; } static inline uint32_t pci_config_size(const PCIDevice *d) diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h index c5d2d318d3..f75b8f22ee 100644 --- a/include/hw/pci/pcie_sriov.h +++ b/include/hw/pci/pcie_sriov.h @@ -18,6 +18,7 @@ typedef struct PCIESriovPF { uint8_t vf_bar_type[PCI_NUM_REGIONS]; /* Store type for each VF bar */ PCIDevice **vf; /* Pointer to an array of num_vfs VF devices */ + bool vf_user_created; /* If VFs are created by user */ } PCIESriovPF; typedef struct PCIESriovVF { @@ -40,6 +41,23 @@ void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num, void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, MemoryRegion *memory); +/** + * pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created + * VFs. + * @dev: A PCIe device being realized. + * @offset: The offset of the SR-IOV capability. + * @errp: pointer to Error*, to store an error if it happens. + * + * Return: The size of added capability. 0 if the user did not create VFs. + * -1 if failed. + */ +int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, + uint16_t offset, + Error **errp); + +bool pcie_sriov_register_device(PCIDevice *dev, Error **errp); +void pcie_sriov_unregister_device(PCIDevice *dev); + /* * Default (minimal) page size support values * as required by the SR/IOV standard: From 3f9cfaa92c96d604e98f16ade5af4742460e4c0f Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:55 +0900 Subject: [PATCH 0868/2760] virtio-pci: Implement SR-IOV PF Allow user to attach SR-IOV VF to a virtio-pci PF. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-6-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-pci.c | 20 +++++++++++++++----- include/hw/virtio/virtio-pci.h | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 0fa8fe4955..fee65d3645 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1962,6 +1962,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) uint8_t *config; uint32_t size; VirtIODevice *vdev = virtio_bus_get_device(bus); + int16_t res; /* * Virtio capabilities present without @@ -2109,6 +2110,14 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) pci_register_bar(&proxy->pci_dev, proxy->legacy_io_bar_idx, PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } + + res = pcie_sriov_pf_init_from_user_created_vfs(&proxy->pci_dev, + proxy->last_pcie_cap_offset, + errp); + if (res > 0) { + proxy->last_pcie_cap_offset += res; + virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); + } } static void virtio_pci_device_unplugged(DeviceState *d) @@ -2199,7 +2208,7 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) if (pcie_port && pci_is_express(pci_dev)) { int pos; - uint16_t last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE; + proxy->last_pcie_cap_offset = PCI_CONFIG_SPACE_SIZE; pos = pcie_endpoint_cap_init(pci_dev, 0); assert(pos > 0); @@ -2216,9 +2225,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3); if (proxy->flags & VIRTIO_PCI_FLAG_AER) { - pcie_aer_init(pci_dev, PCI_ERR_VER, last_pcie_cap_offset, + pcie_aer_init(pci_dev, PCI_ERR_VER, proxy->last_pcie_cap_offset, PCI_ERR_SIZEOF, NULL); - last_pcie_cap_offset += PCI_ERR_SIZEOF; + proxy->last_pcie_cap_offset += PCI_ERR_SIZEOF; } if (proxy->flags & VIRTIO_PCI_FLAG_INIT_DEVERR) { @@ -2243,9 +2252,9 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp) } if (proxy->flags & VIRTIO_PCI_FLAG_ATS) { - pcie_ats_init(pci_dev, last_pcie_cap_offset, + pcie_ats_init(pci_dev, proxy->last_pcie_cap_offset, proxy->flags & VIRTIO_PCI_FLAG_ATS_PAGE_ALIGNED); - last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF; + proxy->last_pcie_cap_offset += PCI_EXT_CAP_ATS_SIZEOF; } if (proxy->flags & VIRTIO_PCI_FLAG_INIT_FLR) { @@ -2273,6 +2282,7 @@ static void virtio_pci_exit(PCIDevice *pci_dev) !pci_bus_is_root(pci_get_bus(pci_dev)); bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY; + pcie_sriov_pf_exit(&proxy->pci_dev); msix_uninit_exclusive_bar(pci_dev); if (proxy->flags & VIRTIO_PCI_FLAG_AER && pcie_port && pci_is_express(pci_dev)) { diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 31ec144509..1dbc3851b0 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -155,6 +155,7 @@ struct VirtIOPCIProxy { uint32_t modern_io_bar_idx; uint32_t modern_mem_bar_idx; int config_cap; + uint16_t last_pcie_cap_offset; uint32_t flags; bool disable_modern; bool ignore_backend_features; From 49f7cb18db0790f7f32cb85dc35ffc25e44a828b Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:56 +0900 Subject: [PATCH 0869/2760] virtio-net: Implement SR-IOV VF A virtio-net device can be added as a SR-IOV VF to another virtio-pci device that will be the PF. Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-7-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio-net-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c index 8cf9788bc3..f857a84f11 100644 --- a/hw/virtio/virtio-net-pci.c +++ b/hw/virtio/virtio-net-pci.c @@ -74,6 +74,7 @@ static void virtio_net_pci_class_init(ObjectClass *klass, const void *data) k->device_id = PCI_DEVICE_ID_VIRTIO_NET; k->revision = VIRTIO_PCI_ABI_VERSION; k->class_id = PCI_CLASS_NETWORK_ETHERNET; + k->sriov_vf_user_creatable = true; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); device_class_set_props(dc, virtio_net_properties); vpciklass->realize = virtio_net_pci_realize; From 6f9bebf1dc6b54b63be739ea247b3942f841b9e3 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:57 +0900 Subject: [PATCH 0870/2760] docs: Document composable SR-IOV device Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-8-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 1 + docs/system/index.rst | 1 + docs/system/sriov.rst | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) create mode 100644 docs/system/sriov.rst diff --git a/MAINTAINERS b/MAINTAINERS index 6dacd6d004..b579358cdd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2058,6 +2058,7 @@ F: hw/pci-bridge/* F: qapi/pci.json F: docs/pci* F: docs/specs/*pci* +F: docs/system/sriov.rst PCIE DOE M: Huai-Cheng Kuo diff --git a/docs/system/index.rst b/docs/system/index.rst index c21065e519..718e9d3c56 100644 --- a/docs/system/index.rst +++ b/docs/system/index.rst @@ -39,3 +39,4 @@ or Hypervisor.Framework. multi-process confidential-guest-support vm-templating + sriov diff --git a/docs/system/sriov.rst b/docs/system/sriov.rst new file mode 100644 index 0000000000..a851a66a4b --- /dev/null +++ b/docs/system/sriov.rst @@ -0,0 +1,36 @@ +.. SPDX-License-Identifier: GPL-2.0-or-later + +Compsable SR-IOV device +======================= + +SR-IOV (Single Root I/O Virtualization) is an optional extended capability of a +PCI Express device. It allows a single physical function (PF) to appear as +multiple virtual functions (VFs) for the main purpose of eliminating software +overhead in I/O from virtual machines. + +There are devices with predefined SR-IOV configurations, but it is also possible +to compose an SR-IOV device yourself. Composing an SR-IOV device is currently +only supported by virtio-net-pci. + +Users can configure an SR-IOV-capable virtio-net device by adding +virtio-net-pci functions to a bus. Below is a command line example: + +.. code-block:: shell + + -netdev user,id=n -netdev user,id=o + -netdev user,id=p -netdev user,id=q + -device pcie-root-port,id=b + -device virtio-net-pci,bus=b,addr=0x0.0x3,netdev=q,sriov-pf=f + -device virtio-net-pci,bus=b,addr=0x0.0x2,netdev=p,sriov-pf=f + -device virtio-net-pci,bus=b,addr=0x0.0x1,netdev=o,sriov-pf=f + -device virtio-net-pci,bus=b,addr=0x0.0x0,netdev=n,id=f + +The VFs specify the paired PF with ``sriov-pf`` property. The PF must be +added after all VFs. It is the user's responsibility to ensure that VFs have +function numbers larger than one of the PF, and that the function numbers +have a consistent stride. + +You may also need to perform additional steps to activate the SR-IOV feature on +your guest. For Linux, refer to [1]_. + +.. [1] https://docs.kernel.org/PCI/pci-iov-howto.html From d0c280d3fac644c26a86d2fb70c5920b3d5bef85 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Fri, 14 Mar 2025 15:14:58 +0900 Subject: [PATCH 0871/2760] pcie_sriov: Make a PCI device with user-created VF ARI-capable Signed-off-by: Akihiko Odaki Message-Id: <20250314-sriov-v9-9-57dae8ae3ab5@daynix.com> Tested-by: Yui Washizu Tested-by: Pasha Tatashin Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- docs/system/sriov.rst | 3 ++- hw/pci/pcie_sriov.c | 8 +++++++- hw/virtio/virtio-pci.c | 16 ++++++++++------ include/hw/pci/pcie_sriov.h | 7 +++++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/system/sriov.rst b/docs/system/sriov.rst index a851a66a4b..d12178f3c3 100644 --- a/docs/system/sriov.rst +++ b/docs/system/sriov.rst @@ -28,7 +28,8 @@ virtio-net-pci functions to a bus. Below is a command line example: The VFs specify the paired PF with ``sriov-pf`` property. The PF must be added after all VFs. It is the user's responsibility to ensure that VFs have function numbers larger than one of the PF, and that the function numbers -have a consistent stride. +have a consistent stride. Both the PF and VFs are ARI-capable so you can have +255 VFs at maximum. You may also need to perform additional steps to activate the SR-IOV feature on your guest. For Linux, refer to [1]_. diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c index 08f707e847..3ad18744f4 100644 --- a/hw/pci/pcie_sriov.c +++ b/hw/pci/pcie_sriov.c @@ -245,6 +245,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, PCIDevice **vfs; BusState *bus = qdev_get_parent_bus(DEVICE(dev)); uint16_t ven_id = pci_get_word(dev->config + PCI_VENDOR_ID); + uint16_t size = PCI_EXT_CAP_SRIOV_SIZEOF; uint16_t vf_dev_id; uint16_t vf_offset; uint16_t vf_stride; @@ -311,6 +312,11 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, return -1; } + if (!pcie_find_capability(dev, PCI_EXT_CAP_ID_ARI)) { + pcie_ari_init(dev, offset + size); + size += PCI_ARI_SIZEOF; + } + for (i = 0; i < pf->len; i++) { vfs[i]->exp.sriov_vf.pf = dev; vfs[i]->exp.sriov_vf.vf_number = i; @@ -331,7 +337,7 @@ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, } } - return PCI_EXT_CAP_SRIOV_SIZEOF; + return size; } bool pcie_sriov_register_device(PCIDevice *dev, Error **errp) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index fee65d3645..9b48aa8c3e 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2111,12 +2111,16 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp) PCI_BASE_ADDRESS_SPACE_IO, &proxy->bar); } - res = pcie_sriov_pf_init_from_user_created_vfs(&proxy->pci_dev, - proxy->last_pcie_cap_offset, - errp); - if (res > 0) { - proxy->last_pcie_cap_offset += res; - virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); + if (pci_is_vf(&proxy->pci_dev)) { + pcie_ari_init(&proxy->pci_dev, proxy->last_pcie_cap_offset); + proxy->last_pcie_cap_offset += PCI_ARI_SIZEOF; + } else { + res = pcie_sriov_pf_init_from_user_created_vfs( + &proxy->pci_dev, proxy->last_pcie_cap_offset, errp); + if (res > 0) { + proxy->last_pcie_cap_offset += res; + virtio_add_feature(&vdev->host_features, VIRTIO_F_SR_IOV); + } } } diff --git a/include/hw/pci/pcie_sriov.h b/include/hw/pci/pcie_sriov.h index f75b8f22ee..aeaa38cf34 100644 --- a/include/hw/pci/pcie_sriov.h +++ b/include/hw/pci/pcie_sriov.h @@ -43,12 +43,15 @@ void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num, /** * pcie_sriov_pf_init_from_user_created_vfs() - Initialize PF with user-created - * VFs. + * VFs, adding ARI to PF * @dev: A PCIe device being realized. * @offset: The offset of the SR-IOV capability. * @errp: pointer to Error*, to store an error if it happens. * - * Return: The size of added capability. 0 if the user did not create VFs. + * Initializes a PF with user-created VFs, adding the ARI extended capability to + * the PF. The VFs should call pcie_ari_init() to form an ARI device. + * + * Return: The size of added capabilities. 0 if the user did not create VFs. * -1 if failed. */ int16_t pcie_sriov_pf_init_from_user_created_vfs(PCIDevice *dev, From 8717987fb528ff704e275a1a99f59a20e0b272f5 Mon Sep 17 00:00:00 2001 From: Stephen Bates Date: Tue, 15 Apr 2025 10:29:56 -0600 Subject: [PATCH 0872/2760] pci-testdev.c: Add membar-backed option for backing membar The pci-testdev device allows for an optional BAR. We have historically used this without backing to test that systems and OSes can accomodate large PCI BARs. However to help test p2pdma operations it is helpful to add an option to back this BAR with host memory. We add a membar-backed boolean parameter and when set to true or on we do a host RAM backing. The default is false which ensures backward compatability. Signed-off-by: Stephen Bates Message-Id: Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/misc/pci-testdev.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/misc/pci-testdev.c b/hw/misc/pci-testdev.c index 3f6a8bba84..ba71c5069f 100644 --- a/hw/misc/pci-testdev.c +++ b/hw/misc/pci-testdev.c @@ -90,6 +90,7 @@ struct PCITestDevState { int current; uint64_t membar_size; + bool membar_backed; MemoryRegion membar; }; @@ -258,8 +259,14 @@ static void pci_testdev_realize(PCIDevice *pci_dev, Error **errp) pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &d->portio); if (d->membar_size) { - memory_region_init(&d->membar, OBJECT(d), "pci-testdev-membar", - d->membar_size); + if (d->membar_backed) + memory_region_init_ram(&d->membar, OBJECT(d), + "pci-testdev-membar-backed", + d->membar_size, NULL); + else + memory_region_init(&d->membar, OBJECT(d), + "pci-testdev-membar", + d->membar_size); pci_register_bar(pci_dev, 2, PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH | @@ -321,6 +328,7 @@ static void qdev_pci_testdev_reset(DeviceState *dev) static const Property pci_testdev_properties[] = { DEFINE_PROP_SIZE("membar", PCITestDevState, membar_size, 0), + DEFINE_PROP_BOOL("membar-backed", PCITestDevState, membar_backed, false), }; static void pci_testdev_class_init(ObjectClass *klass, const void *data) From e0f300b36da1ee794fd81aa95f56e7bc9f010d46 Mon Sep 17 00:00:00 2001 From: Haoqian He Date: Tue, 15 Apr 2025 22:47:26 -0400 Subject: [PATCH 0873/2760] system/runstate: add VM state change cb with return value This patch adds the new VM state change cb type `VMChangeStateHandlerWithRet`, which has return value for `VMChangeStateEntry`. Thus, we can register a new VM state change cb with return value for device. Note that `VMChangeStateHandler` and `VMChangeStateHandlerWithRet` are mutually exclusive and cannot be provided at the same time. This patch is the pre patch for 'vhost-user: return failure if backend crashes when live migration', which makes the live migration aware of the loss of connection with the vhost-user backend and aborts the live migration. Virtio device will use VMChangeStateHandlerWithRet. Signed-off-by: Haoqian He Message-Id: <20250416024729.3289157-2-haoqian.he@smartx.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/block/virtio-blk.c | 2 +- hw/core/vm-change-state-handler.c | 18 ++++++++++------ hw/scsi/scsi-bus.c | 2 +- hw/vfio/migration.c | 2 +- hw/virtio/virtio.c | 2 +- include/system/runstate.h | 13 +++++++++--- system/cpus.c | 8 +++++-- system/runstate.c | 35 ++++++++++++++++++++++++++----- 8 files changed, 62 insertions(+), 20 deletions(-) diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index b54d01d3a2..ea948d18fd 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1802,7 +1802,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp) * called after ->start_ioeventfd() has already set blk's AioContext. */ s->change = - qdev_add_vm_change_state_handler(dev, virtio_blk_dma_restart_cb, s); + qdev_add_vm_change_state_handler(dev, virtio_blk_dma_restart_cb, NULL, s); blk_ram_registrar_init(&s->blk_ram_registrar, s->blk); blk_set_dev_ops(s->blk, &virtio_block_ops, s); diff --git a/hw/core/vm-change-state-handler.c b/hw/core/vm-change-state-handler.c index 7064995578..99c642b558 100644 --- a/hw/core/vm-change-state-handler.c +++ b/hw/core/vm-change-state-handler.c @@ -40,6 +40,7 @@ static int qdev_get_dev_tree_depth(DeviceState *dev) * qdev_add_vm_change_state_handler: * @dev: the device that owns this handler * @cb: the callback function to be invoked + * @cb_ret: the callback function with return value to be invoked * @opaque: user data passed to the callback function * * This function works like qemu_add_vm_change_state_handler() except callbacks @@ -50,25 +51,30 @@ static int qdev_get_dev_tree_depth(DeviceState *dev) * controller's callback is invoked before the children on its bus when the VM * starts running. The order is reversed when the VM stops running. * + * Note that the parameter `cb` and `cb_ret` are mutually exclusive. + * * Returns: an entry to be freed with qemu_del_vm_change_state_handler() */ VMChangeStateEntry *qdev_add_vm_change_state_handler(DeviceState *dev, VMChangeStateHandler *cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque) { - return qdev_add_vm_change_state_handler_full(dev, cb, NULL, opaque); + assert(!cb || !cb_ret); + return qdev_add_vm_change_state_handler_full(dev, cb, NULL, cb_ret, opaque); } /* * Exactly like qdev_add_vm_change_state_handler() but passes a prepare_cb - * argument too. + * and the cb_ret arguments too. */ VMChangeStateEntry *qdev_add_vm_change_state_handler_full( - DeviceState *dev, VMChangeStateHandler *cb, - VMChangeStateHandler *prepare_cb, void *opaque) + DeviceState *dev, VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque) { int depth = qdev_get_dev_tree_depth(dev); - return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, opaque, - depth); + assert(!cb || !cb_ret); + return qemu_add_vm_change_state_handler_prio_full(cb, prepare_cb, cb_ret, + opaque, depth); } diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index 70be4a7367..9b12ee7f1c 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -400,7 +400,7 @@ static void scsi_qdev_realize(DeviceState *qdev, Error **errp) return; } dev->vmsentry = qdev_add_vm_change_state_handler(DEVICE(dev), - scsi_dma_restart_cb, dev); + scsi_dma_restart_cb, NULL, dev); } static void scsi_qdev_unrealize(DeviceState *qdev) diff --git a/hw/vfio/migration.c b/hw/vfio/migration.c index 1dceab1b19..b76697bd1a 100644 --- a/hw/vfio/migration.c +++ b/hw/vfio/migration.c @@ -1016,7 +1016,7 @@ static int vfio_migration_init(VFIODevice *vbasedev) vfio_vmstate_change_prepare : NULL; migration->vm_state = qdev_add_vm_change_state_handler_full( - vbasedev->dev, vfio_vmstate_change, prepare_cb, vbasedev); + vbasedev->dev, vfio_vmstate_change, prepare_cb, NULL, vbasedev); migration_add_notifier(&migration->migration_state, vfio_migration_state_notifier); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 480c2e5036..e3b62522ec 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -3489,7 +3489,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size) vdev->config = NULL; } vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), - virtio_vmstate_change, vdev); + virtio_vmstate_change, NULL, vdev); vdev->device_endian = virtio_default_endian(); vdev->use_guest_notifier_mask = true; } diff --git a/include/system/runstate.h b/include/system/runstate.h index bffc3719d4..fdd5c4a517 100644 --- a/include/system/runstate.h +++ b/include/system/runstate.h @@ -12,6 +12,7 @@ bool runstate_needs_reset(void); void runstate_replay_enable(void); typedef void VMChangeStateHandler(void *opaque, bool running, RunState state); +typedef int VMChangeStateHandlerWithRet(void *opaque, bool running, RunState state); VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, void *opaque); @@ -20,21 +21,27 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( VMChangeStateEntry * qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque, int priority); VMChangeStateEntry *qdev_add_vm_change_state_handler(DeviceState *dev, VMChangeStateHandler *cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque); VMChangeStateEntry *qdev_add_vm_change_state_handler_full( - DeviceState *dev, VMChangeStateHandler *cb, - VMChangeStateHandler *prepare_cb, void *opaque); + DeviceState *dev, VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque); void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); /** * vm_state_notify: Notify the state of the VM * * @running: whether the VM is running or not. * @state: the #RunState of the VM. + * + * Return the result of the callback which has return value. + * If no callback has return value, still return 0 and the + * upper layer should not do additional processing. */ -void vm_state_notify(bool running, RunState state); +int vm_state_notify(bool running, RunState state); static inline bool shutdown_caused_by_guest(ShutdownCause cause) { diff --git a/system/cpus.c b/system/cpus.c index 2cc5f887ab..d16b0dff98 100644 --- a/system/cpus.c +++ b/system/cpus.c @@ -299,14 +299,18 @@ static int do_vm_stop(RunState state, bool send_stop) if (oldstate == RUN_STATE_RUNNING) { pause_all_vcpus(); } - vm_state_notify(0, state); + ret = vm_state_notify(0, state); if (send_stop) { qapi_event_send_stop(); } } bdrv_drain_all(); - ret = bdrv_flush_all(); + /* + * Even if vm_state_notify() return failure, + * it would be better to flush as before. + */ + ret |= bdrv_flush_all(); trace_vm_stop_flush_all(ret); return ret; diff --git a/system/runstate.c b/system/runstate.c index 272801d307..de74d962bc 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -297,6 +297,7 @@ void qemu_system_vmstop_request(RunState state) struct VMChangeStateEntry { VMChangeStateHandler *cb; VMChangeStateHandler *prepare_cb; + VMChangeStateHandlerWithRet *cb_ret; void *opaque; QTAILQ_ENTRY(VMChangeStateEntry) entries; int priority; @@ -320,14 +321,15 @@ static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head = VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( VMChangeStateHandler *cb, void *opaque, int priority) { - return qemu_add_vm_change_state_handler_prio_full(cb, NULL, opaque, - priority); + return qemu_add_vm_change_state_handler_prio_full(cb, NULL, NULL, + opaque, priority); } /** * qemu_add_vm_change_state_handler_prio_full: * @cb: the main callback to invoke * @prepare_cb: a callback to invoke before the main callback + * @cb_ret: the main callback to invoke with return value * @opaque: user data passed to the callbacks * @priority: low priorities execute first when the vm runs and the reverse is * true when the vm stops @@ -344,6 +346,7 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler_prio( VMChangeStateEntry * qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb, VMChangeStateHandler *prepare_cb, + VMChangeStateHandlerWithRet *cb_ret, void *opaque, int priority) { VMChangeStateEntry *e; @@ -352,6 +355,7 @@ qemu_add_vm_change_state_handler_prio_full(VMChangeStateHandler *cb, e = g_malloc0(sizeof(*e)); e->cb = cb; e->prepare_cb = prepare_cb; + e->cb_ret = cb_ret; e->opaque = opaque; e->priority = priority; @@ -379,9 +383,10 @@ void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) g_free(e); } -void vm_state_notify(bool running, RunState state) +int vm_state_notify(bool running, RunState state) { VMChangeStateEntry *e, *next; + int ret = 0; trace_vm_state_notify(running, state, RunState_str(state)); @@ -393,7 +398,17 @@ void vm_state_notify(bool running, RunState state) } QTAILQ_FOREACH_SAFE(e, &vm_change_state_head, entries, next) { - e->cb(e->opaque, running, state); + if (e->cb) { + e->cb(e->opaque, running, state); + } else if (e->cb_ret) { + /* + * Here ignore the return value of cb_ret because + * we only care about the stopping the device during + * the VM live migration to indicate whether the + * connection between qemu and backend is normal. + */ + e->cb_ret(e->opaque, running, state); + } } } else { QTAILQ_FOREACH_REVERSE_SAFE(e, &vm_change_state_head, entries, next) { @@ -403,9 +418,19 @@ void vm_state_notify(bool running, RunState state) } QTAILQ_FOREACH_REVERSE_SAFE(e, &vm_change_state_head, entries, next) { - e->cb(e->opaque, running, state); + if (e->cb) { + e->cb(e->opaque, running, state); + } else if (e->cb_ret) { + /* + * We should execute all registered callbacks even if + * one of them returns failure, otherwise, some cleanup + * work of the device will be skipped. + */ + ret |= e->cb_ret(e->opaque, running, state); + } } } + return ret; } static ShutdownCause reset_requested; From 5a317017b827e338358792cd07663f8ea25f1ffe Mon Sep 17 00:00:00 2001 From: Haoqian He Date: Tue, 15 Apr 2025 22:47:27 -0400 Subject: [PATCH 0874/2760] vhost: return failure if stop virtqueue failed in vhost_dev_stop This patch captures the error of vhost_virtqueue_stop() in vhost_dev_stop() and returns the error upward. Specifically, if QEMU is disconnected from the vhost backend, some actions in vhost_dev_stop() will fail, such as sending vhost-user messages to the backend (GET_VRING_BASE, SET_VRING_ENABLE) and vhost_reset_status. Considering that both set_vring_enable and vhost_reset_status require setting the specific virtio feature bit, we can capture vhost_virtqueue_stop()'s error to indicate that QEMU has lost connection with the backend. This patch is the pre patch for 'vhost-user: return failure if backend crashes when live migration', which makes the live migration aware of the loss of connection with the vhost-user backend and aborts the live migration. Signed-off-by: Haoqian He Message-Id: <20250416024729.3289157-3-haoqian.he@smartx.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost.c | 23 +++++++++++++---------- include/hw/virtio/vhost.h | 8 +++++--- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c index 4cae7c1664..fc43853704 100644 --- a/hw/virtio/vhost.c +++ b/hw/virtio/vhost.c @@ -1367,10 +1367,10 @@ fail_alloc_desc: return r; } -void vhost_virtqueue_stop(struct vhost_dev *dev, - struct VirtIODevice *vdev, - struct vhost_virtqueue *vq, - unsigned idx) +int vhost_virtqueue_stop(struct vhost_dev *dev, + struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, + unsigned idx) { int vhost_vq_index = dev->vhost_ops->vhost_get_vq_index(dev, idx); struct vhost_vring_state state = { @@ -1380,7 +1380,7 @@ void vhost_virtqueue_stop(struct vhost_dev *dev, if (virtio_queue_get_desc_addr(vdev, idx) == 0) { /* Don't stop the virtqueue which might have not been started */ - return; + return 0; } r = dev->vhost_ops->vhost_get_vring_base(dev, &state); @@ -1411,6 +1411,7 @@ void vhost_virtqueue_stop(struct vhost_dev *dev, 0, virtio_queue_get_avail_size(vdev, idx)); vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx), 0, virtio_queue_get_desc_size(vdev, idx)); + return r; } static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev, @@ -2135,9 +2136,10 @@ fail_features: } /* Host notifiers must be enabled at this point. */ -void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) +int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) { int i; + int rc = 0; /* should only be called after backend is connected */ assert(hdev->vhost_ops); @@ -2156,10 +2158,10 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) vhost_dev_set_vring_enable(hdev, false); } for (i = 0; i < hdev->nvqs; ++i) { - vhost_virtqueue_stop(hdev, - vdev, - hdev->vqs + i, - hdev->vq_index + i); + rc |= vhost_virtqueue_stop(hdev, + vdev, + hdev->vqs + i, + hdev->vq_index + i); } if (hdev->vhost_ops->vhost_reset_status) { hdev->vhost_ops->vhost_reset_status(hdev); @@ -2176,6 +2178,7 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings) hdev->started = false; vdev->vhost_started = false; hdev->vdev = NULL; + return rc; } int vhost_net_set_backend(struct vhost_dev *hdev, diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h index bb4b58e115..38800a7156 100644 --- a/include/hw/virtio/vhost.h +++ b/include/hw/virtio/vhost.h @@ -232,8 +232,10 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); * Stop the vhost device. After the device is stopped the notifiers * can be disabled (@vhost_dev_disable_notifiers) and the device can * be torn down (@vhost_dev_cleanup). + * + * Return: 0 on success, != 0 on error when stopping dev. */ -void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); +int vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev, bool vrings); /** * DOC: vhost device configuration handling @@ -333,8 +335,8 @@ int vhost_device_iotlb_miss(struct vhost_dev *dev, uint64_t iova, int write); int vhost_virtqueue_start(struct vhost_dev *dev, struct VirtIODevice *vdev, struct vhost_virtqueue *vq, unsigned idx); -void vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev, - struct vhost_virtqueue *vq, unsigned idx); +int vhost_virtqueue_stop(struct vhost_dev *dev, struct VirtIODevice *vdev, + struct vhost_virtqueue *vq, unsigned idx); void vhost_dev_reset_inflight(struct vhost_inflight *inflight); void vhost_dev_free_inflight(struct vhost_inflight *inflight); From bc85aae4204509420f0a4403ca728801170d9351 Mon Sep 17 00:00:00 2001 From: Haoqian He Date: Tue, 15 Apr 2025 22:47:28 -0400 Subject: [PATCH 0875/2760] vhost-user: return failure if backend crash when live migration Live migration should be terminated if the vhost-user backend crashes before the migration completes. Specifically, since the vhost device will be stopped when VM is stopped before the end of the live migration, in current implementation if the backend crashes, vhost-user device set_status() won't return failure, live migration won't perceive the disconnection between QEMU and the backend. When the VM is migrated to the destination, the inflight IO will be resubmitted, and if the IO was completed out of order before, it will cause IO error. To fix this issue: 1. Add the return value to set_status() for VirtioDeviceClass. a. For the vhost-user device, return failure when the backend crashes. b. For other virtio devices, always return 0. 2. Return failure if vhost_dev_stop() failed for vhost-user device. If QEMU loses connection with the vhost-user backend, virtio set_status() can return failure to the upper layer, migration_completion() can handle the error, terminate the live migration, and restore the VM, so that inflight IO can be completed normally. Signed-off-by: Haoqian He Message-Id: <20250416024729.3289157-4-haoqian.he@smartx.com> Tested-by: Lei Yang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- backends/vhost-user.c | 20 +++++++++---------- hw/block/vhost-user-blk.c | 27 ++++++++++++++------------ hw/block/virtio-blk.c | 5 +++-- hw/char/virtio-serial-bus.c | 3 ++- hw/display/vhost-user-gpu.c | 12 +++++++++--- hw/input/virtio-input.c | 3 ++- hw/net/virtio-net.c | 3 ++- hw/scsi/vhost-scsi-common.c | 13 +++++++------ hw/scsi/vhost-scsi.c | 5 +++-- hw/scsi/vhost-user-scsi.c | 18 ++++++++++------- hw/virtio/vdpa-dev.c | 5 +++-- hw/virtio/vhost-user-base.c | 23 +++++++++++++--------- hw/virtio/vhost-user-fs.c | 23 +++++++++++++--------- hw/virtio/vhost-user-scmi.c | 27 +++++++++++++++----------- hw/virtio/vhost-user-vsock.c | 15 +++++++++----- hw/virtio/vhost-vsock-common.c | 12 ++++++------ hw/virtio/vhost-vsock.c | 11 ++++++----- hw/virtio/virtio-balloon.c | 3 ++- hw/virtio/virtio-crypto.c | 3 ++- hw/virtio/virtio-iommu.c | 3 ++- hw/virtio/virtio-rng.c | 5 +++-- hw/virtio/virtio.c | 22 ++++++++++++++------- include/hw/virtio/vhost-scsi-common.h | 2 +- include/hw/virtio/vhost-vsock-common.h | 2 +- include/hw/virtio/virtio.h | 2 +- include/system/vhost-user-backend.h | 2 +- 26 files changed, 160 insertions(+), 109 deletions(-) diff --git a/backends/vhost-user.c b/backends/vhost-user.c index 94274a619d..42845329e7 100644 --- a/backends/vhost-user.c +++ b/backends/vhost-user.c @@ -97,30 +97,28 @@ err_host_notifiers: vhost_dev_disable_notifiers(&b->dev, b->vdev); } -void +int vhost_user_backend_stop(VhostUserBackend *b) { BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(b->vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); - int ret = 0; + int ret; if (!b->started) { - return; + return 0; } - vhost_dev_stop(&b->dev, b->vdev, true); + ret = vhost_dev_stop(&b->dev, b->vdev, true); - if (k->set_guest_notifiers) { - ret = k->set_guest_notifiers(qbus->parent, - b->dev.nvqs, false); - if (ret < 0) { - error_report("vhost guest notifier cleanup failed: %d", ret); - } + if (k->set_guest_notifiers && + k->set_guest_notifiers(qbus->parent, b->dev.nvqs, false) < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return -1; } - assert(ret >= 0); vhost_dev_disable_notifiers(&b->dev, b->vdev); b->started = false; + return ret; } static void set_chardev(Object *obj, const char *value, Error **errp) diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c index 4bb5ed299e..0eebbcd80d 100644 --- a/hw/block/vhost-user-blk.c +++ b/hw/block/vhost-user-blk.c @@ -204,7 +204,7 @@ err_host_notifiers: return ret; } -static void vhost_user_blk_stop(VirtIODevice *vdev) +static int vhost_user_blk_stop(VirtIODevice *vdev) { VHostUserBlk *s = VHOST_USER_BLK(vdev); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -212,26 +212,26 @@ static void vhost_user_blk_stop(VirtIODevice *vdev) int ret; if (!s->started_vu) { - return; + return 0; } s->started_vu = false; if (!k->set_guest_notifiers) { - return; + return 0; } - vhost_dev_stop(&s->dev, vdev, true); + ret = vhost_dev_stop(&s->dev, vdev, true); - ret = k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false); - if (ret < 0) { + if (k->set_guest_notifiers(qbus->parent, s->dev.nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); - return; + return -1; } vhost_dev_disable_notifiers(&s->dev, vdev); + return ret; } -static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) +static int vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserBlk *s = VHOST_USER_BLK(vdev); bool should_start = virtio_device_should_start(vdev, status); @@ -239,11 +239,11 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) int ret; if (!s->connected) { - return; + return -1; } if (vhost_dev_is_started(&s->dev) == should_start) { - return; + return 0; } if (should_start) { @@ -253,9 +253,12 @@ static void vhost_user_blk_set_status(VirtIODevice *vdev, uint8_t status) qemu_chr_fe_disconnect(&s->chardev); } } else { - vhost_user_blk_stop(vdev); + ret = vhost_user_blk_stop(vdev); + if (ret < 0) { + return ret; + } } - + return 0; } static uint64_t vhost_user_blk_get_features(VirtIODevice *vdev, diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index ea948d18fd..9bab2716c1 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -1270,7 +1270,7 @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features, return features; } -static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) +static int virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) { VirtIOBlock *s = VIRTIO_BLK(vdev); @@ -1279,7 +1279,7 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) } if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { - return; + return 0; } /* A guest that supports VIRTIO_BLK_F_CONFIG_WCE must be able to send @@ -1302,6 +1302,7 @@ static void virtio_blk_set_status(VirtIODevice *vdev, uint8_t status) virtio_vdev_has_feature(vdev, VIRTIO_BLK_F_WCE)); } + return 0; } static void virtio_blk_save_device(VirtIODevice *vdev, QEMUFile *f) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index eb79f5258b..673c50f0be 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -622,7 +622,7 @@ static void guest_reset(VirtIOSerial *vser) } } -static void set_status(VirtIODevice *vdev, uint8_t status) +static int set_status(VirtIODevice *vdev, uint8_t status) { VirtIOSerial *vser; VirtIOSerialPort *port; @@ -650,6 +650,7 @@ static void set_status(VirtIODevice *vdev, uint8_t status) vsc->enable_backend(port, vdev->vm_running); } } + return 0; } static void vser_reset(VirtIODevice *vdev) diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c index 43d4c08a2e..9fc6bbcd2c 100644 --- a/hw/display/vhost-user-gpu.c +++ b/hw/display/vhost-user-gpu.c @@ -516,7 +516,7 @@ vhost_user_gpu_set_config(VirtIODevice *vdev, } } -static void +static int vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val) { VhostUserGPU *g = VHOST_USER_GPU(vdev); @@ -525,18 +525,24 @@ vhost_user_gpu_set_status(VirtIODevice *vdev, uint8_t val) if (val & VIRTIO_CONFIG_S_DRIVER_OK && vdev->vm_running) { if (!vhost_user_gpu_do_set_socket(g, &err)) { error_report_err(err); - return; + return 0; } vhost_user_backend_start(g->vhost); } else { + int ret; + /* unblock any wait and stop processing */ if (g->vhost_gpu_fd != -1) { vhost_user_gpu_update_blocked(g, true); qemu_chr_fe_deinit(&g->vhost_chr, true); g->vhost_gpu_fd = -1; } - vhost_user_backend_stop(g->vhost); + ret = vhost_user_backend_stop(g->vhost); + if (ret < 0) { + return ret; + } } + return 0; } static bool diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c index 1818cbddc7..a3f554f211 100644 --- a/hw/input/virtio-input.c +++ b/hw/input/virtio-input.c @@ -189,7 +189,7 @@ static uint64_t virtio_input_get_features(VirtIODevice *vdev, uint64_t f, return f; } -static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val) +static int virtio_input_set_status(VirtIODevice *vdev, uint8_t val) { VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev); VirtIOInput *vinput = VIRTIO_INPUT(vdev); @@ -202,6 +202,7 @@ static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val) } } } + return 0; } static void virtio_input_reset(VirtIODevice *vdev) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 2de037c273..221252e00a 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -382,7 +382,7 @@ static void virtio_net_drop_tx_queue_data(VirtIODevice *vdev, VirtQueue *vq) } } -static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) +static int virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) { VirtIONet *n = VIRTIO_NET(vdev); VirtIONetQueue *q; @@ -437,6 +437,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status) } } } + return 0; } static void virtio_net_set_link_status(NetClientState *nc) diff --git a/hw/scsi/vhost-scsi-common.c b/hw/scsi/vhost-scsi-common.c index 4c8637045d..43525ba46d 100644 --- a/hw/scsi/vhost-scsi-common.c +++ b/hw/scsi/vhost-scsi-common.c @@ -101,24 +101,25 @@ err_host_notifiers: return ret; } -void vhost_scsi_common_stop(VHostSCSICommon *vsc) +int vhost_scsi_common_stop(VHostSCSICommon *vsc) { VirtIODevice *vdev = VIRTIO_DEVICE(vsc); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus); int ret = 0; - vhost_dev_stop(&vsc->dev, vdev, true); + ret = vhost_dev_stop(&vsc->dev, vdev, true); if (k->set_guest_notifiers) { - ret = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); - if (ret < 0) { - error_report("vhost guest notifier cleanup failed: %d", ret); + int r = k->set_guest_notifiers(qbus->parent, vsc->dev.nvqs, false); + if (r < 0) { + error_report("vhost guest notifier cleanup failed: %d", ret); + return r; } } - assert(ret >= 0); vhost_dev_disable_notifiers(&vsc->dev, vdev); + return ret; } uint64_t vhost_scsi_common_get_features(VirtIODevice *vdev, uint64_t features, diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 10fde8eee0..dd4250ebe8 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -114,7 +114,7 @@ static void vhost_scsi_stop(VHostSCSI *s) vhost_scsi_common_stop(vsc); } -static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) +static int vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) { VHostSCSI *s = VHOST_SCSI(vdev); VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); @@ -125,7 +125,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) } if (vhost_dev_is_started(&vsc->dev) == start) { - return; + return 0; } if (start) { @@ -139,6 +139,7 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) } else { vhost_scsi_stop(s); } + return 0; } static void vhost_dummy_handle_output(VirtIODevice *vdev, VirtQueue *vq) diff --git a/hw/scsi/vhost-user-scsi.c b/hw/scsi/vhost-user-scsi.c index 8298e8cc6d..25f2d894e7 100644 --- a/hw/scsi/vhost-user-scsi.c +++ b/hw/scsi/vhost-user-scsi.c @@ -52,19 +52,19 @@ static int vhost_user_scsi_start(VHostUserSCSI *s, Error **errp) return ret; } -static void vhost_user_scsi_stop(VHostUserSCSI *s) +static int vhost_user_scsi_stop(VHostUserSCSI *s) { VHostSCSICommon *vsc = VHOST_SCSI_COMMON(s); if (!s->started_vu) { - return; + return 0; } s->started_vu = false; - vhost_scsi_common_stop(vsc); + return vhost_scsi_common_stop(vsc); } -static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) +static int vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserSCSI *s = (VHostUserSCSI *)vdev; DeviceState *dev = DEVICE(vdev); @@ -75,11 +75,11 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) int ret; if (!s->connected) { - return; + return -1; } if (vhost_dev_is_started(&vsc->dev) == should_start) { - return; + return 0; } if (should_start) { @@ -91,8 +91,12 @@ static void vhost_user_scsi_set_status(VirtIODevice *vdev, uint8_t status) qemu_chr_fe_disconnect(&vs->conf.chardev); } } else { - vhost_user_scsi_stop(s); + ret = vhost_user_scsi_stop(s); + if (ret) { + return ret; + } } + return 0; } static void vhost_user_scsi_handle_output(VirtIODevice *vdev, VirtQueue *vq) diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c index dd8837ce4e..d1da40afc8 100644 --- a/hw/virtio/vdpa-dev.c +++ b/hw/virtio/vdpa-dev.c @@ -312,7 +312,7 @@ static void vhost_vdpa_device_stop(VirtIODevice *vdev) vhost_dev_disable_notifiers(&s->dev, vdev); } -static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) +static int vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) { VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev); bool should_start = virtio_device_started(vdev, status); @@ -324,7 +324,7 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) } if (s->started == should_start) { - return; + return 0; } if (should_start) { @@ -335,6 +335,7 @@ static void vhost_vdpa_device_set_status(VirtIODevice *vdev, uint8_t status) } else { vhost_vdpa_device_stop(vdev); } + return 0; } static const Property vhost_vdpa_device_properties[] = { diff --git a/hw/virtio/vhost-user-base.c b/hw/virtio/vhost-user-base.c index 77143320a2..ff67a020b4 100644 --- a/hw/virtio/vhost-user-base.c +++ b/hw/virtio/vhost-user-base.c @@ -66,7 +66,7 @@ err_host_notifiers: vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); } -static void vub_stop(VirtIODevice *vdev) +static int vub_stop(VirtIODevice *vdev) { VHostUserBase *vub = VHOST_USER_BASE(vdev); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -74,34 +74,39 @@ static void vub_stop(VirtIODevice *vdev) int ret; if (!k->set_guest_notifiers) { - return; + return 0; } - vhost_dev_stop(&vub->vhost_dev, vdev, true); + ret = vhost_dev_stop(&vub->vhost_dev, vdev, true); - ret = k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false); - if (ret < 0) { + if (k->set_guest_notifiers(qbus->parent, vub->vhost_dev.nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); - return; + return -1; } vhost_dev_disable_notifiers(&vub->vhost_dev, vdev); + return ret; } -static void vub_set_status(VirtIODevice *vdev, uint8_t status) +static int vub_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserBase *vub = VHOST_USER_BASE(vdev); bool should_start = virtio_device_should_start(vdev, status); if (vhost_dev_is_started(&vub->vhost_dev) == should_start) { - return; + return 0; } if (should_start) { vub_start(vdev); } else { - vub_stop(vdev); + int ret; + ret = vub_stop(vdev); + if (ret < 0) { + return ret; + } } + return 0; } /* diff --git a/hw/virtio/vhost-user-fs.c b/hw/virtio/vhost-user-fs.c index f6d1fc8804..e77c69eb12 100644 --- a/hw/virtio/vhost-user-fs.c +++ b/hw/virtio/vhost-user-fs.c @@ -100,7 +100,7 @@ err_host_notifiers: vhost_dev_disable_notifiers(&fs->vhost_dev, vdev); } -static void vuf_stop(VirtIODevice *vdev) +static int vuf_stop(VirtIODevice *vdev) { VHostUserFS *fs = VHOST_USER_FS(vdev); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -108,34 +108,39 @@ static void vuf_stop(VirtIODevice *vdev) int ret; if (!k->set_guest_notifiers) { - return; + return 0; } - vhost_dev_stop(&fs->vhost_dev, vdev, true); + ret = vhost_dev_stop(&fs->vhost_dev, vdev, true); - ret = k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false); - if (ret < 0) { + if (k->set_guest_notifiers(qbus->parent, fs->vhost_dev.nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); - return; + return -1; } vhost_dev_disable_notifiers(&fs->vhost_dev, vdev); + return ret; } -static void vuf_set_status(VirtIODevice *vdev, uint8_t status) +static int vuf_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserFS *fs = VHOST_USER_FS(vdev); bool should_start = virtio_device_should_start(vdev, status); if (vhost_dev_is_started(&fs->vhost_dev) == should_start) { - return; + return 0; } if (should_start) { vuf_start(vdev); } else { - vuf_stop(vdev); + int ret; + ret = vuf_stop(vdev); + if (ret < 0) { + return ret; + } } + return 0; } static uint64_t vuf_get_features(VirtIODevice *vdev, diff --git a/hw/virtio/vhost-user-scmi.c b/hw/virtio/vhost-user-scmi.c index 7a0f622181..f9264c4374 100644 --- a/hw/virtio/vhost-user-scmi.c +++ b/hw/virtio/vhost-user-scmi.c @@ -83,7 +83,7 @@ err_host_notifiers: return ret; } -static void vu_scmi_stop(VirtIODevice *vdev) +static int vu_scmi_stop(VirtIODevice *vdev) { VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -93,41 +93,46 @@ static void vu_scmi_stop(VirtIODevice *vdev) /* vhost_dev_is_started() check in the callers is not fully reliable. */ if (!scmi->started_vu) { - return; + return 0; } scmi->started_vu = false; if (!k->set_guest_notifiers) { - return; + return 0; } - vhost_dev_stop(vhost_dev, vdev, true); + ret = vhost_dev_stop(vhost_dev, vdev, true); - ret = k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false); - if (ret < 0) { + if (k->set_guest_notifiers(qbus->parent, vhost_dev->nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); - return; + return -1; } vhost_dev_disable_notifiers(vhost_dev, vdev); + return ret; } -static void vu_scmi_set_status(VirtIODevice *vdev, uint8_t status) +static int vu_scmi_set_status(VirtIODevice *vdev, uint8_t status) { VHostUserSCMI *scmi = VHOST_USER_SCMI(vdev); bool should_start = virtio_device_should_start(vdev, status); if (!scmi->connected) { - return; + return -1; } if (vhost_dev_is_started(&scmi->vhost_dev) == should_start) { - return; + return 0; } if (should_start) { vu_scmi_start(vdev); } else { - vu_scmi_stop(vdev); + int ret; + ret = vu_scmi_stop(vdev); + if (ret < 0) { + return ret; + } } + return 0; } static uint64_t vu_scmi_get_features(VirtIODevice *vdev, uint64_t features, diff --git a/hw/virtio/vhost-user-vsock.c b/hw/virtio/vhost-user-vsock.c index 2776792f59..993c287348 100644 --- a/hw/virtio/vhost-user-vsock.c +++ b/hw/virtio/vhost-user-vsock.c @@ -54,23 +54,28 @@ const VhostDevConfigOps vsock_ops = { .vhost_dev_config_notifier = vuv_handle_config_change, }; -static void vuv_set_status(VirtIODevice *vdev, uint8_t status) +static int vuv_set_status(VirtIODevice *vdev, uint8_t status) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); bool should_start = virtio_device_should_start(vdev, status); + int ret; if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { - return; + return 0; } if (should_start) { - int ret = vhost_vsock_common_start(vdev); + ret = vhost_vsock_common_start(vdev); if (ret < 0) { - return; + return ret; } } else { - vhost_vsock_common_stop(vdev); + ret = vhost_vsock_common_stop(vdev); + if (ret < 0) { + return ret; + } } + return 0; } static uint64_t vuv_get_features(VirtIODevice *vdev, diff --git a/hw/virtio/vhost-vsock-common.c b/hw/virtio/vhost-vsock-common.c index 4b4fbb45cc..c6c44d8989 100644 --- a/hw/virtio/vhost-vsock-common.c +++ b/hw/virtio/vhost-vsock-common.c @@ -95,7 +95,7 @@ err_host_notifiers: return ret; } -void vhost_vsock_common_stop(VirtIODevice *vdev) +int vhost_vsock_common_stop(VirtIODevice *vdev) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev))); @@ -103,18 +103,18 @@ void vhost_vsock_common_stop(VirtIODevice *vdev) int ret; if (!k->set_guest_notifiers) { - return; + return 0; } - vhost_dev_stop(&vvc->vhost_dev, vdev, true); + ret = vhost_dev_stop(&vvc->vhost_dev, vdev, true); - ret = k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false); - if (ret < 0) { + if (k->set_guest_notifiers(qbus->parent, vvc->vhost_dev.nvqs, false) < 0) { error_report("vhost guest notifier cleanup failed: %d", ret); - return; + return -1; } vhost_dev_disable_notifiers(&vvc->vhost_dev, vdev); + return ret; } diff --git a/hw/virtio/vhost-vsock.c b/hw/virtio/vhost-vsock.c index b73dc723c2..6e4088831f 100644 --- a/hw/virtio/vhost-vsock.c +++ b/hw/virtio/vhost-vsock.c @@ -67,37 +67,38 @@ static int vhost_vsock_set_running(VirtIODevice *vdev, int start) } -static void vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) +static int vhost_vsock_set_status(VirtIODevice *vdev, uint8_t status) { VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev); bool should_start = virtio_device_should_start(vdev, status); int ret; if (vhost_dev_is_started(&vvc->vhost_dev) == should_start) { - return; + return 0; } if (should_start) { ret = vhost_vsock_common_start(vdev); if (ret < 0) { - return; + return 0; } ret = vhost_vsock_set_running(vdev, 1); if (ret < 0) { vhost_vsock_common_stop(vdev); error_report("Error starting vhost vsock: %d", -ret); - return; + return 0; } } else { ret = vhost_vsock_set_running(vdev, 0); if (ret < 0) { error_report("vhost vsock set running failed: %d", ret); - return; + return 0; } vhost_vsock_common_stop(vdev); } + return 0; } static uint64_t vhost_vsock_get_features(VirtIODevice *vdev, diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 91510ec2e2..db787d00b3 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -958,7 +958,7 @@ static void virtio_balloon_device_reset(VirtIODevice *vdev) s->poison_val = 0; } -static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status) +static int virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status) { VirtIOBalloon *s = VIRTIO_BALLOON(vdev); @@ -988,6 +988,7 @@ static void virtio_balloon_set_status(VirtIODevice *vdev, uint8_t status) qemu_mutex_unlock(&s->free_page_lock); } } + return 0; } static ResettableState *virtio_balloon_get_reset_state(Object *obj) diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c index e24d6914b6..517f2089c5 100644 --- a/hw/virtio/virtio-crypto.c +++ b/hw/virtio/virtio-crypto.c @@ -1197,11 +1197,12 @@ static void virtio_crypto_vhost_status(VirtIOCrypto *c, uint8_t status) } } -static void virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status) +static int virtio_crypto_set_status(VirtIODevice *vdev, uint8_t status) { VirtIOCrypto *vcrypto = VIRTIO_CRYPTO(vdev); virtio_crypto_vhost_status(vcrypto, status); + return 0; } static void virtio_crypto_guest_notifier_mask(VirtIODevice *vdev, int idx, diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c index 54060988ef..3500f1b082 100644 --- a/hw/virtio/virtio-iommu.c +++ b/hw/virtio/virtio-iommu.c @@ -1522,9 +1522,10 @@ static void virtio_iommu_device_reset_exit(Object *obj, ResetType type) NULL, NULL, virtio_iommu_put_endpoint); } -static void virtio_iommu_set_status(VirtIODevice *vdev, uint8_t status) +static int virtio_iommu_set_status(VirtIODevice *vdev, uint8_t status) { trace_virtio_iommu_device_status(status); + return 0; } static void virtio_iommu_instance_init(Object *obj) diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index dcb3c71d6a..3df5d2576e 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -159,17 +159,18 @@ static void check_rate_limit(void *opaque) vrng->activate_timer = true; } -static void virtio_rng_set_status(VirtIODevice *vdev, uint8_t status) +static int virtio_rng_set_status(VirtIODevice *vdev, uint8_t status) { VirtIORNG *vrng = VIRTIO_RNG(vdev); if (!vdev->vm_running) { - return; + return 0; } vdev->status = status; /* Something changed, try to process buffers */ virtio_rng_process(vrng); + return 0; } static void virtio_rng_device_realize(DeviceState *dev, Error **errp) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index e3b62522ec..1b55d8d8a2 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2221,12 +2221,12 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) { VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); trace_virtio_set_status(vdev, val); + int ret = 0; if (virtio_vdev_has_feature(vdev, VIRTIO_F_VERSION_1)) { if (!(vdev->status & VIRTIO_CONFIG_S_FEATURES_OK) && val & VIRTIO_CONFIG_S_FEATURES_OK) { - int ret = virtio_validate_features(vdev); - + ret = virtio_validate_features(vdev); if (ret) { return ret; } @@ -2239,11 +2239,15 @@ int virtio_set_status(VirtIODevice *vdev, uint8_t val) } if (k->set_status) { - k->set_status(vdev, val); + ret = k->set_status(vdev, val); + if (ret) { + qemu_log("set %s status to %d failed, old status: %d\n", + vdev->name, val, vdev->status); + } } vdev->status = val; - return 0; + return ret; } static enum virtio_device_endian virtio_default_endian(void) @@ -3419,7 +3423,7 @@ void virtio_cleanup(VirtIODevice *vdev) qemu_del_vm_change_state_handler(vdev->vmstate); } -static void virtio_vmstate_change(void *opaque, bool running, RunState state) +static int virtio_vmstate_change(void *opaque, bool running, RunState state) { VirtIODevice *vdev = opaque; BusState *qbus = qdev_get_parent_bus(DEVICE(vdev)); @@ -3436,8 +3440,12 @@ static void virtio_vmstate_change(void *opaque, bool running, RunState state) } if (!backend_run) { - virtio_set_status(vdev, vdev->status); + int ret = virtio_set_status(vdev, vdev->status); + if (ret) { + return ret; + } } + return 0; } void virtio_instance_init_common(Object *proxy_obj, void *data, @@ -3489,7 +3497,7 @@ void virtio_init(VirtIODevice *vdev, uint16_t device_id, size_t config_size) vdev->config = NULL; } vdev->vmstate = qdev_add_vm_change_state_handler(DEVICE(vdev), - virtio_vmstate_change, NULL, vdev); + NULL, virtio_vmstate_change, vdev); vdev->device_endian = virtio_default_endian(); vdev->use_guest_notifier_mask = true; } diff --git a/include/hw/virtio/vhost-scsi-common.h b/include/hw/virtio/vhost-scsi-common.h index c5d2c09455..d54d9c916f 100644 --- a/include/hw/virtio/vhost-scsi-common.h +++ b/include/hw/virtio/vhost-scsi-common.h @@ -40,7 +40,7 @@ struct VHostSCSICommon { }; int vhost_scsi_common_start(VHostSCSICommon *vsc, Error **errp); -void vhost_scsi_common_stop(VHostSCSICommon *vsc); +int vhost_scsi_common_stop(VHostSCSICommon *vsc); char *vhost_scsi_common_get_fw_dev_path(FWPathProvider *p, BusState *bus, DeviceState *dev); void vhost_scsi_common_set_config(VirtIODevice *vdev, const uint8_t *config); diff --git a/include/hw/virtio/vhost-vsock-common.h b/include/hw/virtio/vhost-vsock-common.h index 75a74e8a99..01bf6062af 100644 --- a/include/hw/virtio/vhost-vsock-common.h +++ b/include/hw/virtio/vhost-vsock-common.h @@ -42,7 +42,7 @@ struct VHostVSockCommon { }; int vhost_vsock_common_start(VirtIODevice *vdev); -void vhost_vsock_common_stop(VirtIODevice *vdev); +int vhost_vsock_common_stop(VirtIODevice *vdev); int vhost_vsock_common_pre_save(void *opaque); int vhost_vsock_common_post_load(void *opaque, int version_id); void vhost_vsock_common_realize(VirtIODevice *vdev); diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index 7e0c471ea4..214d4a77e9 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -186,7 +186,7 @@ struct VirtioDeviceClass { void (*get_config)(VirtIODevice *vdev, uint8_t *config); void (*set_config)(VirtIODevice *vdev, const uint8_t *config); void (*reset)(VirtIODevice *vdev); - void (*set_status)(VirtIODevice *vdev, uint8_t val); + int (*set_status)(VirtIODevice *vdev, uint8_t val); /* Device must validate queue_index. */ void (*queue_reset)(VirtIODevice *vdev, uint32_t queue_index); /* Device must validate queue_index. */ diff --git a/include/system/vhost-user-backend.h b/include/system/vhost-user-backend.h index 5ed953cd53..5634ebdb2e 100644 --- a/include/system/vhost-user-backend.h +++ b/include/system/vhost-user-backend.h @@ -43,6 +43,6 @@ struct VhostUserBackend { int vhost_user_backend_dev_init(VhostUserBackend *b, VirtIODevice *vdev, unsigned nvqs, Error **errp); void vhost_user_backend_start(VhostUserBackend *b); -void vhost_user_backend_stop(VhostUserBackend *b); +int vhost_user_backend_stop(VhostUserBackend *b); #endif From 1a5a2629eab94297a37e4adcc5fb69beb7bb0b0c Mon Sep 17 00:00:00 2001 From: Dongli Zhang Date: Sun, 2 Feb 2025 16:52:15 -0800 Subject: [PATCH 0876/2760] vhost-scsi: support VIRTIO_SCSI_F_HOTPLUG So far there isn't way to test host kernel vhost-scsi event queue path, because VIRTIO_SCSI_F_HOTPLUG isn't supported by QEMU. virtio-scsi.c and vhost-user-scsi.c already support VIRTIO_SCSI_F_HOTPLUG as property "hotplug". Add support to vhost-scsi.c to help evaluate and test event queue. To test the feature: 1. Create vhost-scsi target with targetcli. targetcli /backstores/fileio create name=storage file_or_dev=disk01.raw targetcli /vhost create naa.1123451234512345 targetcli /vhost/naa.1123451234512345/tpg1/luns create /backstores/fileio/storage 2. Create QEMU instance with vhost-scsi. -device vhost-scsi-pci,wwpn=naa.1123451234512345,hotplug=true 3. Once guest bootup, hotplug a new LUN from host. targetcli /backstores/fileio create name=storage02 file_or_dev=disk02.raw targetcli /vhost/naa.1123451234512345/tpg1/luns create /backstores/fileio/storage02 Signed-off-by: Dongli Zhang Message-Id: <20250203005215.1502-1-dongli.zhang@oracle.com> Acked-by: Stefano Garzarella --- hw/scsi/vhost-scsi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index dd4250ebe8..cdf405b0f8 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -359,6 +359,9 @@ static const Property vhost_scsi_properties[] = { DEFINE_PROP_BIT64("t10_pi", VHostSCSICommon, host_features, VIRTIO_SCSI_F_T10_PI, false), + DEFINE_PROP_BIT64("hotplug", VHostSCSICommon, host_features, + VIRTIO_SCSI_F_HOTPLUG, + false), DEFINE_PROP_BOOL("migratable", VHostSCSICommon, migratable, false), DEFINE_PROP_BOOL("worker_per_virtqueue", VirtIOSCSICommon, conf.worker_per_virtqueue, false), From 0caed25cd171c611781589b5402161d27d57229c Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 21 Apr 2025 21:17:20 +0900 Subject: [PATCH 0877/2760] virtio: Call set_features during reset virtio-net expects set_features() will be called when the feature set used by the guest changes to update the number of virtqueues but it is not called during reset, which will clear all features, leaving the queues added for VIRTIO_NET_F_MQ or VIRTIO_NET_F_RSS. Not only these extra queues are visible to the guest, they will cause segmentation fault during migration. Call set_features() during reset to remove those queues for virtio-net as we call set_status(). It will also prevent similar bugs for virtio-net and other devices in the future. Fixes: f9d6dbf0bf6e ("virtio-net: remove virtio queues if the guest doesn't support multiqueue") Buglink: https://issues.redhat.com/browse/RHEL-73842 Cc: qemu-stable@nongnu.org Signed-off-by: Akihiko Odaki Message-Id: <20250421-reset-v2-1-e4c1ead88ea1@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 1b55d8d8a2..3300f4afb0 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2320,6 +2320,8 @@ void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index) } } +static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val); + void virtio_reset(void *opaque) { VirtIODevice *vdev = opaque; @@ -2350,7 +2352,7 @@ void virtio_reset(void *opaque) vdev->start_on_kick = false; vdev->started = false; vdev->broken = false; - vdev->guest_features = 0; + virtio_set_features_nocheck(vdev, 0); vdev->queue_sel = 0; vdev->status = 0; vdev->disabled = false; From 77a9408fc774ad99dcd16ea08f31b96b590fbf99 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 21 Apr 2025 21:17:21 +0900 Subject: [PATCH 0878/2760] virtio: Move virtio_reset() Move virtio_reset() to a later part of the file to remove the forward declaration of virtio_set_features_nocheck() and to prepare the situation that we need more operations to perform during reset. Signed-off-by: Akihiko Odaki Message-Id: <20250421-reset-v2-2-e4c1ead88ea1@daynix.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/virtio.c | 88 ++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 3300f4afb0..2e98cecf64 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2320,51 +2320,6 @@ void virtio_queue_enable(VirtIODevice *vdev, uint32_t queue_index) } } -static int virtio_set_features_nocheck(VirtIODevice *vdev, uint64_t val); - -void virtio_reset(void *opaque) -{ - VirtIODevice *vdev = opaque; - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - int i; - - virtio_set_status(vdev, 0); - if (current_cpu) { - /* Guest initiated reset */ - vdev->device_endian = virtio_current_cpu_endian(); - } else { - /* System reset */ - vdev->device_endian = virtio_default_endian(); - } - - if (k->get_vhost) { - struct vhost_dev *hdev = k->get_vhost(vdev); - /* Only reset when vhost back-end is connected */ - if (hdev && hdev->vhost_ops) { - vhost_reset_device(hdev); - } - } - - if (k->reset) { - k->reset(vdev); - } - - vdev->start_on_kick = false; - vdev->started = false; - vdev->broken = false; - virtio_set_features_nocheck(vdev, 0); - vdev->queue_sel = 0; - vdev->status = 0; - vdev->disabled = false; - qatomic_set(&vdev->isr, 0); - vdev->config_vector = VIRTIO_NO_VECTOR; - virtio_notify_vector(vdev, vdev->config_vector); - - for(i = 0; i < VIRTIO_QUEUE_MAX; i++) { - __virtio_queue_reset(vdev, i); - } -} - void virtio_queue_set_addr(VirtIODevice *vdev, int n, hwaddr addr) { if (!vdev->vq[n].vring.num) { @@ -3175,6 +3130,49 @@ int virtio_set_features(VirtIODevice *vdev, uint64_t val) return ret; } +void virtio_reset(void *opaque) +{ + VirtIODevice *vdev = opaque; + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + int i; + + virtio_set_status(vdev, 0); + if (current_cpu) { + /* Guest initiated reset */ + vdev->device_endian = virtio_current_cpu_endian(); + } else { + /* System reset */ + vdev->device_endian = virtio_default_endian(); + } + + if (k->get_vhost) { + struct vhost_dev *hdev = k->get_vhost(vdev); + /* Only reset when vhost back-end is connected */ + if (hdev && hdev->vhost_ops) { + vhost_reset_device(hdev); + } + } + + if (k->reset) { + k->reset(vdev); + } + + vdev->start_on_kick = false; + vdev->started = false; + vdev->broken = false; + virtio_set_features_nocheck(vdev, 0); + vdev->queue_sel = 0; + vdev->status = 0; + vdev->disabled = false; + qatomic_set(&vdev->isr, 0); + vdev->config_vector = VIRTIO_NO_VECTOR; + virtio_notify_vector(vdev, vdev->config_vector); + + for (i = 0; i < VIRTIO_QUEUE_MAX; i++) { + __virtio_queue_reset(vdev, i); + } +} + static void virtio_device_check_notification_compatibility(VirtIODevice *vdev, Error **errp) { From b1c84782bfddeaa0070f5ae57ac2e4e3992f9f19 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Wed, 30 Apr 2025 12:48:06 +0000 Subject: [PATCH 0879/2760] intel_iommu: Use BQL_LOCK_GUARD to manage cleanup automatically vtd_switch_address_space needs to take the BQL if not already held. Use BQL_LOCK_GUARD to make the iommu implementation more consistent. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250430124750.240412-2-clement.mathieu--drif@eviden.com> Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index 5f8ed1243d..b925e65b02 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -1728,8 +1728,6 @@ static bool vtd_as_pt_enabled(VTDAddressSpace *as) static bool vtd_switch_address_space(VTDAddressSpace *as) { bool use_iommu, pt; - /* Whether we need to take the BQL on our own */ - bool take_bql = !bql_locked(); assert(as); @@ -1746,9 +1744,7 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) * from vtd_pt_enable_fast_path(). However the memory APIs need * it. We'd better make sure we have had it already, or, take it. */ - if (take_bql) { - bql_lock(); - } + BQL_LOCK_GUARD(); /* Turn off first then on the other */ if (use_iommu) { @@ -1801,10 +1797,6 @@ static bool vtd_switch_address_space(VTDAddressSpace *as) memory_region_set_enabled(&as->iommu_ir_fault, false); } - if (take_bql) { - bql_unlock(); - } - return use_iommu; } From 6ea7a5762aa1aacb7a5410e4b805bb8c99c6f133 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 8 May 2025 16:41:16 +0200 Subject: [PATCH 0880/2760] include/hw/dma/xlnx_dpdma: Remove dependency on console.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit console.h brings a dependency on the and the pixman header file (if available), so we should avoid to include this file if it is not really necessary. console.h does not seem to be necessary for the xlnx_dpdma code, so drop the include here. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250508144120.163009-2-thuth@redhat.com> --- include/hw/dma/xlnx_dpdma.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/hw/dma/xlnx_dpdma.h b/include/hw/dma/xlnx_dpdma.h index 1ec0d265be..484b2e377f 100644 --- a/include/hw/dma/xlnx_dpdma.h +++ b/include/hw/dma/xlnx_dpdma.h @@ -26,7 +26,6 @@ #define XLNX_DPDMA_H #include "hw/sysbus.h" -#include "ui/console.h" #include "system/dma.h" #include "qom/object.h" From 7c312d8539fe69338f7343b6514f2dc77ae2efa6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 24 Apr 2025 11:06:40 +0200 Subject: [PATCH 0881/2760] tests/functional/test_s390x_tuxrun: Check whether the machine is available The s390x tuxrun test lacks the call to self.set_machine(), so this test is currently failing in case the 's390-ccw-virtio' machine has not been compiled into the binary. Add the check now to fix it. Signed-off-by: Thomas Huth Message-ID: <20250424090640.664217-1-thuth@redhat.com> --- tests/functional/test_s390x_tuxrun.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/test_s390x_tuxrun.py b/tests/functional/test_s390x_tuxrun.py index a7db4bfd84..8df3c6893b 100755 --- a/tests/functional/test_s390x_tuxrun.py +++ b/tests/functional/test_s390x_tuxrun.py @@ -24,6 +24,7 @@ class TuxRunS390xTest(TuxRunBaselineTest): 'bff7971fc2fef56372d98afe4557b82fd0a785a241e44c29b058e577ad1bbb44') def test_s390(self): + self.set_machine('s390-ccw-virtio') self.wait_for_shutdown=False self.common_tuxrun(kernel_asset=self.ASSET_S390X_KERNEL, rootfs_asset=self.ASSET_S390X_ROOTFS, From c23d3339ce8fc936d8c60a023ea2b052d847dc78 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Tue, 25 Mar 2025 09:17:13 +0100 Subject: [PATCH 0882/2760] tests/functional: Skip the screendump tests if the command is not available It is possible nowadays to compile QEMU without pixman support - in that case the screendump command is not available and the related tests fail. Thus skip these tests if the screendump command could not be executed. Signed-off-by: Thomas Huth Message-ID: <20250325081713.283490-2-thuth@redhat.com> --- tests/functional/test_arm_integratorcp.py | 6 ++++-- tests/functional/test_m68k_nextcube.py | 6 ++++-- tests/functional/test_mips64el_malta.py | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/functional/test_arm_integratorcp.py b/tests/functional/test_arm_integratorcp.py index a85b339d77..4f00924aa0 100755 --- a/tests/functional/test_arm_integratorcp.py +++ b/tests/functional/test_arm_integratorcp.py @@ -73,8 +73,10 @@ class IntegratorMachine(QemuSystemTest): framebuffer_ready = 'Console: switching to colour frame buffer device' wait_for_console_pattern(self, framebuffer_ready) self.vm.cmd('human-monitor-command', command_line='stop') - self.vm.cmd('human-monitor-command', - command_line='screendump %s' % screendump_path) + res = self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) + if 'unknown command' in res: + self.skipTest('screendump not available') logger = logging.getLogger('framebuffer') cpu_count = 1 diff --git a/tests/functional/test_m68k_nextcube.py b/tests/functional/test_m68k_nextcube.py index ff773a7994..13c72bd136 100755 --- a/tests/functional/test_m68k_nextcube.py +++ b/tests/functional/test_m68k_nextcube.py @@ -32,8 +32,10 @@ class NextCubeMachine(QemuSystemTest): # TODO: wait for the 'displaysurface_create 1120x832' trace-event. time.sleep(2) - self.vm.cmd('human-monitor-command', - command_line='screendump %s' % screenshot_path) + res = self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screenshot_path) + if 'unknown command' in res: + self.skipTest('screendump not available') @skipIfMissingImports("PIL") def test_bootrom_framebuffer_size(self): diff --git a/tests/functional/test_mips64el_malta.py b/tests/functional/test_mips64el_malta.py index dd37212f9d..3cc79b74c1 100755 --- a/tests/functional/test_mips64el_malta.py +++ b/tests/functional/test_mips64el_malta.py @@ -155,8 +155,10 @@ class MaltaMachineFramebuffer(LinuxKernelTest): framebuffer_ready = 'Console: switching to colour frame buffer device' self.wait_for_console_pattern(framebuffer_ready) self.vm.cmd('human-monitor-command', command_line='stop') - self.vm.cmd('human-monitor-command', - command_line='screendump %s' % screendump_path) + res = self.vm.cmd('human-monitor-command', + command_line='screendump %s' % screendump_path) + if 'unknown command' in res: + self.skipTest('screendump not available') logger = logging.getLogger('framebuffer') match_threshold = 0.95 From 1b85dff5f0be30ddbcb7edbd3c084c9c5ee351ca Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Wed, 30 Apr 2025 12:48:06 +0000 Subject: [PATCH 0883/2760] intel_iommu: Take locks when looking for and creating address spaces vtd_find_add_as can be called by multiple threads which leads to a race condition. Taking the IOMMU lock ensures we avoid such a race. Moreover we also need to take the bql to avoid an assert to fail in memory_region_add_subregion_overlap when actually allocating a new address space. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250430124750.240412-3-clement.mathieu--drif@eviden.com> Reviewed-by: Zhenzhong Duan Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/intel_iommu.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c index b925e65b02..69d72ad35c 100644 --- a/hw/i386/intel_iommu.c +++ b/hw/i386/intel_iommu.c @@ -4205,9 +4205,30 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, VTDAddressSpace *vtd_dev_as; char name[128]; + vtd_iommu_lock(s); vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key); + vtd_iommu_unlock(s); + if (!vtd_dev_as) { - struct vtd_as_key *new_key = g_malloc(sizeof(*new_key)); + struct vtd_as_key *new_key; + /* Slow path */ + + /* + * memory_region_add_subregion_overlap requires the bql, + * make sure we own it. + */ + BQL_LOCK_GUARD(); + vtd_iommu_lock(s); + + /* Check again as we released the lock for a moment */ + vtd_dev_as = g_hash_table_lookup(s->vtd_address_spaces, &key); + if (vtd_dev_as) { + vtd_iommu_unlock(s); + return vtd_dev_as; + } + + /* Still nothing, allocate a new address space */ + new_key = g_malloc(sizeof(*new_key)); new_key->bus = bus; new_key->devfn = devfn; @@ -4298,6 +4319,8 @@ VTDAddressSpace *vtd_find_add_as(IntelIOMMUState *s, PCIBus *bus, vtd_switch_address_space(vtd_dev_as); g_hash_table_insert(s->vtd_address_spaces, new_key, vtd_dev_as); + + vtd_iommu_unlock(s); } return vtd_dev_as; } From f864a3235ea1d1d714b3cde2d9a810ea6344a7b5 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Sun, 4 May 2025 17:04:04 +0000 Subject: [PATCH 0884/2760] hw/i386/amd_iommu: Isolate AMDVI-PCI from amd-iommu device to allow full control over the PCI device creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current amd-iommu model internally creates an AMDVI-PCI device. Here is a snippet from info qtree: bus: main-system-bus type System dev: amd-iommu, id "" xtsup = false pci-id = "" intremap = "on" device-iotlb = false pt = true ... dev: q35-pcihost, id "" MCFG = -1 (0xffffffffffffffff) pci-hole64-size = 34359738368 (32 GiB) below-4g-mem-size = 134217728 (128 MiB) above-4g-mem-size = 0 (0 B) smm-ranges = true x-pci-hole64-fix = true x-config-reg-migration-enabled = true bypass-iommu = false bus: pcie.0 type PCIE dev: AMDVI-PCI, id "" addr = 01.0 romfile = "" romsize = 4294967295 (0xffffffff) rombar = -1 (0xffffffffffffffff) multifunction = false x-pcie-lnksta-dllla = true x-pcie-extcap-init = true failover_pair_id = "" acpi-index = 0 (0x0) x-pcie-err-unc-mask = true x-pcie-ari-nextfn-1 = false x-max-bounce-buffer-size = 4096 (4 KiB) x-pcie-ext-tag = true busnr = 0 (0x0) class Class 0806, addr 00:01.0, pci id 1022:0000 (sub 1af4:1100) ... This prohibits users from specifying the PCI topology for the amd-iommu device, which becomes a problem when trying to support VM migration since it does not guarantee the same enumeration of AMD IOMMU device. Therefore, allow the 'AMDVI-PCI' device to optionally be pre-created and associated with a 'amd-iommu' device via a new 'pci-id' parameter on the latter. For example: -device AMDVI-PCI,id=iommupci0,bus=pcie.0,addr=0x05 \ -device amd-iommu,intremap=on,pt=on,xtsup=on,pci-id=iommupci0 \ For backward-compatibility, internally create the AMDVI-PCI device if not specified on the CLI. Co-developed-by: Daniel P. Berrangé Reviewed-by: Daniel P. Berrangé Signed-off-by: Suravee Suthikulpanit Message-Id: <20250504170405.12623-2-suravee.suthikulpanit@amd.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-build.c | 8 +++---- hw/i386/amd_iommu.c | 53 ++++++++++++++++++++++++++------------------ hw/i386/amd_iommu.h | 3 ++- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index f40ad062f9..61851cc840 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -2333,10 +2333,10 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id, build_append_int_noprefix(table_data, ivhd_blob->len + 24, 2); /* DeviceID */ build_append_int_noprefix(table_data, - object_property_get_int(OBJECT(&s->pci), "addr", + object_property_get_int(OBJECT(s->pci), "addr", &error_abort), 2); /* Capability offset */ - build_append_int_noprefix(table_data, s->pci.capab_offset, 2); + build_append_int_noprefix(table_data, s->pci->capab_offset, 2); /* IOMMU base address */ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8); /* PCI Segment Group */ @@ -2368,10 +2368,10 @@ build_amd_iommu(GArray *table_data, BIOSLinker *linker, const char *oem_id, build_append_int_noprefix(table_data, ivhd_blob->len + 40, 2); /* DeviceID */ build_append_int_noprefix(table_data, - object_property_get_int(OBJECT(&s->pci), "addr", + object_property_get_int(OBJECT(s->pci), "addr", &error_abort), 2); /* Capability offset */ - build_append_int_noprefix(table_data, s->pci.capab_offset, 2); + build_append_int_noprefix(table_data, s->pci->capab_offset, 2); /* IOMMU base address */ build_append_int_noprefix(table_data, s->mr_mmio.addr, 8); /* PCI Segment Group */ diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 2cf7e24a21..f5466fdc98 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -167,11 +167,11 @@ static void amdvi_generate_msi_interrupt(AMDVIState *s) { MSIMessage msg = {}; MemTxAttrs attrs = { - .requester_id = pci_requester_id(&s->pci.dev) + .requester_id = pci_requester_id(&s->pci->dev) }; - if (msi_enabled(&s->pci.dev)) { - msg = msi_get_message(&s->pci.dev, 0); + if (msi_enabled(&s->pci->dev)) { + msg = msi_get_message(&s->pci->dev, 0); address_space_stl_le(&address_space_memory, msg.address, msg.data, attrs, NULL); } @@ -239,7 +239,7 @@ static void amdvi_page_fault(AMDVIState *s, uint16_t devid, info |= AMDVI_EVENT_IOPF_I | AMDVI_EVENT_IOPF; amdvi_encode_event(evt, devid, addr, info); amdvi_log_event(s, evt); - pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS, PCI_STATUS_SIG_TARGET_ABORT); } /* @@ -256,7 +256,7 @@ static void amdvi_log_devtab_error(AMDVIState *s, uint16_t devid, amdvi_encode_event(evt, devid, devtab, info); amdvi_log_event(s, evt); - pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS, PCI_STATUS_SIG_TARGET_ABORT); } /* log an event trying to access command buffer @@ -269,7 +269,7 @@ static void amdvi_log_command_error(AMDVIState *s, hwaddr addr) amdvi_encode_event(evt, 0, addr, info); amdvi_log_event(s, evt); - pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS, PCI_STATUS_SIG_TARGET_ABORT); } /* log an illegal command event @@ -310,7 +310,7 @@ static void amdvi_log_pagetab_error(AMDVIState *s, uint16_t devid, info |= AMDVI_EVENT_PAGE_TAB_HW_ERROR; amdvi_encode_event(evt, devid, addr, info); amdvi_log_event(s, evt); - pci_word_test_and_set_mask(s->pci.dev.config + PCI_STATUS, + pci_word_test_and_set_mask(s->pci->dev.config + PCI_STATUS, PCI_STATUS_SIG_TARGET_ABORT); } @@ -1607,7 +1607,7 @@ static void amdvi_sysbus_reset(DeviceState *dev) { AMDVIState *s = AMD_IOMMU_DEVICE(dev); - msi_reset(&s->pci.dev); + msi_reset(&s->pci->dev); amdvi_init(s); } @@ -1619,14 +1619,32 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) X86MachineState *x86ms = X86_MACHINE(ms); PCIBus *bus = pcms->pcibus; + if (s->pci_id) { + PCIDevice *pdev = NULL; + int ret = pci_qdev_find_device(s->pci_id, &pdev); + + if (ret) { + error_report("Cannot find PCI device '%s'", s->pci_id); + return; + } + + if (!object_dynamic_cast(OBJECT(pdev), TYPE_AMD_IOMMU_PCI)) { + error_report("Device '%s' must be an AMDVI-PCI device type", s->pci_id); + return; + } + + s->pci = AMD_IOMMU_PCI(pdev); + } else { + s->pci = AMD_IOMMU_PCI(object_new(TYPE_AMD_IOMMU_PCI)); + /* This device should take care of IOMMU PCI properties */ + if (!qdev_realize(DEVICE(s->pci), &bus->qbus, errp)) { + return; + } + } + s->iotlb = g_hash_table_new_full(amdvi_uint64_hash, amdvi_uint64_equal, g_free, g_free); - /* This device should take care of IOMMU PCI properties */ - if (!qdev_realize(DEVICE(&s->pci), &bus->qbus, errp)) { - return; - } - /* Pseudo address space under root PCI bus. */ x86ms->ioapic_as = amdvi_host_dma_iommu(bus, s, AMDVI_IOAPIC_SB_DEVID); @@ -1663,6 +1681,7 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) static const Property amdvi_properties[] = { DEFINE_PROP_BOOL("xtsup", AMDVIState, xtsup, false), + DEFINE_PROP_STRING("pci-id", AMDVIState, pci_id), }; static const VMStateDescription vmstate_amdvi_sysbus = { @@ -1670,13 +1689,6 @@ static const VMStateDescription vmstate_amdvi_sysbus = { .unmigratable = 1 }; -static void amdvi_sysbus_instance_init(Object *klass) -{ - AMDVIState *s = AMD_IOMMU_DEVICE(klass); - - object_initialize(&s->pci, sizeof(s->pci), TYPE_AMD_IOMMU_PCI); -} - static void amdvi_sysbus_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1696,7 +1708,6 @@ static const TypeInfo amdvi_sysbus = { .name = TYPE_AMD_IOMMU_DEVICE, .parent = TYPE_X86_IOMMU_DEVICE, .instance_size = sizeof(AMDVIState), - .instance_init = amdvi_sysbus_instance_init, .class_init = amdvi_sysbus_class_init }; diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 28125130c6..7a28181d9c 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -315,7 +315,8 @@ struct AMDVIPCIState { struct AMDVIState { X86IOMMUState iommu; /* IOMMU bus device */ - AMDVIPCIState pci; /* IOMMU PCI device */ + AMDVIPCIState *pci; /* IOMMU PCI device */ + char *pci_id; /* ID of AMDVI-PCI device, if user created */ uint32_t version; From 28931c2e1591deb4bfaaf744fdc8813e96c230f1 Mon Sep 17 00:00:00 2001 From: Suravee Suthikulpanit Date: Sun, 4 May 2025 17:04:05 +0000 Subject: [PATCH 0885/2760] hw/i386/amd_iommu: Allow migration when explicitly create the AMDVI-PCI device Add migration support for AMD IOMMU model by saving necessary AMDVIState parameters for MMIO registers, device table, command buffer, and event buffers. Also change devtab_len type from size_t to uint64_t to avoid 32-bit build issue. Signed-off-by: Suravee Suthikulpanit Message-Id: <20250504170405.12623-3-suravee.suthikulpanit@amd.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/amd_iommu.c | 48 +++++++++++++++++++++++++++++++++++++++++++++ hw/i386/amd_iommu.h | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index f5466fdc98..0775c8f3bb 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1611,8 +1611,55 @@ static void amdvi_sysbus_reset(DeviceState *dev) amdvi_init(s); } +static const VMStateDescription vmstate_amdvi_sysbus_migratable = { + .name = "amd-iommu", + .version_id = 1, + .minimum_version_id = 1, + .priority = MIG_PRI_IOMMU, + .fields = (VMStateField[]) { + /* Updated in amdvi_handle_control_write() */ + VMSTATE_BOOL(enabled, AMDVIState), + VMSTATE_BOOL(ga_enabled, AMDVIState), + VMSTATE_BOOL(ats_enabled, AMDVIState), + VMSTATE_BOOL(cmdbuf_enabled, AMDVIState), + VMSTATE_BOOL(completion_wait_intr, AMDVIState), + VMSTATE_BOOL(evtlog_enabled, AMDVIState), + VMSTATE_BOOL(evtlog_intr, AMDVIState), + /* Updated in amdvi_handle_devtab_write() */ + VMSTATE_UINT64(devtab, AMDVIState), + VMSTATE_UINT64(devtab_len, AMDVIState), + /* Updated in amdvi_handle_cmdbase_write() */ + VMSTATE_UINT64(cmdbuf, AMDVIState), + VMSTATE_UINT64(cmdbuf_len, AMDVIState), + /* Updated in amdvi_handle_cmdhead_write() */ + VMSTATE_UINT32(cmdbuf_head, AMDVIState), + /* Updated in amdvi_handle_cmdtail_write() */ + VMSTATE_UINT32(cmdbuf_tail, AMDVIState), + /* Updated in amdvi_handle_evtbase_write() */ + VMSTATE_UINT64(evtlog, AMDVIState), + VMSTATE_UINT32(evtlog_len, AMDVIState), + /* Updated in amdvi_handle_evthead_write() */ + VMSTATE_UINT32(evtlog_head, AMDVIState), + /* Updated in amdvi_handle_evttail_write() */ + VMSTATE_UINT32(evtlog_tail, AMDVIState), + /* Updated in amdvi_handle_pprbase_write() */ + VMSTATE_UINT64(ppr_log, AMDVIState), + VMSTATE_UINT32(pprlog_len, AMDVIState), + /* Updated in amdvi_handle_pprhead_write() */ + VMSTATE_UINT32(pprlog_head, AMDVIState), + /* Updated in amdvi_handle_tailhead_write() */ + VMSTATE_UINT32(pprlog_tail, AMDVIState), + /* MMIO registers */ + VMSTATE_UINT8_ARRAY(mmior, AMDVIState, AMDVI_MMIO_SIZE), + VMSTATE_UINT8_ARRAY(romask, AMDVIState, AMDVI_MMIO_SIZE), + VMSTATE_UINT8_ARRAY(w1cmask, AMDVIState, AMDVI_MMIO_SIZE), + VMSTATE_END_OF_LIST() + } +}; + static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) { + DeviceClass *dc = (DeviceClass *) object_get_class(OBJECT(dev)); AMDVIState *s = AMD_IOMMU_DEVICE(dev); MachineState *ms = MACHINE(qdev_get_machine()); PCMachineState *pcms = PC_MACHINE(ms); @@ -1634,6 +1681,7 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) } s->pci = AMD_IOMMU_PCI(pdev); + dc->vmsd = &vmstate_amdvi_sysbus_migratable; } else { s->pci = AMD_IOMMU_PCI(object_new(TYPE_AMD_IOMMU_PCI)); /* This device should take care of IOMMU PCI properties */ diff --git a/hw/i386/amd_iommu.h b/hw/i386/amd_iommu.h index 7a28181d9c..5672bdef89 100644 --- a/hw/i386/amd_iommu.h +++ b/hw/i386/amd_iommu.h @@ -329,7 +329,7 @@ struct AMDVIState { bool excl_enabled; hwaddr devtab; /* base address device table */ - size_t devtab_len; /* device table length */ + uint64_t devtab_len; /* device table length */ hwaddr cmdbuf; /* command buffer base address */ uint64_t cmdbuf_len; /* command buffer length */ From 9c6675e8a5824f4c41c3d122c4b848a67d9d0350 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:45 +0100 Subject: [PATCH 0886/2760] target/microblaze: Use 'obj' in DEVICE() casts in mb_cpu_initfn() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We're about to make a change that removes the only other use of the 'cpu' local variable in mb_cpu_initfn(); since the DEVICE() casts work fine with the Object*, use that instead, so that we can remove the local variable when we make the following change. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Message-id: 20250429132200.605611-2-peter.maydell@linaro.org --- target/microblaze/cpu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index d069e40e70..d895d68395 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -344,11 +344,11 @@ static void mb_cpu_initfn(Object *obj) #ifndef CONFIG_USER_ONLY /* Inbound IRQ and FIR lines */ - qdev_init_gpio_in(DEVICE(cpu), microblaze_cpu_set_irq, 2); - qdev_init_gpio_in_named(DEVICE(cpu), mb_cpu_ns_axi_dp, "ns_axi_dp", 1); - qdev_init_gpio_in_named(DEVICE(cpu), mb_cpu_ns_axi_ip, "ns_axi_ip", 1); - qdev_init_gpio_in_named(DEVICE(cpu), mb_cpu_ns_axi_dc, "ns_axi_dc", 1); - qdev_init_gpio_in_named(DEVICE(cpu), mb_cpu_ns_axi_ic, "ns_axi_ic", 1); + qdev_init_gpio_in(DEVICE(obj), microblaze_cpu_set_irq, 2); + qdev_init_gpio_in_named(DEVICE(obj), mb_cpu_ns_axi_dp, "ns_axi_dp", 1); + qdev_init_gpio_in_named(DEVICE(obj), mb_cpu_ns_axi_ip, "ns_axi_ip", 1); + qdev_init_gpio_in_named(DEVICE(obj), mb_cpu_ns_axi_dc, "ns_axi_dc", 1); + qdev_init_gpio_in_named(DEVICE(obj), mb_cpu_ns_axi_ic, "ns_axi_ic", 1); #endif /* Restricted 'endianness' property is equivalent of 'little-endian' */ From 6222ae143da0408c7e5b727082975dc394f5a23f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:45 +0100 Subject: [PATCH 0887/2760] target/microblaze: Delay gdb_register_coprocessor() to realize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the microblaze code calls gdb_register_coprocessor() in its initfn. This works, but we would like to delay setting up GDB registers until realize. All other target architectures only call gdb_register_coprocessor() in realize, after the call to cpu_exec_realizefn(). Move the microblaze gdb_register_coprocessor() use, bringing it in line with other targets. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250429132200.605611-3-peter.maydell@linaro.org --- target/microblaze/cpu.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index d895d68395..615a959200 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -263,6 +263,11 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) return; } + gdb_register_coprocessor(cs, mb_cpu_gdb_read_stack_protect, + mb_cpu_gdb_write_stack_protect, + gdb_find_static_feature("microblaze-stack-protect.xml"), + 0); + qemu_init_vcpu(cs); version = cpu->cfg.version ? cpu->cfg.version : DEFAULT_CPU_VERSION; @@ -335,13 +340,6 @@ static void mb_cpu_realizefn(DeviceState *dev, Error **errp) static void mb_cpu_initfn(Object *obj) { - MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj); - - gdb_register_coprocessor(CPU(cpu), mb_cpu_gdb_read_stack_protect, - mb_cpu_gdb_write_stack_protect, - gdb_find_static_feature("microblaze-stack-protect.xml"), - 0); - #ifndef CONFIG_USER_ONLY /* Inbound IRQ and FIR lines */ qdev_init_gpio_in(DEVICE(obj), microblaze_cpu_set_irq, 2); From b4ae54989b911876540ba4ba9090901235e3047a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:45 +0100 Subject: [PATCH 0888/2760] hw/core/cpu-common: Don't init gdbstub until cpu_exec_realizefn() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we call gdb_init_cpu() in cpu_common_initfn(), which is very early in the CPU object's init->realize creation sequence. In particular this happens before the architecture-specific subclass's init fn has even run. This means that gdb_init_cpu() can only do things that depend strictly on the class, not on the object, because the CPUState* that it is passed is currently half-initialized. In commit a1f728ecc90cf6c6 we accidentally broke this rule, by adding a call to the gdb_get_core_xml_file method which takes the CPUState. At the moment we get away with this because the only implementation doesn't actually look at the pointer it is passed. However the whole reason we created that method was so that we could make the "which XML file?" decision based on a property of the CPU object, and we currently can't change the Arm implementation of the method to do what we want without causing wrong behaviour or a crash. The ordering restrictions here are: * we must call gdb_init_cpu before: - any call to gdb_register_coprocessor() - any use of the gdb_num_regs field (this is only used in code that's about to call gdb_register_coprocessor() and wants to know the first register number of the set of registers it's about to add) * we must call gdb_init_cpu after CPU properties have been set, which is to say somewhere in realize The function cpu_exec_realizefn() meets both of these requirements, as it is called by the architecture-specific CPU realize function early in realize, before any calls ot gdb_register_coprocessor(). Move the gdb_init_cpu() call to there. Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250429132200.605611-4-peter.maydell@linaro.org --- hw/core/cpu-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c index 92c40b6bf8..39e674aca2 100644 --- a/hw/core/cpu-common.c +++ b/hw/core/cpu-common.c @@ -234,6 +234,8 @@ bool cpu_exec_realizefn(CPUState *cpu, Error **errp) return false; } + gdb_init_cpu(cpu); + /* Wait until cpu initialization complete before exposing cpu. */ cpu_list_add(cpu); @@ -304,7 +306,6 @@ static void cpu_common_initfn(Object *obj) /* cache the cpu class for the hotpath */ cpu->cc = CPU_GET_CLASS(cpu); - gdb_init_cpu(cpu); cpu->cpu_index = UNASSIGNED_CPU_INDEX; cpu->cluster_index = UNASSIGNED_CLUSTER_INDEX; cpu->as = NULL; From d2c655a5f42ef7466c70cb223a9b9fc292f6b593 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:46 +0100 Subject: [PATCH 0889/2760] target/arm: Present AArch64 gdbstub based on ARM_FEATURE_AARCH64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we provide an AArch64 gdbstub for CPUs which are TYPE_AARCH64_CPU, and an AArch32 gdbstub for those which are only TYPE_ARM_CPU. This mostly does the right thing, except in the corner case of KVM with -cpu host,aarch64=off. That produces a CPU which is TYPE_AARCH64_CPU but which has ARM_FEATURE_AARCH64 removed and which to the guest is in AArch32 mode. Now we have moved all the handling of AArch64-vs-AArch32 gdbstub behaviour into TYPE_ARM_CPU we can change the condition we use for whether to select the AArch64 gdbstub to look at ARM_FEATURE_AARCH64. This will mean that we now correctly provide an AArch32 gdbstub for aarch64=off CPUs. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250429132200.605611-5-peter.maydell@linaro.org --- target/arm/internals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index 660d3a88e0..a396c0be3b 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1833,7 +1833,7 @@ void aarch64_add_sme_properties(Object *obj); /* Return true if the gdbstub is presenting an AArch64 CPU */ static inline bool arm_gdbstub_is_aarch64(ARMCPU *cpu) { - return object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU); + return arm_feature(&cpu->env, ARM_FEATURE_AARCH64); } /* Read the CONTROL register as the MRS instruction would. */ From 0ab97bc070f9df7fd155707c7800667cbf26790f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:46 +0100 Subject: [PATCH 0890/2760] target/arm: Move aarch64 CPU property code to TYPE_ARM_CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only thing we have left in the TYPE_AARCH64_CPU class that makes it different to TYPE_ARM_CPU is that we register the handling of the "aarch64" property there. Move the handling of this property to the base class, where we make it a property of the object rather than of the class, and add it to the CPU if it has the ARM_FEATURE_AARCH64 property present at init. This is in line with how we handle other Arm CPU properties, and should not change which CPUs it's visible for. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250429132200.605611-6-peter.maydell@linaro.org --- target/arm/cpu.c | 36 ++++++++++++++++++++++++++++++++++++ target/arm/cpu64.c | 33 --------------------------------- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 45cb6fd7ee..603f08d05a 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1609,6 +1609,35 @@ static void arm_set_pmu(Object *obj, bool value, Error **errp) cpu->has_pmu = value; } +static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + + return arm_feature(&cpu->env, ARM_FEATURE_AARCH64); +} + +static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) +{ + ARMCPU *cpu = ARM_CPU(obj); + + /* + * At this time, this property is only allowed if KVM is enabled. This + * restriction allows us to avoid fixing up functionality that assumes a + * uniform execution state like do_interrupt. + */ + if (value == false) { + if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { + error_setg(errp, "'aarch64' feature cannot be disabled " + "unless KVM is enabled and 32-bit EL1 " + "is supported"); + return; + } + unset_feature(&cpu->env, ARM_FEATURE_AARCH64); + } else { + set_feature(&cpu->env, ARM_FEATURE_AARCH64); + } +} + unsigned int gt_cntfrq_period_ns(ARMCPU *cpu) { /* @@ -1736,6 +1765,13 @@ void arm_cpu_post_init(Object *obj) */ arm_cpu_propagate_feature_implications(cpu); + if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { + object_property_add_bool(obj, "aarch64", aarch64_cpu_get_aarch64, + aarch64_cpu_set_aarch64); + object_property_set_description(obj, "aarch64", + "Set on/off to enable/disable aarch64 " + "execution state "); + } if (arm_feature(&cpu->env, ARM_FEATURE_CBAR) || arm_feature(&cpu->env, ARM_FEATURE_CBAR_RO)) { qdev_property_add_static(DEVICE(obj), &arm_cpu_reset_cbar_property); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index 00629a5d1d..e527465a3c 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -781,45 +781,12 @@ static const ARMCPUInfo aarch64_cpus[] = { #endif }; -static bool aarch64_cpu_get_aarch64(Object *obj, Error **errp) -{ - ARMCPU *cpu = ARM_CPU(obj); - - return arm_feature(&cpu->env, ARM_FEATURE_AARCH64); -} - -static void aarch64_cpu_set_aarch64(Object *obj, bool value, Error **errp) -{ - ARMCPU *cpu = ARM_CPU(obj); - - /* At this time, this property is only allowed if KVM is enabled. This - * restriction allows us to avoid fixing up functionality that assumes a - * uniform execution state like do_interrupt. - */ - if (value == false) { - if (!kvm_enabled() || !kvm_arm_aarch32_supported()) { - error_setg(errp, "'aarch64' feature cannot be disabled " - "unless KVM is enabled and 32-bit EL1 " - "is supported"); - return; - } - unset_feature(&cpu->env, ARM_FEATURE_AARCH64); - } else { - set_feature(&cpu->env, ARM_FEATURE_AARCH64); - } -} - static void aarch64_cpu_finalizefn(Object *obj) { } static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) { - object_class_property_add_bool(oc, "aarch64", aarch64_cpu_get_aarch64, - aarch64_cpu_set_aarch64); - object_class_property_set_description(oc, "aarch64", - "Set on/off to enable/disable aarch64 " - "execution state "); } static void aarch64_cpu_instance_init(Object *obj) From c6650a8c6cc18cdc4a46a6eef41b7d57e6bc0b2b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:46 +0100 Subject: [PATCH 0891/2760] target/arm/kvm: don't check TYPE_AARCH64_CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to merge TYPE_AARCH64_CPU with TYPE_ARM_CPU, so enforcing in kvm_arch_init_vcpu() that the CPU class is a subclass of TYPE_AARCH64_CPU will no longer be possible. It's safe to just remove this test, because any purely-AArch32 CPU will fail the "kvm_target isn't set" check, because we no longer support the old AArch32-host KVM setup and so CPUs like the Cortex-A7 no longer set cpu->kvm_target. Only the 'host', 'max', and the odd special cases 'cortex-a53' and 'cortex-a57' set kvm_target. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250429132200.605611-7-peter.maydell@linaro.org --- target/arm/kvm.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 9c62d12b23..85911e3024 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -1843,8 +1843,7 @@ int kvm_arch_init_vcpu(CPUState *cs) CPUARMState *env = &cpu->env; uint64_t psciver; - if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE || - !object_dynamic_cast(OBJECT(cpu), TYPE_AARCH64_CPU)) { + if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE) { error_report("KVM is not supported for this guest CPU type"); return -EINVAL; } From ec7e5a90fea996f04ea24e81b680a87bc975354a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:46 +0100 Subject: [PATCH 0892/2760] target/arm: Remove TYPE_AARCH64_CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TYPE_AARCH64_CPU class is an abstract type that is the parent of all the AArch64 CPUs. It now has no special behaviour of its own, so we can eliminate it and make the AArch64 CPUs directly inherit from TYPE_ARM_CPU. Signed-off-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Message-id: 20250429132200.605611-8-peter.maydell@linaro.org --- target/arm/cpu-qom.h | 5 ----- target/arm/cpu.h | 4 ---- target/arm/cpu64.c | 49 +----------------------------------------- target/arm/internals.h | 1 - target/arm/tcg/cpu64.c | 2 +- 5 files changed, 2 insertions(+), 59 deletions(-) diff --git a/target/arm/cpu-qom.h b/target/arm/cpu-qom.h index b497667d61..2fcb0e1252 100644 --- a/target/arm/cpu-qom.h +++ b/target/arm/cpu-qom.h @@ -28,11 +28,6 @@ OBJECT_DECLARE_CPU_TYPE(ARMCPU, ARMCPUClass, ARM_CPU) #define TYPE_ARM_MAX_CPU "max-" TYPE_ARM_CPU -#define TYPE_AARCH64_CPU "aarch64-cpu" -typedef struct AArch64CPUClass AArch64CPUClass; -DECLARE_CLASS_CHECKERS(AArch64CPUClass, AARCH64_CPU, - TYPE_AARCH64_CPU) - #define ARM_CPU_TYPE_SUFFIX "-" TYPE_ARM_CPU #define ARM_CPU_TYPE_NAME(name) (name ARM_CPU_TYPE_SUFFIX) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 6ed6409cb7..302c24e232 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1138,10 +1138,6 @@ struct ARMCPUClass { ResettablePhases parent_phases; }; -struct AArch64CPUClass { - ARMCPUClass parent_class; -}; - /* Callback functions for the generic timer's timers. */ void arm_gt_ptimer_cb(void *opaque); void arm_gt_vtimer_cb(void *opaque); diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c index e527465a3c..200da1c489 100644 --- a/target/arm/cpu64.c +++ b/target/arm/cpu64.c @@ -781,59 +781,12 @@ static const ARMCPUInfo aarch64_cpus[] = { #endif }; -static void aarch64_cpu_finalizefn(Object *obj) -{ -} - -static void aarch64_cpu_class_init(ObjectClass *oc, const void *data) -{ -} - -static void aarch64_cpu_instance_init(Object *obj) -{ - ARMCPUClass *acc = ARM_CPU_GET_CLASS(obj); - - acc->info->initfn(obj); - arm_cpu_post_init(obj); -} - -static void cpu_register_class_init(ObjectClass *oc, const void *data) -{ - ARMCPUClass *acc = ARM_CPU_CLASS(oc); - - acc->info = data; -} - -void aarch64_cpu_register(const ARMCPUInfo *info) -{ - TypeInfo type_info = { - .parent = TYPE_AARCH64_CPU, - .instance_init = aarch64_cpu_instance_init, - .class_init = info->class_init ?: cpu_register_class_init, - .class_data = info, - }; - - type_info.name = g_strdup_printf("%s-" TYPE_ARM_CPU, info->name); - type_register_static(&type_info); - g_free((void *)type_info.name); -} - -static const TypeInfo aarch64_cpu_type_info = { - .name = TYPE_AARCH64_CPU, - .parent = TYPE_ARM_CPU, - .instance_finalize = aarch64_cpu_finalizefn, - .abstract = true, - .class_init = aarch64_cpu_class_init, -}; - static void aarch64_cpu_register_types(void) { size_t i; - type_register_static(&aarch64_cpu_type_info); - for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { - aarch64_cpu_register(&aarch64_cpus[i]); + arm_cpu_register(&aarch64_cpus[i]); } } diff --git a/target/arm/internals.h b/target/arm/internals.h index a396c0be3b..702eb1a548 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -354,7 +354,6 @@ static inline int r14_bank_number(int mode) } void arm_cpu_register(const ARMCPUInfo *info); -void aarch64_cpu_register(const ARMCPUInfo *info); void register_cp_regs_for_features(ARMCPU *cpu); void init_cpreg_list(ARMCPU *cpu); diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index 29ab0ac79d..5d8ed2794d 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -1316,7 +1316,7 @@ static void aarch64_cpu_register_types(void) size_t i; for (i = 0; i < ARRAY_SIZE(aarch64_cpus); ++i) { - aarch64_cpu_register(&aarch64_cpus[i]); + arm_cpu_register(&aarch64_cpus[i]); } } From 6414b7709d404bf410da360bab865133832ade85 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Wed, 14 May 2025 14:29:47 +0100 Subject: [PATCH 0893/2760] rust: pl011: Cut down amount of text quoted from PL011 TRM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently the comments in the Rust pl011 register.rs file include large amounts of text from the PL011 TRM. This is much more commentary than we typically quote from a device reference manual, and much of it is not relevant to QEMU. Compress and rephrase the comments so that we are not quoting such a large volume of TRM text. We add a URL for the TRM; readers who need more detail on the function of the register bits can find it there, presented in context with the overall description of the hardware. Signed-off-by: Peter Maydell Reviewed-by: Daniel P. Berrangé --- rust/hw/char/pl011/src/registers.rs | 261 ++++++---------------------- 1 file changed, 51 insertions(+), 210 deletions(-) diff --git a/rust/hw/char/pl011/src/registers.rs b/rust/hw/char/pl011/src/registers.rs index cd92fa2c30..690feb6378 100644 --- a/rust/hw/char/pl011/src/registers.rs +++ b/rust/hw/char/pl011/src/registers.rs @@ -5,13 +5,13 @@ //! Device registers exposed as typed structs which are backed by arbitrary //! integer bitmaps. [`Data`], [`Control`], [`LineControl`], etc. +// For more detail see the PL011 Technical Reference Manual DDI0183: +// https://developer.arm.com/documentation/ddi0183/latest/ + use bilge::prelude::*; use qemu_api::impl_vmstate_bitsized; /// Offset of each register from the base memory address of the device. -/// -/// # Source -/// ARM DDI 0183G, Table 3-1 p.3-3 #[doc(alias = "offset")] #[allow(non_camel_case_types)] #[repr(u64)] @@ -87,48 +87,11 @@ pub struct Errors { _reserved_unpredictable: u4, } -// TODO: FIFO Mode has different semantics /// Data Register, `UARTDR` /// -/// The `UARTDR` register is the data register. -/// -/// For words to be transmitted: -/// -/// - if the FIFOs are enabled, data written to this location is pushed onto the -/// transmit -/// FIFO -/// - if the FIFOs are not enabled, data is stored in the transmitter holding -/// register (the -/// bottom word of the transmit FIFO). -/// -/// The write operation initiates transmission from the UART. The data is -/// prefixed with a start bit, appended with the appropriate parity bit -/// (if parity is enabled), and a stop bit. The resultant word is then -/// transmitted. -/// -/// For received words: -/// -/// - if the FIFOs are enabled, the data byte and the 4-bit status (break, -/// frame, parity, -/// and overrun) is pushed onto the 12-bit wide receive FIFO -/// - if the FIFOs are not enabled, the data byte and status are stored in the -/// receiving -/// holding register (the bottom word of the receive FIFO). -/// -/// The received data byte is read by performing reads from the `UARTDR` -/// register along with the corresponding status information. The status -/// information can also be read by a read of the `UARTRSR/UARTECR` -/// register. -/// -/// # Note -/// -/// You must disable the UART before any of the control registers are -/// reprogrammed. When the UART is disabled in the middle of -/// transmission or reception, it completes the current character before -/// stopping. -/// -/// # Source -/// ARM DDI 0183G 3.3.1 Data Register, UARTDR +/// The `UARTDR` register is the data register; write for TX and +/// read for RX. It is a 12-bit register, where bits 7..0 are the +/// character and bits 11..8 are error bits. #[bitsize(32)] #[derive(Clone, Copy, Default, DebugBits, FromBits)] #[doc(alias = "UARTDR")] @@ -144,30 +107,17 @@ impl Data { pub const BREAK: Self = Self { value: 1 << 10 }; } -// TODO: FIFO Mode has different semantics /// Receive Status Register / Error Clear Register, `UARTRSR/UARTECR` /// -/// The UARTRSR/UARTECR register is the receive status register/error clear -/// register. Receive status can also be read from the `UARTRSR` -/// register. If the status is read from this register, then the status -/// information for break, framing and parity corresponds to the -/// data character read from the [Data register](Data), `UARTDR` prior to -/// reading the UARTRSR register. The status information for overrun is -/// set immediately when an overrun condition occurs. +/// This register provides a different way to read the four receive +/// status error bits that can be found in bits 11..8 of the UARTDR +/// on a read. It gets updated when the guest reads UARTDR, and the +/// status bits correspond to that character that was just read. /// -/// -/// # Note -/// The received data character must be read first from the [Data -/// Register](Data), `UARTDR` before reading the error status associated -/// with that data character from the `UARTRSR` register. This read -/// sequence cannot be reversed, because the `UARTRSR` register is -/// updated only when a read occurs from the `UARTDR` register. However, -/// the status information can also be obtained by reading the `UARTDR` -/// register -/// -/// # Source -/// ARM DDI 0183G 3.3.2 Receive Status Register/Error Clear Register, -/// UARTRSR/UARTECR +/// The TRM confusingly describes this offset as UARTRSR for reads +/// and UARTECR for writes, but really it's a single error status +/// register where writing anything to the register clears the error +/// bits. #[bitsize(32)] #[derive(Clone, Copy, DebugBits, FromBits)] pub struct ReceiveStatusErrorClear { @@ -196,54 +146,29 @@ impl Default for ReceiveStatusErrorClear { #[bitsize(32)] #[derive(Clone, Copy, DebugBits, FromBits)] /// Flag Register, `UARTFR` +/// +/// This has the usual inbound RS232 modem-control signals, plus flags +/// for RX and TX FIFO fill levels and a BUSY flag. #[doc(alias = "UARTFR")] pub struct Flags { - /// CTS Clear to send. This bit is the complement of the UART clear to - /// send, `nUARTCTS`, modem status input. That is, the bit is 1 - /// when `nUARTCTS` is LOW. + /// CTS: Clear to send pub clear_to_send: bool, - /// DSR Data set ready. This bit is the complement of the UART data set - /// ready, `nUARTDSR`, modem status input. That is, the bit is 1 when - /// `nUARTDSR` is LOW. + /// DSR: Data set ready pub data_set_ready: bool, - /// DCD Data carrier detect. This bit is the complement of the UART data - /// carrier detect, `nUARTDCD`, modem status input. That is, the bit is - /// 1 when `nUARTDCD` is LOW. + /// DCD: Data carrier detect pub data_carrier_detect: bool, - /// BUSY UART busy. If this bit is set to 1, the UART is busy - /// transmitting data. This bit remains set until the complete - /// byte, including all the stop bits, has been sent from the - /// shift register. This bit is set as soon as the transmit FIFO - /// becomes non-empty, regardless of whether the UART is enabled - /// or not. + /// BUSY: UART busy. In real hardware, set while the UART is + /// busy transmitting data. QEMU's implementation never sets BUSY. pub busy: bool, - /// RXFE Receive FIFO empty. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_H register. If the FIFO - /// is disabled, this bit is set when the receive holding - /// register is empty. If the FIFO is enabled, the RXFE bit is - /// set when the receive FIFO is empty. + /// RXFE: Receive FIFO empty pub receive_fifo_empty: bool, - /// TXFF Transmit FIFO full. The meaning of this bit depends on the - /// state of the FEN bit in the UARTLCR_H register. If the FIFO - /// is disabled, this bit is set when the transmit holding - /// register is full. If the FIFO is enabled, the TXFF bit is - /// set when the transmit FIFO is full. + /// TXFF: Transmit FIFO full pub transmit_fifo_full: bool, - /// RXFF Receive FIFO full. The meaning of this bit depends on the state - /// of the FEN bit in the UARTLCR_H register. If the FIFO is - /// disabled, this bit is set when the receive holding register - /// is full. If the FIFO is enabled, the RXFF bit is set when - /// the receive FIFO is full. + /// RXFF: Receive FIFO full pub receive_fifo_full: bool, - /// Transmit FIFO empty. The meaning of this bit depends on the state of - /// the FEN bit in the [Line Control register](LineControl), - /// `UARTLCR_H`. If the FIFO is disabled, this bit is set when the - /// transmit holding register is empty. If the FIFO is enabled, - /// the TXFE bit is set when the transmit FIFO is empty. This - /// bit does not indicate if there is data in the transmit shift - /// register. + /// TXFE: Transmit FIFO empty pub transmit_fifo_empty: bool, - /// `RI`, is `true` when `nUARTRI` is `LOW`. + /// RI: Ring indicator pub ring_indicator: bool, _reserved_zero_no_modify: u23, } @@ -270,54 +195,23 @@ impl Default for Flags { /// Line Control Register, `UARTLCR_H` #[doc(alias = "UARTLCR_H")] pub struct LineControl { - /// BRK Send break. - /// - /// If this bit is set to `1`, a low-level is continually output on the - /// `UARTTXD` output, after completing transmission of the - /// current character. For the proper execution of the break command, - /// the software must set this bit for at least two complete - /// frames. For normal use, this bit must be cleared to `0`. + /// BRK: Send break pub send_break: bool, - /// 1 PEN Parity enable: - /// - /// - 0 = parity is disabled and no parity bit added to the data frame - /// - 1 = parity checking and generation is enabled. - /// - /// See Table 3-11 on page 3-14 for the parity truth table. + /// PEN: Parity enable pub parity_enabled: bool, - /// EPS Even parity select. Controls the type of parity the UART uses - /// during transmission and reception: - /// - 0 = odd parity. The UART generates or checks for an odd number of 1s - /// in the data and parity bits. - /// - 1 = even parity. The UART generates or checks for an even number of 1s - /// in the data and parity bits. - /// This bit has no effect when the `PEN` bit disables parity checking - /// and generation. See Table 3-11 on page 3-14 for the parity - /// truth table. + /// EPS: Even parity select pub parity: Parity, - /// 3 STP2 Two stop bits select. If this bit is set to 1, two stop bits - /// are transmitted at the end of the frame. The receive - /// logic does not check for two stop bits being received. + /// STP2: Two stop bits select pub two_stops_bits: bool, - /// FEN Enable FIFOs: - /// 0 = FIFOs are disabled (character mode) that is, the FIFOs become - /// 1-byte-deep holding registers 1 = transmit and receive FIFO - /// buffers are enabled (FIFO mode). + /// FEN: Enable FIFOs pub fifos_enabled: Mode, - /// WLEN Word length. These bits indicate the number of data bits - /// transmitted or received in a frame as follows: b11 = 8 bits + /// WLEN: Word length in bits + /// b11 = 8 bits /// b10 = 7 bits /// b01 = 6 bits /// b00 = 5 bits. pub word_length: WordLength, - /// 7 SPS Stick parity select. - /// 0 = stick parity is disabled - /// 1 = either: - /// • if the EPS bit is 0 then the parity bit is transmitted and checked - /// as a 1 • if the EPS bit is 1 then the parity bit is - /// transmitted and checked as a 0. This bit has no effect when - /// the PEN bit disables parity checking and generation. See Table 3-11 - /// on page 3-14 for the parity truth table. + /// SPS Stick parity select pub sticky_parity: bool, /// 31:8 - Reserved, do not modify, read as zero. _reserved_zero_no_modify: u24, @@ -342,11 +236,7 @@ impl Default for LineControl { /// `EPS` "Even parity select", field of [Line Control /// register](LineControl). pub enum Parity { - /// - 0 = odd parity. The UART generates or checks for an odd number of 1s - /// in the data and parity bits. Odd = 0, - /// - 1 = even parity. The UART generates or checks for an even number of 1s - /// in the data and parity bits. Even = 1, } @@ -381,88 +271,39 @@ pub enum WordLength { /// Control Register, `UARTCR` /// -/// The `UARTCR` register is the control register. All the bits are cleared -/// to `0` on reset except for bits `9` and `8` that are set to `1`. -/// -/// # Source -/// ARM DDI 0183G, 3.3.8 Control Register, `UARTCR`, Table 3-12 +/// The `UARTCR` register is the control register. It contains various +/// enable bits, and the bits to write to set the usual outbound RS232 +/// modem control signals. All bits reset to 0 except TXE and RXE. #[bitsize(32)] #[doc(alias = "UARTCR")] #[derive(Clone, Copy, DebugBits, FromBits)] pub struct Control { - /// `UARTEN` UART enable: 0 = UART is disabled. If the UART is disabled - /// in the middle of transmission or reception, it completes the current - /// character before stopping. 1 = the UART is enabled. Data - /// transmission and reception occurs for either UART signals or SIR - /// signals depending on the setting of the SIREN bit. + /// `UARTEN` UART enable: 0 = UART is disabled. pub enable_uart: bool, - /// `SIREN` `SIR` enable: 0 = IrDA SIR ENDEC is disabled. `nSIROUT` - /// remains LOW (no light pulse generated), and signal transitions on - /// SIRIN have no effect. 1 = IrDA SIR ENDEC is enabled. Data is - /// transmitted and received on nSIROUT and SIRIN. UARTTXD remains HIGH, - /// in the marking state. Signal transitions on UARTRXD or modem status - /// inputs have no effect. This bit has no effect if the UARTEN bit - /// disables the UART. + /// `SIREN` `SIR` enable: disable or enable IrDA SIR ENDEC. + /// QEMU does not model this. pub enable_sir: bool, - /// `SIRLP` SIR low-power IrDA mode. This bit selects the IrDA encoding - /// mode. If this bit is cleared to 0, low-level bits are transmitted as - /// an active high pulse with a width of 3/ 16th of the bit period. If - /// this bit is set to 1, low-level bits are transmitted with a pulse - /// width that is 3 times the period of the IrLPBaud16 input signal, - /// regardless of the selected bit rate. Setting this bit uses less - /// power, but might reduce transmission distances. + /// `SIRLP` SIR low-power IrDA mode. QEMU does not model this. pub sir_lowpower_irda_mode: u1, /// Reserved, do not modify, read as zero. _reserved_zero_no_modify: u4, - /// `LBE` Loopback enable. If this bit is set to 1 and the SIREN bit is - /// set to 1 and the SIRTEST bit in the Test Control register, UARTTCR - /// on page 4-5 is set to 1, then the nSIROUT path is inverted, and fed - /// through to the SIRIN path. The SIRTEST bit in the test register must - /// be set to 1 to override the normal half-duplex SIR operation. This - /// must be the requirement for accessing the test registers during - /// normal operation, and SIRTEST must be cleared to 0 when loopback - /// testing is finished. This feature reduces the amount of external - /// coupling required during system test. If this bit is set to 1, and - /// the SIRTEST bit is set to 0, the UARTTXD path is fed through to the - /// UARTRXD path. In either SIR mode or UART mode, when this bit is set, - /// the modem outputs are also fed through to the modem inputs. This bit - /// is cleared to 0 on reset, to disable loopback. + /// `LBE` Loopback enable: feed UART output back to the input pub enable_loopback: bool, - /// `TXE` Transmit enable. If this bit is set to 1, the transmit section - /// of the UART is enabled. Data transmission occurs for either UART - /// signals, or SIR signals depending on the setting of the SIREN bit. - /// When the UART is disabled in the middle of transmission, it - /// completes the current character before stopping. + /// `TXE` Transmit enable pub enable_transmit: bool, - /// `RXE` Receive enable. If this bit is set to 1, the receive section - /// of the UART is enabled. Data reception occurs for either UART - /// signals or SIR signals depending on the setting of the SIREN bit. - /// When the UART is disabled in the middle of reception, it completes - /// the current character before stopping. + /// `RXE` Receive enable pub enable_receive: bool, - /// `DTR` Data transmit ready. This bit is the complement of the UART - /// data transmit ready, `nUARTDTR`, modem status output. That is, when - /// the bit is programmed to a 1 then `nUARTDTR` is LOW. + /// `DTR` Data transmit ready pub data_transmit_ready: bool, - /// `RTS` Request to send. This bit is the complement of the UART - /// request to send, `nUARTRTS`, modem status output. That is, when the - /// bit is programmed to a 1 then `nUARTRTS` is LOW. + /// `RTS` Request to send pub request_to_send: bool, - /// `Out1` This bit is the complement of the UART Out1 (`nUARTOut1`) - /// modem status output. That is, when the bit is programmed to a 1 the - /// output is 0. For DTE this can be used as Data Carrier Detect (DCD). + /// `Out1` UART Out1 signal; can be used as DCD pub out_1: bool, - /// `Out2` This bit is the complement of the UART Out2 (`nUARTOut2`) - /// modem status output. That is, when the bit is programmed to a 1, the - /// output is 0. For DTE this can be used as Ring Indicator (RI). + /// `Out2` UART Out2 signal; can be used as RI pub out_2: bool, - /// `RTSEn` RTS hardware flow control enable. If this bit is set to 1, - /// RTS hardware flow control is enabled. Data is only requested when - /// there is space in the receive FIFO for it to be received. + /// `RTSEn` RTS hardware flow control enable pub rts_hardware_flow_control_enable: bool, - /// `CTSEn` CTS hardware flow control enable. If this bit is set to 1, - /// CTS hardware flow control is enabled. Data is only transmitted when - /// the `nUARTCTS` signal is asserted. + /// `CTSEn` CTS hardware flow control enable pub cts_hardware_flow_control_enable: bool, /// 31:16 - Reserved, do not modify, read as zero. _reserved_zero_no_modify2: u16, From edf838289b7fc698013f18d7a8a83b6b50ec41bb Mon Sep 17 00:00:00 2001 From: Santiago Monserrat Campanello Date: Wed, 14 May 2025 14:29:47 +0100 Subject: [PATCH 0894/2760] hw/arm: Replace TABs for spaces in OMAP board and device code In hw/arm and include/hw/arm, some source files for the OMAP SoC and the sx1 boards that are our only remaining OMAP boards still have hard-coded tabs (almost entirely used for the indent on inline comments, not for actual code indent). Replace the tabs with spaces using vim :retab. I used 4 spaces except in some defines and comments where I tried to put everything aligned in the same column for better readability. This commit is a purely whitespace-only change. Signed-off-by: Santiago Monserrat Campanello Message-id: 20250505131130.82206-1-santimonserr@gmail.com Resolves: https://gitlab.com/qemu-project/qemu/-/issues/373 [PMM: expanded commit message] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/omap1.c | 1016 +++++++++++++++++++------------------- hw/arm/omap_sx1.c | 2 +- hw/dma/omap_dma.c | 334 ++++++------- hw/gpio/omap_gpio.c | 28 +- hw/i2c/omap_i2c.c | 178 +++---- hw/intc/omap_intc.c | 154 +++--- hw/misc/omap_clk.c | 470 +++++++++--------- hw/timer/pxa2xx_timer.c | 76 +-- include/hw/arm/omap.h | 534 ++++++++++---------- include/hw/arm/sharpsl.h | 2 +- include/hw/arm/soc_dma.h | 4 +- 11 files changed, 1399 insertions(+), 1399 deletions(-) diff --git a/hw/arm/omap1.c b/hw/arm/omap1.c index 91d7e3f04b..74458fb7c6 100644 --- a/hw/arm/omap1.c +++ b/hw/arm/omap1.c @@ -144,7 +144,7 @@ static inline void omap_timer_update(struct omap_mpu_timer_s *timer) int64_t expires; if (timer->enable && timer->st && timer->rate) { - timer->val = timer->reset_val; /* Should skip this on clk enable */ + timer->val = timer->reset_val; /* Should skip this on clk enable */ expires = muldiv64((uint64_t) timer->val << (timer->ptv + 1), NANOSECONDS_PER_SECOND, timer->rate); @@ -212,13 +212,13 @@ static uint64_t omap_mpu_timer_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CNTL_TIMER */ + case 0x00: /* CNTL_TIMER */ return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st; - case 0x04: /* LOAD_TIM */ + case 0x04: /* LOAD_TIM */ break; - case 0x08: /* READ_TIM */ + case 0x08: /* READ_TIM */ return omap_timer_read(s); } @@ -237,7 +237,7 @@ static void omap_mpu_timer_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CNTL_TIMER */ + case 0x00: /* CNTL_TIMER */ omap_timer_sync(s); s->enable = (value >> 5) & 1; s->ptv = (value >> 2) & 7; @@ -246,11 +246,11 @@ static void omap_mpu_timer_write(void *opaque, hwaddr addr, omap_timer_update(s); return; - case 0x04: /* LOAD_TIM */ + case 0x04: /* LOAD_TIM */ s->reset_val = value; return; - case 0x08: /* READ_TIM */ + case 0x08: /* READ_TIM */ OMAP_RO_REG(addr); break; @@ -318,14 +318,14 @@ static uint64_t omap_wd_timer_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CNTL_TIMER */ + case 0x00: /* CNTL_TIMER */ return (s->timer.ptv << 9) | (s->timer.ar << 8) | (s->timer.st << 7) | (s->free << 1); - case 0x04: /* READ_TIMER */ + case 0x04: /* READ_TIMER */ return omap_timer_read(&s->timer); - case 0x08: /* TIMER_MODE */ + case 0x08: /* TIMER_MODE */ return s->mode << 15; } @@ -344,7 +344,7 @@ static void omap_wd_timer_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CNTL_TIMER */ + case 0x00: /* CNTL_TIMER */ omap_timer_sync(&s->timer); s->timer.ptv = (value >> 9) & 7; s->timer.ar = (value >> 8) & 1; @@ -353,11 +353,11 @@ static void omap_wd_timer_write(void *opaque, hwaddr addr, omap_timer_update(&s->timer); break; - case 0x04: /* LOAD_TIMER */ + case 0x04: /* LOAD_TIMER */ s->timer.reset_val = value & 0xffff; break; - case 0x08: /* TIMER_MODE */ + case 0x08: /* TIMER_MODE */ if (!s->mode && ((value >> 15) & 1)) omap_clk_get(s->timer.clk); s->mode |= (value >> 15) & 1; @@ -442,13 +442,13 @@ static uint64_t omap_os_timer_read(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* TVR */ + case 0x00: /* TVR */ return s->timer.reset_val; - case 0x04: /* TCR */ + case 0x04: /* TCR */ return omap_timer_read(&s->timer); - case 0x08: /* CR */ + case 0x08: /* CR */ return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st; default: @@ -470,15 +470,15 @@ static void omap_os_timer_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* TVR */ + case 0x00: /* TVR */ s->timer.reset_val = value & 0x00ffffff; break; - case 0x04: /* TCR */ + case 0x04: /* TCR */ OMAP_RO_REG(addr); break; - case 0x08: /* CR */ + case 0x08: /* CR */ s->timer.ar = (value >> 3) & 1; s->timer.it_ena = (value >> 2) & 1; if (s->timer.st != (value & 1) || (value & 2)) { @@ -543,34 +543,34 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x14: /* IT_STATUS */ + case 0x14: /* IT_STATUS */ ret = s->ulpd_pm_regs[addr >> 2]; s->ulpd_pm_regs[addr >> 2] = 0; qemu_irq_lower(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); return ret; - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); /* fall through */ - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x10: /* GAUGING_CTRL */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x30: /* CLOCK_CTRL */ - case 0x34: /* SOFT_REQ */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x3c: /* DPLL_CTRL */ - case 0x40: /* STATUS_REQ */ + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x10: /* GAUGING_CTRL */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x30: /* CLOCK_CTRL */ + case 0x34: /* SOFT_REQ */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x3c: /* DPLL_CTRL */ + case 0x40: /* STATUS_REQ */ /* XXX: check clk::usecount state for every clock */ - case 0x48: /* LOCL_TIME */ - case 0x4c: /* APLL_CTRL */ - case 0x50: /* POWER_CTRL */ + case 0x48: /* LOCL_TIME */ + case 0x4c: /* APLL_CTRL */ + case 0x50: /* POWER_CTRL */ return s->ulpd_pm_regs[addr >> 2]; } @@ -581,22 +581,22 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s, uint16_t diff, uint16_t value) { - if (diff & (1 << 4)) /* USB_MCLK_EN */ + if (diff & (1 << 4)) /* USB_MCLK_EN */ omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1); - if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ + if (diff & (1 << 5)) /* DIS_USB_PVCI_CLK */ omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1); } static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s, uint16_t diff, uint16_t value) { - if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ + if (diff & (1 << 0)) /* SOFT_DPLL_REQ */ omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1); - if (diff & (1 << 1)) /* SOFT_COM_REQ */ + if (diff & (1 << 1)) /* SOFT_COM_REQ */ omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1); - if (diff & (1 << 2)) /* SOFT_SDW_REQ */ + if (diff & (1 << 2)) /* SOFT_SDW_REQ */ omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1); - if (diff & (1 << 3)) /* SOFT_USB_REQ */ + if (diff & (1 << 3)) /* SOFT_USB_REQ */ omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1); } @@ -615,16 +615,16 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* COUNTER_32_LSB */ - case 0x04: /* COUNTER_32_MSB */ - case 0x08: /* COUNTER_HIGH_FREQ_LSB */ - case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ - case 0x14: /* IT_STATUS */ - case 0x40: /* STATUS_REQ */ + case 0x00: /* COUNTER_32_LSB */ + case 0x04: /* COUNTER_32_MSB */ + case 0x08: /* COUNTER_HIGH_FREQ_LSB */ + case 0x0c: /* COUNTER_HIGH_FREQ_MSB */ + case 0x14: /* IT_STATUS */ + case 0x40: /* STATUS_REQ */ OMAP_RO_REG(addr); break; - case 0x10: /* GAUGING_CTRL */ + case 0x10: /* GAUGING_CTRL */ /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */ if ((s->ulpd_pm_regs[addr >> 2] ^ value) & 1) { now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); @@ -638,50 +638,50 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, ticks = muldiv64(now, 32768, NANOSECONDS_PER_SECOND); s->ulpd_pm_regs[0x00 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_32K */ + if (ticks >> 32) /* OVERFLOW_32K */ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2; /* High frequency ticks */ ticks = muldiv64(now, 12000000, NANOSECONDS_PER_SECOND); s->ulpd_pm_regs[0x08 >> 2] = (ticks >> 0) & 0xffff; s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff; - if (ticks >> 32) /* OVERFLOW_HI_FREQ */ + if (ticks >> 32) /* OVERFLOW_HI_FREQ */ s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1; - s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ + s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0; /* IT_GAUGING */ qemu_irq_raise(qdev_get_gpio_in(s->ih[1], OMAP_INT_GAUGE_32K)); } } s->ulpd_pm_regs[addr >> 2] = value; break; - case 0x18: /* Reserved */ - case 0x1c: /* Reserved */ - case 0x20: /* Reserved */ - case 0x28: /* Reserved */ - case 0x2c: /* Reserved */ + case 0x18: /* Reserved */ + case 0x1c: /* Reserved */ + case 0x20: /* Reserved */ + case 0x28: /* Reserved */ + case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); /* fall through */ - case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ - case 0x38: /* COUNTER_32_FIQ */ - case 0x48: /* LOCL_TIME */ - case 0x50: /* POWER_CTRL */ + case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ + case 0x38: /* COUNTER_32_FIQ */ + case 0x48: /* LOCL_TIME */ + case 0x50: /* POWER_CTRL */ s->ulpd_pm_regs[addr >> 2] = value; break; - case 0x30: /* CLOCK_CTRL */ + case 0x30: /* CLOCK_CTRL */ diff = s->ulpd_pm_regs[addr >> 2] ^ value; s->ulpd_pm_regs[addr >> 2] = value & 0x3f; omap_ulpd_clk_update(s, diff, value); break; - case 0x34: /* SOFT_REQ */ + case 0x34: /* SOFT_REQ */ diff = s->ulpd_pm_regs[addr >> 2] ^ value; s->ulpd_pm_regs[addr >> 2] = value & 0x1f; omap_ulpd_req_update(s, diff, value); break; - case 0x3c: /* DPLL_CTRL */ + case 0x3c: /* DPLL_CTRL */ /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is * omitted altogether, probably a typo. */ /* This register has identical semantics with DPLL(1:3) control @@ -689,11 +689,11 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, diff = s->ulpd_pm_regs[addr >> 2] & value; s->ulpd_pm_regs[addr >> 2] = value & 0x2fff; if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ mult = 1; } omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult); @@ -708,10 +708,10 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, s->ulpd_pm_regs[addr >> 2] |= 2; break; - case 0x4c: /* APLL_CTRL */ + case 0x4c: /* APLL_CTRL */ diff = s->ulpd_pm_regs[addr >> 2] & value; s->ulpd_pm_regs[addr >> 2] = value & 0xf; - if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ + if (diff & (1 << 0)) /* APLL_NDPLL_SWITCH */ omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s, (value & (1 << 0)) ? "apll" : "dpll4")); break; @@ -775,43 +775,43 @@ static uint64_t omap_pin_cfg_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* FUNC_MUX_CTRL_0 */ - case 0x04: /* FUNC_MUX_CTRL_1 */ - case 0x08: /* FUNC_MUX_CTRL_2 */ + case 0x00: /* FUNC_MUX_CTRL_0 */ + case 0x04: /* FUNC_MUX_CTRL_1 */ + case 0x08: /* FUNC_MUX_CTRL_2 */ return s->func_mux_ctrl[addr >> 2]; - case 0x0c: /* COMP_MODE_CTRL_0 */ + case 0x0c: /* COMP_MODE_CTRL_0 */ return s->comp_mode_ctrl[0]; - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ return s->func_mux_ctrl[(addr >> 2) - 1]; - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ return s->pull_dwn_ctrl[(addr & 0xf) >> 2]; - case 0x50: /* GATE_INH_CTRL_0 */ + case 0x50: /* GATE_INH_CTRL_0 */ return s->gate_inh_ctrl[0]; - case 0x60: /* VOLTAGE_CTRL_0 */ + case 0x60: /* VOLTAGE_CTRL_0 */ return s->voltage_ctrl[0]; - case 0x70: /* TEST_DBG_CTRL_0 */ + case 0x70: /* TEST_DBG_CTRL_0 */ return s->test_dbg_ctrl[0]; - case 0x80: /* MOD_CONF_CTRL_0 */ + case 0x80: /* MOD_CONF_CTRL_0 */ return s->mod_conf_ctrl[0]; } @@ -823,10 +823,10 @@ static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s, uint32_t diff, uint32_t value) { if (s->compat1509) { - if (diff & (1 << 9)) /* BLUETOOTH */ + if (diff & (1 << 9)) /* BLUETOOTH */ omap_clk_onoff(omap_findclk(s, "bt_mclk_out"), (~value >> 9) & 1); - if (diff & (1 << 7)) /* USB.CLKO */ + if (diff & (1 << 7)) /* USB.CLKO */ omap_clk_onoff(omap_findclk(s, "usb.clko"), (value >> 7) & 1); } @@ -856,23 +856,23 @@ static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s, omap_findclk(s, ((value >> 31) & 1) ? "ck_48m" : "armper_ck")); } - if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ + if (diff & (1 << 30)) /* CONF_MOD_UART2_CLK_MODE_R */ omap_clk_reparent(omap_findclk(s, "uart2_ck"), omap_findclk(s, ((value >> 30) & 1) ? "ck_48m" : "armper_ck")); - if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ + if (diff & (1 << 29)) /* CONF_MOD_UART1_CLK_MODE_R */ omap_clk_reparent(omap_findclk(s, "uart1_ck"), omap_findclk(s, ((value >> 29) & 1) ? "ck_48m" : "armper_ck")); - if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ + if (diff & (1 << 23)) /* CONF_MOD_MMC_SD_CLK_REQ_R */ omap_clk_reparent(omap_findclk(s, "mmc_ck"), omap_findclk(s, ((value >> 23) & 1) ? "ck_48m" : "armper_ck")); - if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ + if (diff & (1 << 12)) /* CONF_MOD_COM_MCLK_12_48_S */ omap_clk_reparent(omap_findclk(s, "com_mclk_out"), omap_findclk(s, ((value >> 12) & 1) ? "ck_48m" : "armper_ck")); - if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ + if (diff & (1 << 9)) /* CONF_MOD_USB_HOST_HHC_UHO */ omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1); } @@ -888,63 +888,63 @@ static void omap_pin_cfg_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* FUNC_MUX_CTRL_0 */ + case 0x00: /* FUNC_MUX_CTRL_0 */ diff = s->func_mux_ctrl[addr >> 2] ^ value; s->func_mux_ctrl[addr >> 2] = value; omap_pin_funcmux0_update(s, diff, value); return; - case 0x04: /* FUNC_MUX_CTRL_1 */ + case 0x04: /* FUNC_MUX_CTRL_1 */ diff = s->func_mux_ctrl[addr >> 2] ^ value; s->func_mux_ctrl[addr >> 2] = value; omap_pin_funcmux1_update(s, diff, value); return; - case 0x08: /* FUNC_MUX_CTRL_2 */ + case 0x08: /* FUNC_MUX_CTRL_2 */ s->func_mux_ctrl[addr >> 2] = value; return; - case 0x0c: /* COMP_MODE_CTRL_0 */ + case 0x0c: /* COMP_MODE_CTRL_0 */ s->comp_mode_ctrl[0] = value; s->compat1509 = (value != 0x0000eaef); omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]); omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]); return; - case 0x10: /* FUNC_MUX_CTRL_3 */ - case 0x14: /* FUNC_MUX_CTRL_4 */ - case 0x18: /* FUNC_MUX_CTRL_5 */ - case 0x1c: /* FUNC_MUX_CTRL_6 */ - case 0x20: /* FUNC_MUX_CTRL_7 */ - case 0x24: /* FUNC_MUX_CTRL_8 */ - case 0x28: /* FUNC_MUX_CTRL_9 */ - case 0x2c: /* FUNC_MUX_CTRL_A */ - case 0x30: /* FUNC_MUX_CTRL_B */ - case 0x34: /* FUNC_MUX_CTRL_C */ - case 0x38: /* FUNC_MUX_CTRL_D */ + case 0x10: /* FUNC_MUX_CTRL_3 */ + case 0x14: /* FUNC_MUX_CTRL_4 */ + case 0x18: /* FUNC_MUX_CTRL_5 */ + case 0x1c: /* FUNC_MUX_CTRL_6 */ + case 0x20: /* FUNC_MUX_CTRL_7 */ + case 0x24: /* FUNC_MUX_CTRL_8 */ + case 0x28: /* FUNC_MUX_CTRL_9 */ + case 0x2c: /* FUNC_MUX_CTRL_A */ + case 0x30: /* FUNC_MUX_CTRL_B */ + case 0x34: /* FUNC_MUX_CTRL_C */ + case 0x38: /* FUNC_MUX_CTRL_D */ s->func_mux_ctrl[(addr >> 2) - 1] = value; return; - case 0x40: /* PULL_DWN_CTRL_0 */ - case 0x44: /* PULL_DWN_CTRL_1 */ - case 0x48: /* PULL_DWN_CTRL_2 */ - case 0x4c: /* PULL_DWN_CTRL_3 */ + case 0x40: /* PULL_DWN_CTRL_0 */ + case 0x44: /* PULL_DWN_CTRL_1 */ + case 0x48: /* PULL_DWN_CTRL_2 */ + case 0x4c: /* PULL_DWN_CTRL_3 */ s->pull_dwn_ctrl[(addr & 0xf) >> 2] = value; return; - case 0x50: /* GATE_INH_CTRL_0 */ + case 0x50: /* GATE_INH_CTRL_0 */ s->gate_inh_ctrl[0] = value; return; - case 0x60: /* VOLTAGE_CTRL_0 */ + case 0x60: /* VOLTAGE_CTRL_0 */ s->voltage_ctrl[0] = value; return; - case 0x70: /* TEST_DBG_CTRL_0 */ + case 0x70: /* TEST_DBG_CTRL_0 */ s->test_dbg_ctrl[0] = value; return; - case 0x80: /* MOD_CONF_CTRL_0 */ + case 0x80: /* MOD_CONF_CTRL_0 */ diff = s->mod_conf_ctrl[0] ^ value; s->mod_conf_ctrl[0] = value; omap_pin_modconf1_update(s, diff, value); @@ -998,17 +998,17 @@ static uint64_t omap_id_read(void *opaque, hwaddr addr, } switch (addr) { - case 0xfffe1800: /* DIE_ID_LSB */ + case 0xfffe1800: /* DIE_ID_LSB */ return 0xc9581f0e; - case 0xfffe1804: /* DIE_ID_MSB */ + case 0xfffe1804: /* DIE_ID_MSB */ return 0xa8858bfa; - case 0xfffe2000: /* PRODUCT_ID_LSB */ + case 0xfffe2000: /* PRODUCT_ID_LSB */ return 0x00aaaafc; - case 0xfffe2004: /* PRODUCT_ID_MSB */ + case 0xfffe2004: /* PRODUCT_ID_MSB */ return 0xcafeb574; - case 0xfffed400: /* JTAG_ID_LSB */ + case 0xfffed400: /* JTAG_ID_LSB */ switch (s->mpu_model) { case omap310: return 0x03310315; @@ -1019,7 +1019,7 @@ static uint64_t omap_id_read(void *opaque, hwaddr addr, } break; - case 0xfffed404: /* JTAG_ID_MSB */ + case 0xfffed404: /* JTAG_ID_MSB */ switch (s->mpu_model) { case omap310: return 0xfb57402f; @@ -1080,22 +1080,22 @@ static uint64_t omap_mpui_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CTRL */ + case 0x00: /* CTRL */ return s->mpui_ctrl; - case 0x04: /* DEBUG_ADDR */ + case 0x04: /* DEBUG_ADDR */ return 0x01ffffff; - case 0x08: /* DEBUG_DATA */ + case 0x08: /* DEBUG_DATA */ return 0xffffffff; - case 0x0c: /* DEBUG_FLAG */ + case 0x0c: /* DEBUG_FLAG */ return 0x00000800; - case 0x10: /* STATUS */ + case 0x10: /* STATUS */ return 0x00000000; /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ - case 0x18: /* DSP_BOOT_CONFIG */ + case 0x14: /* DSP_STATUS */ + case 0x18: /* DSP_BOOT_CONFIG */ return 0x00000000; - case 0x1c: /* DSP_MPUI_CONFIG */ + case 0x1c: /* DSP_MPUI_CONFIG */ return 0x0000ffff; } @@ -1114,20 +1114,20 @@ static void omap_mpui_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* CTRL */ + case 0x00: /* CTRL */ s->mpui_ctrl = value & 0x007fffff; break; - case 0x04: /* DEBUG_ADDR */ - case 0x08: /* DEBUG_DATA */ - case 0x0c: /* DEBUG_FLAG */ - case 0x10: /* STATUS */ + case 0x04: /* DEBUG_ADDR */ + case 0x08: /* DEBUG_DATA */ + case 0x0c: /* DEBUG_FLAG */ + case 0x10: /* STATUS */ /* Not in OMAP310 */ - case 0x14: /* DSP_STATUS */ + case 0x14: /* DSP_STATUS */ OMAP_RO_REG(addr); break; - case 0x18: /* DSP_BOOT_CONFIG */ - case 0x1c: /* DSP_MPUI_CONFIG */ + case 0x18: /* DSP_BOOT_CONFIG */ + case 0x1c: /* DSP_MPUI_CONFIG */ break; default: @@ -1178,19 +1178,19 @@ static uint64_t omap_tipb_bridge_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* TIPB_CNTL */ + case 0x00: /* TIPB_CNTL */ return s->control; - case 0x04: /* TIPB_BUS_ALLOC */ + case 0x04: /* TIPB_BUS_ALLOC */ return s->alloc; - case 0x08: /* MPU_TIPB_CNTL */ + case 0x08: /* MPU_TIPB_CNTL */ return s->buffer; - case 0x0c: /* ENHANCED_TIPB_CNTL */ + case 0x0c: /* ENHANCED_TIPB_CNTL */ return s->enh_control; - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ return 0xffff; - case 0x1c: /* DEBUG_CNTR_SIG */ + case 0x1c: /* DEBUG_CNTR_SIG */ return 0x00f8; } @@ -1209,27 +1209,27 @@ static void omap_tipb_bridge_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* TIPB_CNTL */ + case 0x00: /* TIPB_CNTL */ s->control = value & 0xffff; break; - case 0x04: /* TIPB_BUS_ALLOC */ + case 0x04: /* TIPB_BUS_ALLOC */ s->alloc = value & 0x003f; break; - case 0x08: /* MPU_TIPB_CNTL */ + case 0x08: /* MPU_TIPB_CNTL */ s->buffer = value & 0x0003; break; - case 0x0c: /* ENHANCED_TIPB_CNTL */ + case 0x0c: /* ENHANCED_TIPB_CNTL */ s->width_intr = !(value & 2); s->enh_control = value & 0x000f; break; - case 0x10: /* ADDRESS_DBG */ - case 0x14: /* DATA_DEBUG_LOW */ - case 0x18: /* DATA_DEBUG_HIGH */ - case 0x1c: /* DEBUG_CNTR_SIG */ + case 0x10: /* ADDRESS_DBG */ + case 0x14: /* DATA_DEBUG_LOW */ + case 0x18: /* DATA_DEBUG_HIGH */ + case 0x1c: /* DEBUG_CNTR_SIG */ OMAP_RO_REG(addr); break; @@ -1280,23 +1280,23 @@ static uint64_t omap_tcmi_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x0c: /* EMIFS_CONFIG */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x0c: /* EMIFS_CONFIG */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ return s->tcmi_regs[addr >> 2]; - case 0x20: /* EMIFF_SDRAM_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ ret = s->tcmi_regs[addr >> 2]; s->tcmi_regs[addr >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ /* XXX: We can try using the VGA_DIRTY flag for this */ @@ -1318,23 +1318,23 @@ static void omap_tcmi_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* IMIF_PRIO */ - case 0x04: /* EMIFS_PRIO */ - case 0x08: /* EMIFF_PRIO */ - case 0x10: /* EMIFS_CS0_CONFIG */ - case 0x14: /* EMIFS_CS1_CONFIG */ - case 0x18: /* EMIFS_CS2_CONFIG */ - case 0x1c: /* EMIFS_CS3_CONFIG */ - case 0x20: /* EMIFF_SDRAM_CONFIG */ - case 0x24: /* EMIFF_MRS */ - case 0x28: /* TIMEOUT1 */ - case 0x2c: /* TIMEOUT2 */ - case 0x30: /* TIMEOUT3 */ - case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ - case 0x40: /* EMIFS_CFG_DYN_WAIT */ + case 0x00: /* IMIF_PRIO */ + case 0x04: /* EMIFS_PRIO */ + case 0x08: /* EMIFF_PRIO */ + case 0x10: /* EMIFS_CS0_CONFIG */ + case 0x14: /* EMIFS_CS1_CONFIG */ + case 0x18: /* EMIFS_CS2_CONFIG */ + case 0x1c: /* EMIFS_CS3_CONFIG */ + case 0x20: /* EMIFF_SDRAM_CONFIG */ + case 0x24: /* EMIFF_MRS */ + case 0x28: /* TIMEOUT1 */ + case 0x2c: /* TIMEOUT2 */ + case 0x30: /* TIMEOUT3 */ + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ + case 0x40: /* EMIFS_CFG_DYN_WAIT */ s->tcmi_regs[addr >> 2] = value; break; - case 0x0c: /* EMIFS_CONFIG */ + case 0x0c: /* EMIFS_CONFIG */ s->tcmi_regs[addr >> 2] = (value & 0xf) | (1 << 4); break; @@ -1393,7 +1393,7 @@ static uint64_t omap_dpll_read(void *opaque, hwaddr addr, return omap_badwidth_read16(opaque, addr); } - if (addr == 0x00) /* CTL_REG */ + if (addr == 0x00) /* CTL_REG */ return s->mode; OMAP_BAD_REG(addr); @@ -1413,16 +1413,16 @@ static void omap_dpll_write(void *opaque, hwaddr addr, return; } - if (addr == 0x00) { /* CTL_REG */ + if (addr == 0x00) { /* CTL_REG */ /* See omap_ulpd_pm_write() too */ diff = s->mode & value; s->mode = value & 0x2fff; if (diff & (0x3ff << 2)) { - if (value & (1 << 4)) { /* PLL_ENABLE */ - div = ((value >> 5) & 3) + 1; /* PLL_DIV */ - mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ + if (value & (1 << 4)) { /* PLL_ENABLE */ + div = ((value >> 5) & 3) + 1; /* PLL_DIV */ + mult = MIN((value >> 7) & 0x1f, 1); /* PLL_MULT */ } else { - div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ + div = bypass_div[((value >> 2) & 3)]; /* BYPASS_DIV */ mult = 1; } omap_clk_setrate(s->dpll, div, mult); @@ -1474,31 +1474,31 @@ static uint64_t omap_clkm_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* ARM_CKCTL */ + case 0x00: /* ARM_CKCTL */ return s->clkm.arm_ckctl; - case 0x04: /* ARM_IDLECT1 */ + case 0x04: /* ARM_IDLECT1 */ return s->clkm.arm_idlect1; - case 0x08: /* ARM_IDLECT2 */ + case 0x08: /* ARM_IDLECT2 */ return s->clkm.arm_idlect2; - case 0x0c: /* ARM_EWUPCT */ + case 0x0c: /* ARM_EWUPCT */ return s->clkm.arm_ewupct; - case 0x10: /* ARM_RSTCT1 */ + case 0x10: /* ARM_RSTCT1 */ return s->clkm.arm_rstct1; - case 0x14: /* ARM_RSTCT2 */ + case 0x14: /* ARM_RSTCT2 */ return s->clkm.arm_rstct2; - case 0x18: /* ARM_SYSST */ + case 0x18: /* ARM_SYSST */ return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; - case 0x1c: /* ARM_CKOUT1 */ + case 0x1c: /* ARM_CKOUT1 */ return s->clkm.arm_ckout1; - case 0x20: /* ARM_CKOUT2 */ + case 0x20: /* ARM_CKOUT2 */ break; } @@ -1511,7 +1511,7 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, { omap_clk clk; - if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ + if (diff & (1 << 14)) { /* ARM_INTHCK_SEL */ if (value & (1 << 14)) /* Reserved */; else { @@ -1519,7 +1519,7 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, omap_clk_reparent(clk, omap_findclk(s, "tc_ck")); } } - if (diff & (1 << 12)) { /* ARM_TIMXO */ + if (diff & (1 << 12)) { /* ARM_TIMXO */ clk = omap_findclk(s, "armtim_ck"); if (value & (1 << 12)) omap_clk_reparent(clk, omap_findclk(s, "clkin")); @@ -1527,27 +1527,27 @@ static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s, omap_clk_reparent(clk, omap_findclk(s, "ck_gen1")); } /* XXX: en_dspck */ - if (diff & (3 << 10)) { /* DSPMMUDIV */ + if (diff & (3 << 10)) { /* DSPMMUDIV */ clk = omap_findclk(s, "dspmmu_ck"); omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1); } - if (diff & (3 << 8)) { /* TCDIV */ + if (diff & (3 << 8)) { /* TCDIV */ clk = omap_findclk(s, "tc_ck"); omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1); } - if (diff & (3 << 6)) { /* DSPDIV */ + if (diff & (3 << 6)) { /* DSPDIV */ clk = omap_findclk(s, "dsp_ck"); omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1); } - if (diff & (3 << 4)) { /* ARMDIV */ + if (diff & (3 << 4)) { /* ARMDIV */ clk = omap_findclk(s, "arm_ck"); omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1); } - if (diff & (3 << 2)) { /* LCDDIV */ + if (diff & (3 << 2)) { /* LCDDIV */ clk = omap_findclk(s, "lcd_ck"); omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1); } - if (diff & (3 << 0)) { /* PERDIV */ + if (diff & (3 << 0)) { /* PERDIV */ clk = omap_findclk(s, "armper_ck"); omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1); } @@ -1566,25 +1566,25 @@ static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s, qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); } -#define SET_CANIDLE(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_canidle(clk, (value >> bit) & 1); \ +#define SET_CANIDLE(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_canidle(clk, (value >> bit) & 1); \ } - SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ - SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ - SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ - SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ - SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ - SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ - SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ - SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ - SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ - SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ + SET_CANIDLE("mpuwd_ck", 0) /* IDLWDT_ARM */ + SET_CANIDLE("armxor_ck", 1) /* IDLXORP_ARM */ + SET_CANIDLE("mpuper_ck", 2) /* IDLPER_ARM */ + SET_CANIDLE("lcd_ck", 3) /* IDLLCD_ARM */ + SET_CANIDLE("lb_ck", 4) /* IDLLB_ARM */ + SET_CANIDLE("hsab_ck", 5) /* IDLHSAB_ARM */ + SET_CANIDLE("tipb_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dma_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("tc_ck", 6) /* IDLIF_ARM */ + SET_CANIDLE("dpll1", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll2", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("dpll3", 7) /* IDLDPLL_ARM */ + SET_CANIDLE("mpui_ck", 8) /* IDLAPI_ARM */ + SET_CANIDLE("armtim_ck", 9) /* IDLTIM_ARM */ } static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, @@ -1592,22 +1592,22 @@ static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s, { omap_clk clk; -#define SET_ONOFF(clock, bit) \ - if (diff & (1 << bit)) { \ - clk = omap_findclk(s, clock); \ - omap_clk_onoff(clk, (value >> bit) & 1); \ +#define SET_ONOFF(clock, bit) \ + if (diff & (1 << bit)) { \ + clk = omap_findclk(s, clock); \ + omap_clk_onoff(clk, (value >> bit) & 1); \ } - SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ - SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ - SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ - SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ - SET_ONOFF("lb_ck", 4) /* EN_LBCK */ - SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ - SET_ONOFF("mpui_ck", 6) /* EN_APICK */ - SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ - SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ - SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ - SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ + SET_ONOFF("mpuwd_ck", 0) /* EN_WDTCK */ + SET_ONOFF("armxor_ck", 1) /* EN_XORPCK */ + SET_ONOFF("mpuper_ck", 2) /* EN_PERCK */ + SET_ONOFF("lcd_ck", 3) /* EN_LCDCK */ + SET_ONOFF("lb_ck", 4) /* EN_LBCK */ + SET_ONOFF("hsab_ck", 5) /* EN_HSABCK */ + SET_ONOFF("mpui_ck", 6) /* EN_APICK */ + SET_ONOFF("armtim_ck", 7) /* EN_TIMCK */ + SET_CANIDLE("dma_ck", 8) /* DMACK_REQ */ + SET_ONOFF("arm_gpio_ck", 9) /* EN_GPIOCK */ + SET_ONOFF("lbfree_ck", 10) /* EN_LBFREECK */ } static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, @@ -1615,7 +1615,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, { omap_clk clk; - if (diff & (3 << 4)) { /* TCLKOUT */ + if (diff & (3 << 4)) { /* TCLKOUT */ clk = omap_findclk(s, "tclk_out"); switch ((value >> 4) & 3) { case 1: @@ -1630,7 +1630,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, omap_clk_onoff(clk, 0); } } - if (diff & (3 << 2)) { /* DCLKOUT */ + if (diff & (3 << 2)) { /* DCLKOUT */ clk = omap_findclk(s, "dclk_out"); switch ((value >> 2) & 3) { case 0: @@ -1647,7 +1647,7 @@ static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s, break; } } - if (diff & (3 << 0)) { /* ACLKOUT */ + if (diff & (3 << 0)) { /* ACLKOUT */ clk = omap_findclk(s, "aclk_out"); switch ((value >> 0) & 3) { case 1: @@ -1685,51 +1685,51 @@ static void omap_clkm_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x00: /* ARM_CKCTL */ + case 0x00: /* ARM_CKCTL */ diff = s->clkm.arm_ckctl ^ value; s->clkm.arm_ckctl = value & 0x7fff; omap_clkm_ckctl_update(s, diff, value); return; - case 0x04: /* ARM_IDLECT1 */ + case 0x04: /* ARM_IDLECT1 */ diff = s->clkm.arm_idlect1 ^ value; s->clkm.arm_idlect1 = value & 0x0fff; omap_clkm_idlect1_update(s, diff, value); return; - case 0x08: /* ARM_IDLECT2 */ + case 0x08: /* ARM_IDLECT2 */ diff = s->clkm.arm_idlect2 ^ value; s->clkm.arm_idlect2 = value & 0x07ff; omap_clkm_idlect2_update(s, diff, value); return; - case 0x0c: /* ARM_EWUPCT */ + case 0x0c: /* ARM_EWUPCT */ s->clkm.arm_ewupct = value & 0x003f; return; - case 0x10: /* ARM_RSTCT1 */ + case 0x10: /* ARM_RSTCT1 */ diff = s->clkm.arm_rstct1 ^ value; s->clkm.arm_rstct1 = value & 0x0007; if (value & 9) { qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); s->clkm.cold_start = 0xa; } - if (diff & ~value & 4) { /* DSP_RST */ + if (diff & ~value & 4) { /* DSP_RST */ omap_mpui_reset(s); omap_tipb_bridge_reset(s->private_tipb); omap_tipb_bridge_reset(s->public_tipb); } - if (diff & 2) { /* DSP_EN */ + if (diff & 2) { /* DSP_EN */ clk = omap_findclk(s, "dsp_ck"); omap_clk_canidle(clk, (~value >> 1) & 1); } return; - case 0x14: /* ARM_RSTCT2 */ + case 0x14: /* ARM_RSTCT2 */ s->clkm.arm_rstct2 = value & 0x0001; return; - case 0x18: /* ARM_SYSST */ + case 0x18: /* ARM_SYSST */ if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) { s->clkm.clocking_scheme = (value >> 11) & 7; trace_omap1_pwl_clocking_scheme( @@ -1738,13 +1738,13 @@ static void omap_clkm_write(void *opaque, hwaddr addr, s->clkm.cold_start &= value & 0x3f; return; - case 0x1c: /* ARM_CKOUT1 */ + case 0x1c: /* ARM_CKOUT1 */ diff = s->clkm.arm_ckout1 ^ value; s->clkm.arm_ckout1 = value & 0x003f; omap_clkm_ckout1_update(s, diff, value); return; - case 0x20: /* ARM_CKOUT2 */ + case 0x20: /* ARM_CKOUT2 */ default: OMAP_BAD_REG(addr); } @@ -1767,16 +1767,16 @@ static uint64_t omap_clkdsp_read(void *opaque, hwaddr addr, } switch (addr) { - case 0x04: /* DSP_IDLECT1 */ + case 0x04: /* DSP_IDLECT1 */ return s->clkm.dsp_idlect1; - case 0x08: /* DSP_IDLECT2 */ + case 0x08: /* DSP_IDLECT2 */ return s->clkm.dsp_idlect2; - case 0x14: /* DSP_RSTCT2 */ + case 0x14: /* DSP_RSTCT2 */ return s->clkm.dsp_rstct2; - case 0x18: /* DSP_SYSST */ + case 0x18: /* DSP_SYSST */ return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | (cpu->halted << 6); /* Quite useless... */ } @@ -1790,7 +1790,7 @@ static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s, { omap_clk clk; - SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ + SET_CANIDLE("dspxor_ck", 1); /* IDLXORP_DSP */ } static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, @@ -1798,7 +1798,7 @@ static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s, { omap_clk clk; - SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ + SET_ONOFF("dspxor_ck", 1); /* EN_XORPCK */ } static void omap_clkdsp_write(void *opaque, hwaddr addr, @@ -1813,23 +1813,23 @@ static void omap_clkdsp_write(void *opaque, hwaddr addr, } switch (addr) { - case 0x04: /* DSP_IDLECT1 */ + case 0x04: /* DSP_IDLECT1 */ diff = s->clkm.dsp_idlect1 ^ value; s->clkm.dsp_idlect1 = value & 0x01f7; omap_clkdsp_idlect1_update(s, diff, value); break; - case 0x08: /* DSP_IDLECT2 */ + case 0x08: /* DSP_IDLECT2 */ s->clkm.dsp_idlect2 = value & 0x0037; diff = s->clkm.dsp_idlect1 ^ value; omap_clkdsp_idlect2_update(s, diff, value); break; - case 0x14: /* DSP_RSTCT2 */ + case 0x14: /* DSP_RSTCT2 */ s->clkm.dsp_rstct2 = value & 0x0001; break; - case 0x18: /* DSP_SYSST */ + case 0x18: /* DSP_SYSST */ s->clkm.cold_start &= value & 0x3f; break; @@ -1928,8 +1928,8 @@ static void omap_mpuio_set(void *opaque, int line, int level) qemu_irq_raise(s->irq); /* TODO: wakeup */ } - if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ - (s->event >> 1) == line) /* PIN_SELECT */ + if ((s->event & (1 << 0)) && /* SET_GPIO_EVENT_MODE */ + (s->event >> 1) == line) /* PIN_SELECT */ s->latch = s->inputs; } } @@ -1959,47 +1959,47 @@ static uint64_t omap_mpuio_read(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* INPUT_LATCH */ + case 0x00: /* INPUT_LATCH */ return s->inputs; - case 0x04: /* OUTPUT_REG */ + case 0x04: /* OUTPUT_REG */ return s->outputs; - case 0x08: /* IO_CNTL */ + case 0x08: /* IO_CNTL */ return s->dir; - case 0x10: /* KBR_LATCH */ + case 0x10: /* KBR_LATCH */ return s->row_latch; - case 0x14: /* KBC_REG */ + case 0x14: /* KBC_REG */ return s->cols; - case 0x18: /* GPIO_EVENT_MODE_REG */ + case 0x18: /* GPIO_EVENT_MODE_REG */ return s->event; - case 0x1c: /* GPIO_INT_EDGE_REG */ + case 0x1c: /* GPIO_INT_EDGE_REG */ return s->edge; - case 0x20: /* KBD_INT */ + case 0x20: /* KBD_INT */ return (~s->row_latch & 0x1f) && !s->kbd_mask; - case 0x24: /* GPIO_INT */ + case 0x24: /* GPIO_INT */ ret = s->ints; s->ints &= s->mask; if (ret) qemu_irq_lower(s->irq); return ret; - case 0x28: /* KBD_MASKIT */ + case 0x28: /* KBD_MASKIT */ return s->kbd_mask; - case 0x2c: /* GPIO_MASKIT */ + case 0x2c: /* GPIO_MASKIT */ return s->mask; - case 0x30: /* GPIO_DEBOUNCING_REG */ + case 0x30: /* GPIO_DEBOUNCING_REG */ return s->debounce; - case 0x34: /* GPIO_LATCH_REG */ + case 0x34: /* GPIO_LATCH_REG */ return s->latch; } @@ -2021,7 +2021,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x04: /* OUTPUT_REG */ + case 0x04: /* OUTPUT_REG */ diff = (s->outputs ^ value) & ~s->dir; s->outputs = value; while ((ln = ctz32(diff)) != 32) { @@ -2031,7 +2031,7 @@ static void omap_mpuio_write(void *opaque, hwaddr addr, } break; - case 0x08: /* IO_CNTL */ + case 0x08: /* IO_CNTL */ diff = s->outputs & (s->dir ^ value); s->dir = value; @@ -2043,37 +2043,37 @@ static void omap_mpuio_write(void *opaque, hwaddr addr, } break; - case 0x14: /* KBC_REG */ + case 0x14: /* KBC_REG */ s->cols = value; omap_mpuio_kbd_update(s); break; - case 0x18: /* GPIO_EVENT_MODE_REG */ + case 0x18: /* GPIO_EVENT_MODE_REG */ s->event = value & 0x1f; break; - case 0x1c: /* GPIO_INT_EDGE_REG */ + case 0x1c: /* GPIO_INT_EDGE_REG */ s->edge = value; break; - case 0x28: /* KBD_MASKIT */ + case 0x28: /* KBD_MASKIT */ s->kbd_mask = value & 1; omap_mpuio_kbd_update(s); break; - case 0x2c: /* GPIO_MASKIT */ + case 0x2c: /* GPIO_MASKIT */ s->mask = value; break; - case 0x30: /* GPIO_DEBOUNCING_REG */ + case 0x30: /* GPIO_DEBOUNCING_REG */ s->debounce = value & 0x1ff; break; - case 0x00: /* INPUT_LATCH */ - case 0x10: /* KBR_LATCH */ - case 0x20: /* KBD_INT */ - case 0x24: /* GPIO_INT */ - case 0x34: /* GPIO_LATCH_REG */ + case 0x00: /* INPUT_LATCH */ + case 0x10: /* KBR_LATCH */ + case 0x20: /* KBD_INT */ + case 0x24: /* GPIO_INT */ + case 0x34: /* GPIO_LATCH_REG */ OMAP_RO_REG(addr); return; @@ -2176,24 +2176,24 @@ struct omap_uwire_s { static void omap_uwire_transfer_start(struct omap_uwire_s *s) { - int chipselect = (s->control >> 10) & 3; /* INDEX */ + int chipselect = (s->control >> 10) & 3; /* INDEX */ - if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ + if ((s->control >> 5) & 0x1f) { /* NB_BITS_WR */ if (s->control & (1 << 12)) { /* CS_CMD */ qemu_log_mask(LOG_UNIMP, "uWireSlave TX CS:%d data:0x%04x\n", chipselect, s->txbuf >> (16 - ((s->control >> 5) & 0x1f))); } - s->control &= ~(1 << 14); /* CSRB */ + s->control &= ~(1 << 14); /* CSRB */ /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or * a DRQ. When is the level IRQ supposed to be reset? */ } - if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ + if ((s->control >> 0) & 0x1f) { /* NB_BITS_RD */ if (s->control & (1 << 12)) { /* CS_CMD */ qemu_log_mask(LOG_UNIMP, "uWireSlave RX CS:%d\n", chipselect); } - s->control |= 1 << 15; /* RDRB */ + s->control |= 1 << 15; /* RDRB */ /* TODO: depending on s->setup[4] bits [1:0] assert an IRQ or * a DRQ. When is the level IRQ supposed to be reset? */ } @@ -2209,22 +2209,22 @@ static uint64_t omap_uwire_read(void *opaque, hwaddr addr, unsigned size) } switch (offset) { - case 0x00: /* RDR */ - s->control &= ~(1 << 15); /* RDRB */ + case 0x00: /* RDR */ + s->control &= ~(1 << 15); /* RDRB */ return s->rxbuf; - case 0x04: /* CSR */ + case 0x04: /* CSR */ return s->control; - case 0x08: /* SR1 */ + case 0x08: /* SR1 */ return s->setup[0]; - case 0x0c: /* SR2 */ + case 0x0c: /* SR2 */ return s->setup[1]; - case 0x10: /* SR3 */ + case 0x10: /* SR3 */ return s->setup[2]; - case 0x14: /* SR4 */ + case 0x14: /* SR4 */ return s->setup[3]; - case 0x18: /* SR5 */ + case 0x18: /* SR5 */ return s->setup[4]; } @@ -2244,39 +2244,39 @@ static void omap_uwire_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* TDR */ - s->txbuf = value; /* TD */ - if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ - ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ - (s->control & (1 << 12)))) { /* CS_CMD */ - s->control |= 1 << 14; /* CSRB */ + case 0x00: /* TDR */ + s->txbuf = value; /* TD */ + if ((s->setup[4] & (1 << 2)) && /* AUTO_TX_EN */ + ((s->setup[4] & (1 << 3)) || /* CS_TOGGLE_TX_EN */ + (s->control & (1 << 12)))) { /* CS_CMD */ + s->control |= 1 << 14; /* CSRB */ omap_uwire_transfer_start(s); } break; - case 0x04: /* CSR */ + case 0x04: /* CSR */ s->control = value & 0x1fff; - if (value & (1 << 13)) /* START */ + if (value & (1 << 13)) /* START */ omap_uwire_transfer_start(s); break; - case 0x08: /* SR1 */ + case 0x08: /* SR1 */ s->setup[0] = value & 0x003f; break; - case 0x0c: /* SR2 */ + case 0x0c: /* SR2 */ s->setup[1] = value & 0x0fc0; break; - case 0x10: /* SR3 */ + case 0x10: /* SR3 */ s->setup[2] = value & 0x0003; break; - case 0x14: /* SR4 */ + case 0x14: /* SR4 */ s->setup[3] = value & 0x0001; break; - case 0x18: /* SR5 */ + case 0x18: /* SR5 */ s->setup[4] = value & 0x000f; break; @@ -2350,9 +2350,9 @@ static uint64_t omap_pwl_read(void *opaque, hwaddr addr, unsigned size) } switch (offset) { - case 0x00: /* PWL_LEVEL */ + case 0x00: /* PWL_LEVEL */ return s->level; - case 0x04: /* PWL_CTRL */ + case 0x04: /* PWL_CTRL */ return s->enable; } OMAP_BAD_REG(addr); @@ -2371,11 +2371,11 @@ static void omap_pwl_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* PWL_LEVEL */ + case 0x00: /* PWL_LEVEL */ s->level = value; omap_pwl_update(s); break; - case 0x04: /* PWL_CTRL */ + case 0x04: /* PWL_CTRL */ s->enable = value & 1; omap_pwl_update(s); break; @@ -2443,11 +2443,11 @@ static uint64_t omap_pwt_read(void *opaque, hwaddr addr, unsigned size) } switch (offset) { - case 0x00: /* FRC */ + case 0x00: /* FRC */ return s->frc; - case 0x04: /* VCR */ + case 0x04: /* VCR */ return s->vrc; - case 0x08: /* GCR */ + case 0x08: /* GCR */ return s->gcr; } OMAP_BAD_REG(addr); @@ -2466,10 +2466,10 @@ static void omap_pwt_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* FRC */ + case 0x00: /* FRC */ s->frc = value & 0x3f; break; - case 0x04: /* VRC */ + case 0x04: /* VRC */ if ((value ^ s->vrc) & 1) { if (value & 1) { trace_omap1_pwt_buzz( @@ -2494,7 +2494,7 @@ static void omap_pwt_write(void *opaque, hwaddr addr, } s->vrc = value & 0x7f; break; - case 0x08: /* GCR */ + case 0x08: /* GCR */ s->gcr = value & 3; break; default: @@ -2577,69 +2577,69 @@ static uint64_t omap_rtc_read(void *opaque, hwaddr addr, unsigned size) } switch (offset) { - case 0x00: /* SECONDS_REG */ + case 0x00: /* SECONDS_REG */ return to_bcd(s->current_tm.tm_sec); - case 0x04: /* MINUTES_REG */ + case 0x04: /* MINUTES_REG */ return to_bcd(s->current_tm.tm_min); - case 0x08: /* HOURS_REG */ + case 0x08: /* HOURS_REG */ if (s->pm_am) return ((s->current_tm.tm_hour > 11) << 7) | to_bcd(((s->current_tm.tm_hour - 1) % 12) + 1); else return to_bcd(s->current_tm.tm_hour); - case 0x0c: /* DAYS_REG */ + case 0x0c: /* DAYS_REG */ return to_bcd(s->current_tm.tm_mday); - case 0x10: /* MONTHS_REG */ + case 0x10: /* MONTHS_REG */ return to_bcd(s->current_tm.tm_mon + 1); - case 0x14: /* YEARS_REG */ + case 0x14: /* YEARS_REG */ return to_bcd(s->current_tm.tm_year % 100); - case 0x18: /* WEEK_REG */ + case 0x18: /* WEEK_REG */ return s->current_tm.tm_wday; - case 0x20: /* ALARM_SECONDS_REG */ + case 0x20: /* ALARM_SECONDS_REG */ return to_bcd(s->alarm_tm.tm_sec); - case 0x24: /* ALARM_MINUTES_REG */ + case 0x24: /* ALARM_MINUTES_REG */ return to_bcd(s->alarm_tm.tm_min); - case 0x28: /* ALARM_HOURS_REG */ + case 0x28: /* ALARM_HOURS_REG */ if (s->pm_am) return ((s->alarm_tm.tm_hour > 11) << 7) | to_bcd(((s->alarm_tm.tm_hour - 1) % 12) + 1); else return to_bcd(s->alarm_tm.tm_hour); - case 0x2c: /* ALARM_DAYS_REG */ + case 0x2c: /* ALARM_DAYS_REG */ return to_bcd(s->alarm_tm.tm_mday); - case 0x30: /* ALARM_MONTHS_REG */ + case 0x30: /* ALARM_MONTHS_REG */ return to_bcd(s->alarm_tm.tm_mon + 1); - case 0x34: /* ALARM_YEARS_REG */ + case 0x34: /* ALARM_YEARS_REG */ return to_bcd(s->alarm_tm.tm_year % 100); - case 0x40: /* RTC_CTRL_REG */ + case 0x40: /* RTC_CTRL_REG */ return (s->pm_am << 3) | (s->auto_comp << 2) | (s->round << 1) | s->running; - case 0x44: /* RTC_STATUS_REG */ + case 0x44: /* RTC_STATUS_REG */ i = s->status; s->status &= ~0x3d; return i; - case 0x48: /* RTC_INTERRUPTS_REG */ + case 0x48: /* RTC_INTERRUPTS_REG */ return s->interrupts; - case 0x4c: /* RTC_COMP_LSB_REG */ + case 0x4c: /* RTC_COMP_LSB_REG */ return ((uint16_t) s->comp_reg) & 0xff; - case 0x50: /* RTC_COMP_MSB_REG */ + case 0x50: /* RTC_COMP_MSB_REG */ return ((uint16_t) s->comp_reg) >> 8; } @@ -2661,17 +2661,17 @@ static void omap_rtc_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* SECONDS_REG */ + case 0x00: /* SECONDS_REG */ s->ti -= s->current_tm.tm_sec; s->ti += from_bcd(value); return; - case 0x04: /* MINUTES_REG */ + case 0x04: /* MINUTES_REG */ s->ti -= s->current_tm.tm_min * 60; s->ti += from_bcd(value) * 60; return; - case 0x08: /* HOURS_REG */ + case 0x08: /* HOURS_REG */ s->ti -= s->current_tm.tm_hour * 3600; if (s->pm_am) { s->ti += (from_bcd(value & 0x3f) & 12) * 3600; @@ -2680,12 +2680,12 @@ static void omap_rtc_write(void *opaque, hwaddr addr, s->ti += from_bcd(value & 0x3f) * 3600; return; - case 0x0c: /* DAYS_REG */ + case 0x0c: /* DAYS_REG */ s->ti -= s->current_tm.tm_mday * 86400; s->ti += from_bcd(value) * 86400; return; - case 0x10: /* MONTHS_REG */ + case 0x10: /* MONTHS_REG */ memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); new_tm.tm_mon = from_bcd(value); ti[0] = mktimegm(&s->current_tm); @@ -2701,7 +2701,7 @@ static void omap_rtc_write(void *opaque, hwaddr addr, } return; - case 0x14: /* YEARS_REG */ + case 0x14: /* YEARS_REG */ memcpy(&new_tm, &s->current_tm, sizeof(new_tm)); new_tm.tm_year += from_bcd(value) - (new_tm.tm_year % 100); ti[0] = mktimegm(&s->current_tm); @@ -2717,20 +2717,20 @@ static void omap_rtc_write(void *opaque, hwaddr addr, } return; - case 0x18: /* WEEK_REG */ - return; /* Ignored */ + case 0x18: /* WEEK_REG */ + return; /* Ignored */ - case 0x20: /* ALARM_SECONDS_REG */ + case 0x20: /* ALARM_SECONDS_REG */ s->alarm_tm.tm_sec = from_bcd(value); omap_rtc_alarm_update(s); return; - case 0x24: /* ALARM_MINUTES_REG */ + case 0x24: /* ALARM_MINUTES_REG */ s->alarm_tm.tm_min = from_bcd(value); omap_rtc_alarm_update(s); return; - case 0x28: /* ALARM_HOURS_REG */ + case 0x28: /* ALARM_HOURS_REG */ if (s->pm_am) s->alarm_tm.tm_hour = ((from_bcd(value & 0x3f)) % 12) + @@ -2740,22 +2740,22 @@ static void omap_rtc_write(void *opaque, hwaddr addr, omap_rtc_alarm_update(s); return; - case 0x2c: /* ALARM_DAYS_REG */ + case 0x2c: /* ALARM_DAYS_REG */ s->alarm_tm.tm_mday = from_bcd(value); omap_rtc_alarm_update(s); return; - case 0x30: /* ALARM_MONTHS_REG */ + case 0x30: /* ALARM_MONTHS_REG */ s->alarm_tm.tm_mon = from_bcd(value); omap_rtc_alarm_update(s); return; - case 0x34: /* ALARM_YEARS_REG */ + case 0x34: /* ALARM_YEARS_REG */ s->alarm_tm.tm_year = from_bcd(value); omap_rtc_alarm_update(s); return; - case 0x40: /* RTC_CTRL_REG */ + case 0x40: /* RTC_CTRL_REG */ s->pm_am = (value >> 3) & 1; s->auto_comp = (value >> 2) & 1; s->round = (value >> 1) & 1; @@ -2764,21 +2764,21 @@ static void omap_rtc_write(void *opaque, hwaddr addr, s->status |= s->running << 1; return; - case 0x44: /* RTC_STATUS_REG */ + case 0x44: /* RTC_STATUS_REG */ s->status &= ~((value & 0xc0) ^ 0x80); omap_rtc_interrupts_update(s); return; - case 0x48: /* RTC_INTERRUPTS_REG */ + case 0x48: /* RTC_INTERRUPTS_REG */ s->interrupts = value; return; - case 0x4c: /* RTC_COMP_LSB_REG */ + case 0x4c: /* RTC_COMP_LSB_REG */ s->comp_reg &= 0xff00; s->comp_reg |= 0x00ff & value; return; - case 0x50: /* RTC_COMP_MSB_REG */ + case 0x50: /* RTC_COMP_MSB_REG */ s->comp_reg &= 0x00ff; s->comp_reg |= 0xff00 & (value << 8); return; @@ -2929,12 +2929,12 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) { int irq; - switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ + switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ case 0: - irq = (s->spcr[0] >> 1) & 1; /* RRDY */ + irq = (s->spcr[0] >> 1) & 1; /* RRDY */ break; case 3: - irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ + irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ break; default: irq = 0; @@ -2944,12 +2944,12 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) if (irq) qemu_irq_pulse(s->rxirq); - switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ + switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ case 0: - irq = (s->spcr[1] >> 1) & 1; /* XRDY */ + irq = (s->spcr[1] >> 1) & 1; /* XRDY */ break; case 3: - irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ + irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ break; default: irq = 0; @@ -2962,9 +2962,9 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) { - if ((s->spcr[0] >> 1) & 1) /* RRDY */ - s->spcr[0] |= 1 << 2; /* RFULL */ - s->spcr[0] |= 1 << 1; /* RRDY */ + if ((s->spcr[0] >> 1) & 1) /* RRDY */ + s->spcr[0] |= 1 << 2; /* RFULL */ + s->spcr[0] |= 1 << 1; /* RRDY */ qemu_irq_raise(s->rxdrq); omap_mcbsp_intr_update(s); } @@ -3004,14 +3004,14 @@ static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) { - s->spcr[0] &= ~(1 << 1); /* RRDY */ + s->spcr[0] &= ~(1 << 1); /* RRDY */ qemu_irq_lower(s->rxdrq); omap_mcbsp_intr_update(s); } static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) { - s->spcr[1] |= 1 << 1; /* XRDY */ + s->spcr[1] |= 1 << 1; /* XRDY */ qemu_irq_raise(s->txdrq); omap_mcbsp_intr_update(s); } @@ -3046,7 +3046,7 @@ static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) { - s->spcr[1] &= ~(1 << 1); /* XRDY */ + s->spcr[1] &= ~(1 << 1); /* XRDY */ qemu_irq_lower(s->txdrq); omap_mcbsp_intr_update(s); if (s->codec && s->codec->cts) @@ -3064,27 +3064,27 @@ static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) { int prev_rx_rate, prev_tx_rate; int rx_rate = 0, tx_rate = 0; - int cpu_rate = 1500000; /* XXX */ + int cpu_rate = 1500000; /* XXX */ /* TODO: check CLKSTP bit */ - if (s->spcr[1] & (1 << 6)) { /* GRST */ - if (s->spcr[0] & (1 << 0)) { /* RRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 8))) { /* CLKRM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ + if (s->spcr[1] & (1 << 6)) { /* GRST */ + if (s->spcr[0] & (1 << 0)) { /* RRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 8))) { /* CLKRM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ rx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ } else if (s->codec) rx_rate = s->codec->rx_rate; } - if (s->spcr[1] & (1 << 0)) { /* XRST */ - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ - (s->pcr & (1 << 9))) { /* CLKXM */ - if (~s->pcr & (1 << 7)) /* SCLKME */ + if (s->spcr[1] & (1 << 0)) { /* XRST */ + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ + (s->pcr & (1 << 9))) { /* CLKXM */ + if (~s->pcr & (1 << 7)) /* SCLKME */ tx_rate = cpu_rate / - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ } else if (s->codec) tx_rate = s->codec->tx_rate; @@ -3121,11 +3121,11 @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* DRR2 */ - if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ + case 0x00: /* DRR2 */ + if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ return 0x0000; /* Fall through. */ - case 0x02: /* DRR1 */ + case 0x02: /* DRR1 */ if (s->rx_req < 2) { qemu_log_mask(LOG_GUEST_ERROR, "%s: Rx FIFO underrun\n", __func__); omap_mcbsp_rx_done(s); @@ -3143,63 +3143,63 @@ static uint64_t omap_mcbsp_read(void *opaque, hwaddr addr, } return 0x0000; - case 0x04: /* DXR2 */ - case 0x06: /* DXR1 */ + case 0x04: /* DXR2 */ + case 0x06: /* DXR1 */ return 0x0000; - case 0x08: /* SPCR2 */ + case 0x08: /* SPCR2 */ return s->spcr[1]; - case 0x0a: /* SPCR1 */ + case 0x0a: /* SPCR1 */ return s->spcr[0]; - case 0x0c: /* RCR2 */ + case 0x0c: /* RCR2 */ return s->rcr[1]; - case 0x0e: /* RCR1 */ + case 0x0e: /* RCR1 */ return s->rcr[0]; - case 0x10: /* XCR2 */ + case 0x10: /* XCR2 */ return s->xcr[1]; - case 0x12: /* XCR1 */ + case 0x12: /* XCR1 */ return s->xcr[0]; - case 0x14: /* SRGR2 */ + case 0x14: /* SRGR2 */ return s->srgr[1]; - case 0x16: /* SRGR1 */ + case 0x16: /* SRGR1 */ return s->srgr[0]; - case 0x18: /* MCR2 */ + case 0x18: /* MCR2 */ return s->mcr[1]; - case 0x1a: /* MCR1 */ + case 0x1a: /* MCR1 */ return s->mcr[0]; - case 0x1c: /* RCERA */ + case 0x1c: /* RCERA */ return s->rcer[0]; - case 0x1e: /* RCERB */ + case 0x1e: /* RCERB */ return s->rcer[1]; - case 0x20: /* XCERA */ + case 0x20: /* XCERA */ return s->xcer[0]; - case 0x22: /* XCERB */ + case 0x22: /* XCERB */ return s->xcer[1]; - case 0x24: /* PCR0 */ + case 0x24: /* PCR0 */ return s->pcr; - case 0x26: /* RCERC */ + case 0x26: /* RCERC */ return s->rcer[2]; - case 0x28: /* RCERD */ + case 0x28: /* RCERD */ return s->rcer[3]; - case 0x2a: /* XCERC */ + case 0x2a: /* XCERC */ return s->xcer[2]; - case 0x2c: /* XCERD */ + case 0x2c: /* XCERD */ return s->xcer[3]; - case 0x2e: /* RCERE */ + case 0x2e: /* RCERE */ return s->rcer[4]; - case 0x30: /* RCERF */ + case 0x30: /* RCERF */ return s->rcer[5]; - case 0x32: /* XCERE */ + case 0x32: /* XCERE */ return s->xcer[4]; - case 0x34: /* XCERF */ + case 0x34: /* XCERF */ return s->xcer[5]; - case 0x36: /* RCERG */ + case 0x36: /* RCERG */ return s->rcer[6]; - case 0x38: /* RCERH */ + case 0x38: /* RCERH */ return s->rcer[7]; - case 0x3a: /* XCERG */ + case 0x3a: /* XCERG */ return s->xcer[6]; - case 0x3c: /* XCERH */ + case 0x3c: /* XCERH */ return s->xcer[7]; } @@ -3214,16 +3214,16 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { - case 0x00: /* DRR2 */ - case 0x02: /* DRR1 */ + case 0x00: /* DRR2 */ + case 0x02: /* DRR1 */ OMAP_RO_REG(addr); return; - case 0x04: /* DXR2 */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + case 0x04: /* DXR2 */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ return; /* Fall through. */ - case 0x06: /* DXR1 */ + case 0x06: /* DXR1 */ if (s->tx_req > 1) { s->tx_req -= 2; if (s->codec && s->codec->cts) { @@ -3237,15 +3237,15 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, } return; - case 0x08: /* SPCR2 */ + case 0x08: /* SPCR2 */ s->spcr[1] &= 0x0002; s->spcr[1] |= 0x03f9 & value; - s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ - if (~value & 1) /* XRST */ + s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ + if (~value & 1) /* XRST */ s->spcr[1] &= ~6; omap_mcbsp_req_update(s); return; - case 0x0a: /* SPCR1 */ + case 0x0a: /* SPCR1 */ s->spcr[0] &= 0x0006; s->spcr[0] |= 0xf8f9 & value; if (value & (1 << 15)) { /* DLB */ @@ -3253,7 +3253,7 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, "%s: Digital Loopback mode enable attempt\n", __func__); } - if (~value & 1) { /* RRST */ + if (~value & 1) { /* RRST */ s->spcr[0] &= ~6; s->rx_req = 0; omap_mcbsp_rx_done(s); @@ -3261,27 +3261,27 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, omap_mcbsp_req_update(s); return; - case 0x0c: /* RCR2 */ + case 0x0c: /* RCR2 */ s->rcr[1] = value & 0xffff; return; - case 0x0e: /* RCR1 */ + case 0x0e: /* RCR1 */ s->rcr[0] = value & 0x7fe0; return; - case 0x10: /* XCR2 */ + case 0x10: /* XCR2 */ s->xcr[1] = value & 0xffff; return; - case 0x12: /* XCR1 */ + case 0x12: /* XCR1 */ s->xcr[0] = value & 0x7fe0; return; - case 0x14: /* SRGR2 */ + case 0x14: /* SRGR2 */ s->srgr[1] = value & 0xffff; omap_mcbsp_req_update(s); return; - case 0x16: /* SRGR1 */ + case 0x16: /* SRGR1 */ s->srgr[0] = value & 0xffff; omap_mcbsp_req_update(s); return; - case 0x18: /* MCR2 */ + case 0x18: /* MCR2 */ s->mcr[1] = value & 0x03e3; if (value & 3) { /* XMCM */ qemu_log_mask(LOG_UNIMP, @@ -3289,7 +3289,7 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, __func__); } return; - case 0x1a: /* MCR1 */ + case 0x1a: /* MCR1 */ s->mcr[0] = value & 0x03e1; if (value & 1) { /* RMCM */ qemu_log_mask(LOG_UNIMP, @@ -3297,55 +3297,55 @@ static void omap_mcbsp_writeh(void *opaque, hwaddr addr, __func__); } return; - case 0x1c: /* RCERA */ + case 0x1c: /* RCERA */ s->rcer[0] = value & 0xffff; return; - case 0x1e: /* RCERB */ + case 0x1e: /* RCERB */ s->rcer[1] = value & 0xffff; return; - case 0x20: /* XCERA */ + case 0x20: /* XCERA */ s->xcer[0] = value & 0xffff; return; - case 0x22: /* XCERB */ + case 0x22: /* XCERB */ s->xcer[1] = value & 0xffff; return; - case 0x24: /* PCR0 */ + case 0x24: /* PCR0 */ s->pcr = value & 0x7faf; return; - case 0x26: /* RCERC */ + case 0x26: /* RCERC */ s->rcer[2] = value & 0xffff; return; - case 0x28: /* RCERD */ + case 0x28: /* RCERD */ s->rcer[3] = value & 0xffff; return; - case 0x2a: /* XCERC */ + case 0x2a: /* XCERC */ s->xcer[2] = value & 0xffff; return; - case 0x2c: /* XCERD */ + case 0x2c: /* XCERD */ s->xcer[3] = value & 0xffff; return; - case 0x2e: /* RCERE */ + case 0x2e: /* RCERE */ s->rcer[4] = value & 0xffff; return; - case 0x30: /* RCERF */ + case 0x30: /* RCERF */ s->rcer[5] = value & 0xffff; return; - case 0x32: /* XCERE */ + case 0x32: /* XCERE */ s->xcer[4] = value & 0xffff; return; - case 0x34: /* XCERF */ + case 0x34: /* XCERF */ s->xcer[5] = value & 0xffff; return; - case 0x36: /* RCERG */ + case 0x36: /* RCERG */ s->rcer[6] = value & 0xffff; return; - case 0x38: /* RCERH */ + case 0x38: /* RCERH */ s->rcer[7] = value & 0xffff; return; - case 0x3a: /* XCERG */ + case 0x3a: /* XCERG */ s->xcer[6] = value & 0xffff; return; - case 0x3c: /* XCERH */ + case 0x3c: /* XCERH */ s->xcer[7] = value & 0xffff; return; } @@ -3359,8 +3359,8 @@ static void omap_mcbsp_writew(void *opaque, hwaddr addr, struct omap_mcbsp_s *s = opaque; int offset = addr & OMAP_MPUI_REG_MASK; - if (offset == 0x04) { /* DXR */ - if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ + if (offset == 0x04) { /* DXR */ + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ return; if (s->tx_req > 3) { s->tx_req -= 4; @@ -3504,15 +3504,15 @@ static void omap_lpg_update(struct omap_lpg_s *s) int64_t on, period = 1, ticks = 1000; static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 }; - if (~s->control & (1 << 6)) /* LPGRES */ + if (~s->control & (1 << 6)) /* LPGRES */ on = 0; - else if (s->control & (1 << 7)) /* PERM_ON */ + else if (s->control & (1 << 7)) /* PERM_ON */ on = period; else { - period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ + period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */ 256 / 32); on = (s->clk && s->power) ? muldiv64(ticks, - per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ + per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */ } timer_del(s->tm); @@ -3550,10 +3550,10 @@ static uint64_t omap_lpg_read(void *opaque, hwaddr addr, unsigned size) } switch (offset) { - case 0x00: /* LCR */ + case 0x00: /* LCR */ return s->control; - case 0x04: /* PMR */ + case 0x04: /* PMR */ return s->power; } @@ -3573,14 +3573,14 @@ static void omap_lpg_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* LCR */ - if (~value & (1 << 6)) /* LPGRES */ + case 0x00: /* LCR */ + if (~value & (1 << 6)) /* LPGRES */ omap_lpg_reset(s); s->control = value & 0xff; omap_lpg_update(s); return; - case 0x04: /* PMR */ + case 0x04: /* PMR */ s->power = value & 0x01; omap_lpg_update(s); return; @@ -3630,7 +3630,7 @@ static uint64_t omap_mpui_io_read(void *opaque, hwaddr addr, return omap_badwidth_read16(opaque, addr); } - if (addr == OMAP_MPUI_BASE) /* CMR */ + if (addr == OMAP_MPUI_BASE) /* CMR */ return 0xfe4d; OMAP_BAD_REG(addr); @@ -3703,25 +3703,25 @@ static const struct omap_map_s { const char *name; } omap15xx_dsp_mm[] = { /* Strobe 0 */ - { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ - { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ - { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ - { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ - { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ - { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ - { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ - { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ - { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ - { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ - { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ - { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ - { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ - { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ - { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ - { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ - { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ + { 0xe1010000, 0xfffb0000, 0x800, "UART1 BT" }, /* CS0 */ + { 0xe1010800, 0xfffb0800, 0x800, "UART2 COM" }, /* CS1 */ + { 0xe1011800, 0xfffb1800, 0x800, "McBSP1 audio" }, /* CS3 */ + { 0xe1012000, 0xfffb2000, 0x800, "MCSI2 communication" }, /* CS4 */ + { 0xe1012800, 0xfffb2800, 0x800, "MCSI1 BT u-Law" }, /* CS5 */ + { 0xe1013000, 0xfffb3000, 0x800, "uWire" }, /* CS6 */ + { 0xe1013800, 0xfffb3800, 0x800, "I^2C" }, /* CS7 */ + { 0xe1014000, 0xfffb4000, 0x800, "USB W2FC" }, /* CS8 */ + { 0xe1014800, 0xfffb4800, 0x800, "RTC" }, /* CS9 */ + { 0xe1015000, 0xfffb5000, 0x800, "MPUIO" }, /* CS10 */ + { 0xe1015800, 0xfffb5800, 0x800, "PWL" }, /* CS11 */ + { 0xe1016000, 0xfffb6000, 0x800, "PWT" }, /* CS12 */ + { 0xe1017000, 0xfffb7000, 0x800, "McBSP3" }, /* CS14 */ + { 0xe1017800, 0xfffb7800, 0x800, "MMC" }, /* CS15 */ + { 0xe1019000, 0xfffb9000, 0x800, "32-kHz timer" }, /* CS18 */ + { 0xe1019800, 0xfffb9800, 0x800, "UART3" }, /* CS19 */ + { 0xe101c800, 0xfffbc800, 0x800, "TIPB switches" }, /* CS25 */ /* Strobe 1 */ - { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ + { 0xe101e000, 0xfffce000, 0x800, "GPIOs" }, /* CS28 */ { 0 } }; @@ -4025,18 +4025,18 @@ struct omap_mpu_state_s *omap310_mpu_init(MemoryRegion *dram, 0xfffbd800, omap_findclk(s, "clk32-kHz")); /* Register mappings not currently implemented: - * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) - * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) - * USB W2FC fffb4000 - fffb47ff - * Camera Interface fffb6800 - fffb6fff - * USB Host fffba000 - fffba7ff - * FAC fffba800 - fffbafff - * HDQ/1-Wire fffbc000 - fffbc7ff - * TIPB switches fffbc800 - fffbcfff - * Mailbox fffcf000 - fffcf7ff - * Local bus IF fffec100 - fffec1ff - * Local bus MMU fffec200 - fffec2ff - * DSP MMU fffed200 - fffed2ff + * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) + * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) + * USB W2FC fffb4000 - fffb47ff + * Camera Interface fffb6800 - fffb6fff + * USB Host fffba000 - fffba7ff + * FAC fffba800 - fffbafff + * HDQ/1-Wire fffbc000 - fffbc7ff + * TIPB switches fffbc800 - fffbcfff + * Mailbox fffcf000 - fffcf7ff + * Local bus IF fffec100 - fffec1ff + * Local bus MMU fffec200 - fffec2ff + * DSP MMU fffed200 - fffed2ff */ omap_setup_dsp_mapping(system_memory, omap15xx_dsp_mm); diff --git a/hw/arm/omap_sx1.c b/hw/arm/omap_sx1.c index 1d89a202bb..5d4a31b7ae 100644 --- a/hw/arm/omap_sx1.c +++ b/hw/arm/omap_sx1.c @@ -1,7 +1,7 @@ /* omap_sx1.c Support for the Siemens SX1 smartphone emulation. * * Copyright (C) 2008 - * Jean-Christophe PLAGNIOL-VILLARD + * Jean-Christophe PLAGNIOL-VILLARD * Copyright (C) 2007 Vladimir Ananiev * * based on PalmOne's (TM) PDAs support (palm.c) diff --git a/hw/dma/omap_dma.c b/hw/dma/omap_dma.c index 9a8c3c34a0..101f91f4a3 100644 --- a/hw/dma/omap_dma.c +++ b/hw/dma/omap_dma.c @@ -131,9 +131,9 @@ struct omap_dma_s { #define LAST_FRAME_INTR (1 << 4) #define END_BLOCK_INTR (1 << 5) #define SYNC (1 << 6) -#define END_PKT_INTR (1 << 7) -#define TRANS_ERR_INTR (1 << 8) -#define MISALIGN_INTR (1 << 11) +#define END_PKT_INTR (1 << 7) +#define TRANS_ERR_INTR (1 << 8) +#define MISALIGN_INTR (1 << 11) static inline void omap_dma_interrupts_update(struct omap_dma_s *s) { @@ -526,12 +526,12 @@ static void omap_dma_transfer_setup(struct soc_dma_ch_s *dma) /* Check all the conditions that terminate the transfer starting * with those that can occur the soonest. */ -#define INTR_CHECK(cond, id, nelements) \ - if (cond) { \ - elements[id] = nelements; \ - if (elements[id] < min_elems) \ - min_elems = elements[id]; \ - } else \ +#define INTR_CHECK(cond, id, nelements) \ + if (cond) { \ + elements[id] = nelements; \ + if (elements[id] < min_elems) \ + min_elems = elements[id]; \ + } else \ elements[id] = INT_MAX; /* Elements */ @@ -740,7 +740,7 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, struct omap_dma_channel_s *ch, int reg, uint16_t *value) { switch (reg) { - case 0x00: /* SYS_DMA_CSDP_CH0 */ + case 0x00: /* SYS_DMA_CSDP_CH0 */ *value = (ch->burst[1] << 14) | (ch->pack[1] << 13) | (ch->port[1] << 9) | @@ -750,9 +750,9 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, (ch->data_type >> 1); break; - case 0x02: /* SYS_DMA_CCR_CH0 */ + case 0x02: /* SYS_DMA_CCR_CH0 */ if (s->model <= omap_dma_3_1) - *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ + *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ else *value = ch->omap_3_1_compatible_disable << 10; *value |= (ch->mode[1] << 14) | @@ -765,11 +765,11 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, (ch->fs << 5) | ch->sync; break; - case 0x04: /* SYS_DMA_CICR_CH0 */ + case 0x04: /* SYS_DMA_CICR_CH0 */ *value = ch->interrupts; break; - case 0x06: /* SYS_DMA_CSR_CH0 */ + case 0x06: /* SYS_DMA_CSR_CH0 */ *value = ch->status; ch->status &= SYNC; if (!ch->omap_3_1_compatible_disable && ch->sibling) { @@ -779,77 +779,77 @@ static int omap_dma_ch_reg_read(struct omap_dma_s *s, qemu_irq_lower(ch->irq); break; - case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ *value = ch->addr[0] & 0x0000ffff; break; - case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ *value = ch->addr[0] >> 16; break; - case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ *value = ch->addr[1] & 0x0000ffff; break; - case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ *value = ch->addr[1] >> 16; break; - case 0x10: /* SYS_DMA_CEN_CH0 */ + case 0x10: /* SYS_DMA_CEN_CH0 */ *value = ch->elements; break; - case 0x12: /* SYS_DMA_CFN_CH0 */ + case 0x12: /* SYS_DMA_CFN_CH0 */ *value = ch->frames; break; - case 0x14: /* SYS_DMA_CFI_CH0 */ + case 0x14: /* SYS_DMA_CFI_CH0 */ *value = ch->frame_index[0]; break; - case 0x16: /* SYS_DMA_CEI_CH0 */ + case 0x16: /* SYS_DMA_CEI_CH0 */ *value = ch->element_index[0]; break; - case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ if (ch->omap_3_1_compatible_disable) - *value = ch->active_set.src & 0xffff; /* CSAC */ + *value = ch->active_set.src & 0xffff; /* CSAC */ else *value = ch->cpc; break; - case 0x1a: /* DMA_CDAC */ - *value = ch->active_set.dest & 0xffff; /* CDAC */ + case 0x1a: /* DMA_CDAC */ + *value = ch->active_set.dest & 0xffff; /* CDAC */ break; - case 0x1c: /* DMA_CDEI */ + case 0x1c: /* DMA_CDEI */ *value = ch->element_index[1]; break; - case 0x1e: /* DMA_CDFI */ + case 0x1e: /* DMA_CDFI */ *value = ch->frame_index[1]; break; - case 0x20: /* DMA_COLOR_L */ + case 0x20: /* DMA_COLOR_L */ *value = ch->color & 0xffff; break; - case 0x22: /* DMA_COLOR_U */ + case 0x22: /* DMA_COLOR_U */ *value = ch->color >> 16; break; - case 0x24: /* DMA_CCR2 */ + case 0x24: /* DMA_CCR2 */ *value = (ch->bs << 2) | (ch->transparent_copy << 1) | ch->constant_fill; break; - case 0x28: /* DMA_CLNK_CTRL */ + case 0x28: /* DMA_CLNK_CTRL */ *value = (ch->link_enabled << 15) | (ch->link_next_ch & 0xf); break; - case 0x2a: /* DMA_LCH_CTRL */ + case 0x2a: /* DMA_LCH_CTRL */ *value = (ch->interleave_disabled << 15) | ch->type; break; @@ -864,7 +864,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, struct omap_dma_channel_s *ch, int reg, uint16_t value) { switch (reg) { - case 0x00: /* SYS_DMA_CSDP_CH0 */ + case 0x00: /* SYS_DMA_CSDP_CH0 */ ch->burst[1] = (value & 0xc000) >> 14; ch->pack[1] = (value & 0x2000) >> 13; ch->port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9); @@ -887,7 +887,7 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, } break; - case 0x02: /* SYS_DMA_CCR_CH0 */ + case 0x02: /* SYS_DMA_CCR_CH0 */ ch->mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14); ch->mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12); ch->end_prog = (value & 0x0800) >> 11; @@ -909,88 +909,88 @@ static int omap_dma_ch_reg_write(struct omap_dma_s *s, break; - case 0x04: /* SYS_DMA_CICR_CH0 */ + case 0x04: /* SYS_DMA_CICR_CH0 */ ch->interrupts = value & 0x3f; break; - case 0x06: /* SYS_DMA_CSR_CH0 */ + case 0x06: /* SYS_DMA_CSR_CH0 */ OMAP_RO_REG((hwaddr) reg); break; - case 0x08: /* SYS_DMA_CSSA_L_CH0 */ + case 0x08: /* SYS_DMA_CSSA_L_CH0 */ ch->addr[0] &= 0xffff0000; ch->addr[0] |= value; break; - case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ + case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ ch->addr[0] &= 0x0000ffff; ch->addr[0] |= (uint32_t) value << 16; break; - case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ + case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ ch->addr[1] &= 0xffff0000; ch->addr[1] |= value; break; - case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ + case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ ch->addr[1] &= 0x0000ffff; ch->addr[1] |= (uint32_t) value << 16; break; - case 0x10: /* SYS_DMA_CEN_CH0 */ + case 0x10: /* SYS_DMA_CEN_CH0 */ ch->elements = value; break; - case 0x12: /* SYS_DMA_CFN_CH0 */ + case 0x12: /* SYS_DMA_CFN_CH0 */ ch->frames = value; break; - case 0x14: /* SYS_DMA_CFI_CH0 */ + case 0x14: /* SYS_DMA_CFI_CH0 */ ch->frame_index[0] = (int16_t) value; break; - case 0x16: /* SYS_DMA_CEI_CH0 */ + case 0x16: /* SYS_DMA_CEI_CH0 */ ch->element_index[0] = (int16_t) value; break; - case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ + case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ OMAP_RO_REG((hwaddr) reg); break; - case 0x1c: /* DMA_CDEI */ + case 0x1c: /* DMA_CDEI */ ch->element_index[1] = (int16_t) value; break; - case 0x1e: /* DMA_CDFI */ + case 0x1e: /* DMA_CDFI */ ch->frame_index[1] = (int16_t) value; break; - case 0x20: /* DMA_COLOR_L */ + case 0x20: /* DMA_COLOR_L */ ch->color &= 0xffff0000; ch->color |= value; break; - case 0x22: /* DMA_COLOR_U */ + case 0x22: /* DMA_COLOR_U */ ch->color &= 0xffff; ch->color |= (uint32_t)value << 16; break; - case 0x24: /* DMA_CCR2 */ + case 0x24: /* DMA_CCR2 */ ch->bs = (value >> 2) & 0x1; ch->transparent_copy = (value >> 1) & 0x1; ch->constant_fill = value & 0x1; break; - case 0x28: /* DMA_CLNK_CTRL */ + case 0x28: /* DMA_CLNK_CTRL */ ch->link_enabled = (value >> 15) & 0x1; - if (value & (1 << 14)) { /* Stop_Lnk */ + if (value & (1 << 14)) { /* Stop_Lnk */ ch->link_enabled = 0; omap_dma_disable_channel(s, ch); } ch->link_next_ch = value & 0x1f; break; - case 0x2a: /* DMA_LCH_CTRL */ + case 0x2a: /* DMA_LCH_CTRL */ ch->interleave_disabled = (value >> 15) & 0x1; ch->type = value & 0xf; break; @@ -1005,7 +1005,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, uint16_t value) { switch (offset) { - case 0xbc0: /* DMA_LCD_CSDP */ + case 0xbc0: /* DMA_LCD_CSDP */ s->brust_f2 = (value >> 14) & 0x3; s->pack_f2 = (value >> 13) & 0x1; s->data_type_f2 = (1 << ((value >> 11) & 0x3)); @@ -1014,7 +1014,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, s->data_type_f1 = (1 << ((value >> 0) & 0x3)); break; - case 0xbc2: /* DMA_LCD_CCR */ + case 0xbc2: /* DMA_LCD_CCR */ s->mode_f2 = (value >> 14) & 0x3; s->mode_f1 = (value >> 12) & 0x3; s->end_prog = (value >> 11) & 0x1; @@ -1026,7 +1026,7 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, s->bs = (value >> 4) & 0x1; break; - case 0xbc4: /* DMA_LCD_CTRL */ + case 0xbc4: /* DMA_LCD_CTRL */ s->dst = (value >> 8) & 0x1; s->src = ((value >> 6) & 0x3) << 1; s->condition = 0; @@ -1035,91 +1035,91 @@ static int omap_dma_3_2_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, s->dual = value & 1; break; - case 0xbc8: /* TOP_B1_L */ + case 0xbc8: /* TOP_B1_L */ s->src_f1_top &= 0xffff0000; s->src_f1_top |= 0x0000ffff & value; break; - case 0xbca: /* TOP_B1_U */ + case 0xbca: /* TOP_B1_U */ s->src_f1_top &= 0x0000ffff; s->src_f1_top |= (uint32_t)value << 16; break; - case 0xbcc: /* BOT_B1_L */ + case 0xbcc: /* BOT_B1_L */ s->src_f1_bottom &= 0xffff0000; s->src_f1_bottom |= 0x0000ffff & value; break; - case 0xbce: /* BOT_B1_U */ + case 0xbce: /* BOT_B1_U */ s->src_f1_bottom &= 0x0000ffff; s->src_f1_bottom |= (uint32_t) value << 16; break; - case 0xbd0: /* TOP_B2_L */ + case 0xbd0: /* TOP_B2_L */ s->src_f2_top &= 0xffff0000; s->src_f2_top |= 0x0000ffff & value; break; - case 0xbd2: /* TOP_B2_U */ + case 0xbd2: /* TOP_B2_U */ s->src_f2_top &= 0x0000ffff; s->src_f2_top |= (uint32_t) value << 16; break; - case 0xbd4: /* BOT_B2_L */ + case 0xbd4: /* BOT_B2_L */ s->src_f2_bottom &= 0xffff0000; s->src_f2_bottom |= 0x0000ffff & value; break; - case 0xbd6: /* BOT_B2_U */ + case 0xbd6: /* BOT_B2_U */ s->src_f2_bottom &= 0x0000ffff; s->src_f2_bottom |= (uint32_t) value << 16; break; - case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ s->element_index_f1 = value; break; - case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ s->frame_index_f1 &= 0xffff0000; s->frame_index_f1 |= 0x0000ffff & value; break; - case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ s->frame_index_f1 &= 0x0000ffff; s->frame_index_f1 |= (uint32_t) value << 16; break; - case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ s->element_index_f2 = value; break; - case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ s->frame_index_f2 &= 0xffff0000; s->frame_index_f2 |= 0x0000ffff & value; break; - case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ s->frame_index_f2 &= 0x0000ffff; s->frame_index_f2 |= (uint32_t) value << 16; break; - case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ s->elements_f1 = value; break; - case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ s->frames_f1 = value; break; - case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ s->elements_f2 = value; break; - case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ s->frames_f2 = value; break; - case 0xbea: /* DMA_LCD_LCH_CTRL */ + case 0xbea: /* DMA_LCD_LCH_CTRL */ s->lch_type = value & 0xf; break; @@ -1133,7 +1133,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, uint16_t *ret) { switch (offset) { - case 0xbc0: /* DMA_LCD_CSDP */ + case 0xbc0: /* DMA_LCD_CSDP */ *ret = (s->brust_f2 << 14) | (s->pack_f2 << 13) | ((s->data_type_f2 >> 1) << 11) | @@ -1142,7 +1142,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, ((s->data_type_f1 >> 1) << 0); break; - case 0xbc2: /* DMA_LCD_CCR */ + case 0xbc2: /* DMA_LCD_CCR */ *ret = (s->mode_f2 << 14) | (s->mode_f1 << 12) | (s->end_prog << 11) | @@ -1154,7 +1154,7 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, (s->bs << 4); break; - case 0xbc4: /* DMA_LCD_CTRL */ + case 0xbc4: /* DMA_LCD_CTRL */ qemu_irq_lower(s->irq); *ret = (s->dst << 8) | ((s->src & 0x6) << 5) | @@ -1163,79 +1163,79 @@ static int omap_dma_3_2_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, s->dual; break; - case 0xbc8: /* TOP_B1_L */ + case 0xbc8: /* TOP_B1_L */ *ret = s->src_f1_top & 0xffff; break; - case 0xbca: /* TOP_B1_U */ + case 0xbca: /* TOP_B1_U */ *ret = s->src_f1_top >> 16; break; - case 0xbcc: /* BOT_B1_L */ + case 0xbcc: /* BOT_B1_L */ *ret = s->src_f1_bottom & 0xffff; break; - case 0xbce: /* BOT_B1_U */ + case 0xbce: /* BOT_B1_U */ *ret = s->src_f1_bottom >> 16; break; - case 0xbd0: /* TOP_B2_L */ + case 0xbd0: /* TOP_B2_L */ *ret = s->src_f2_top & 0xffff; break; - case 0xbd2: /* TOP_B2_U */ + case 0xbd2: /* TOP_B2_U */ *ret = s->src_f2_top >> 16; break; - case 0xbd4: /* BOT_B2_L */ + case 0xbd4: /* BOT_B2_L */ *ret = s->src_f2_bottom & 0xffff; break; - case 0xbd6: /* BOT_B2_U */ + case 0xbd6: /* BOT_B2_U */ *ret = s->src_f2_bottom >> 16; break; - case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ + case 0xbd8: /* DMA_LCD_SRC_EI_B1 */ *ret = s->element_index_f1; break; - case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ + case 0xbda: /* DMA_LCD_SRC_FI_B1_L */ *ret = s->frame_index_f1 & 0xffff; break; - case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ + case 0xbf4: /* DMA_LCD_SRC_FI_B1_U */ *ret = s->frame_index_f1 >> 16; break; - case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ + case 0xbdc: /* DMA_LCD_SRC_EI_B2 */ *ret = s->element_index_f2; break; - case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ + case 0xbde: /* DMA_LCD_SRC_FI_B2_L */ *ret = s->frame_index_f2 & 0xffff; break; - case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ + case 0xbf6: /* DMA_LCD_SRC_FI_B2_U */ *ret = s->frame_index_f2 >> 16; break; - case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ + case 0xbe0: /* DMA_LCD_SRC_EN_B1 */ *ret = s->elements_f1; break; - case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ + case 0xbe4: /* DMA_LCD_SRC_FN_B1 */ *ret = s->frames_f1; break; - case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ + case 0xbe2: /* DMA_LCD_SRC_EN_B2 */ *ret = s->elements_f2; break; - case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ + case 0xbe6: /* DMA_LCD_SRC_FN_B2 */ *ret = s->frames_f2; break; - case 0xbea: /* DMA_LCD_LCH_CTRL */ + case 0xbea: /* DMA_LCD_LCH_CTRL */ *ret = s->lch_type; break; @@ -1249,7 +1249,7 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, uint16_t value) { switch (offset) { - case 0x300: /* SYS_DMA_LCD_CTRL */ + case 0x300: /* SYS_DMA_LCD_CTRL */ s->src = (value & 0x40) ? imif : emiff; s->condition = 0; /* Assume no bus errors and thus no BUS_ERROR irq bits. */ @@ -1257,42 +1257,42 @@ static int omap_dma_3_1_lcd_write(struct omap_dma_lcd_channel_s *s, int offset, s->dual = value & 1; break; - case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ s->src_f1_top &= 0xffff0000; s->src_f1_top |= 0x0000ffff & value; break; - case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ s->src_f1_top &= 0x0000ffff; s->src_f1_top |= (uint32_t)value << 16; break; - case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ s->src_f1_bottom &= 0xffff0000; s->src_f1_bottom |= 0x0000ffff & value; break; - case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ s->src_f1_bottom &= 0x0000ffff; s->src_f1_bottom |= (uint32_t)value << 16; break; - case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ s->src_f2_top &= 0xffff0000; s->src_f2_top |= 0x0000ffff & value; break; - case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ s->src_f2_top &= 0x0000ffff; s->src_f2_top |= (uint32_t)value << 16; break; - case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ s->src_f2_bottom &= 0xffff0000; s->src_f2_bottom |= 0x0000ffff & value; break; - case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ s->src_f2_bottom &= 0x0000ffff; s->src_f2_bottom |= (uint32_t)value << 16; break; @@ -1309,7 +1309,7 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, int i; switch (offset) { - case 0x300: /* SYS_DMA_LCD_CTRL */ + case 0x300: /* SYS_DMA_LCD_CTRL */ i = s->condition; s->condition = 0; qemu_irq_lower(s->irq); @@ -1317,35 +1317,35 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, (s->interrupts << 1) | s->dual; break; - case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ + case 0x302: /* SYS_DMA_LCD_TOP_F1_L */ *ret = s->src_f1_top & 0xffff; break; - case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ + case 0x304: /* SYS_DMA_LCD_TOP_F1_U */ *ret = s->src_f1_top >> 16; break; - case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ + case 0x306: /* SYS_DMA_LCD_BOT_F1_L */ *ret = s->src_f1_bottom & 0xffff; break; - case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ + case 0x308: /* SYS_DMA_LCD_BOT_F1_U */ *ret = s->src_f1_bottom >> 16; break; - case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ + case 0x30a: /* SYS_DMA_LCD_TOP_F2_L */ *ret = s->src_f2_top & 0xffff; break; - case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ + case 0x30c: /* SYS_DMA_LCD_TOP_F2_U */ *ret = s->src_f2_top >> 16; break; - case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ + case 0x30e: /* SYS_DMA_LCD_BOT_F2_L */ *ret = s->src_f2_bottom & 0xffff; break; - case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ + case 0x310: /* SYS_DMA_LCD_BOT_F2_U */ *ret = s->src_f2_bottom >> 16; break; @@ -1358,18 +1358,18 @@ static int omap_dma_3_1_lcd_read(struct omap_dma_lcd_channel_s *s, int offset, static int omap_dma_sys_write(struct omap_dma_s *s, int offset, uint16_t value) { switch (offset) { - case 0x400: /* SYS_DMA_GCR */ + case 0x400: /* SYS_DMA_GCR */ s->gcr = value; break; - case 0x404: /* DMA_GSCR */ + case 0x404: /* DMA_GSCR */ if (value & 0x8) omap_dma_disable_3_1_mapping(s); else omap_dma_enable_3_1_mapping(s); break; - case 0x408: /* DMA_GRST */ + case 0x408: /* DMA_GRST */ if (value & 0x1) omap_dma_reset(s->dma); break; @@ -1384,57 +1384,57 @@ static int omap_dma_sys_read(struct omap_dma_s *s, int offset, uint16_t *ret) { switch (offset) { - case 0x400: /* SYS_DMA_GCR */ + case 0x400: /* SYS_DMA_GCR */ *ret = s->gcr; break; - case 0x404: /* DMA_GSCR */ + case 0x404: /* DMA_GSCR */ *ret = s->omap_3_1_mapping_disabled << 3; break; - case 0x408: /* DMA_GRST */ + case 0x408: /* DMA_GRST */ *ret = 0; break; - case 0x442: /* DMA_HW_ID */ - case 0x444: /* DMA_PCh2_ID */ - case 0x446: /* DMA_PCh0_ID */ - case 0x448: /* DMA_PCh1_ID */ - case 0x44a: /* DMA_PChG_ID */ - case 0x44c: /* DMA_PChD_ID */ + case 0x442: /* DMA_HW_ID */ + case 0x444: /* DMA_PCh2_ID */ + case 0x446: /* DMA_PCh0_ID */ + case 0x448: /* DMA_PCh1_ID */ + case 0x44a: /* DMA_PChG_ID */ + case 0x44c: /* DMA_PChD_ID */ *ret = 1; break; - case 0x44e: /* DMA_CAPS_0_U */ + case 0x44e: /* DMA_CAPS_0_U */ *ret = (s->caps[0] >> 16) & 0xffff; break; - case 0x450: /* DMA_CAPS_0_L */ + case 0x450: /* DMA_CAPS_0_L */ *ret = (s->caps[0] >> 0) & 0xffff; break; - case 0x452: /* DMA_CAPS_1_U */ + case 0x452: /* DMA_CAPS_1_U */ *ret = (s->caps[1] >> 16) & 0xffff; break; - case 0x454: /* DMA_CAPS_1_L */ + case 0x454: /* DMA_CAPS_1_L */ *ret = (s->caps[1] >> 0) & 0xffff; break; - case 0x456: /* DMA_CAPS_2 */ + case 0x456: /* DMA_CAPS_2 */ *ret = s->caps[2]; break; - case 0x458: /* DMA_CAPS_3 */ + case 0x458: /* DMA_CAPS_3 */ *ret = s->caps[3]; break; - case 0x45a: /* DMA_CAPS_4 */ + case 0x45a: /* DMA_CAPS_4 */ *ret = s->caps[4]; break; - case 0x460: /* DMA_PCh2_SR */ - case 0x480: /* DMA_PCh0_SR */ - case 0x482: /* DMA_PCh1_SR */ - case 0x4c0: /* DMA_PChD_SR_0 */ + case 0x460: /* DMA_PCh2_SR */ + case 0x480: /* DMA_PCh0_SR */ + case 0x482: /* DMA_PCh1_SR */ + case 0x4c0: /* DMA_PChD_SR_0 */ qemu_log_mask(LOG_UNIMP, "%s: Physical Channel Status Registers not implemented\n", __func__); @@ -1582,38 +1582,38 @@ static void omap_dma_setcaps(struct omap_dma_s *s) case omap_dma_3_2: /* XXX Only available for sDMA */ s->caps[0] = - (1 << 19) | /* Constant Fill Capability */ - (1 << 18); /* Transparent BLT Capability */ + (1 << 19) | /* Constant Fill Capability */ + (1 << 18); /* Transparent BLT Capability */ s->caps[1] = - (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */ + (1 << 1); /* 1-bit palettized capability (DMA 3.2 only) */ s->caps[2] = - (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */ - (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */ - (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */ - (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */ - (1 << 4) | /* DST_CONST_ADRS_CPBLTY */ - (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */ - (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */ - (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */ - (1 << 0); /* SRC_CONST_ADRS_CPBLTY */ + (1 << 8) | /* SEPARATE_SRC_AND_DST_INDEX_CPBLTY */ + (1 << 7) | /* DST_DOUBLE_INDEX_ADRS_CPBLTY */ + (1 << 6) | /* DST_SINGLE_INDEX_ADRS_CPBLTY */ + (1 << 5) | /* DST_POST_INCRMNT_ADRS_CPBLTY */ + (1 << 4) | /* DST_CONST_ADRS_CPBLTY */ + (1 << 3) | /* SRC_DOUBLE_INDEX_ADRS_CPBLTY */ + (1 << 2) | /* SRC_SINGLE_INDEX_ADRS_CPBLTY */ + (1 << 1) | /* SRC_POST_INCRMNT_ADRS_CPBLTY */ + (1 << 0); /* SRC_CONST_ADRS_CPBLTY */ s->caps[3] = - (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */ - (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */ - (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */ - (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */ - (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */ - (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */ - (1 << 1) | /* FRAME_SYNCHR_CPBLTY */ - (1 << 0); /* ELMNT_SYNCHR_CPBLTY */ + (1 << 6) | /* BLOCK_SYNCHR_CPBLTY (DMA 4 only) */ + (1 << 7) | /* PKT_SYNCHR_CPBLTY (DMA 4 only) */ + (1 << 5) | /* CHANNEL_CHAINING_CPBLTY */ + (1 << 4) | /* LCh_INTERLEAVE_CPBLTY */ + (1 << 3) | /* AUTOINIT_REPEAT_CPBLTY (DMA 3.2 only) */ + (1 << 2) | /* AUTOINIT_ENDPROG_CPBLTY (DMA 3.2 only) */ + (1 << 1) | /* FRAME_SYNCHR_CPBLTY */ + (1 << 0); /* ELMNT_SYNCHR_CPBLTY */ s->caps[4] = - (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */ - (1 << 6) | /* SYNC_STATUS_CPBLTY */ - (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */ - (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */ - (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */ - (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */ - (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */ - (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */ + (1 << 7) | /* PKT_INTERRUPT_CPBLTY (DMA 4 only) */ + (1 << 6) | /* SYNC_STATUS_CPBLTY */ + (1 << 5) | /* BLOCK_INTERRUPT_CPBLTY */ + (1 << 4) | /* LAST_FRAME_INTERRUPT_CPBLTY */ + (1 << 3) | /* FRAME_INTERRUPT_CPBLTY */ + (1 << 2) | /* HALF_FRAME_INTERRUPT_CPBLTY */ + (1 << 1) | /* EVENT_DROP_INTERRUPT_CPBLTY */ + (1 << 0); /* TIMEOUT_INTERRUPT_CPBLTY (DMA 3.2 only) */ break; } } diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c index 61ea7862af..f27806b774 100644 --- a/hw/gpio/omap_gpio.c +++ b/hw/gpio/omap_gpio.c @@ -80,25 +80,25 @@ static uint64_t omap_gpio_read(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* DATA_INPUT */ + case 0x00: /* DATA_INPUT */ return s->inputs & s->pins; - case 0x04: /* DATA_OUTPUT */ + case 0x04: /* DATA_OUTPUT */ return s->outputs; - case 0x08: /* DIRECTION_CONTROL */ + case 0x08: /* DIRECTION_CONTROL */ return s->dir; - case 0x0c: /* INTERRUPT_CONTROL */ + case 0x0c: /* INTERRUPT_CONTROL */ return s->edge; - case 0x10: /* INTERRUPT_MASK */ + case 0x10: /* INTERRUPT_MASK */ return s->mask; - case 0x14: /* INTERRUPT_STATUS */ + case 0x14: /* INTERRUPT_STATUS */ return s->ints; - case 0x18: /* PIN_CONTROL (not in OMAP310) */ + case 0x18: /* PIN_CONTROL (not in OMAP310) */ OMAP_BAD_REG(addr); return s->pins; } @@ -121,11 +121,11 @@ static void omap_gpio_write(void *opaque, hwaddr addr, } switch (offset) { - case 0x00: /* DATA_INPUT */ + case 0x00: /* DATA_INPUT */ OMAP_RO_REG(addr); return; - case 0x04: /* DATA_OUTPUT */ + case 0x04: /* DATA_OUTPUT */ diff = (s->outputs ^ value) & ~s->dir; s->outputs = value; while ((ln = ctz32(diff)) != 32) { @@ -135,7 +135,7 @@ static void omap_gpio_write(void *opaque, hwaddr addr, } break; - case 0x08: /* DIRECTION_CONTROL */ + case 0x08: /* DIRECTION_CONTROL */ diff = s->outputs & (s->dir ^ value); s->dir = value; @@ -147,21 +147,21 @@ static void omap_gpio_write(void *opaque, hwaddr addr, } break; - case 0x0c: /* INTERRUPT_CONTROL */ + case 0x0c: /* INTERRUPT_CONTROL */ s->edge = value; break; - case 0x10: /* INTERRUPT_MASK */ + case 0x10: /* INTERRUPT_MASK */ s->mask = value; break; - case 0x14: /* INTERRUPT_STATUS */ + case 0x14: /* INTERRUPT_STATUS */ s->ints &= ~value; if (!s->ints) qemu_irq_lower(s->irq); break; - case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ + case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ OMAP_BAD_REG(addr); s->pins = value; break; diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c index 2e45266e74..751bf748fd 100644 --- a/hw/i2c/omap_i2c.c +++ b/hw/i2c/omap_i2c.c @@ -55,16 +55,16 @@ struct OMAPI2CState { uint16_t test; }; -#define OMAP2_INTR_REV 0x34 -#define OMAP2_GC_REV 0x34 +#define OMAP2_INTR_REV 0x34 +#define OMAP2_GC_REV 0x34 static void omap_i2c_interrupts_update(OMAPI2CState *s) { qemu_set_irq(s->irq, s->stat & s->mask); - if ((s->dma >> 15) & 1) /* RDMA_EN */ - qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ - if ((s->dma >> 7) & 1) /* XDMA_EN */ - qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ + if ((s->dma >> 15) & 1) /* RDMA_EN */ + qemu_set_irq(s->drq[0], (s->stat >> 3) & 1); /* RRDY */ + if ((s->dma >> 7) & 1) /* XDMA_EN */ + qemu_set_irq(s->drq[1], (s->stat >> 4) & 1); /* XRDY */ } static void omap_i2c_fifo_run(OMAPI2CState *s) @@ -74,25 +74,25 @@ static void omap_i2c_fifo_run(OMAPI2CState *s) if (!i2c_bus_busy(s->bus)) return; - if ((s->control >> 2) & 1) { /* RM */ - if ((s->control >> 1) & 1) { /* STP */ + if ((s->control >> 2) & 1) { /* RM */ + if ((s->control >> 1) & 1) { /* STP */ i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ + s->control &= ~(1 << 1); /* STP */ s->count_cur = s->count; s->txlen = 0; - } else if ((s->control >> 9) & 1) { /* TRX */ + } else if ((s->control >> 9) & 1) { /* TRX */ while (ack && s->txlen) ack = (i2c_send(s->bus, (s->fifo >> ((-- s->txlen) << 3)) & 0xff) >= 0); - s->stat |= 1 << 4; /* XRDY */ + s->stat |= 1 << 4; /* XRDY */ } else { while (s->rxlen < 4) s->fifo |= i2c_recv(s->bus) << ((s->rxlen ++) << 3); - s->stat |= 1 << 3; /* RRDY */ + s->stat |= 1 << 3; /* RRDY */ } } else { - if ((s->control >> 9) & 1) { /* TRX */ + if ((s->control >> 9) & 1) { /* TRX */ while (ack && s->count_cur && s->txlen) { ack = (i2c_send(s->bus, (s->fifo >> ((-- s->txlen) << 3)) & @@ -100,12 +100,12 @@ static void omap_i2c_fifo_run(OMAPI2CState *s) s->count_cur --; } if (ack && s->count_cur) - s->stat |= 1 << 4; /* XRDY */ + s->stat |= 1 << 4; /* XRDY */ else - s->stat &= ~(1 << 4); /* XRDY */ + s->stat &= ~(1 << 4); /* XRDY */ if (!s->count_cur) { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ } } else { while (s->count_cur && s->rxlen < 4) { @@ -113,26 +113,26 @@ static void omap_i2c_fifo_run(OMAPI2CState *s) s->count_cur --; } if (s->rxlen) - s->stat |= 1 << 3; /* RRDY */ + s->stat |= 1 << 3; /* RRDY */ else - s->stat &= ~(1 << 3); /* RRDY */ + s->stat &= ~(1 << 3); /* RRDY */ } if (!s->count_cur) { - if ((s->control >> 1) & 1) { /* STP */ + if ((s->control >> 1) & 1) { /* STP */ i2c_end_transfer(s->bus); - s->control &= ~(1 << 1); /* STP */ + s->control &= ~(1 << 1); /* STP */ s->count_cur = s->count; s->txlen = 0; } else { - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ } } } - s->stat |= (!ack) << 1; /* NACK */ + s->stat |= (!ack) << 1; /* NACK */ if (!ack) - s->control &= ~(1 << 1); /* STP */ + s->control &= ~(1 << 1); /* STP */ } static void omap_i2c_reset(DeviceState *dev) @@ -163,16 +163,16 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr) uint16_t ret; switch (offset) { - case 0x00: /* I2C_REV */ - return s->revision; /* REV */ + case 0x00: /* I2C_REV */ + return s->revision; /* REV */ - case 0x04: /* I2C_IE */ + case 0x04: /* I2C_IE */ return s->mask; - case 0x08: /* I2C_STAT */ + case 0x08: /* I2C_STAT */ return s->stat | (i2c_bus_busy(s->bus) << 12); - case 0x0c: /* I2C_IV */ + case 0x0c: /* I2C_IV */ if (s->revision >= OMAP2_INTR_REV) break; ret = ctz32(s->stat & s->mask); @@ -185,18 +185,18 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr) omap_i2c_interrupts_update(s); return ret; - case 0x10: /* I2C_SYSS */ - return (s->control >> 15) & 1; /* I2C_EN */ + case 0x10: /* I2C_SYSS */ + return (s->control >> 15) & 1; /* I2C_EN */ - case 0x14: /* I2C_BUF */ + case 0x14: /* I2C_BUF */ return s->dma; - case 0x18: /* I2C_CNT */ - return s->count_cur; /* DCOUNT */ + case 0x18: /* I2C_CNT */ + return s->count_cur; /* DCOUNT */ - case 0x1c: /* I2C_DATA */ + case 0x1c: /* I2C_DATA */ ret = 0; - if (s->control & (1 << 14)) { /* BE */ + if (s->control & (1 << 14)) { /* BE */ ret |= ((s->fifo >> 0) & 0xff) << 8; ret |= ((s->fifo >> 8) & 0xff) << 0; } else { @@ -204,7 +204,7 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr) ret |= ((s->fifo >> 0) & 0xff) << 0; } if (s->rxlen == 1) { - s->stat |= 1 << 15; /* SBD */ + s->stat |= 1 << 15; /* SBD */ s->rxlen = 0; } else if (s->rxlen > 1) { if (s->rxlen > 2) @@ -214,41 +214,41 @@ static uint32_t omap_i2c_read(void *opaque, hwaddr addr) /* XXX: remote access (qualifier) error - what's that? */ } if (!s->rxlen) { - s->stat &= ~(1 << 3); /* RRDY */ - if (((s->control >> 10) & 1) && /* MST */ - ((~s->control >> 9) & 1)) { /* TRX */ - s->stat |= 1 << 2; /* ARDY */ - s->control &= ~(1 << 10); /* MST */ + s->stat &= ~(1 << 3); /* RRDY */ + if (((s->control >> 10) & 1) && /* MST */ + ((~s->control >> 9) & 1)) { /* TRX */ + s->stat |= 1 << 2; /* ARDY */ + s->control &= ~(1 << 10); /* MST */ } } - s->stat &= ~(1 << 11); /* ROVR */ + s->stat &= ~(1 << 11); /* ROVR */ omap_i2c_fifo_run(s); omap_i2c_interrupts_update(s); return ret; - case 0x20: /* I2C_SYSC */ + case 0x20: /* I2C_SYSC */ return 0; - case 0x24: /* I2C_CON */ + case 0x24: /* I2C_CON */ return s->control; - case 0x28: /* I2C_OA */ + case 0x28: /* I2C_OA */ return s->addr[0]; - case 0x2c: /* I2C_SA */ + case 0x2c: /* I2C_SA */ return s->addr[1]; - case 0x30: /* I2C_PSC */ + case 0x30: /* I2C_PSC */ return s->divider; - case 0x34: /* I2C_SCLL */ + case 0x34: /* I2C_SCLL */ return s->times[0]; - case 0x38: /* I2C_SCLH */ + case 0x38: /* I2C_SCLH */ return s->times[1]; - case 0x3c: /* I2C_SYSTEST */ - if (s->test & (1 << 15)) { /* ST_EN */ + case 0x3c: /* I2C_SYSTEST */ + if (s->test & (1 << 15)) { /* ST_EN */ s->test ^= 0xa; return s->test; } else @@ -267,17 +267,17 @@ static void omap_i2c_write(void *opaque, hwaddr addr, int nack; switch (offset) { - case 0x00: /* I2C_REV */ - case 0x0c: /* I2C_IV */ - case 0x10: /* I2C_SYSS */ + case 0x00: /* I2C_REV */ + case 0x0c: /* I2C_IV */ + case 0x10: /* I2C_SYSS */ OMAP_RO_REG(addr); return; - case 0x04: /* I2C_IE */ + case 0x04: /* I2C_IE */ s->mask = value & (s->revision < OMAP2_GC_REV ? 0x1f : 0x3f); break; - case 0x08: /* I2C_STAT */ + case 0x08: /* I2C_STAT */ if (s->revision < OMAP2_INTR_REV) { OMAP_RO_REG(addr); return; @@ -288,40 +288,40 @@ static void omap_i2c_write(void *opaque, hwaddr addr, omap_i2c_interrupts_update(s); break; - case 0x14: /* I2C_BUF */ + case 0x14: /* I2C_BUF */ s->dma = value & 0x8080; - if (value & (1 << 15)) /* RDMA_EN */ - s->mask &= ~(1 << 3); /* RRDY_IE */ - if (value & (1 << 7)) /* XDMA_EN */ - s->mask &= ~(1 << 4); /* XRDY_IE */ + if (value & (1 << 15)) /* RDMA_EN */ + s->mask &= ~(1 << 3); /* RRDY_IE */ + if (value & (1 << 7)) /* XDMA_EN */ + s->mask &= ~(1 << 4); /* XRDY_IE */ break; - case 0x18: /* I2C_CNT */ - s->count = value; /* DCOUNT */ + case 0x18: /* I2C_CNT */ + s->count = value; /* DCOUNT */ break; - case 0x1c: /* I2C_DATA */ + case 0x1c: /* I2C_DATA */ if (s->txlen > 2) { /* XXX: remote access (qualifier) error - what's that? */ break; } s->fifo <<= 16; s->txlen += 2; - if (s->control & (1 << 14)) { /* BE */ + if (s->control & (1 << 14)) { /* BE */ s->fifo |= ((value >> 8) & 0xff) << 8; s->fifo |= ((value >> 0) & 0xff) << 0; } else { s->fifo |= ((value >> 0) & 0xff) << 8; s->fifo |= ((value >> 8) & 0xff) << 0; } - s->stat &= ~(1 << 10); /* XUDF */ + s->stat &= ~(1 << 10); /* XUDF */ if (s->txlen > 2) - s->stat &= ~(1 << 4); /* XRDY */ + s->stat &= ~(1 << 4); /* XRDY */ omap_i2c_fifo_run(s); omap_i2c_interrupts_update(s); break; - case 0x20: /* I2C_SYSC */ + case 0x20: /* I2C_SYSC */ if (s->revision < OMAP2_INTR_REV) { OMAP_BAD_REG(addr); return; @@ -332,9 +332,9 @@ static void omap_i2c_write(void *opaque, hwaddr addr, } break; - case 0x24: /* I2C_CON */ + case 0x24: /* I2C_CON */ s->control = value & 0xcf87; - if (~value & (1 << 15)) { /* I2C_EN */ + if (~value & (1 << 15)) { /* I2C_EN */ if (s->revision < OMAP2_INTR_REV) { omap_i2c_reset(DEVICE(s)); } @@ -351,14 +351,14 @@ static void omap_i2c_write(void *opaque, hwaddr addr, __func__); break; } - if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */ - nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ - (~value >> 9) & 1); /* TRX */ - s->stat |= nack << 1; /* NACK */ - s->control &= ~(1 << 0); /* STT */ + if ((value & (1 << 15)) && value & (1 << 0)) { /* STT */ + nack = !!i2c_start_transfer(s->bus, s->addr[1], /* SA */ + (~value >> 9) & 1); /* TRX */ + s->stat |= nack << 1; /* NACK */ + s->control &= ~(1 << 0); /* STT */ s->fifo = 0; if (nack) - s->control &= ~(1 << 1); /* STP */ + s->control &= ~(1 << 1); /* STP */ else { s->count_cur = s->count; omap_i2c_fifo_run(s); @@ -367,34 +367,34 @@ static void omap_i2c_write(void *opaque, hwaddr addr, } break; - case 0x28: /* I2C_OA */ + case 0x28: /* I2C_OA */ s->addr[0] = value & 0x3ff; break; - case 0x2c: /* I2C_SA */ + case 0x2c: /* I2C_SA */ s->addr[1] = value & 0x3ff; break; - case 0x30: /* I2C_PSC */ + case 0x30: /* I2C_PSC */ s->divider = value; break; - case 0x34: /* I2C_SCLL */ + case 0x34: /* I2C_SCLL */ s->times[0] = value; break; - case 0x38: /* I2C_SCLH */ + case 0x38: /* I2C_SCLH */ s->times[1] = value; break; - case 0x3c: /* I2C_SYSTEST */ + case 0x3c: /* I2C_SYSTEST */ s->test = value & 0xf80f; - if (value & (1 << 11)) /* SBB */ + if (value & (1 << 11)) /* SBB */ if (s->revision >= OMAP2_INTR_REV) { s->stat |= 0x3f; omap_i2c_interrupts_update(s); } - if (value & (1 << 15)) { /* ST_EN */ + if (value & (1 << 15)) { /* ST_EN */ qemu_log_mask(LOG_UNIMP, "%s: System Test not supported\n", __func__); } @@ -413,7 +413,7 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr, int offset = addr & OMAP_MPUI_REG_MASK; switch (offset) { - case 0x1c: /* I2C_DATA */ + case 0x1c: /* I2C_DATA */ if (s->txlen > 2) { /* XXX: remote access (qualifier) error - what's that? */ break; @@ -421,9 +421,9 @@ static void omap_i2c_writeb(void *opaque, hwaddr addr, s->fifo <<= 8; s->txlen += 1; s->fifo |= value & 0xff; - s->stat &= ~(1 << 10); /* XUDF */ + s->stat &= ~(1 << 10); /* XUDF */ if (s->txlen > 2) - s->stat &= ~(1 << 4); /* XRDY */ + s->stat &= ~(1 << 4); /* XRDY */ omap_i2c_fifo_run(s); omap_i2c_interrupts_update(s); break; diff --git a/hw/intc/omap_intc.c b/hw/intc/omap_intc.c index 9e8737be33..c61158bddd 100644 --- a/hw/intc/omap_intc.c +++ b/hw/intc/omap_intc.c @@ -102,8 +102,8 @@ static inline void omap_inth_update(OMAPIntcState *s, int is_fiq) } } -#define INT_FALLING_EDGE 0 -#define INT_LOW_LEVEL 1 +#define INT_FALLING_EDGE 0 +#define INT_LOW_LEVEL 1 static void omap_set_intr(void *opaque, int irq, int req) { @@ -142,13 +142,13 @@ static uint64_t omap_inth_read(void *opaque, hwaddr addr, offset &= 0xff; switch (offset) { - case 0x00: /* ITR */ + case 0x00: /* ITR */ return bank->irqs; - case 0x04: /* MIR */ + case 0x04: /* MIR */ return bank->mask; - case 0x10: /* SIR_IRQ_CODE */ + case 0x10: /* SIR_IRQ_CODE */ case 0x14: /* SIR_FIQ_CODE */ if (bank_no != 0) break; @@ -159,49 +159,49 @@ static uint64_t omap_inth_read(void *opaque, hwaddr addr, bank->irqs &= ~(1 << i); return line_no; - case 0x18: /* CONTROL_REG */ + case 0x18: /* CONTROL_REG */ if (bank_no != 0) break; return 0; - case 0x1c: /* ILR0 */ - case 0x20: /* ILR1 */ - case 0x24: /* ILR2 */ - case 0x28: /* ILR3 */ - case 0x2c: /* ILR4 */ - case 0x30: /* ILR5 */ - case 0x34: /* ILR6 */ - case 0x38: /* ILR7 */ - case 0x3c: /* ILR8 */ - case 0x40: /* ILR9 */ - case 0x44: /* ILR10 */ - case 0x48: /* ILR11 */ - case 0x4c: /* ILR12 */ - case 0x50: /* ILR13 */ - case 0x54: /* ILR14 */ - case 0x58: /* ILR15 */ - case 0x5c: /* ILR16 */ - case 0x60: /* ILR17 */ - case 0x64: /* ILR18 */ - case 0x68: /* ILR19 */ - case 0x6c: /* ILR20 */ - case 0x70: /* ILR21 */ - case 0x74: /* ILR22 */ - case 0x78: /* ILR23 */ - case 0x7c: /* ILR24 */ - case 0x80: /* ILR25 */ - case 0x84: /* ILR26 */ - case 0x88: /* ILR27 */ - case 0x8c: /* ILR28 */ - case 0x90: /* ILR29 */ - case 0x94: /* ILR30 */ - case 0x98: /* ILR31 */ + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; return (bank->priority[i] << 2) | (((bank->sens_edge >> i) & 1) << 1) | ((bank->fiq >> i) & 1); - case 0x9c: /* ISR */ + case 0x9c: /* ISR */ return 0x00000000; } @@ -219,24 +219,24 @@ static void omap_inth_write(void *opaque, hwaddr addr, offset &= 0xff; switch (offset) { - case 0x00: /* ITR */ + case 0x00: /* ITR */ /* Important: ignore the clearing if the IRQ is level-triggered and the input bit is 1 */ bank->irqs &= value | (bank->inputs & bank->sens_edge); return; - case 0x04: /* MIR */ + case 0x04: /* MIR */ bank->mask = value; omap_inth_update(s, 0); omap_inth_update(s, 1); return; - case 0x10: /* SIR_IRQ_CODE */ - case 0x14: /* SIR_FIQ_CODE */ + case 0x10: /* SIR_IRQ_CODE */ + case 0x14: /* SIR_FIQ_CODE */ OMAP_RO_REG(addr); break; - case 0x18: /* CONTROL_REG */ + case 0x18: /* CONTROL_REG */ if (bank_no != 0) break; if (value & 2) { @@ -251,38 +251,38 @@ static void omap_inth_write(void *opaque, hwaddr addr, } return; - case 0x1c: /* ILR0 */ - case 0x20: /* ILR1 */ - case 0x24: /* ILR2 */ - case 0x28: /* ILR3 */ - case 0x2c: /* ILR4 */ - case 0x30: /* ILR5 */ - case 0x34: /* ILR6 */ - case 0x38: /* ILR7 */ - case 0x3c: /* ILR8 */ - case 0x40: /* ILR9 */ - case 0x44: /* ILR10 */ - case 0x48: /* ILR11 */ - case 0x4c: /* ILR12 */ - case 0x50: /* ILR13 */ - case 0x54: /* ILR14 */ - case 0x58: /* ILR15 */ - case 0x5c: /* ILR16 */ - case 0x60: /* ILR17 */ - case 0x64: /* ILR18 */ - case 0x68: /* ILR19 */ - case 0x6c: /* ILR20 */ - case 0x70: /* ILR21 */ - case 0x74: /* ILR22 */ - case 0x78: /* ILR23 */ - case 0x7c: /* ILR24 */ - case 0x80: /* ILR25 */ - case 0x84: /* ILR26 */ - case 0x88: /* ILR27 */ - case 0x8c: /* ILR28 */ - case 0x90: /* ILR29 */ - case 0x94: /* ILR30 */ - case 0x98: /* ILR31 */ + case 0x1c: /* ILR0 */ + case 0x20: /* ILR1 */ + case 0x24: /* ILR2 */ + case 0x28: /* ILR3 */ + case 0x2c: /* ILR4 */ + case 0x30: /* ILR5 */ + case 0x34: /* ILR6 */ + case 0x38: /* ILR7 */ + case 0x3c: /* ILR8 */ + case 0x40: /* ILR9 */ + case 0x44: /* ILR10 */ + case 0x48: /* ILR11 */ + case 0x4c: /* ILR12 */ + case 0x50: /* ILR13 */ + case 0x54: /* ILR14 */ + case 0x58: /* ILR15 */ + case 0x5c: /* ILR16 */ + case 0x60: /* ILR17 */ + case 0x64: /* ILR18 */ + case 0x68: /* ILR19 */ + case 0x6c: /* ILR20 */ + case 0x70: /* ILR21 */ + case 0x74: /* ILR22 */ + case 0x78: /* ILR23 */ + case 0x7c: /* ILR24 */ + case 0x80: /* ILR25 */ + case 0x84: /* ILR26 */ + case 0x88: /* ILR27 */ + case 0x8c: /* ILR28 */ + case 0x90: /* ILR29 */ + case 0x94: /* ILR30 */ + case 0x98: /* ILR31 */ i = (offset - 0x1c) >> 2; bank->priority[i] = (value >> 2) & 0x1f; bank->sens_edge &= ~(1 << i); @@ -291,7 +291,7 @@ static void omap_inth_write(void *opaque, hwaddr addr, bank->fiq |= (value & 1) << i; return; - case 0x9c: /* ISR */ + case 0x9c: /* ISR */ for (i = 0; i < 32; i ++) if (value & (1 << i)) { omap_set_intr(s, 32 * bank_no + i, 1); diff --git a/hw/misc/omap_clk.c b/hw/misc/omap_clk.c index 0157c9be75..da95c4ace5 100644 --- a/hw/misc/omap_clk.c +++ b/hw/misc/omap_clk.c @@ -30,170 +30,170 @@ struct clk { struct clk *parent; struct clk *child1; struct clk *sibling; -#define ALWAYS_ENABLED (1 << 0) -#define CLOCK_IN_OMAP310 (1 << 10) -#define CLOCK_IN_OMAP730 (1 << 11) -#define CLOCK_IN_OMAP1510 (1 << 12) -#define CLOCK_IN_OMAP16XX (1 << 13) +#define ALWAYS_ENABLED (1 << 0) +#define CLOCK_IN_OMAP310 (1 << 10) +#define CLOCK_IN_OMAP730 (1 << 11) +#define CLOCK_IN_OMAP1510 (1 << 12) +#define CLOCK_IN_OMAP16XX (1 << 13) uint32_t flags; int id; - int running; /* Is currently ticking */ - int enabled; /* Is enabled, regardless of its input clk */ - unsigned long rate; /* Current rate (if .running) */ - unsigned int divisor; /* Rate relative to input (if .enabled) */ - unsigned int multiplier; /* Rate relative to input (if .enabled) */ - qemu_irq users[16]; /* Who to notify on change */ - int usecount; /* Automatically idle when unused */ + int running; /* Is currently ticking */ + int enabled; /* Is enabled, regardless of its input clk */ + unsigned long rate; /* Current rate (if .running) */ + unsigned int divisor; /* Rate relative to input (if .enabled) */ + unsigned int multiplier; /* Rate relative to input (if .enabled) */ + qemu_irq users[16]; /* Who to notify on change */ + int usecount; /* Automatically idle when unused */ }; static struct clk xtal_osc12m = { - .name = "xtal_osc_12m", - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "xtal_osc_12m", + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk xtal_osc32k = { - .name = "xtal_osc_32k", - .rate = 32768, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "xtal_osc_32k", + .rate = 32768, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk ck_ref = { - .name = "ck_ref", - .alias = "clkin", - .parent = &xtal_osc12m, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "ck_ref", + .alias = "clkin", + .parent = &xtal_osc12m, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; /* If a dpll is disabled it becomes a bypass, child clocks don't stop */ static struct clk dpll1 = { - .name = "dpll1", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "dpll1", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk dpll2 = { - .name = "dpll2", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .name = "dpll2", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk dpll3 = { - .name = "dpll3", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .name = "dpll3", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk dpll4 = { - .name = "dpll4", - .parent = &ck_ref, - .multiplier = 4, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "dpll4", + .parent = &ck_ref, + .multiplier = 4, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk apll = { - .name = "apll", - .parent = &ck_ref, - .multiplier = 48, - .divisor = 12, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "apll", + .parent = &ck_ref, + .multiplier = 48, + .divisor = 12, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk ck_48m = { - .name = "ck_48m", - .parent = &dpll4, /* either dpll4 or apll */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "ck_48m", + .parent = &dpll4, /* either dpll4 or apll */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk ck_dpll1out = { - .name = "ck_dpll1out", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP16XX, + .name = "ck_dpll1out", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk sossi_ck = { - .name = "ck_sossi", - .parent = &ck_dpll1out, - .flags = CLOCK_IN_OMAP16XX, + .name = "ck_sossi", + .parent = &ck_dpll1out, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk clkm1 = { - .name = "clkm1", - .alias = "ck_gen1", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "clkm1", + .alias = "ck_gen1", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk clkm2 = { - .name = "clkm2", - .alias = "ck_gen2", - .parent = &dpll1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "clkm2", + .alias = "ck_gen2", + .parent = &dpll1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk clkm3 = { - .name = "clkm3", - .alias = "ck_gen3", - .parent = &dpll1, /* either dpll1 or ck_ref */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "clkm3", + .alias = "ck_gen3", + .parent = &dpll1, /* either dpll1 or ck_ref */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk arm_ck = { - .name = "arm_ck", - .alias = "mpu_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "arm_ck", + .alias = "mpu_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk armper_ck = { - .name = "armper_ck", - .alias = "mpuper_ck", - .parent = &clkm1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "armper_ck", + .alias = "mpuper_ck", + .parent = &clkm1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk arm_gpio_ck = { - .name = "arm_gpio_ck", - .alias = "mpu_gpio_ck", - .parent = &clkm1, - .divisor = 1, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .name = "arm_gpio_ck", + .alias = "mpu_gpio_ck", + .parent = &clkm1, + .divisor = 1, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk armxor_ck = { - .name = "armxor_ck", - .alias = "mpuxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "armxor_ck", + .alias = "mpuxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk armtim_ck = { - .name = "armtim_ck", - .alias = "mputim_ck", - .parent = &ck_ref, /* either CLKIN or DPLL1 */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "armtim_ck", + .alias = "mputim_ck", + .parent = &ck_ref, /* either CLKIN or DPLL1 */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk armwdt_ck = { - .name = "armwdt_ck", - .alias = "mpuwd_ck", - .parent = &clkm1, - .divisor = 14, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "armwdt_ck", + .alias = "mpuwd_ck", + .parent = &clkm1, + .divisor = 14, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk arminth_ck16xx = { - .name = "arminth_ck", - .parent = &arm_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .name = "arminth_ck", + .parent = &arm_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, /* Note: On 16xx the frequency can be divided by 2 by programming * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1 * @@ -202,48 +202,48 @@ static struct clk arminth_ck16xx = { }; static struct clk dsp_ck = { - .name = "dsp_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "dsp_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk dspmmu_ck = { - .name = "dspmmu_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .name = "dspmmu_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, }; static struct clk dspper_ck = { - .name = "dspper_ck", - .parent = &clkm2, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "dspper_ck", + .parent = &clkm2, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk dspxor_ck = { - .name = "dspxor_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "dspxor_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk dsptim_ck = { - .name = "dsptim_ck", - .parent = &ck_ref, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "dsptim_ck", + .parent = &ck_ref, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk tc_ck = { - .name = "tc_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .name = "tc_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk arminth_ck15xx = { - .name = "arminth_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .name = "arminth_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, /* Note: On 1510 the frequency follows TC_CK * * 16xx version is in MPU clocks. @@ -252,259 +252,259 @@ static struct clk arminth_ck15xx = { static struct clk tipb_ck = { /* No-idle controlled by "tc_ck" */ - .name = "tipb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .name = "tipb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk l3_ocpi_ck = { /* No-idle controlled by "tc_ck" */ - .name = "l3_ocpi_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .name = "l3_ocpi_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk tc1_ck = { - .name = "tc1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .name = "tc1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk tc2_ck = { - .name = "tc2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX, + .name = "tc2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk dma_ck = { /* No-idle controlled by "tc_ck" */ - .name = "dma_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .name = "dma_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk dma_lcdfree_ck = { - .name = "dma_lcdfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .name = "dma_lcdfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, }; static struct clk api_ck = { - .name = "api_ck", - .alias = "mpui_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .name = "api_ck", + .alias = "mpui_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk lb_ck = { - .name = "lb_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .name = "lb_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk lbfree_ck = { - .name = "lbfree_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .name = "lbfree_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk hsab_ck = { - .name = "hsab_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .name = "hsab_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk rhea1_ck = { - .name = "rhea1_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .name = "rhea1_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, }; static struct clk rhea2_ck = { - .name = "rhea2_ck", - .parent = &tc_ck, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .name = "rhea2_ck", + .parent = &tc_ck, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, }; static struct clk lcd_ck_16xx = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730, }; static struct clk lcd_ck_1510 = { - .name = "lcd_ck", - .parent = &clkm3, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .name = "lcd_ck", + .parent = &clkm3, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk uart1_1510 = { - .name = "uart1_ck", + .name = "uart1_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk uart1_16xx = { - .name = "uart1_ck", + .name = "uart1_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk uart2_ck = { - .name = "uart2_ck", + .name = "uart2_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk uart3_1510 = { - .name = "uart3_ck", + .name = "uart3_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, }; static struct clk uart3_16xx = { - .name = "uart3_ck", + .name = "uart3_ck", /* Direct from ULPD, no real parent */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, }; -static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ - .name = "usb_clk0", - .alias = "usb.clko", +static struct clk usb_clk0 = { /* 6 MHz output on W4_USB_CLK0 */ + .name = "usb_clk0", + .alias = "usb.clko", /* Direct from ULPD, no parent */ - .rate = 6000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .rate = 6000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk usb_hhc_ck1510 = { - .name = "usb_hhc_ck", + .name = "usb_hhc_ck", /* Direct from ULPD, no parent */ - .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, + .rate = 48000000, /* Actually 2 clocks, 12MHz and 48MHz */ + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, }; static struct clk usb_hhc_ck16xx = { - .name = "usb_hhc_ck", + .name = "usb_hhc_ck", /* Direct from ULPD, no parent */ - .rate = 48000000, + .rate = 48000000, /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */ - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk usb_w2fc_mclk = { - .name = "usb_w2fc_mclk", - .alias = "usb_w2fc_ck", - .parent = &ck_48m, - .rate = 48000000, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "usb_w2fc_mclk", + .alias = "usb_w2fc_ck", + .parent = &ck_48m, + .rate = 48000000, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk mclk_1510 = { - .name = "mclk", + .name = "mclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, }; static struct clk bclk_310 = { - .name = "bt_mclk_out", /* Alias midi_mclk_out? */ - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, + .name = "bt_mclk_out", /* Alias midi_mclk_out? */ + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, }; static struct clk mclk_310 = { - .name = "com_mclk_out", - .parent = &armper_ck, - .flags = CLOCK_IN_OMAP310, + .name = "com_mclk_out", + .parent = &armper_ck, + .flags = CLOCK_IN_OMAP310, }; static struct clk mclk_16xx = { - .name = "mclk", + .name = "mclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk bclk_1510 = { - .name = "bclk", + .name = "bclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .rate = 12000000, - .flags = CLOCK_IN_OMAP1510, + .rate = 12000000, + .flags = CLOCK_IN_OMAP1510, }; static struct clk bclk_16xx = { - .name = "bclk", + .name = "bclk", /* Direct from ULPD, no parent. May be enabled by ext hardware. */ - .flags = CLOCK_IN_OMAP16XX, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk mmc1_ck = { - .name = "mmc_ck", - .id = 1, + .name = "mmc_ck", + .id = 1, /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, /* either armper_ck or dpll4 */ - .rate = 48000000, - .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, + .parent = &armper_ck, /* either armper_ck or dpll4 */ + .rate = 48000000, + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310, }; static struct clk mmc2_ck = { - .name = "mmc_ck", - .id = 2, + .name = "mmc_ck", + .id = 2, /* Functional clock is direct from ULPD, interface clock is ARMPER */ - .parent = &armper_ck, - .rate = 48000000, - .flags = CLOCK_IN_OMAP16XX, + .parent = &armper_ck, + .rate = 48000000, + .flags = CLOCK_IN_OMAP16XX, }; static struct clk cam_mclk = { - .name = "cam.mclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, - .rate = 12000000, + .name = "cam.mclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .rate = 12000000, }; static struct clk cam_exclk = { - .name = "cam.exclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "cam.exclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, /* Either 12M from cam.mclk or 48M from dpll4 */ - .parent = &cam_mclk, + .parent = &cam_mclk, }; static struct clk cam_lclk = { - .name = "cam.lclk", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, + .name = "cam.lclk", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, }; static struct clk i2c_fck = { - .name = "i2c_fck", - .id = 1, - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .name = "i2c_fck", + .id = 1, + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - .parent = &armxor_ck, + .parent = &armxor_ck, }; static struct clk i2c_ick = { - .name = "i2c_ick", - .id = 1, - .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - .parent = &armper_ck, + .name = "i2c_ick", + .id = 1, + .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, + .parent = &armper_ck, }; static struct clk clk32k = { - .name = "clk32-kHz", - .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | + .name = "clk32-kHz", + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ALWAYS_ENABLED, - .parent = &xtal_osc32k, + .parent = &xtal_osc32k, }; static struct clk *onchip_clks[] = { diff --git a/hw/timer/pxa2xx_timer.c b/hw/timer/pxa2xx_timer.c index 7a94366b0f..6d4ac31574 100644 --- a/hw/timer/pxa2xx_timer.c +++ b/hw/timer/pxa2xx_timer.c @@ -19,41 +19,41 @@ #include "qom/object.h" #include "system/watchdog.h" -#define OSMR0 0x00 -#define OSMR1 0x04 -#define OSMR2 0x08 -#define OSMR3 0x0c -#define OSMR4 0x80 -#define OSMR5 0x84 -#define OSMR6 0x88 -#define OSMR7 0x8c -#define OSMR8 0x90 -#define OSMR9 0x94 -#define OSMR10 0x98 -#define OSMR11 0x9c -#define OSCR 0x10 /* OS Timer Count */ -#define OSCR4 0x40 -#define OSCR5 0x44 -#define OSCR6 0x48 -#define OSCR7 0x4c -#define OSCR8 0x50 -#define OSCR9 0x54 -#define OSCR10 0x58 -#define OSCR11 0x5c -#define OSSR 0x14 /* Timer status register */ -#define OWER 0x18 -#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ -#define OMCR4 0xc0 /* OS Match Control registers */ -#define OMCR5 0xc4 -#define OMCR6 0xc8 -#define OMCR7 0xcc -#define OMCR8 0xd0 -#define OMCR9 0xd4 -#define OMCR10 0xd8 -#define OMCR11 0xdc -#define OSNR 0x20 +#define OSMR0 0x00 +#define OSMR1 0x04 +#define OSMR2 0x08 +#define OSMR3 0x0c +#define OSMR4 0x80 +#define OSMR5 0x84 +#define OSMR6 0x88 +#define OSMR7 0x8c +#define OSMR8 0x90 +#define OSMR9 0x94 +#define OSMR10 0x98 +#define OSMR11 0x9c +#define OSCR 0x10 /* OS Timer Count */ +#define OSCR4 0x40 +#define OSCR5 0x44 +#define OSCR6 0x48 +#define OSCR7 0x4c +#define OSCR8 0x50 +#define OSCR9 0x54 +#define OSCR10 0x58 +#define OSCR11 0x5c +#define OSSR 0x14 /* Timer status register */ +#define OWER 0x18 +#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */ +#define OMCR4 0xc0 /* OS Match Control registers */ +#define OMCR5 0xc4 +#define OMCR6 0xc8 +#define OMCR7 0xcc +#define OMCR8 0xd0 +#define OMCR9 0xd4 +#define OMCR10 0xd8 +#define OMCR11 0xdc +#define OSNR 0x20 -#define PXA25X_FREQ 3686400 /* 3.6864 MHz */ +#define PXA25X_FREQ 3686400 /* 3.6864 MHz */ static int pxa2xx_timer4_freq[8] = { [0] = 0, @@ -106,7 +106,7 @@ struct PXA2xxTimerInfo { PXA2xxTimer4 tm4[8]; }; -#define PXA2XX_TIMER_HAVE_TM4 0 +#define PXA2XX_TIMER_HAVE_TM4 0 static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s) { @@ -230,7 +230,7 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, NANOSECONDS_PER_SECOND); case OIER: return s->irq_enabled; - case OSSR: /* Status register */ + case OSSR: /* Status register */ return s->events; case OWER: return s->reset3; @@ -336,7 +336,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, case OIER: s->irq_enabled = value & 0xfff; break; - case OSSR: /* Status register */ + case OSSR: /* Status register */ value &= s->events; s->events &= ~value; for (i = 0; i < 4; i ++, value >>= 1) @@ -345,7 +345,7 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value) qemu_irq_lower(s->irq4); break; - case OWER: /* XXX: Reset on OSMR3 match? */ + case OWER: /* XXX: Reset on OSMR3 match? */ s->reset3 = value; break; case OMCR7: tm ++; diff --git a/include/hw/arm/omap.h b/include/hw/arm/omap.h index 6185507373..bdb2e887e4 100644 --- a/include/hw/arm/omap.h +++ b/include/hw/arm/omap.h @@ -25,24 +25,24 @@ #include "qemu/log.h" #include "qom/object.h" -# define OMAP_EMIFS_BASE 0x00000000 -# define OMAP_CS0_BASE 0x00000000 -# define OMAP_CS1_BASE 0x04000000 -# define OMAP_CS2_BASE 0x08000000 -# define OMAP_CS3_BASE 0x0c000000 -# define OMAP_EMIFF_BASE 0x10000000 -# define OMAP_IMIF_BASE 0x20000000 -# define OMAP_LOCALBUS_BASE 0x30000000 -# define OMAP_MPUI_BASE 0xe1000000 +#define OMAP_EMIFS_BASE 0x00000000 +#define OMAP_CS0_BASE 0x00000000 +#define OMAP_CS1_BASE 0x04000000 +#define OMAP_CS2_BASE 0x08000000 +#define OMAP_CS3_BASE 0x0c000000 +#define OMAP_EMIFF_BASE 0x10000000 +#define OMAP_IMIF_BASE 0x20000000 +#define OMAP_LOCALBUS_BASE 0x30000000 +#define OMAP_MPUI_BASE 0xe1000000 -# define OMAP730_SRAM_SIZE 0x00032000 -# define OMAP15XX_SRAM_SIZE 0x00030000 -# define OMAP16XX_SRAM_SIZE 0x00004000 -# define OMAP1611_SRAM_SIZE 0x0003e800 -# define OMAP_CS0_SIZE 0x04000000 -# define OMAP_CS1_SIZE 0x04000000 -# define OMAP_CS2_SIZE 0x04000000 -# define OMAP_CS3_SIZE 0x04000000 +#define OMAP730_SRAM_SIZE 0x00032000 +#define OMAP15XX_SRAM_SIZE 0x00030000 +#define OMAP16XX_SRAM_SIZE 0x00004000 +#define OMAP1611_SRAM_SIZE 0x0003e800 +#define OMAP_CS0_SIZE 0x04000000 +#define OMAP_CS1_SIZE 0x04000000 +#define OMAP_CS2_SIZE 0x04000000 +#define OMAP_CS3_SIZE 0x04000000 /* omap_clk.c */ struct omap_mpu_state_s; @@ -103,228 +103,228 @@ void omap_gpio_set_clk(Omap1GpioState *gpio, omap_clk clk); * Common IRQ numbers for level 1 interrupt handler * See /usr/include/asm-arm/arch-omap/irqs.h in Linux. */ -# define OMAP_INT_CAMERA 1 -# define OMAP_INT_FIQ 3 -# define OMAP_INT_RTDX 6 -# define OMAP_INT_DSP_MMU_ABORT 7 -# define OMAP_INT_HOST 8 -# define OMAP_INT_ABORT 9 -# define OMAP_INT_BRIDGE_PRIV 13 -# define OMAP_INT_GPIO_BANK1 14 -# define OMAP_INT_UART3 15 -# define OMAP_INT_TIMER3 16 -# define OMAP_INT_DMA_CH0_6 19 -# define OMAP_INT_DMA_CH1_7 20 -# define OMAP_INT_DMA_CH2_8 21 -# define OMAP_INT_DMA_CH3 22 -# define OMAP_INT_DMA_CH4 23 -# define OMAP_INT_DMA_CH5 24 -# define OMAP_INT_DMA_LCD 25 -# define OMAP_INT_TIMER1 26 -# define OMAP_INT_WD_TIMER 27 -# define OMAP_INT_BRIDGE_PUB 28 -# define OMAP_INT_TIMER2 30 -# define OMAP_INT_LCD_CTRL 31 +#define OMAP_INT_CAMERA 1 +#define OMAP_INT_FIQ 3 +#define OMAP_INT_RTDX 6 +#define OMAP_INT_DSP_MMU_ABORT 7 +#define OMAP_INT_HOST 8 +#define OMAP_INT_ABORT 9 +#define OMAP_INT_BRIDGE_PRIV 13 +#define OMAP_INT_GPIO_BANK1 14 +#define OMAP_INT_UART3 15 +#define OMAP_INT_TIMER3 16 +#define OMAP_INT_DMA_CH0_6 19 +#define OMAP_INT_DMA_CH1_7 20 +#define OMAP_INT_DMA_CH2_8 21 +#define OMAP_INT_DMA_CH3 22 +#define OMAP_INT_DMA_CH4 23 +#define OMAP_INT_DMA_CH5 24 +#define OMAP_INT_DMA_LCD 25 +#define OMAP_INT_TIMER1 26 +#define OMAP_INT_WD_TIMER 27 +#define OMAP_INT_BRIDGE_PUB 28 +#define OMAP_INT_TIMER2 30 +#define OMAP_INT_LCD_CTRL 31 /* * Common OMAP-15xx IRQ numbers for level 1 interrupt handler */ -# define OMAP_INT_15XX_IH2_IRQ 0 -# define OMAP_INT_15XX_LB_MMU 17 -# define OMAP_INT_15XX_LOCAL_BUS 29 +#define OMAP_INT_15XX_IH2_IRQ 0 +#define OMAP_INT_15XX_LB_MMU 17 +#define OMAP_INT_15XX_LOCAL_BUS 29 /* * OMAP-1510 specific IRQ numbers for level 1 interrupt handler */ -# define OMAP_INT_1510_SPI_TX 4 -# define OMAP_INT_1510_SPI_RX 5 -# define OMAP_INT_1510_DSP_MAILBOX1 10 -# define OMAP_INT_1510_DSP_MAILBOX2 11 +#define OMAP_INT_1510_SPI_TX 4 +#define OMAP_INT_1510_SPI_RX 5 +#define OMAP_INT_1510_DSP_MAILBOX1 10 +#define OMAP_INT_1510_DSP_MAILBOX2 11 /* * OMAP-310 specific IRQ numbers for level 1 interrupt handler */ -# define OMAP_INT_310_McBSP2_TX 4 -# define OMAP_INT_310_McBSP2_RX 5 -# define OMAP_INT_310_HSB_MAILBOX1 12 -# define OMAP_INT_310_HSAB_MMU 18 +#define OMAP_INT_310_McBSP2_TX 4 +#define OMAP_INT_310_McBSP2_RX 5 +#define OMAP_INT_310_HSB_MAILBOX1 12 +#define OMAP_INT_310_HSAB_MMU 18 /* * OMAP-1610 specific IRQ numbers for level 1 interrupt handler */ -# define OMAP_INT_1610_IH2_IRQ 0 -# define OMAP_INT_1610_IH2_FIQ 2 -# define OMAP_INT_1610_McBSP2_TX 4 -# define OMAP_INT_1610_McBSP2_RX 5 -# define OMAP_INT_1610_DSP_MAILBOX1 10 -# define OMAP_INT_1610_DSP_MAILBOX2 11 -# define OMAP_INT_1610_LCD_LINE 12 -# define OMAP_INT_1610_GPTIMER1 17 -# define OMAP_INT_1610_GPTIMER2 18 -# define OMAP_INT_1610_SSR_FIFO_0 29 +#define OMAP_INT_1610_IH2_IRQ 0 +#define OMAP_INT_1610_IH2_FIQ 2 +#define OMAP_INT_1610_McBSP2_TX 4 +#define OMAP_INT_1610_McBSP2_RX 5 +#define OMAP_INT_1610_DSP_MAILBOX1 10 +#define OMAP_INT_1610_DSP_MAILBOX2 11 +#define OMAP_INT_1610_LCD_LINE 12 +#define OMAP_INT_1610_GPTIMER1 17 +#define OMAP_INT_1610_GPTIMER2 18 +#define OMAP_INT_1610_SSR_FIFO_0 29 /* * OMAP-730 specific IRQ numbers for level 1 interrupt handler */ -# define OMAP_INT_730_IH2_FIQ 0 -# define OMAP_INT_730_IH2_IRQ 1 -# define OMAP_INT_730_USB_NON_ISO 2 -# define OMAP_INT_730_USB_ISO 3 -# define OMAP_INT_730_ICR 4 -# define OMAP_INT_730_EAC 5 -# define OMAP_INT_730_GPIO_BANK1 6 -# define OMAP_INT_730_GPIO_BANK2 7 -# define OMAP_INT_730_GPIO_BANK3 8 -# define OMAP_INT_730_McBSP2TX 10 -# define OMAP_INT_730_McBSP2RX 11 -# define OMAP_INT_730_McBSP2RX_OVF 12 -# define OMAP_INT_730_LCD_LINE 14 -# define OMAP_INT_730_GSM_PROTECT 15 -# define OMAP_INT_730_TIMER3 16 -# define OMAP_INT_730_GPIO_BANK5 17 -# define OMAP_INT_730_GPIO_BANK6 18 -# define OMAP_INT_730_SPGIO_WR 29 +#define OMAP_INT_730_IH2_FIQ 0 +#define OMAP_INT_730_IH2_IRQ 1 +#define OMAP_INT_730_USB_NON_ISO 2 +#define OMAP_INT_730_USB_ISO 3 +#define OMAP_INT_730_ICR 4 +#define OMAP_INT_730_EAC 5 +#define OMAP_INT_730_GPIO_BANK1 6 +#define OMAP_INT_730_GPIO_BANK2 7 +#define OMAP_INT_730_GPIO_BANK3 8 +#define OMAP_INT_730_McBSP2TX 10 +#define OMAP_INT_730_McBSP2RX 11 +#define OMAP_INT_730_McBSP2RX_OVF 12 +#define OMAP_INT_730_LCD_LINE 14 +#define OMAP_INT_730_GSM_PROTECT 15 +#define OMAP_INT_730_TIMER3 16 +#define OMAP_INT_730_GPIO_BANK5 17 +#define OMAP_INT_730_GPIO_BANK6 18 +#define OMAP_INT_730_SPGIO_WR 29 /* * Common IRQ numbers for level 2 interrupt handler */ -# define OMAP_INT_KEYBOARD 1 -# define OMAP_INT_uWireTX 2 -# define OMAP_INT_uWireRX 3 -# define OMAP_INT_I2C 4 -# define OMAP_INT_MPUIO 5 -# define OMAP_INT_USB_HHC_1 6 -# define OMAP_INT_McBSP3TX 10 -# define OMAP_INT_McBSP3RX 11 -# define OMAP_INT_McBSP1TX 12 -# define OMAP_INT_McBSP1RX 13 -# define OMAP_INT_UART1 14 -# define OMAP_INT_UART2 15 -# define OMAP_INT_USB_W2FC 20 -# define OMAP_INT_1WIRE 21 -# define OMAP_INT_OS_TIMER 22 -# define OMAP_INT_OQN 23 -# define OMAP_INT_GAUGE_32K 24 -# define OMAP_INT_RTC_TIMER 25 -# define OMAP_INT_RTC_ALARM 26 -# define OMAP_INT_DSP_MMU 28 +#define OMAP_INT_KEYBOARD 1 +#define OMAP_INT_uWireTX 2 +#define OMAP_INT_uWireRX 3 +#define OMAP_INT_I2C 4 +#define OMAP_INT_MPUIO 5 +#define OMAP_INT_USB_HHC_1 6 +#define OMAP_INT_McBSP3TX 10 +#define OMAP_INT_McBSP3RX 11 +#define OMAP_INT_McBSP1TX 12 +#define OMAP_INT_McBSP1RX 13 +#define OMAP_INT_UART1 14 +#define OMAP_INT_UART2 15 +#define OMAP_INT_USB_W2FC 20 +#define OMAP_INT_1WIRE 21 +#define OMAP_INT_OS_TIMER 22 +#define OMAP_INT_OQN 23 +#define OMAP_INT_GAUGE_32K 24 +#define OMAP_INT_RTC_TIMER 25 +#define OMAP_INT_RTC_ALARM 26 +#define OMAP_INT_DSP_MMU 28 /* * OMAP-1510 specific IRQ numbers for level 2 interrupt handler */ -# define OMAP_INT_1510_BT_MCSI1TX 16 -# define OMAP_INT_1510_BT_MCSI1RX 17 -# define OMAP_INT_1510_SoSSI_MATCH 19 -# define OMAP_INT_1510_MEM_STICK 27 -# define OMAP_INT_1510_COM_SPI_RO 31 +#define OMAP_INT_1510_BT_MCSI1TX 16 +#define OMAP_INT_1510_BT_MCSI1RX 17 +#define OMAP_INT_1510_SoSSI_MATCH 19 +#define OMAP_INT_1510_MEM_STICK 27 +#define OMAP_INT_1510_COM_SPI_RO 31 /* * OMAP-310 specific IRQ numbers for level 2 interrupt handler */ -# define OMAP_INT_310_FAC 0 -# define OMAP_INT_310_USB_HHC_2 7 -# define OMAP_INT_310_MCSI1_FE 16 -# define OMAP_INT_310_MCSI2_FE 17 -# define OMAP_INT_310_USB_W2FC_ISO 29 -# define OMAP_INT_310_USB_W2FC_NON_ISO 30 -# define OMAP_INT_310_McBSP2RX_OF 31 +#define OMAP_INT_310_FAC 0 +#define OMAP_INT_310_USB_HHC_2 7 +#define OMAP_INT_310_MCSI1_FE 16 +#define OMAP_INT_310_MCSI2_FE 17 +#define OMAP_INT_310_USB_W2FC_ISO 29 +#define OMAP_INT_310_USB_W2FC_NON_ISO 30 +#define OMAP_INT_310_McBSP2RX_OF 31 /* * OMAP-1610 specific IRQ numbers for level 2 interrupt handler */ -# define OMAP_INT_1610_FAC 0 -# define OMAP_INT_1610_USB_HHC_2 7 -# define OMAP_INT_1610_USB_OTG 8 -# define OMAP_INT_1610_SoSSI 9 -# define OMAP_INT_1610_BT_MCSI1TX 16 -# define OMAP_INT_1610_BT_MCSI1RX 17 -# define OMAP_INT_1610_SoSSI_MATCH 19 -# define OMAP_INT_1610_MEM_STICK 27 -# define OMAP_INT_1610_McBSP2RX_OF 31 -# define OMAP_INT_1610_STI 32 -# define OMAP_INT_1610_STI_WAKEUP 33 -# define OMAP_INT_1610_GPTIMER3 34 -# define OMAP_INT_1610_GPTIMER4 35 -# define OMAP_INT_1610_GPTIMER5 36 -# define OMAP_INT_1610_GPTIMER6 37 -# define OMAP_INT_1610_GPTIMER7 38 -# define OMAP_INT_1610_GPTIMER8 39 -# define OMAP_INT_1610_GPIO_BANK2 40 -# define OMAP_INT_1610_GPIO_BANK3 41 -# define OMAP_INT_1610_MMC2 42 -# define OMAP_INT_1610_CF 43 -# define OMAP_INT_1610_WAKE_UP_REQ 46 -# define OMAP_INT_1610_GPIO_BANK4 48 -# define OMAP_INT_1610_SPI 49 -# define OMAP_INT_1610_DMA_CH6 53 -# define OMAP_INT_1610_DMA_CH7 54 -# define OMAP_INT_1610_DMA_CH8 55 -# define OMAP_INT_1610_DMA_CH9 56 -# define OMAP_INT_1610_DMA_CH10 57 -# define OMAP_INT_1610_DMA_CH11 58 -# define OMAP_INT_1610_DMA_CH12 59 -# define OMAP_INT_1610_DMA_CH13 60 -# define OMAP_INT_1610_DMA_CH14 61 -# define OMAP_INT_1610_DMA_CH15 62 -# define OMAP_INT_1610_NAND 63 +#define OMAP_INT_1610_FAC 0 +#define OMAP_INT_1610_USB_HHC_2 7 +#define OMAP_INT_1610_USB_OTG 8 +#define OMAP_INT_1610_SoSSI 9 +#define OMAP_INT_1610_BT_MCSI1TX 16 +#define OMAP_INT_1610_BT_MCSI1RX 17 +#define OMAP_INT_1610_SoSSI_MATCH 19 +#define OMAP_INT_1610_MEM_STICK 27 +#define OMAP_INT_1610_McBSP2RX_OF 31 +#define OMAP_INT_1610_STI 32 +#define OMAP_INT_1610_STI_WAKEUP 33 +#define OMAP_INT_1610_GPTIMER3 34 +#define OMAP_INT_1610_GPTIMER4 35 +#define OMAP_INT_1610_GPTIMER5 36 +#define OMAP_INT_1610_GPTIMER6 37 +#define OMAP_INT_1610_GPTIMER7 38 +#define OMAP_INT_1610_GPTIMER8 39 +#define OMAP_INT_1610_GPIO_BANK2 40 +#define OMAP_INT_1610_GPIO_BANK3 41 +#define OMAP_INT_1610_MMC2 42 +#define OMAP_INT_1610_CF 43 +#define OMAP_INT_1610_WAKE_UP_REQ 46 +#define OMAP_INT_1610_GPIO_BANK4 48 +#define OMAP_INT_1610_SPI 49 +#define OMAP_INT_1610_DMA_CH6 53 +#define OMAP_INT_1610_DMA_CH7 54 +#define OMAP_INT_1610_DMA_CH8 55 +#define OMAP_INT_1610_DMA_CH9 56 +#define OMAP_INT_1610_DMA_CH10 57 +#define OMAP_INT_1610_DMA_CH11 58 +#define OMAP_INT_1610_DMA_CH12 59 +#define OMAP_INT_1610_DMA_CH13 60 +#define OMAP_INT_1610_DMA_CH14 61 +#define OMAP_INT_1610_DMA_CH15 62 +#define OMAP_INT_1610_NAND 63 /* * OMAP-730 specific IRQ numbers for level 2 interrupt handler */ -# define OMAP_INT_730_HW_ERRORS 0 -# define OMAP_INT_730_NFIQ_PWR_FAIL 1 -# define OMAP_INT_730_CFCD 2 -# define OMAP_INT_730_CFIREQ 3 -# define OMAP_INT_730_I2C 4 -# define OMAP_INT_730_PCC 5 -# define OMAP_INT_730_MPU_EXT_NIRQ 6 -# define OMAP_INT_730_SPI_100K_1 7 -# define OMAP_INT_730_SYREN_SPI 8 -# define OMAP_INT_730_VLYNQ 9 -# define OMAP_INT_730_GPIO_BANK4 10 -# define OMAP_INT_730_McBSP1TX 11 -# define OMAP_INT_730_McBSP1RX 12 -# define OMAP_INT_730_McBSP1RX_OF 13 -# define OMAP_INT_730_UART_MODEM_IRDA_2 14 -# define OMAP_INT_730_UART_MODEM_1 15 -# define OMAP_INT_730_MCSI 16 -# define OMAP_INT_730_uWireTX 17 -# define OMAP_INT_730_uWireRX 18 -# define OMAP_INT_730_SMC_CD 19 -# define OMAP_INT_730_SMC_IREQ 20 -# define OMAP_INT_730_HDQ_1WIRE 21 -# define OMAP_INT_730_TIMER32K 22 -# define OMAP_INT_730_MMC_SDIO 23 -# define OMAP_INT_730_UPLD 24 -# define OMAP_INT_730_USB_HHC_1 27 -# define OMAP_INT_730_USB_HHC_2 28 -# define OMAP_INT_730_USB_GENI 29 -# define OMAP_INT_730_USB_OTG 30 -# define OMAP_INT_730_CAMERA_IF 31 -# define OMAP_INT_730_RNG 32 -# define OMAP_INT_730_DUAL_MODE_TIMER 33 -# define OMAP_INT_730_DBB_RF_EN 34 -# define OMAP_INT_730_MPUIO_KEYPAD 35 -# define OMAP_INT_730_SHA1_MD5 36 -# define OMAP_INT_730_SPI_100K_2 37 -# define OMAP_INT_730_RNG_IDLE 38 -# define OMAP_INT_730_MPUIO 39 -# define OMAP_INT_730_LLPC_LCD_CTRL_OFF 40 -# define OMAP_INT_730_LLPC_OE_FALLING 41 -# define OMAP_INT_730_LLPC_OE_RISING 42 -# define OMAP_INT_730_LLPC_VSYNC 43 -# define OMAP_INT_730_WAKE_UP_REQ 46 -# define OMAP_INT_730_DMA_CH6 53 -# define OMAP_INT_730_DMA_CH7 54 -# define OMAP_INT_730_DMA_CH8 55 -# define OMAP_INT_730_DMA_CH9 56 -# define OMAP_INT_730_DMA_CH10 57 -# define OMAP_INT_730_DMA_CH11 58 -# define OMAP_INT_730_DMA_CH12 59 -# define OMAP_INT_730_DMA_CH13 60 -# define OMAP_INT_730_DMA_CH14 61 -# define OMAP_INT_730_DMA_CH15 62 -# define OMAP_INT_730_NAND 63 +#define OMAP_INT_730_HW_ERRORS 0 +#define OMAP_INT_730_NFIQ_PWR_FAIL 1 +#define OMAP_INT_730_CFCD 2 +#define OMAP_INT_730_CFIREQ 3 +#define OMAP_INT_730_I2C 4 +#define OMAP_INT_730_PCC 5 +#define OMAP_INT_730_MPU_EXT_NIRQ 6 +#define OMAP_INT_730_SPI_100K_1 7 +#define OMAP_INT_730_SYREN_SPI 8 +#define OMAP_INT_730_VLYNQ 9 +#define OMAP_INT_730_GPIO_BANK4 10 +#define OMAP_INT_730_McBSP1TX 11 +#define OMAP_INT_730_McBSP1RX 12 +#define OMAP_INT_730_McBSP1RX_OF 13 +#define OMAP_INT_730_UART_MODEM_IRDA_2 14 +#define OMAP_INT_730_UART_MODEM_1 15 +#define OMAP_INT_730_MCSI 16 +#define OMAP_INT_730_uWireTX 17 +#define OMAP_INT_730_uWireRX 18 +#define OMAP_INT_730_SMC_CD 19 +#define OMAP_INT_730_SMC_IREQ 20 +#define OMAP_INT_730_HDQ_1WIRE 21 +#define OMAP_INT_730_TIMER32K 22 +#define OMAP_INT_730_MMC_SDIO 23 +#define OMAP_INT_730_UPLD 24 +#define OMAP_INT_730_USB_HHC_1 27 +#define OMAP_INT_730_USB_HHC_2 28 +#define OMAP_INT_730_USB_GENI 29 +#define OMAP_INT_730_USB_OTG 30 +#define OMAP_INT_730_CAMERA_IF 31 +#define OMAP_INT_730_RNG 32 +#define OMAP_INT_730_DUAL_MODE_TIMER 33 +#define OMAP_INT_730_DBB_RF_EN 34 +#define OMAP_INT_730_MPUIO_KEYPAD 35 +#define OMAP_INT_730_SHA1_MD5 36 +#define OMAP_INT_730_SPI_100K_2 37 +#define OMAP_INT_730_RNG_IDLE 38 +#define OMAP_INT_730_MPUIO 39 +#define OMAP_INT_730_LLPC_LCD_CTRL_OFF 40 +#define OMAP_INT_730_LLPC_OE_FALLING 41 +#define OMAP_INT_730_LLPC_OE_RISING 42 +#define OMAP_INT_730_LLPC_VSYNC 43 +#define OMAP_INT_730_WAKE_UP_REQ 46 +#define OMAP_INT_730_DMA_CH6 53 +#define OMAP_INT_730_DMA_CH7 54 +#define OMAP_INT_730_DMA_CH8 55 +#define OMAP_INT_730_DMA_CH9 56 +#define OMAP_INT_730_DMA_CH10 57 +#define OMAP_INT_730_DMA_CH11 58 +#define OMAP_INT_730_DMA_CH12 59 +#define OMAP_INT_730_DMA_CH13 60 +#define OMAP_INT_730_DMA_CH14 61 +#define OMAP_INT_730_DMA_CH15 62 +#define OMAP_INT_730_NAND 63 /* omap_dma.c */ enum omap_dma_model { @@ -353,9 +353,9 @@ struct dma_irq_map { enum omap_dma_port { emiff = 0, emifs, - imif, /* omap16xx: ocp_t1 */ + imif, /* omap16xx: ocp_t1 */ tipb, - local, /* omap16xx: ocp_t2 */ + local, /* omap16xx: ocp_t2 */ tipb_mpui, __omap_dma_port_last, }; @@ -418,65 +418,65 @@ struct omap_dma_lcd_channel_s { * DMA request numbers for OMAP1 * See /usr/include/asm-arm/arch-omap/dma.h in Linux. */ -# define OMAP_DMA_NO_DEVICE 0 -# define OMAP_DMA_MCSI1_TX 1 -# define OMAP_DMA_MCSI1_RX 2 -# define OMAP_DMA_I2C_RX 3 -# define OMAP_DMA_I2C_TX 4 -# define OMAP_DMA_EXT_NDMA_REQ0 5 -# define OMAP_DMA_EXT_NDMA_REQ1 6 -# define OMAP_DMA_UWIRE_TX 7 -# define OMAP_DMA_MCBSP1_TX 8 -# define OMAP_DMA_MCBSP1_RX 9 -# define OMAP_DMA_MCBSP3_TX 10 -# define OMAP_DMA_MCBSP3_RX 11 -# define OMAP_DMA_UART1_TX 12 -# define OMAP_DMA_UART1_RX 13 -# define OMAP_DMA_UART2_TX 14 -# define OMAP_DMA_UART2_RX 15 -# define OMAP_DMA_MCBSP2_TX 16 -# define OMAP_DMA_MCBSP2_RX 17 -# define OMAP_DMA_UART3_TX 18 -# define OMAP_DMA_UART3_RX 19 -# define OMAP_DMA_CAMERA_IF_RX 20 -# define OMAP_DMA_MMC_TX 21 -# define OMAP_DMA_MMC_RX 22 -# define OMAP_DMA_NAND 23 /* Not in OMAP310 */ -# define OMAP_DMA_IRQ_LCD_LINE 24 /* Not in OMAP310 */ -# define OMAP_DMA_MEMORY_STICK 25 /* Not in OMAP310 */ -# define OMAP_DMA_USB_W2FC_RX0 26 -# define OMAP_DMA_USB_W2FC_RX1 27 -# define OMAP_DMA_USB_W2FC_RX2 28 -# define OMAP_DMA_USB_W2FC_TX0 29 -# define OMAP_DMA_USB_W2FC_TX1 30 -# define OMAP_DMA_USB_W2FC_TX2 31 +#define OMAP_DMA_NO_DEVICE 0 +#define OMAP_DMA_MCSI1_TX 1 +#define OMAP_DMA_MCSI1_RX 2 +#define OMAP_DMA_I2C_RX 3 +#define OMAP_DMA_I2C_TX 4 +#define OMAP_DMA_EXT_NDMA_REQ0 5 +#define OMAP_DMA_EXT_NDMA_REQ1 6 +#define OMAP_DMA_UWIRE_TX 7 +#define OMAP_DMA_MCBSP1_TX 8 +#define OMAP_DMA_MCBSP1_RX 9 +#define OMAP_DMA_MCBSP3_TX 10 +#define OMAP_DMA_MCBSP3_RX 11 +#define OMAP_DMA_UART1_TX 12 +#define OMAP_DMA_UART1_RX 13 +#define OMAP_DMA_UART2_TX 14 +#define OMAP_DMA_UART2_RX 15 +#define OMAP_DMA_MCBSP2_TX 16 +#define OMAP_DMA_MCBSP2_RX 17 +#define OMAP_DMA_UART3_TX 18 +#define OMAP_DMA_UART3_RX 19 +#define OMAP_DMA_CAMERA_IF_RX 20 +#define OMAP_DMA_MMC_TX 21 +#define OMAP_DMA_MMC_RX 22 +#define OMAP_DMA_NAND 23 /* Not in OMAP310 */ +#define OMAP_DMA_IRQ_LCD_LINE 24 /* Not in OMAP310 */ +#define OMAP_DMA_MEMORY_STICK 25 /* Not in OMAP310 */ +#define OMAP_DMA_USB_W2FC_RX0 26 +#define OMAP_DMA_USB_W2FC_RX1 27 +#define OMAP_DMA_USB_W2FC_RX2 28 +#define OMAP_DMA_USB_W2FC_TX0 29 +#define OMAP_DMA_USB_W2FC_TX1 30 +#define OMAP_DMA_USB_W2FC_TX2 31 /* These are only for 1610 */ -# define OMAP_DMA_CRYPTO_DES_IN 32 -# define OMAP_DMA_SPI_TX 33 -# define OMAP_DMA_SPI_RX 34 -# define OMAP_DMA_CRYPTO_HASH 35 -# define OMAP_DMA_CCP_ATTN 36 -# define OMAP_DMA_CCP_FIFO_NOT_EMPTY 37 -# define OMAP_DMA_CMT_APE_TX_CHAN_0 38 -# define OMAP_DMA_CMT_APE_RV_CHAN_0 39 -# define OMAP_DMA_CMT_APE_TX_CHAN_1 40 -# define OMAP_DMA_CMT_APE_RV_CHAN_1 41 -# define OMAP_DMA_CMT_APE_TX_CHAN_2 42 -# define OMAP_DMA_CMT_APE_RV_CHAN_2 43 -# define OMAP_DMA_CMT_APE_TX_CHAN_3 44 -# define OMAP_DMA_CMT_APE_RV_CHAN_3 45 -# define OMAP_DMA_CMT_APE_TX_CHAN_4 46 -# define OMAP_DMA_CMT_APE_RV_CHAN_4 47 -# define OMAP_DMA_CMT_APE_TX_CHAN_5 48 -# define OMAP_DMA_CMT_APE_RV_CHAN_5 49 -# define OMAP_DMA_CMT_APE_TX_CHAN_6 50 -# define OMAP_DMA_CMT_APE_RV_CHAN_6 51 -# define OMAP_DMA_CMT_APE_TX_CHAN_7 52 -# define OMAP_DMA_CMT_APE_RV_CHAN_7 53 -# define OMAP_DMA_MMC2_TX 54 -# define OMAP_DMA_MMC2_RX 55 -# define OMAP_DMA_CRYPTO_DES_OUT 56 +#define OMAP_DMA_CRYPTO_DES_IN 32 +#define OMAP_DMA_SPI_TX 33 +#define OMAP_DMA_SPI_RX 34 +#define OMAP_DMA_CRYPTO_HASH 35 +#define OMAP_DMA_CCP_ATTN 36 +#define OMAP_DMA_CCP_FIFO_NOT_EMPTY 37 +#define OMAP_DMA_CMT_APE_TX_CHAN_0 38 +#define OMAP_DMA_CMT_APE_RV_CHAN_0 39 +#define OMAP_DMA_CMT_APE_TX_CHAN_1 40 +#define OMAP_DMA_CMT_APE_RV_CHAN_1 41 +#define OMAP_DMA_CMT_APE_TX_CHAN_2 42 +#define OMAP_DMA_CMT_APE_RV_CHAN_2 43 +#define OMAP_DMA_CMT_APE_TX_CHAN_3 44 +#define OMAP_DMA_CMT_APE_RV_CHAN_3 45 +#define OMAP_DMA_CMT_APE_TX_CHAN_4 46 +#define OMAP_DMA_CMT_APE_RV_CHAN_4 47 +#define OMAP_DMA_CMT_APE_TX_CHAN_5 48 +#define OMAP_DMA_CMT_APE_RV_CHAN_5 49 +#define OMAP_DMA_CMT_APE_TX_CHAN_6 50 +#define OMAP_DMA_CMT_APE_RV_CHAN_6 51 +#define OMAP_DMA_CMT_APE_TX_CHAN_7 52 +#define OMAP_DMA_CMT_APE_RV_CHAN_7 53 +#define OMAP_DMA_MMC2_TX 54 +#define OMAP_DMA_MMC2_RX 55 +#define OMAP_DMA_CRYPTO_DES_OUT 56 struct omap_uart_s; struct omap_uart_s *omap_uart_init(hwaddr base, @@ -542,14 +542,14 @@ void omap_mmc_set_clk(DeviceState *dev, omap_clk clk); /* omap_i2c.c */ I2CBus *omap_i2c_bus(DeviceState *omap_i2c); -# define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) -# define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) -# define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610) -# define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710) +#define cpu_is_omap310(cpu) (cpu->mpu_model == omap310) +#define cpu_is_omap1510(cpu) (cpu->mpu_model == omap1510) +#define cpu_is_omap1610(cpu) (cpu->mpu_model == omap1610) +#define cpu_is_omap1710(cpu) (cpu->mpu_model == omap1710) -# define cpu_is_omap15xx(cpu) \ +#define cpu_is_omap15xx(cpu) \ (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu)) -# define cpu_is_omap16xx(cpu) \ +#define cpu_is_omap16xx(cpu) \ (cpu_is_omap1610(cpu) || cpu_is_omap1710(cpu)) struct omap_mpu_state_s { @@ -685,14 +685,14 @@ void omap_badwidth_write32(void *opaque, hwaddr addr, void omap_mpu_wakeup(void *opaque, int irq, int req); -# define OMAP_BAD_REG(paddr) \ +#define OMAP_BAD_REG(paddr) \ qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad register %#08"HWADDR_PRIx"\n", \ __func__, paddr) -# define OMAP_RO_REG(paddr) \ +#define OMAP_RO_REG(paddr) \ qemu_log_mask(LOG_GUEST_ERROR, "%s: Read-only register %#08" \ HWADDR_PRIx "\n", \ __func__, paddr) -# define OMAP_MPUI_REG_MASK 0x000007ff +#define OMAP_MPUI_REG_MASK 0x000007ff #endif diff --git a/include/hw/arm/sharpsl.h b/include/hw/arm/sharpsl.h index e986b28c52..1e3992fcd0 100644 --- a/include/hw/arm/sharpsl.h +++ b/include/hw/arm/sharpsl.h @@ -11,7 +11,7 @@ /* zaurus.c */ -#define SL_PXA_PARAM_BASE 0xa0000a00 +#define SL_PXA_PARAM_BASE 0xa0000a00 void sl_bootparam_write(hwaddr ptr); #endif diff --git a/include/hw/arm/soc_dma.h b/include/hw/arm/soc_dma.h index e93a7499a8..bcdb91425a 100644 --- a/include/hw/arm/soc_dma.h +++ b/include/hw/arm/soc_dma.h @@ -54,7 +54,7 @@ struct soc_dma_ch_s { int bytes; /* Initialised by the DMA module, call soc_dma_ch_update after writing. */ enum soc_dma_access_type type[2]; - hwaddr vaddr[2]; /* Updated by .transfer_fn(). */ + hwaddr vaddr[2]; /* Updated by .transfer_fn(). */ /* Private */ void *paddr[2]; soc_dma_io_t io_fn[2]; @@ -70,7 +70,7 @@ struct soc_dma_ch_s { struct soc_dma_s { /* Following fields are set by the SoC DMA module and can be used * by anybody. */ - uint64_t drqbmp; /* Is zeroed by soc_dma_reset() */ + uint64_t drqbmp; /* Is zeroed by soc_dma_reset() */ qemu_irq *drq; void *opaque; int64_t freq; From 2a952e052ab0dab5dc309f9521e655e1011c92a8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 14 May 2025 14:29:47 +0100 Subject: [PATCH 0895/2760] MAINTAINERS: Add an entry for the Bananapi machine This machine was still missing from the MAINTAINERS file. Since there is likely no active maintainer around for this machine (I didn't spot any contributions from Qianfan Zhao in the git log after 2023), I'm suggesting Peter as maintainer with status set to "Odd fixes". Signed-off-by: Thomas Huth Message-id: 20250508072706.114278-1-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- MAINTAINERS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6dacd6d004..ca0ffc02d4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -732,6 +732,16 @@ F: include/hw/timer/armv7m_systick.h F: include/hw/misc/armv7m_ras.h F: tests/qtest/test-arm-mptimer.c +Bananapi M2U +M: Peter Maydell +L: qemu-arm@nongnu.org +S: Odd Fixes +F: docs/system/arm/bananapi_m2u.rst +F: hw/*/allwinner-r40*.c +F: hw/arm/bananapi_m2u.c +F: include/hw/*/allwinner-r40*.h +F: tests/functional/test_arm_bpim2u.py + B-L475E-IOT01A IoT Node M: Samuel Tardieu L: qemu-arm@nongnu.org From 133edc4f220c9c415f68832e6341f461bf04152a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 11:04:15 -0700 Subject: [PATCH 0896/2760] target/arm: Replace target_ulong -> vaddr for HWBreakpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Pierrick Bouvier Reviewed-by: Alex Bennée Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-2-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/hyp_gdbstub.c | 6 +++--- target/arm/internals.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/target/arm/hyp_gdbstub.c b/target/arm/hyp_gdbstub.c index 0512d67f8c..bb5969720c 100644 --- a/target/arm/hyp_gdbstub.c +++ b/target/arm/hyp_gdbstub.c @@ -54,7 +54,7 @@ GArray *hw_breakpoints, *hw_watchpoints; * here so future PC comparisons will work properly. */ -int insert_hw_breakpoint(target_ulong addr) +int insert_hw_breakpoint(vaddr addr) { HWBreakpoint brk = { .bcr = 0x1, /* BCR E=1, enable */ @@ -80,7 +80,7 @@ int insert_hw_breakpoint(target_ulong addr) * Delete a breakpoint and shuffle any above down */ -int delete_hw_breakpoint(target_ulong pc) +int delete_hw_breakpoint(vaddr pc) { int i; for (i = 0; i < hw_breakpoints->len; i++) { @@ -226,7 +226,7 @@ int delete_hw_watchpoint(vaddr addr, vaddr len, int type) return -ENOENT; } -bool find_hw_breakpoint(CPUState *cpu, target_ulong pc) +bool find_hw_breakpoint(CPUState *cpu, vaddr pc) { int i; diff --git a/target/arm/internals.h b/target/arm/internals.h index 702eb1a548..3360de9150 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1948,9 +1948,9 @@ extern GArray *hw_breakpoints, *hw_watchpoints; #define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i)) #define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i)) -bool find_hw_breakpoint(CPUState *cpu, target_ulong pc); -int insert_hw_breakpoint(target_ulong pc); -int delete_hw_breakpoint(target_ulong pc); +bool find_hw_breakpoint(CPUState *cpu, vaddr pc); +int insert_hw_breakpoint(vaddr pc); +int delete_hw_breakpoint(vaddr pc); bool check_watchpoint_in_range(int i, vaddr addr); CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, vaddr addr); From af3ca6e7f09d8ed0e8c9a3fff55d7a68b5019033 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:16 -0700 Subject: [PATCH 0897/2760] include/system/hvf: missing vaddr include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On MacOS x86_64: In file included from ../target/i386/hvf/x86_task.c:13: /Users/runner/work/qemu/qemu/include/system/hvf.h:42:5: error: unknown type name 'vaddr' vaddr pc; ^ /Users/runner/work/qemu/qemu/include/system/hvf.h:43:5: error: unknown type name 'vaddr' vaddr saved_insn; ^ /Users/runner/work/qemu/qemu/include/system/hvf.h:45:5: error: type name requires a specifier or qualifier QTAILQ_ENTRY(hvf_sw_breakpoint) entry; ^ /Users/runner/work/qemu/qemu/include/system/hvf.h:45:18: error: a parameter list without types is only allowed in a function definition QTAILQ_ENTRY(hvf_sw_breakpoint) entry; ^ /Users/runner/work/qemu/qemu/include/system/hvf.h:45:36: error: expected ';' at end of declaration list QTAILQ_ENTRY(hvf_sw_breakpoint) entry; Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-3-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- include/system/hvf.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/system/hvf.h b/include/system/hvf.h index 7b45a2e198..a9a502f0c8 100644 --- a/include/system/hvf.h +++ b/include/system/hvf.h @@ -17,6 +17,7 @@ #include "qemu/queue.h" #include "exec/vaddr.h" #include "qom/object.h" +#include "exec/vaddr.h" #ifdef COMPILING_PER_TARGET # ifdef CONFIG_HVF From b2bb3f3576e5dc99218607dde09e25ac0e55693c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:17 -0700 Subject: [PATCH 0898/2760] meson: add common libs for target and target_system Following what we did for hw/, we need target specific common libraries for target. We need 2 different libraries: - code common to a base architecture - system code common to a base architecture For user code, it can stay compiled per target for now. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-4-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- meson.build | 78 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 17 deletions(-) diff --git a/meson.build b/meson.build index 7f91500bb7..ad2053f968 100644 --- a/meson.build +++ b/meson.build @@ -3709,6 +3709,8 @@ target_arch = {} target_system_arch = {} target_user_arch = {} hw_common_arch = {} +target_common_arch = {} +target_common_system_arch = {} # NOTE: the trace/ subdirectory needs the qapi_trace_events variable # that is filled in by qapi/. @@ -4107,29 +4109,59 @@ common_all = static_library('common', # construct common libraries per base architecture hw_common_arch_libs = {} +target_common_arch_libs = {} +target_common_system_arch_libs = {} foreach target : target_dirs config_target = config_target_mak[target] target_base_arch = config_target['TARGET_BASE_ARCH'] + target_inc = [include_directories('target' / target_base_arch)] + inc = [common_user_inc + target_inc] - # check if already generated - if target_base_arch in hw_common_arch_libs - continue - endif + # prevent common code to access cpu compile time definition, + # but still allow access to cpu.h + target_c_args = ['-DCPU_DEFS_H'] + target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'] if target_base_arch in hw_common_arch - target_inc = [include_directories('target' / target_base_arch)] - src = hw_common_arch[target_base_arch] - lib = static_library( - 'hw_' + target_base_arch, - build_by_default: false, - sources: src.all_sources() + genh, - include_directories: common_user_inc + target_inc, - implicit_include_directories: false, - # prevent common code to access cpu compile time - # definition, but still allow access to cpu.h - c_args: ['-DCPU_DEFS_H', '-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'], - dependencies: src.all_dependencies()) - hw_common_arch_libs += {target_base_arch: lib} + if target_base_arch not in hw_common_arch_libs + src = hw_common_arch[target_base_arch] + lib = static_library( + 'hw_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_system_c_args, + dependencies: src.all_dependencies()) + hw_common_arch_libs += {target_base_arch: lib} + endif + endif + + if target_base_arch in target_common_arch + if target_base_arch not in target_common_arch_libs + src = target_common_arch[target_base_arch] + lib = static_library( + 'target_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_c_args, + dependencies: src.all_dependencies()) + target_common_arch_libs += {target_base_arch: lib} + endif + endif + + if target_base_arch in target_common_system_arch + if target_base_arch not in target_common_system_arch_libs + src = target_common_system_arch[target_base_arch] + lib = static_library( + 'target_system_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_system_c_args, + dependencies: src.all_dependencies()) + target_common_system_arch_libs += {target_base_arch: lib} + endif endif endforeach @@ -4300,12 +4332,24 @@ foreach target : target_dirs target_common = common_ss.apply(config_target, strict: false) objects = [common_all.extract_objects(target_common.sources())] arch_deps += target_common.dependencies() + if target_base_arch in target_common_arch_libs + src = target_common_arch[target_base_arch].apply(config_target, strict: false) + lib = target_common_arch_libs[target_base_arch] + objects += lib.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif if target_type == 'system' and target_base_arch in hw_common_arch_libs src = hw_common_arch[target_base_arch].apply(config_target, strict: false) lib = hw_common_arch_libs[target_base_arch] objects += lib.extract_objects(src.sources()) arch_deps += src.dependencies() endif + if target_type == 'system' and target_base_arch in target_common_system_arch_libs + src = target_common_system_arch[target_base_arch].apply(config_target, strict: false) + lib = target_common_system_arch_libs[target_base_arch] + objects += lib.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif target_specific = specific_ss.apply(config_target, strict: false) arch_srcs += target_specific.sources() From 9a27ee9ca4999cd9f299dfc33e8af7d789ddc6c6 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:18 -0700 Subject: [PATCH 0899/2760] target/arm: move kvm stubs and remove CONFIG_KVM from kvm_arm.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a forward decl for struct kvm_vcpu_init to avoid pulling all kvm headers. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-5-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm-stub.c | 77 +++++++++++++++++++++++++++++++++++++++ target/arm/kvm_arm.h | 83 +------------------------------------------ 2 files changed, 78 insertions(+), 82 deletions(-) diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index 965a486b32..2b73d0598c 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -22,3 +22,80 @@ bool write_list_to_kvmstate(ARMCPU *cpu, int level) { g_assert_not_reached(); } + +/* + * It's safe to call these functions without KVM support. + * They should either do nothing or return "not supported". + */ +bool kvm_arm_aarch32_supported(void) +{ + return false; +} + +bool kvm_arm_pmu_supported(void) +{ + return false; +} + +bool kvm_arm_sve_supported(void) +{ + return false; +} + +bool kvm_arm_mte_supported(void) +{ + return false; +} + +/* + * These functions should never actually be called without KVM support. + */ +void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) +{ + g_assert_not_reached(); +} + +void kvm_arm_add_vcpu_properties(ARMCPU *cpu) +{ + g_assert_not_reached(); +} + +int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa) +{ + g_assert_not_reached(); +} + +int kvm_arm_vgic_probe(void) +{ + g_assert_not_reached(); +} + +void kvm_arm_pmu_set_irq(ARMCPU *cpu, int irq) +{ + g_assert_not_reached(); +} + +void kvm_arm_pmu_init(ARMCPU *cpu) +{ + g_assert_not_reached(); +} + +void kvm_arm_pvtime_init(ARMCPU *cpu, uint64_t ipa) +{ + g_assert_not_reached(); +} + +void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp) +{ + g_assert_not_reached(); +} + +uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu) +{ + g_assert_not_reached(); +} + +void kvm_arm_enable_mte(Object *cpuobj, Error **errp) +{ + g_assert_not_reached(); +} diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 5f17fc2f3d..5bf5d56648 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -94,7 +94,7 @@ void kvm_arm_cpu_post_load(ARMCPU *cpu); */ void kvm_arm_reset_vcpu(ARMCPU *cpu); -#ifdef CONFIG_KVM +struct kvm_vcpu_init; /** * kvm_arm_create_scratch_host_vcpu: * @fdarray: filled in with kvmfd, vmfd, cpufd file descriptors in that order @@ -216,85 +216,4 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); void kvm_arm_enable_mte(Object *cpuobj, Error **errp); -#else - -/* - * It's safe to call these functions without KVM support. - * They should either do nothing or return "not supported". - */ -static inline bool kvm_arm_aarch32_supported(void) -{ - return false; -} - -static inline bool kvm_arm_pmu_supported(void) -{ - return false; -} - -static inline bool kvm_arm_sve_supported(void) -{ - return false; -} - -static inline bool kvm_arm_mte_supported(void) -{ - return false; -} - -/* - * These functions should never actually be called without KVM support. - */ -static inline void kvm_arm_set_cpu_features_from_host(ARMCPU *cpu) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_add_vcpu_properties(ARMCPU *cpu) -{ - g_assert_not_reached(); -} - -static inline int kvm_arm_get_max_vm_ipa_size(MachineState *ms, bool *fixed_ipa) -{ - g_assert_not_reached(); -} - -static inline int kvm_arm_vgic_probe(void) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_pmu_set_irq(ARMCPU *cpu, int irq) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_pmu_init(ARMCPU *cpu) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_pvtime_init(ARMCPU *cpu, uint64_t ipa) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_steal_time_finalize(ARMCPU *cpu, Error **errp) -{ - g_assert_not_reached(); -} - -static inline uint32_t kvm_arm_sve_get_vls(ARMCPU *cpu) -{ - g_assert_not_reached(); -} - -static inline void kvm_arm_enable_mte(Object *cpuobj, Error **errp) -{ - g_assert_not_reached(); -} - -#endif - #endif From 2bff5f4715c85854bc133b56f5f09606f0ed9a5b Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:19 -0700 Subject: [PATCH 0900/2760] target/arm/kvm-stub: add kvm_arm_reset_vcpu stub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed in target/arm/cpu.c once kvm is possible. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-6-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm-stub.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index 2b73d0598c..e34d3f5e6b 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -99,3 +99,8 @@ void kvm_arm_enable_mte(Object *cpuobj, Error **errp) { g_assert_not_reached(); } + +void kvm_arm_reset_vcpu(ARMCPU *cpu) +{ + g_assert_not_reached(); +} From 3a2964ccb4ebec97764d2b6168b60b778cc52b2f Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:20 -0700 Subject: [PATCH 0901/2760] target/arm/cpu: move arm_cpu_kvm_set_irq to kvm.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow to get rid of CONFIG_KVM in target/arm/cpu.c Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-7-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 31 ------------------------------- target/arm/kvm-stub.c | 5 +++++ target/arm/kvm.c | 29 +++++++++++++++++++++++++++++ target/arm/kvm_arm.h | 2 ++ 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 603f08d05a..6604769341 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1098,37 +1098,6 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level) } } -static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) -{ -#ifdef CONFIG_KVM - ARMCPU *cpu = opaque; - CPUARMState *env = &cpu->env; - CPUState *cs = CPU(cpu); - uint32_t linestate_bit; - int irq_id; - - switch (irq) { - case ARM_CPU_IRQ: - irq_id = KVM_ARM_IRQ_CPU_IRQ; - linestate_bit = CPU_INTERRUPT_HARD; - break; - case ARM_CPU_FIQ: - irq_id = KVM_ARM_IRQ_CPU_FIQ; - linestate_bit = CPU_INTERRUPT_FIQ; - break; - default: - g_assert_not_reached(); - } - - if (level) { - env->irq_line_state |= linestate_bit; - } else { - env->irq_line_state &= ~linestate_bit; - } - kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level); -#endif -} - static bool arm_cpu_virtio_is_big_endian(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index e34d3f5e6b..4806365cdc 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -104,3 +104,8 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu) { g_assert_not_reached(); } + +void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level) +{ + g_assert_not_reached(); +} diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 85911e3024..82668d6438 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -2428,3 +2428,32 @@ void kvm_arm_enable_mte(Object *cpuobj, Error **errp) cpu->kvm_mte = true; } } + +void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level) +{ + ARMCPU *cpu = arm_cpu; + CPUARMState *env = &cpu->env; + CPUState *cs = CPU(cpu); + uint32_t linestate_bit; + int irq_id; + + switch (irq) { + case ARM_CPU_IRQ: + irq_id = KVM_ARM_IRQ_CPU_IRQ; + linestate_bit = CPU_INTERRUPT_HARD; + break; + case ARM_CPU_FIQ: + irq_id = KVM_ARM_IRQ_CPU_FIQ; + linestate_bit = CPU_INTERRUPT_FIQ; + break; + default: + g_assert_not_reached(); + } + + if (level) { + env->irq_line_state |= linestate_bit; + } else { + env->irq_line_state &= ~linestate_bit; + } + kvm_arm_set_irq(cs->cpu_index, KVM_ARM_IRQ_TYPE_CPU, irq_id, !!level); +} diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index 5bf5d56648..b638e09a68 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -216,4 +216,6 @@ int kvm_arm_set_irq(int cpu, int irqtype, int irq, int level); void kvm_arm_enable_mte(Object *cpuobj, Error **errp); +void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level); + #endif From 911a63dd25bf1f244ff8561f800a25b8033fbc87 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:21 -0700 Subject: [PATCH 0902/2760] target/arm/cpu: remove TARGET_BIG_ENDIAN dependency Reviewed-by: Richard Henderson Reviewed-by: Anton Johansson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-8-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 6604769341..c7e00e6432 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -23,6 +23,7 @@ #include "qemu/timer.h" #include "qemu/log.h" #include "exec/page-vary.h" +#include "exec/tswap.h" #include "target/arm/idau.h" #include "qemu/module.h" #include "qapi/error.h" @@ -1171,7 +1172,7 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) info->endian = BFD_ENDIAN_LITTLE; if (bswap_code(sctlr_b)) { - info->endian = TARGET_BIG_ENDIAN ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; + info->endian = target_big_endian() ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; } info->flags &= ~INSN_ARM_BE32; #ifndef CONFIG_USER_ONLY From 07e13d5fb5d289d4ae758cfd1f77356052789ad2 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:22 -0700 Subject: [PATCH 0903/2760] target/arm/cpu: remove TARGET_AARCH64 around aarch64_cpu_dump_state common Call is guarded by is_a64(env), so it's safe to expose without needing to assert anything. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-9-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index c7e00e6432..ec9bc72c3d 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1182,8 +1182,6 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info) #endif } -#ifdef TARGET_AARCH64 - static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) { ARMCPU *cpu = ARM_CPU(cs); @@ -1341,15 +1339,6 @@ static void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) } } -#else - -static inline void aarch64_cpu_dump_state(CPUState *cs, FILE *f, int flags) -{ - g_assert_not_reached(); -} - -#endif - static void arm_cpu_dump_state(CPUState *cs, FILE *f, int flags) { ARMCPU *cpu = ARM_CPU(cs); From 2a028eab3909687f1799b53488cd199fe4775126 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:23 -0700 Subject: [PATCH 0904/2760] target/arm/cpu: remove TARGET_AARCH64 in arm_cpu_finalize_features MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need to stub cpu64 finalize functions. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-10-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu.c | 2 -- target/arm/cpu32-stubs.c | 26 ++++++++++++++++++++++++++ target/arm/meson.build | 11 +++++++---- 3 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 target/arm/cpu32-stubs.c diff --git a/target/arm/cpu.c b/target/arm/cpu.c index ec9bc72c3d..ca5ed7892e 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1913,7 +1913,6 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) { Error *local_err = NULL; -#ifdef TARGET_AARCH64 if (arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) { arm_cpu_sve_finalize(cpu, &local_err); if (local_err != NULL) { @@ -1949,7 +1948,6 @@ void arm_cpu_finalize_features(ARMCPU *cpu, Error **errp) return; } } -#endif if (kvm_enabled()) { kvm_arm_steal_time_finalize(cpu, &local_err); diff --git a/target/arm/cpu32-stubs.c b/target/arm/cpu32-stubs.c new file mode 100644 index 0000000000..81be44d846 --- /dev/null +++ b/target/arm/cpu32-stubs.c @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "target/arm/cpu.h" +#include "target/arm/internals.h" +#include + +void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp) +{ + g_assert_not_reached(); +} + +void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp) +{ + g_assert_not_reached(); +} + +void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp) +{ + g_assert_not_reached(); +} + +void arm_cpu_lpa2_finalize(ARMCPU *cpu, Error **errp) +{ + g_assert_not_reached(); +} diff --git a/target/arm/meson.build b/target/arm/meson.build index 3065081d24..c39ddc4427 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -11,10 +11,13 @@ arm_ss.add(zlib) arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'), if_false: files('kvm-stub.c')) arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) -arm_ss.add(when: 'TARGET_AARCH64', if_true: files( - 'cpu64.c', - 'gdbstub64.c', -)) +arm_ss.add(when: 'TARGET_AARCH64', + if_true: files( + 'cpu64.c', + 'gdbstub64.c'), + if_false: files( + 'cpu32-stubs.c'), +) arm_system_ss = ss.source_set() arm_system_ss.add(files( From 5ae609b629e9de4e4c6d18ecc33bdb1f02e431d6 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:24 -0700 Subject: [PATCH 0905/2760] target/arm/cpu: compile file twice (user, system) only Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-11-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index c39ddc4427..89e305eb56 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,6 +1,6 @@ arm_ss = ss.source_set() +arm_common_ss = ss.source_set() arm_ss.add(files( - 'cpu.c', 'debug_helper.c', 'gdbstub.c', 'helper.c', @@ -20,6 +20,7 @@ arm_ss.add(when: 'TARGET_AARCH64', ) arm_system_ss = ss.source_set() +arm_common_system_ss = ss.source_set() arm_system_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', @@ -30,6 +31,9 @@ arm_system_ss.add(files( )) arm_user_ss = ss.source_set() +arm_user_ss.add(files('cpu.c')) + +arm_common_system_ss.add(files('cpu.c'), capstone) subdir('hvf') @@ -42,3 +46,5 @@ endif target_arch += {'arm': arm_ss} target_system_arch += {'arm': arm_system_ss} target_user_arch += {'arm': arm_user_ss} +target_common_arch += {'arm': arm_common_ss} +target_common_system_arch += {'arm': arm_common_system_ss} From b757ae80c6f389dd8d6f8069e413a52c7ef76c20 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:25 -0700 Subject: [PATCH 0906/2760] target/arm/cpu32-stubs.c: compile file twice (user, system) It could be squashed with commit introducing it, but I would prefer to introduce target/arm/cpu.c first. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-12-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 89e305eb56..de214fe5d5 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -11,13 +11,9 @@ arm_ss.add(zlib) arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'), if_false: files('kvm-stub.c')) arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) -arm_ss.add(when: 'TARGET_AARCH64', - if_true: files( - 'cpu64.c', - 'gdbstub64.c'), - if_false: files( - 'cpu32-stubs.c'), -) +arm_ss.add(when: 'TARGET_AARCH64', if_true: files( + 'cpu64.c', + 'gdbstub64.c')) arm_system_ss = ss.source_set() arm_common_system_ss = ss.source_set() @@ -32,8 +28,12 @@ arm_system_ss.add(files( arm_user_ss = ss.source_set() arm_user_ss.add(files('cpu.c')) +arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files( + 'cpu32-stubs.c')) arm_common_system_ss.add(files('cpu.c'), capstone) +arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( + 'cpu32-stubs.c')) subdir('hvf') From 21a75f792f088d0aabebf6b7d96490e37fe8b779 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:26 -0700 Subject: [PATCH 0907/2760] tcg: add vaddr type for helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Defined as an alias of i32/i64 depending on host pointer size. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-13-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- include/exec/helper-head.h.inc | 11 +++++++++++ include/tcg/tcg-op-common.h | 1 + include/tcg/tcg.h | 14 ++++++++++++++ tcg/tcg.c | 5 +++++ 4 files changed, 31 insertions(+) diff --git a/include/exec/helper-head.h.inc b/include/exec/helper-head.h.inc index bce5db06ef..5b248fd713 100644 --- a/include/exec/helper-head.h.inc +++ b/include/exec/helper-head.h.inc @@ -58,6 +58,17 @@ # define dh_ctype_tl target_ulong #endif /* COMPILING_PER_TARGET */ +#if __SIZEOF_POINTER__ == 4 +# define dh_alias_vaddr i32 +# define dh_typecode_vaddr dh_typecode_i32 +#elif __SIZEOF_POINTER__ == 8 +# define dh_alias_vaddr i64 +# define dh_typecode_vaddr dh_typecode_i64 +#else +# error "sizeof pointer is different from {4,8}" +#endif /* __SIZEOF_POINTER__ */ +# define dh_ctype_vaddr uintptr_t + /* We can't use glue() here because it falls foul of C preprocessor recursive expansion rules. */ #define dh_retvar_decl0_void void diff --git a/include/tcg/tcg-op-common.h b/include/tcg/tcg-op-common.h index b439bdb385..e1071adebf 100644 --- a/include/tcg/tcg-op-common.h +++ b/include/tcg/tcg-op-common.h @@ -14,6 +14,7 @@ TCGv_i32 tcg_constant_i32(int32_t val); TCGv_i64 tcg_constant_i64(int64_t val); +TCGv_vaddr tcg_constant_vaddr(uintptr_t val); TCGv_vec tcg_constant_vec(TCGType type, unsigned vece, int64_t val); TCGv_vec tcg_constant_vec_matching(TCGv_vec match, unsigned vece, int64_t val); diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index a8c00c72cc..3fa5a7aed2 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -189,6 +189,7 @@ typedef tcg_target_ulong TCGArg; * TCGv_i64 : 64 bit integer type * TCGv_i128 : 128 bit integer type * TCGv_ptr : a host pointer type + * TCGv_vaddr: an integer type wide enough to hold a target pointer type * TCGv_vec : a host vector type; the exact size is not exposed to the CPU front-end code. * TCGv : an integer type the same size as target_ulong @@ -217,6 +218,14 @@ typedef struct TCGv_ptr_d *TCGv_ptr; typedef struct TCGv_vec_d *TCGv_vec; typedef TCGv_ptr TCGv_env; +#if __SIZEOF_POINTER__ == 4 +typedef TCGv_i32 TCGv_vaddr; +#elif __SIZEOF_POINTER__ == 8 +typedef TCGv_i64 TCGv_vaddr; +#else +# error "sizeof pointer is different from {4,8}" +#endif /* __SIZEOF_POINTER__ */ + /* call flags */ /* Helper does not read globals (either directly or through an exception). It implies TCG_CALL_NO_WRITE_GLOBALS. */ @@ -577,6 +586,11 @@ static inline TCGv_ptr temp_tcgv_ptr(TCGTemp *t) return (TCGv_ptr)temp_tcgv_i32(t); } +static inline TCGv_vaddr temp_tcgv_vaddr(TCGTemp *t) +{ + return (TCGv_vaddr)temp_tcgv_i32(t); +} + static inline TCGv_vec temp_tcgv_vec(TCGTemp *t) { return (TCGv_vec)temp_tcgv_i32(t); diff --git a/tcg/tcg.c b/tcg/tcg.c index 648333a9fb..ae27a2607d 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -2367,6 +2367,11 @@ TCGv_i64 tcg_constant_i64(int64_t val) return temp_tcgv_i64(tcg_constant_internal(TCG_TYPE_I64, val)); } +TCGv_vaddr tcg_constant_vaddr(uintptr_t val) +{ + return temp_tcgv_vaddr(tcg_constant_internal(TCG_TYPE_PTR, val)); +} + TCGv_ptr tcg_constant_ptr_int(intptr_t val) { return temp_tcgv_ptr(tcg_constant_internal(TCG_TYPE_PTR, val)); From a0307ea3dde1089d764a4449b62815023a1abbc6 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:27 -0700 Subject: [PATCH 0908/2760] target/arm/helper: use vaddr instead of target_ulong for exception_pc_alignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-14-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 2 +- target/arm/tcg/tlb_helper.c | 2 +- target/arm/tcg/translate-a64.c | 2 +- target/arm/tcg/translate.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 0907505839..95b9211c6f 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -49,7 +49,7 @@ DEF_HELPER_3(exception_with_syndrome, noreturn, env, i32, i32) DEF_HELPER_4(exception_with_syndrome_el, noreturn, env, i32, i32, i32) DEF_HELPER_2(exception_bkpt_insn, noreturn, env, i32) DEF_HELPER_2(exception_swstep, noreturn, env, i32) -DEF_HELPER_2(exception_pc_alignment, noreturn, env, tl) +DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr) DEF_HELPER_1(setend, void, env) DEF_HELPER_2(wfi, void, env, i32) DEF_HELPER_1(wfe, void, env) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index 5ea4d6590f..d9e6c827d4 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -276,7 +276,7 @@ void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, arm_deliver_fault(cpu, vaddr, access_type, mmu_idx, &fi); } -void helper_exception_pc_alignment(CPUARMState *env, target_ulong pc) +void helper_exception_pc_alignment(CPUARMState *env, vaddr pc) { ARMMMUFaultInfo fi = { .type = ARMFault_Alignment }; int target_el = exception_target_el(env); diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index 52cf47e775..ac80f572a2 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -10242,7 +10242,7 @@ static void aarch64_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * start of the TB. */ assert(s->base.num_insns == 1); - gen_helper_exception_pc_alignment(tcg_env, tcg_constant_tl(pc)); + gen_helper_exception_pc_alignment(tcg_env, tcg_constant_vaddr(pc)); s->base.is_jmp = DISAS_NORETURN; s->base.pc_next = QEMU_ALIGN_UP(pc, 4); return; diff --git a/target/arm/tcg/translate.c b/target/arm/tcg/translate.c index e773ab7268..9962f43b1d 100644 --- a/target/arm/tcg/translate.c +++ b/target/arm/tcg/translate.c @@ -7791,7 +7791,7 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu) * be possible after an indirect branch, at the start of the TB. */ assert(dc->base.num_insns == 1); - gen_helper_exception_pc_alignment(tcg_env, tcg_constant_tl(pc)); + gen_helper_exception_pc_alignment(tcg_env, tcg_constant_vaddr(pc)); dc->base.is_jmp = DISAS_NORETURN; dc->base.pc_next = QEMU_ALIGN_UP(pc, 4); return; From 5296a79b5a14d072af6fe2c8a8c00793862f18d4 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:28 -0700 Subject: [PATCH 0909/2760] target/arm/helper: use vaddr instead of target_ulong for probe_access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-15-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 2 +- target/arm/tcg/op_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/helper.h b/target/arm/helper.h index 95b9211c6f..0a4fc90fa8 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -104,7 +104,7 @@ DEF_HELPER_FLAGS_1(rebuild_hflags_a32_newel, TCG_CALL_NO_RWG, void, env) DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int) DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int) -DEF_HELPER_FLAGS_5(probe_access, TCG_CALL_NO_WG, void, env, tl, i32, i32, i32) +DEF_HELPER_FLAGS_5(probe_access, TCG_CALL_NO_WG, void, env, vaddr, i32, i32, i32) DEF_HELPER_1(vfp_get_fpscr, i32, env) DEF_HELPER_2(vfp_set_fpscr, void, env, i32) diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index dc3f83c37d..575e566280 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -1222,7 +1222,7 @@ uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) } } -void HELPER(probe_access)(CPUARMState *env, target_ulong ptr, +void HELPER(probe_access)(CPUARMState *env, vaddr ptr, uint32_t access_type, uint32_t mmu_idx, uint32_t size) { From a7a3ae9edc65032c6362bb3af6fe611df10aa705 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:29 -0700 Subject: [PATCH 0910/2760] target/arm/helper: extract common helpers Allow later commits to include only the "new" tcg/helper.h, thus preventing to pull aarch64 helpers (+ target/arm/helper.h contains a ifdef TARGET_AARCH64). Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-16-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.h | 1152 +------------------------------------- target/arm/tcg/helper.h | 1153 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 1155 insertions(+), 1150 deletions(-) create mode 100644 target/arm/tcg/helper.h diff --git a/target/arm/helper.h b/target/arm/helper.h index 0a4fc90fa8..f340a49a28 100644 --- a/target/arm/helper.h +++ b/target/arm/helper.h @@ -1,1154 +1,6 @@ -DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32) -DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32) +/* SPDX-License-Identifier: GPL-2.0-or-later */ -DEF_HELPER_3(add_setq, i32, env, i32, i32) -DEF_HELPER_3(add_saturate, i32, env, i32, i32) -DEF_HELPER_3(sub_saturate, i32, env, i32, i32) -DEF_HELPER_3(add_usaturate, i32, env, i32, i32) -DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) -DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_RWG, s32, env, s32, s32) -DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_RWG, i32, env, i32, i32) -DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32) - -#define PAS_OP(pfx) \ - DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ - DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \ - DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \ - DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \ - DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \ - DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr) - -PAS_OP(s) -PAS_OP(u) -#undef PAS_OP - -#define PAS_OP(pfx) \ - DEF_HELPER_2(pfx ## add8, i32, i32, i32) \ - DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \ - DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \ - DEF_HELPER_2(pfx ## add16, i32, i32, i32) \ - DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \ - DEF_HELPER_2(pfx ## subaddx, i32, i32, i32) -PAS_OP(q) -PAS_OP(sh) -PAS_OP(uq) -PAS_OP(uh) -#undef PAS_OP - -DEF_HELPER_3(ssat, i32, env, i32, i32) -DEF_HELPER_3(usat, i32, env, i32, i32) -DEF_HELPER_3(ssat16, i32, env, i32, i32) -DEF_HELPER_3(usat16, i32, env, i32, i32) - -DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) - -DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, - i32, i32, i32, i32) -DEF_HELPER_2(exception_internal, noreturn, env, i32) -DEF_HELPER_3(exception_with_syndrome, noreturn, env, i32, i32) -DEF_HELPER_4(exception_with_syndrome_el, noreturn, env, i32, i32, i32) -DEF_HELPER_2(exception_bkpt_insn, noreturn, env, i32) -DEF_HELPER_2(exception_swstep, noreturn, env, i32) -DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr) -DEF_HELPER_1(setend, void, env) -DEF_HELPER_2(wfi, void, env, i32) -DEF_HELPER_1(wfe, void, env) -DEF_HELPER_2(wfit, void, env, i64) -DEF_HELPER_1(yield, void, env) -DEF_HELPER_1(pre_hvc, void, env) -DEF_HELPER_2(pre_smc, void, env, i32) -DEF_HELPER_1(vesb, void, env) - -DEF_HELPER_3(cpsr_write, void, env, i32, i32) -DEF_HELPER_2(cpsr_write_eret, void, env, i32) -DEF_HELPER_1(cpsr_read, i32, env) - -DEF_HELPER_3(v7m_msr, void, env, i32, i32) -DEF_HELPER_2(v7m_mrs, i32, env, i32) - -DEF_HELPER_2(v7m_bxns, void, env, i32) -DEF_HELPER_2(v7m_blxns, void, env, i32) - -DEF_HELPER_3(v7m_tt, i32, env, i32, i32) - -DEF_HELPER_1(v7m_preserve_fp_state, void, env) - -DEF_HELPER_2(v7m_vlstm, void, env, i32) -DEF_HELPER_2(v7m_vlldm, void, env, i32) - -DEF_HELPER_2(v8m_stackcheck, void, env, i32) - -DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32) - -DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32) -DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32) -DEF_HELPER_FLAGS_2(tidcp_el0, TCG_CALL_NO_WG, void, env, i32) -DEF_HELPER_FLAGS_2(tidcp_el1, TCG_CALL_NO_WG, void, env, i32) -DEF_HELPER_3(set_cp_reg, void, env, cptr, i32) -DEF_HELPER_2(get_cp_reg, i32, env, cptr) -DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64) -DEF_HELPER_2(get_cp_reg64, i64, env, cptr) - -DEF_HELPER_2(get_r13_banked, i32, env, i32) -DEF_HELPER_3(set_r13_banked, void, env, i32, i32) - -DEF_HELPER_3(mrs_banked, i32, env, i32, i32) -DEF_HELPER_4(msr_banked, void, env, i32, i32, i32) - -DEF_HELPER_2(get_user_reg, i32, env, i32) -DEF_HELPER_3(set_user_reg, void, env, i32, i32) - -DEF_HELPER_FLAGS_1(rebuild_hflags_m32_newel, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_FLAGS_2(rebuild_hflags_m32, TCG_CALL_NO_RWG, void, env, int) -DEF_HELPER_FLAGS_1(rebuild_hflags_a32_newel, TCG_CALL_NO_RWG, void, env) -DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int) -DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int) - -DEF_HELPER_FLAGS_5(probe_access, TCG_CALL_NO_WG, void, env, vaddr, i32, i32, i32) - -DEF_HELPER_1(vfp_get_fpscr, i32, env) -DEF_HELPER_2(vfp_set_fpscr, void, env, i32) - -DEF_HELPER_3(vfp_addh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_adds, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_addd, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_subh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_subs, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_subd, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_mulh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_muls, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_muld, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_divh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_divs, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_divd, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_maxh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_maxs, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_maxd, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_minh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_mins, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_mind, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_maxnumh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_maxnums, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_maxnumd, f64, f64, f64, fpst) -DEF_HELPER_3(vfp_minnumh, f16, f16, f16, fpst) -DEF_HELPER_3(vfp_minnums, f32, f32, f32, fpst) -DEF_HELPER_3(vfp_minnumd, f64, f64, f64, fpst) -DEF_HELPER_2(vfp_sqrth, f16, f16, fpst) -DEF_HELPER_2(vfp_sqrts, f32, f32, fpst) -DEF_HELPER_2(vfp_sqrtd, f64, f64, fpst) -DEF_HELPER_3(vfp_cmph, void, f16, f16, env) -DEF_HELPER_3(vfp_cmps, void, f32, f32, env) -DEF_HELPER_3(vfp_cmpd, void, f64, f64, env) -DEF_HELPER_3(vfp_cmpeh, void, f16, f16, env) -DEF_HELPER_3(vfp_cmpes, void, f32, f32, env) -DEF_HELPER_3(vfp_cmped, void, f64, f64, env) - -DEF_HELPER_2(vfp_fcvtds, f64, f32, fpst) -DEF_HELPER_2(vfp_fcvtsd, f32, f64, fpst) -DEF_HELPER_FLAGS_2(bfcvt, TCG_CALL_NO_RWG, i32, f32, fpst) -DEF_HELPER_FLAGS_2(bfcvt_pair, TCG_CALL_NO_RWG, i32, i64, fpst) - -DEF_HELPER_2(vfp_uitoh, f16, i32, fpst) -DEF_HELPER_2(vfp_uitos, f32, i32, fpst) -DEF_HELPER_2(vfp_uitod, f64, i32, fpst) -DEF_HELPER_2(vfp_sitoh, f16, i32, fpst) -DEF_HELPER_2(vfp_sitos, f32, i32, fpst) -DEF_HELPER_2(vfp_sitod, f64, i32, fpst) - -DEF_HELPER_2(vfp_touih, i32, f16, fpst) -DEF_HELPER_2(vfp_touis, i32, f32, fpst) -DEF_HELPER_2(vfp_touid, i32, f64, fpst) -DEF_HELPER_2(vfp_touizh, i32, f16, fpst) -DEF_HELPER_2(vfp_touizs, i32, f32, fpst) -DEF_HELPER_2(vfp_touizd, i32, f64, fpst) -DEF_HELPER_2(vfp_tosih, s32, f16, fpst) -DEF_HELPER_2(vfp_tosis, s32, f32, fpst) -DEF_HELPER_2(vfp_tosid, s32, f64, fpst) -DEF_HELPER_2(vfp_tosizh, s32, f16, fpst) -DEF_HELPER_2(vfp_tosizs, s32, f32, fpst) -DEF_HELPER_2(vfp_tosizd, s32, f64, fpst) - -DEF_HELPER_3(vfp_toshh_round_to_zero, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toslh_round_to_zero, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_touhh_round_to_zero, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toulh_round_to_zero, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toshs_round_to_zero, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_tosls_round_to_zero, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_touhs_round_to_zero, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_touls_round_to_zero, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_toshd_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tosld_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tosqd_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_touhd_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tould_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_touqd_round_to_zero, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_touhh, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toshh, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toulh, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_toslh, i32, f16, i32, fpst) -DEF_HELPER_3(vfp_touqh, i64, f16, i32, fpst) -DEF_HELPER_3(vfp_tosqh, i64, f16, i32, fpst) -DEF_HELPER_3(vfp_toshs, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_tosls, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_tosqs, i64, f32, i32, fpst) -DEF_HELPER_3(vfp_touhs, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_touls, i32, f32, i32, fpst) -DEF_HELPER_3(vfp_touqs, i64, f32, i32, fpst) -DEF_HELPER_3(vfp_toshd, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tosld, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tosqd, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_touhd, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_tould, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_touqd, i64, f64, i32, fpst) -DEF_HELPER_3(vfp_shtos, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_sltos, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_sqtos, f32, i64, i32, fpst) -DEF_HELPER_3(vfp_uhtos, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_ultos, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_uqtos, f32, i64, i32, fpst) -DEF_HELPER_3(vfp_shtod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_sltod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_sqtod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_uhtod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_ultod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_uqtod, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_shtoh, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_uhtoh, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_sltoh, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_ultoh, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_sqtoh, f16, i64, i32, fpst) -DEF_HELPER_3(vfp_uqtoh, f16, i64, i32, fpst) - -DEF_HELPER_3(vfp_shtos_round_to_nearest, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_sltos_round_to_nearest, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_uhtos_round_to_nearest, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_ultos_round_to_nearest, f32, i32, i32, fpst) -DEF_HELPER_3(vfp_shtod_round_to_nearest, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_sltod_round_to_nearest, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_uhtod_round_to_nearest, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_ultod_round_to_nearest, f64, i64, i32, fpst) -DEF_HELPER_3(vfp_shtoh_round_to_nearest, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_uhtoh_round_to_nearest, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_sltoh_round_to_nearest, f16, i32, i32, fpst) -DEF_HELPER_3(vfp_ultoh_round_to_nearest, f16, i32, i32, fpst) - -DEF_HELPER_FLAGS_2(set_rmode, TCG_CALL_NO_RWG, i32, i32, fpst) - -DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f32, TCG_CALL_NO_RWG, f32, f16, fpst, i32) -DEF_HELPER_FLAGS_3(vfp_fcvt_f32_to_f16, TCG_CALL_NO_RWG, f16, f32, fpst, i32) -DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, f16, fpst, i32) -DEF_HELPER_FLAGS_3(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, f16, f64, fpst, i32) - -DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, fpst) -DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, fpst) -DEF_HELPER_4(vfp_muladdh, f16, f16, f16, f16, fpst) - -DEF_HELPER_FLAGS_2(recpe_f16, TCG_CALL_NO_RWG, f16, f16, fpst) -DEF_HELPER_FLAGS_2(recpe_f32, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(recpe_rpres_f32, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, fpst) -DEF_HELPER_FLAGS_2(rsqrte_f16, TCG_CALL_NO_RWG, f16, f16, fpst) -DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(rsqrte_rpres_f32, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, fpst) -DEF_HELPER_FLAGS_1(recpe_u32, TCG_CALL_NO_RWG, i32, i32) -DEF_HELPER_FLAGS_1(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32) -DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i64, env, i32, i64, i64) - -DEF_HELPER_3(shl_cc, i32, env, i32, i32) -DEF_HELPER_3(shr_cc, i32, env, i32, i32) -DEF_HELPER_3(sar_cc, i32, env, i32, i32) -DEF_HELPER_3(ror_cc, i32, env, i32, i32) - -DEF_HELPER_FLAGS_2(rinth_exact, TCG_CALL_NO_RWG, f16, f16, fpst) -DEF_HELPER_FLAGS_2(rints_exact, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(rintd_exact, TCG_CALL_NO_RWG, f64, f64, fpst) -DEF_HELPER_FLAGS_2(rinth, TCG_CALL_NO_RWG, f16, f16, fpst) -DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, fpst) - -DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env) -DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, fpst) - -DEF_HELPER_FLAGS_3(check_hcr_el2_trap, TCG_CALL_NO_WG, void, env, i32, i32) - -/* neon_helper.c */ -DEF_HELPER_2(neon_pmin_u8, i32, i32, i32) -DEF_HELPER_2(neon_pmin_s8, i32, i32, i32) -DEF_HELPER_2(neon_pmin_u16, i32, i32, i32) -DEF_HELPER_2(neon_pmin_s16, i32, i32, i32) -DEF_HELPER_2(neon_pmax_u8, i32, i32, i32) -DEF_HELPER_2(neon_pmax_s8, i32, i32, i32) -DEF_HELPER_2(neon_pmax_u16, i32, i32, i32) -DEF_HELPER_2(neon_pmax_s16, i32, i32, i32) - -DEF_HELPER_2(neon_shl_u16, i32, i32, i32) -DEF_HELPER_2(neon_shl_s16, i32, i32, i32) -DEF_HELPER_2(neon_rshl_u8, i32, i32, i32) -DEF_HELPER_2(neon_rshl_s8, i32, i32, i32) -DEF_HELPER_2(neon_rshl_u16, i32, i32, i32) -DEF_HELPER_2(neon_rshl_s16, i32, i32, i32) -DEF_HELPER_2(neon_rshl_u32, i32, i32, i32) -DEF_HELPER_2(neon_rshl_s32, i32, i32, i32) -DEF_HELPER_2(neon_rshl_u64, i64, i64, i64) -DEF_HELPER_2(neon_rshl_s64, i64, i64, i64) -DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64) -DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64) -DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64) -DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64) -DEF_HELPER_FLAGS_5(neon_sqshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_sqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(neon_uqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_uqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_uqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_uqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_uqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshlui_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshlui_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshlui_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_4(neon_sqshlui_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(gvec_srshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_srshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_srshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_srshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_urshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_urshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_urshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_urshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_2(neon_add_u8, i32, i32, i32) -DEF_HELPER_2(neon_add_u16, i32, i32, i32) -DEF_HELPER_2(neon_sub_u8, i32, i32, i32) -DEF_HELPER_2(neon_sub_u16, i32, i32, i32) -DEF_HELPER_2(neon_mul_u8, i32, i32, i32) -DEF_HELPER_2(neon_mul_u16, i32, i32, i32) - -DEF_HELPER_2(neon_tst_u8, i32, i32, i32) -DEF_HELPER_2(neon_tst_u16, i32, i32, i32) -DEF_HELPER_2(neon_tst_u32, i32, i32, i32) - -DEF_HELPER_1(neon_clz_u8, i32, i32) -DEF_HELPER_1(neon_clz_u16, i32, i32) -DEF_HELPER_1(neon_cls_s8, i32, i32) -DEF_HELPER_1(neon_cls_s16, i32, i32) -DEF_HELPER_1(neon_cls_s32, i32, i32) -DEF_HELPER_FLAGS_3(gvec_cnt_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_rbit_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32) -DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32) -DEF_HELPER_4(neon_qrdmlah_s16, i32, env, i32, i32, i32) -DEF_HELPER_4(neon_qrdmlsh_s16, i32, env, i32, i32, i32) -DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32) -DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) -DEF_HELPER_4(neon_qrdmlah_s32, i32, env, s32, s32, s32) -DEF_HELPER_4(neon_qrdmlsh_s32, i32, env, s32, s32, s32) - -DEF_HELPER_1(neon_narrow_u8, i64, i64) -DEF_HELPER_1(neon_narrow_u16, i64, i64) -DEF_HELPER_2(neon_unarrow_sat8, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_u8, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_s8, i64, env, i64) -DEF_HELPER_2(neon_unarrow_sat16, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_u16, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_s16, i64, env, i64) -DEF_HELPER_2(neon_unarrow_sat32, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_u32, i64, env, i64) -DEF_HELPER_2(neon_narrow_sat_s32, i64, env, i64) -DEF_HELPER_1(neon_narrow_high_u8, i32, i64) -DEF_HELPER_1(neon_narrow_high_u16, i32, i64) -DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) -DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64) -DEF_HELPER_1(neon_widen_u8, i64, i32) -DEF_HELPER_1(neon_widen_s8, i64, i32) -DEF_HELPER_1(neon_widen_u16, i64, i32) -DEF_HELPER_1(neon_widen_s16, i64, i32) - -DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64) -DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) -DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) -DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) -DEF_HELPER_2(neon_abdl_s16, i64, i32, i32) -DEF_HELPER_2(neon_abdl_u32, i64, i32, i32) -DEF_HELPER_2(neon_abdl_s32, i64, i32, i32) -DEF_HELPER_2(neon_abdl_u64, i64, i32, i32) -DEF_HELPER_2(neon_abdl_s64, i64, i32, i32) -DEF_HELPER_2(neon_mull_u8, i64, i32, i32) -DEF_HELPER_2(neon_mull_s8, i64, i32, i32) -DEF_HELPER_2(neon_mull_u16, i64, i32, i32) -DEF_HELPER_2(neon_mull_s16, i64, i32, i32) - -DEF_HELPER_1(neon_negl_u16, i64, i64) -DEF_HELPER_1(neon_negl_u32, i64, i64) - -DEF_HELPER_FLAGS_2(neon_qabs_s8, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qabs_s16, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qabs_s32, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qabs_s64, TCG_CALL_NO_RWG, i64, env, i64) -DEF_HELPER_FLAGS_2(neon_qneg_s8, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qneg_s16, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qneg_s32, TCG_CALL_NO_RWG, i32, env, i32) -DEF_HELPER_FLAGS_2(neon_qneg_s64, TCG_CALL_NO_RWG, i64, env, i64) - -DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, fpst) -DEF_HELPER_3(neon_cge_f32, i32, i32, i32, fpst) -DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, fpst) -DEF_HELPER_3(neon_acge_f32, i32, i32, i32, fpst) -DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, fpst) -DEF_HELPER_3(neon_acge_f64, i64, i64, i64, fpst) -DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, fpst) - -/* iwmmxt_helper.c */ -DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64) -DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64) -DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64) -DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64) -DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64) -DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64) - -#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ -DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \ -DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \ -DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \ - -DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) -DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) - -DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64) -DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64) - -DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) -DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) -DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) - -DEF_IWMMXT_HELPER_SIZE_ENV(mins) -DEF_IWMMXT_HELPER_SIZE_ENV(minu) -DEF_IWMMXT_HELPER_SIZE_ENV(maxs) -DEF_IWMMXT_HELPER_SIZE_ENV(maxu) - -DEF_IWMMXT_HELPER_SIZE_ENV(subn) -DEF_IWMMXT_HELPER_SIZE_ENV(addn) -DEF_IWMMXT_HELPER_SIZE_ENV(subu) -DEF_IWMMXT_HELPER_SIZE_ENV(addu) -DEF_IWMMXT_HELPER_SIZE_ENV(subs) -DEF_IWMMXT_HELPER_SIZE_ENV(adds) - -DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64) - -DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32) -DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32) - -DEF_HELPER_1(iwmmxt_bcstb, i64, i32) -DEF_HELPER_1(iwmmxt_bcstw, i64, i32) -DEF_HELPER_1(iwmmxt_bcstl, i64, i32) - -DEF_HELPER_1(iwmmxt_addcb, i64, i64) -DEF_HELPER_1(iwmmxt_addcw, i64, i64) -DEF_HELPER_1(iwmmxt_addcl, i64, i64) - -DEF_HELPER_1(iwmmxt_msbb, i32, i64) -DEF_HELPER_1(iwmmxt_msbw, i32, i64) -DEF_HELPER_1(iwmmxt_msbl, i32, i64) - -DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32) -DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32) - -DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64) -DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64) - -DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) -DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) -DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) - -DEF_HELPER_FLAGS_2(neon_unzip8, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_unzip16, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qunzip8, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qunzip16, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qunzip32, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_zip8, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_zip16, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qzip8, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qzip16, TCG_CALL_NO_RWG, void, ptr, ptr) -DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr) - -DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_aesd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_aesimc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_sha1su0, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha1c, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha1p, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha1m, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sha512su1, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_sm3tt1a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm3tt1b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm3tt2a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm3tt2b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm3partw1, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm3partw2, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(crypto_rax1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) -DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) - -DEF_HELPER_FLAGS_5(gvec_qrdmlah_s16, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_qrdmlsh_s16, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_qrdmlah_s32, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_qrdmlsh_s32, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(sve2_sqrdmlah_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlah_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlah_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlah_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_sdot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_udot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sdot_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_udot_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usdot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_sdot_idx_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_udot_idx_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sdot_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_udot_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sudot_idx_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usdot_idx_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_fcaddh, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcadds, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcaddd, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_6(gvec_fcmlah, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fcmlah_idx, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fcmlas, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fcmlas_idx, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fcmlad, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_sstoh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_sitos, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_ustoh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_uitos, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_tosszh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_tosizs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_touszh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_touizs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vcvt_sf, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_uf, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fu, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vcvt_sh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_uh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hu, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vcvt_sd, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_ud, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_ds, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rz_du, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sd, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ud, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ss, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_us, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vcvt_rm_uh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vrint_rm_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vrint_rm_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_vrintx_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_vrintx_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_frecpe_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frecpe_rpres_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frecpe_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_frsqrte_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frsqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frsqrte_rpres_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_frsqrte_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_fcgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcgt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcgt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_fcge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcge0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcge0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_fceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fceq0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fceq0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_fcle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcle0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fcle0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_fclt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fclt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_4(gvec_fclt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fadd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fsub_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmul_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmul_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmul_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_ah_fabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ah_fabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ah_fabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fceq_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fceq_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fceq_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fcge_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcge_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcge_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fcgt_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcgt_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fcgt_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_facge_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_facge_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_facge_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_facgt_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_facgt_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_facgt_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmax_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmax_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmax_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmin_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmin_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmin_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmaxnum_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxnum_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxnum_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fminnum_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminnum_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminnum_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_recps_nf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_recps_nf_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_rsqrts_nf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_rsqrts_nf_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmla_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmla_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmls_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmls_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_vfma_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_vfma_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_vfma_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_vfms_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_vfms_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_vfms_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_ah_vfms_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ah_vfms_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ah_vfms_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_ftsmul_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ftsmul_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_ftsmul_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmul_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmul_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmul_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmla_nf_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmla_nf_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmls_nf_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmls_nf_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_6(gvec_fmla_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fmla_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fmla_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_6(gvec_fmls_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fmls_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_fmls_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_uqadd_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqadd_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqadd_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqadd_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqadd_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqadd_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqadd_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqadd_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqsub_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqsub_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqsub_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uqsub_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqsub_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqsub_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqsub_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sqsub_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usqadd_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usqadd_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usqadd_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usqadd_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_suqadd_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_suqadd_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_suqadd_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_suqadd_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_fmlal_a32, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_fmlal_a64, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_2(frint32_s, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, fpst) -DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, fpst) -DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, fpst) - -DEF_HELPER_FLAGS_3(gvec_ceq0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_clt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_clt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cle0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cgt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cge0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_cge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_smulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_smulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_smulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_smulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_umulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_umulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_umulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_umulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_sshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_ushl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_ushl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_pmul_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_pmull_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(neon_pmull_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_ssra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ssra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ssra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ssra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_usra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_usra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_usra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_usra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_srshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_urshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_urshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_urshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_urshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_srsra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srsra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srsra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_srsra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_ursra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ursra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ursra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ursra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_sri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sri_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_sli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sli_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sli_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_sli_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_sabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_uabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_saba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_saba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_saba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_saba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_uaba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uaba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uaba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uaba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_mul_idx_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_mul_idx_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_mul_idx_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_mla_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_mla_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_mla_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_mls_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_mls_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_mls_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqdmulh_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqdmulh_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqrdmulh_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqrdmulh_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqdmulh_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqdmulh_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqrdmulh_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqrdmulh_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqrdmlah_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqrdmlah_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(neon_sqrdmlsh_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(neon_sqrdmlsh_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(sve2_sqdmulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqdmulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqdmulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqdmulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_6(sve2_fmlal_zzzw_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(sve2_fmlal_zzxw_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_4(gvec_xar_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_smmla_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_ummla_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_usmmla_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_6(gvec_bfdot, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, env, i32) -DEF_HELPER_FLAGS_6(gvec_bfdot_idx, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_6(gvec_bfmmla, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, env, i32) - -DEF_HELPER_FLAGS_6(gvec_bfmlal, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_6(gvec_bfmlal_idx, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_sclamp_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sclamp_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sclamp_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_sclamp_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_uclamp_b, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uclamp_h, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uclamp_s, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_5(gvec_uclamp_d, TCG_CALL_NO_RWG, - void, ptr, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_5(gvec_faddp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_faddp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_faddp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fmaxnump_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxnump_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fmaxnump_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_5(gvec_fminnump_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminnump_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) -DEF_HELPER_FLAGS_5(gvec_fminnump_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) - -DEF_HELPER_FLAGS_4(gvec_addp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_addp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_addp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_addp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_smaxp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_smaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_smaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_sminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_sminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_umaxp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_umaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_umaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_4(gvec_uminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(gvec_uminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) - -DEF_HELPER_FLAGS_3(gvec_urecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) -DEF_HELPER_FLAGS_3(gvec_ursqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +#include "tcg/helper.h" #ifdef TARGET_AARCH64 #include "tcg/helper-a64.h" diff --git a/target/arm/tcg/helper.h b/target/arm/tcg/helper.h new file mode 100644 index 0000000000..80db7c2c37 --- /dev/null +++ b/target/arm/tcg/helper.h @@ -0,0 +1,1153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +DEF_HELPER_FLAGS_1(sxtb16, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(uxtb16, TCG_CALL_NO_RWG_SE, i32, i32) + +DEF_HELPER_3(add_setq, i32, env, i32, i32) +DEF_HELPER_3(add_saturate, i32, env, i32, i32) +DEF_HELPER_3(sub_saturate, i32, env, i32, i32) +DEF_HELPER_3(add_usaturate, i32, env, i32, i32) +DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(sdiv, TCG_CALL_NO_RWG, s32, env, s32, s32) +DEF_HELPER_FLAGS_3(udiv, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_1(rbit, TCG_CALL_NO_RWG_SE, i32, i32) + +#define PAS_OP(pfx) \ + DEF_HELPER_3(pfx ## add8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub8, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## sub16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## add16, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## addsubx, i32, i32, i32, ptr) \ + DEF_HELPER_3(pfx ## subaddx, i32, i32, i32, ptr) + +PAS_OP(s) +PAS_OP(u) +#undef PAS_OP + +#define PAS_OP(pfx) \ + DEF_HELPER_2(pfx ## add8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub8, i32, i32, i32) \ + DEF_HELPER_2(pfx ## sub16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## add16, i32, i32, i32) \ + DEF_HELPER_2(pfx ## addsubx, i32, i32, i32) \ + DEF_HELPER_2(pfx ## subaddx, i32, i32, i32) +PAS_OP(q) +PAS_OP(sh) +PAS_OP(uq) +PAS_OP(uh) +#undef PAS_OP + +DEF_HELPER_3(ssat, i32, env, i32, i32) +DEF_HELPER_3(usat, i32, env, i32, i32) +DEF_HELPER_3(ssat16, i32, env, i32, i32) +DEF_HELPER_3(usat16, i32, env, i32, i32) + +DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32) + +DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE, + i32, i32, i32, i32) +DEF_HELPER_2(exception_internal, noreturn, env, i32) +DEF_HELPER_3(exception_with_syndrome, noreturn, env, i32, i32) +DEF_HELPER_4(exception_with_syndrome_el, noreturn, env, i32, i32, i32) +DEF_HELPER_2(exception_bkpt_insn, noreturn, env, i32) +DEF_HELPER_2(exception_swstep, noreturn, env, i32) +DEF_HELPER_2(exception_pc_alignment, noreturn, env, vaddr) +DEF_HELPER_1(setend, void, env) +DEF_HELPER_2(wfi, void, env, i32) +DEF_HELPER_1(wfe, void, env) +DEF_HELPER_2(wfit, void, env, i64) +DEF_HELPER_1(yield, void, env) +DEF_HELPER_1(pre_hvc, void, env) +DEF_HELPER_2(pre_smc, void, env, i32) +DEF_HELPER_1(vesb, void, env) + +DEF_HELPER_3(cpsr_write, void, env, i32, i32) +DEF_HELPER_2(cpsr_write_eret, void, env, i32) +DEF_HELPER_1(cpsr_read, i32, env) + +DEF_HELPER_3(v7m_msr, void, env, i32, i32) +DEF_HELPER_2(v7m_mrs, i32, env, i32) + +DEF_HELPER_2(v7m_bxns, void, env, i32) +DEF_HELPER_2(v7m_blxns, void, env, i32) + +DEF_HELPER_3(v7m_tt, i32, env, i32, i32) + +DEF_HELPER_1(v7m_preserve_fp_state, void, env) + +DEF_HELPER_2(v7m_vlstm, void, env, i32) +DEF_HELPER_2(v7m_vlldm, void, env, i32) + +DEF_HELPER_2(v8m_stackcheck, void, env, i32) + +DEF_HELPER_FLAGS_2(check_bxj_trap, TCG_CALL_NO_WG, void, env, i32) + +DEF_HELPER_4(access_check_cp_reg, cptr, env, i32, i32, i32) +DEF_HELPER_FLAGS_2(lookup_cp_reg, TCG_CALL_NO_RWG_SE, cptr, env, i32) +DEF_HELPER_FLAGS_2(tidcp_el0, TCG_CALL_NO_WG, void, env, i32) +DEF_HELPER_FLAGS_2(tidcp_el1, TCG_CALL_NO_WG, void, env, i32) +DEF_HELPER_3(set_cp_reg, void, env, cptr, i32) +DEF_HELPER_2(get_cp_reg, i32, env, cptr) +DEF_HELPER_3(set_cp_reg64, void, env, cptr, i64) +DEF_HELPER_2(get_cp_reg64, i64, env, cptr) + +DEF_HELPER_2(get_r13_banked, i32, env, i32) +DEF_HELPER_3(set_r13_banked, void, env, i32, i32) + +DEF_HELPER_3(mrs_banked, i32, env, i32, i32) +DEF_HELPER_4(msr_banked, void, env, i32, i32, i32) + +DEF_HELPER_2(get_user_reg, i32, env, i32) +DEF_HELPER_3(set_user_reg, void, env, i32, i32) + +DEF_HELPER_FLAGS_1(rebuild_hflags_m32_newel, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_2(rebuild_hflags_m32, TCG_CALL_NO_RWG, void, env, int) +DEF_HELPER_FLAGS_1(rebuild_hflags_a32_newel, TCG_CALL_NO_RWG, void, env) +DEF_HELPER_FLAGS_2(rebuild_hflags_a32, TCG_CALL_NO_RWG, void, env, int) +DEF_HELPER_FLAGS_2(rebuild_hflags_a64, TCG_CALL_NO_RWG, void, env, int) + +DEF_HELPER_FLAGS_5(probe_access, TCG_CALL_NO_WG, void, env, vaddr, i32, i32, i32) + +DEF_HELPER_1(vfp_get_fpscr, i32, env) +DEF_HELPER_2(vfp_set_fpscr, void, env, i32) + +DEF_HELPER_3(vfp_addh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_adds, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_addd, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_subh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_subs, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_subd, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_mulh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_muls, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_muld, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_divh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_divs, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_divd, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_maxh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_maxs, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_maxd, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_minh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_mins, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_mind, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_maxnumh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_maxnums, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_maxnumd, f64, f64, f64, fpst) +DEF_HELPER_3(vfp_minnumh, f16, f16, f16, fpst) +DEF_HELPER_3(vfp_minnums, f32, f32, f32, fpst) +DEF_HELPER_3(vfp_minnumd, f64, f64, f64, fpst) +DEF_HELPER_2(vfp_sqrth, f16, f16, fpst) +DEF_HELPER_2(vfp_sqrts, f32, f32, fpst) +DEF_HELPER_2(vfp_sqrtd, f64, f64, fpst) +DEF_HELPER_3(vfp_cmph, void, f16, f16, env) +DEF_HELPER_3(vfp_cmps, void, f32, f32, env) +DEF_HELPER_3(vfp_cmpd, void, f64, f64, env) +DEF_HELPER_3(vfp_cmpeh, void, f16, f16, env) +DEF_HELPER_3(vfp_cmpes, void, f32, f32, env) +DEF_HELPER_3(vfp_cmped, void, f64, f64, env) + +DEF_HELPER_2(vfp_fcvtds, f64, f32, fpst) +DEF_HELPER_2(vfp_fcvtsd, f32, f64, fpst) +DEF_HELPER_FLAGS_2(bfcvt, TCG_CALL_NO_RWG, i32, f32, fpst) +DEF_HELPER_FLAGS_2(bfcvt_pair, TCG_CALL_NO_RWG, i32, i64, fpst) + +DEF_HELPER_2(vfp_uitoh, f16, i32, fpst) +DEF_HELPER_2(vfp_uitos, f32, i32, fpst) +DEF_HELPER_2(vfp_uitod, f64, i32, fpst) +DEF_HELPER_2(vfp_sitoh, f16, i32, fpst) +DEF_HELPER_2(vfp_sitos, f32, i32, fpst) +DEF_HELPER_2(vfp_sitod, f64, i32, fpst) + +DEF_HELPER_2(vfp_touih, i32, f16, fpst) +DEF_HELPER_2(vfp_touis, i32, f32, fpst) +DEF_HELPER_2(vfp_touid, i32, f64, fpst) +DEF_HELPER_2(vfp_touizh, i32, f16, fpst) +DEF_HELPER_2(vfp_touizs, i32, f32, fpst) +DEF_HELPER_2(vfp_touizd, i32, f64, fpst) +DEF_HELPER_2(vfp_tosih, s32, f16, fpst) +DEF_HELPER_2(vfp_tosis, s32, f32, fpst) +DEF_HELPER_2(vfp_tosid, s32, f64, fpst) +DEF_HELPER_2(vfp_tosizh, s32, f16, fpst) +DEF_HELPER_2(vfp_tosizs, s32, f32, fpst) +DEF_HELPER_2(vfp_tosizd, s32, f64, fpst) + +DEF_HELPER_3(vfp_toshh_round_to_zero, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toslh_round_to_zero, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_touhh_round_to_zero, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toulh_round_to_zero, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toshs_round_to_zero, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_tosls_round_to_zero, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_touhs_round_to_zero, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_touls_round_to_zero, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_toshd_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tosld_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tosqd_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_touhd_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tould_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_touqd_round_to_zero, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_touhh, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toshh, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toulh, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_toslh, i32, f16, i32, fpst) +DEF_HELPER_3(vfp_touqh, i64, f16, i32, fpst) +DEF_HELPER_3(vfp_tosqh, i64, f16, i32, fpst) +DEF_HELPER_3(vfp_toshs, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_tosls, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_tosqs, i64, f32, i32, fpst) +DEF_HELPER_3(vfp_touhs, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_touls, i32, f32, i32, fpst) +DEF_HELPER_3(vfp_touqs, i64, f32, i32, fpst) +DEF_HELPER_3(vfp_toshd, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tosld, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tosqd, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_touhd, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_tould, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_touqd, i64, f64, i32, fpst) +DEF_HELPER_3(vfp_shtos, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_sltos, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_sqtos, f32, i64, i32, fpst) +DEF_HELPER_3(vfp_uhtos, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_ultos, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_uqtos, f32, i64, i32, fpst) +DEF_HELPER_3(vfp_shtod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_sltod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_sqtod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_uhtod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_ultod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_uqtod, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_shtoh, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_uhtoh, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_sltoh, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_ultoh, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_sqtoh, f16, i64, i32, fpst) +DEF_HELPER_3(vfp_uqtoh, f16, i64, i32, fpst) + +DEF_HELPER_3(vfp_shtos_round_to_nearest, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_sltos_round_to_nearest, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_uhtos_round_to_nearest, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_ultos_round_to_nearest, f32, i32, i32, fpst) +DEF_HELPER_3(vfp_shtod_round_to_nearest, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_sltod_round_to_nearest, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_uhtod_round_to_nearest, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_ultod_round_to_nearest, f64, i64, i32, fpst) +DEF_HELPER_3(vfp_shtoh_round_to_nearest, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_uhtoh_round_to_nearest, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_sltoh_round_to_nearest, f16, i32, i32, fpst) +DEF_HELPER_3(vfp_ultoh_round_to_nearest, f16, i32, i32, fpst) + +DEF_HELPER_FLAGS_2(set_rmode, TCG_CALL_NO_RWG, i32, i32, fpst) + +DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f32, TCG_CALL_NO_RWG, f32, f16, fpst, i32) +DEF_HELPER_FLAGS_3(vfp_fcvt_f32_to_f16, TCG_CALL_NO_RWG, f16, f32, fpst, i32) +DEF_HELPER_FLAGS_3(vfp_fcvt_f16_to_f64, TCG_CALL_NO_RWG, f64, f16, fpst, i32) +DEF_HELPER_FLAGS_3(vfp_fcvt_f64_to_f16, TCG_CALL_NO_RWG, f16, f64, fpst, i32) + +DEF_HELPER_4(vfp_muladdd, f64, f64, f64, f64, fpst) +DEF_HELPER_4(vfp_muladds, f32, f32, f32, f32, fpst) +DEF_HELPER_4(vfp_muladdh, f16, f16, f16, f16, fpst) + +DEF_HELPER_FLAGS_2(recpe_f16, TCG_CALL_NO_RWG, f16, f16, fpst) +DEF_HELPER_FLAGS_2(recpe_f32, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(recpe_rpres_f32, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(recpe_f64, TCG_CALL_NO_RWG, f64, f64, fpst) +DEF_HELPER_FLAGS_2(rsqrte_f16, TCG_CALL_NO_RWG, f16, f16, fpst) +DEF_HELPER_FLAGS_2(rsqrte_f32, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(rsqrte_rpres_f32, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(rsqrte_f64, TCG_CALL_NO_RWG, f64, f64, fpst) +DEF_HELPER_FLAGS_1(recpe_u32, TCG_CALL_NO_RWG, i32, i32) +DEF_HELPER_FLAGS_1(rsqrte_u32, TCG_CALL_NO_RWG, i32, i32) +DEF_HELPER_FLAGS_4(neon_tbl, TCG_CALL_NO_RWG, i64, env, i32, i64, i64) + +DEF_HELPER_3(shl_cc, i32, env, i32, i32) +DEF_HELPER_3(shr_cc, i32, env, i32, i32) +DEF_HELPER_3(sar_cc, i32, env, i32, i32) +DEF_HELPER_3(ror_cc, i32, env, i32, i32) + +DEF_HELPER_FLAGS_2(rinth_exact, TCG_CALL_NO_RWG, f16, f16, fpst) +DEF_HELPER_FLAGS_2(rints_exact, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(rintd_exact, TCG_CALL_NO_RWG, f64, f64, fpst) +DEF_HELPER_FLAGS_2(rinth, TCG_CALL_NO_RWG, f16, f16, fpst) +DEF_HELPER_FLAGS_2(rints, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(rintd, TCG_CALL_NO_RWG, f64, f64, fpst) + +DEF_HELPER_FLAGS_2(vjcvt, TCG_CALL_NO_RWG, i32, f64, env) +DEF_HELPER_FLAGS_2(fjcvtzs, TCG_CALL_NO_RWG, i64, f64, fpst) + +DEF_HELPER_FLAGS_3(check_hcr_el2_trap, TCG_CALL_NO_WG, void, env, i32, i32) + +/* neon_helper.c */ +DEF_HELPER_2(neon_pmin_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmin_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmin_s16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s8, i32, i32, i32) +DEF_HELPER_2(neon_pmax_u16, i32, i32, i32) +DEF_HELPER_2(neon_pmax_s16, i32, i32, i32) + +DEF_HELPER_2(neon_shl_u16, i32, i32, i32) +DEF_HELPER_2(neon_shl_s16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s8, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s16, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_s32, i32, i32, i32) +DEF_HELPER_2(neon_rshl_u64, i64, i64, i64) +DEF_HELPER_2(neon_rshl_s64, i64, i64, i64) +DEF_HELPER_3(neon_qshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qshl_s64, i64, env, i64, i64) +DEF_HELPER_3(neon_qshlu_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qshlu_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qshlu_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qshlu_s64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_u8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s8, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrshl_u64, i64, env, i64, i64) +DEF_HELPER_3(neon_qrshl_s64, i64, env, i64, i64) +DEF_HELPER_FLAGS_5(neon_sqshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_sqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqrshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqrshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqrshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(neon_uqrshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_uqshli_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(neon_sqshlui_d, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(gvec_srshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_srshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_srshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_srshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_urshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_urshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_urshl_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_urshl_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_2(neon_add_u8, i32, i32, i32) +DEF_HELPER_2(neon_add_u16, i32, i32, i32) +DEF_HELPER_2(neon_sub_u8, i32, i32, i32) +DEF_HELPER_2(neon_sub_u16, i32, i32, i32) +DEF_HELPER_2(neon_mul_u8, i32, i32, i32) +DEF_HELPER_2(neon_mul_u16, i32, i32, i32) + +DEF_HELPER_2(neon_tst_u8, i32, i32, i32) +DEF_HELPER_2(neon_tst_u16, i32, i32, i32) +DEF_HELPER_2(neon_tst_u32, i32, i32, i32) + +DEF_HELPER_1(neon_clz_u8, i32, i32) +DEF_HELPER_1(neon_clz_u16, i32, i32) +DEF_HELPER_1(neon_cls_s8, i32, i32) +DEF_HELPER_1(neon_cls_s16, i32, i32) +DEF_HELPER_1(neon_cls_s32, i32, i32) +DEF_HELPER_FLAGS_3(gvec_cnt_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_rbit_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_3(neon_qdmulh_s16, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s16, i32, env, i32, i32) +DEF_HELPER_4(neon_qrdmlah_s16, i32, env, i32, i32, i32) +DEF_HELPER_4(neon_qrdmlsh_s16, i32, env, i32, i32, i32) +DEF_HELPER_3(neon_qdmulh_s32, i32, env, i32, i32) +DEF_HELPER_3(neon_qrdmulh_s32, i32, env, i32, i32) +DEF_HELPER_4(neon_qrdmlah_s32, i32, env, s32, s32, s32) +DEF_HELPER_4(neon_qrdmlsh_s32, i32, env, s32, s32, s32) + +DEF_HELPER_1(neon_narrow_u8, i64, i64) +DEF_HELPER_1(neon_narrow_u16, i64, i64) +DEF_HELPER_2(neon_unarrow_sat8, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u8, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s8, i64, env, i64) +DEF_HELPER_2(neon_unarrow_sat16, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u16, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s16, i64, env, i64) +DEF_HELPER_2(neon_unarrow_sat32, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_u32, i64, env, i64) +DEF_HELPER_2(neon_narrow_sat_s32, i64, env, i64) +DEF_HELPER_1(neon_narrow_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_high_u16, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u8, i32, i64) +DEF_HELPER_1(neon_narrow_round_high_u16, i32, i64) +DEF_HELPER_1(neon_widen_u8, i64, i32) +DEF_HELPER_1(neon_widen_s8, i64, i32) +DEF_HELPER_1(neon_widen_u16, i64, i32) +DEF_HELPER_1(neon_widen_s16, i64, i32) + +DEF_HELPER_FLAGS_1(neon_addlp_s8, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_FLAGS_1(neon_addlp_s16, TCG_CALL_NO_RWG_SE, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s32, i64, env, i64, i64) +DEF_HELPER_3(neon_addl_saturate_s64, i64, env, i64, i64) +DEF_HELPER_2(neon_abdl_u16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s16, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s32, i64, i32, i32) +DEF_HELPER_2(neon_abdl_u64, i64, i32, i32) +DEF_HELPER_2(neon_abdl_s64, i64, i32, i32) +DEF_HELPER_2(neon_mull_u8, i64, i32, i32) +DEF_HELPER_2(neon_mull_s8, i64, i32, i32) +DEF_HELPER_2(neon_mull_u16, i64, i32, i32) +DEF_HELPER_2(neon_mull_s16, i64, i32, i32) + +DEF_HELPER_1(neon_negl_u16, i64, i64) +DEF_HELPER_1(neon_negl_u32, i64, i64) + +DEF_HELPER_FLAGS_2(neon_qabs_s8, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qabs_s16, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qabs_s32, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qabs_s64, TCG_CALL_NO_RWG, i64, env, i64) +DEF_HELPER_FLAGS_2(neon_qneg_s8, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qneg_s16, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qneg_s32, TCG_CALL_NO_RWG, i32, env, i32) +DEF_HELPER_FLAGS_2(neon_qneg_s64, TCG_CALL_NO_RWG, i64, env, i64) + +DEF_HELPER_3(neon_ceq_f32, i32, i32, i32, fpst) +DEF_HELPER_3(neon_cge_f32, i32, i32, i32, fpst) +DEF_HELPER_3(neon_cgt_f32, i32, i32, i32, fpst) +DEF_HELPER_3(neon_acge_f32, i32, i32, i32, fpst) +DEF_HELPER_3(neon_acgt_f32, i32, i32, i32, fpst) +DEF_HELPER_3(neon_acge_f64, i64, i64, i64, fpst) +DEF_HELPER_3(neon_acgt_f64, i64, i64, i64, fpst) + +/* iwmmxt_helper.c */ +DEF_HELPER_2(iwmmxt_maddsq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_madduq, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadb, i64, i64, i64) +DEF_HELPER_2(iwmmxt_sadw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulslw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mulshw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_mululw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_muluhw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macsw, i64, i64, i64) +DEF_HELPER_2(iwmmxt_macuw, i64, i64, i64) +DEF_HELPER_1(iwmmxt_setpsr_nz, i32, i64) + +#define DEF_IWMMXT_HELPER_SIZE_ENV(name) \ +DEF_HELPER_3(iwmmxt_##name##b, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##w, i64, env, i64, i64) \ +DEF_HELPER_3(iwmmxt_##name##l, i64, env, i64, i64) \ + +DEF_IWMMXT_HELPER_SIZE_ENV(unpackl) +DEF_IWMMXT_HELPER_SIZE_ENV(unpackh) + +DEF_HELPER_2(iwmmxt_unpacklub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackluw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhub, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhuw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhul, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpacklsl, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsb, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsw, i64, env, i64) +DEF_HELPER_2(iwmmxt_unpackhsl, i64, env, i64) + +DEF_IWMMXT_HELPER_SIZE_ENV(cmpeq) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgtu) +DEF_IWMMXT_HELPER_SIZE_ENV(cmpgts) + +DEF_IWMMXT_HELPER_SIZE_ENV(mins) +DEF_IWMMXT_HELPER_SIZE_ENV(minu) +DEF_IWMMXT_HELPER_SIZE_ENV(maxs) +DEF_IWMMXT_HELPER_SIZE_ENV(maxu) + +DEF_IWMMXT_HELPER_SIZE_ENV(subn) +DEF_IWMMXT_HELPER_SIZE_ENV(addn) +DEF_IWMMXT_HELPER_SIZE_ENV(subu) +DEF_IWMMXT_HELPER_SIZE_ENV(addu) +DEF_IWMMXT_HELPER_SIZE_ENV(subs) +DEF_IWMMXT_HELPER_SIZE_ENV(adds) + +DEF_HELPER_3(iwmmxt_avgb0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgb1, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw0, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_avgw1, i64, env, i64, i64) + +DEF_HELPER_3(iwmmxt_align, i64, i64, i64, i32) +DEF_HELPER_4(iwmmxt_insr, i64, i64, i32, i32, i32) + +DEF_HELPER_1(iwmmxt_bcstb, i64, i32) +DEF_HELPER_1(iwmmxt_bcstw, i64, i32) +DEF_HELPER_1(iwmmxt_bcstl, i64, i32) + +DEF_HELPER_1(iwmmxt_addcb, i64, i64) +DEF_HELPER_1(iwmmxt_addcw, i64, i64) +DEF_HELPER_1(iwmmxt_addcl, i64, i64) + +DEF_HELPER_1(iwmmxt_msbb, i32, i64) +DEF_HELPER_1(iwmmxt_msbw, i32, i64) +DEF_HELPER_1(iwmmxt_msbl, i32, i64) + +DEF_HELPER_3(iwmmxt_srlw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_srlq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_slll, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sllq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sral, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_sraq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorw, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorl, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_rorq, i64, env, i64, i32) +DEF_HELPER_3(iwmmxt_shufh, i64, env, i64, i32) + +DEF_HELPER_3(iwmmxt_packuw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packul, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packuq, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsw, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsl, i64, env, i64, i64) +DEF_HELPER_3(iwmmxt_packsq, i64, env, i64, i64) + +DEF_HELPER_3(iwmmxt_muladdsl, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdsw, i64, i64, i32, i32) +DEF_HELPER_3(iwmmxt_muladdswl, i64, i64, i32, i32) + +DEF_HELPER_FLAGS_2(neon_unzip8, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_unzip16, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qunzip8, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qunzip16, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qunzip32, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_zip8, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_zip16, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qzip8, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qzip16, TCG_CALL_NO_RWG, void, ptr, ptr) +DEF_HELPER_FLAGS_2(neon_qzip32, TCG_CALL_NO_RWG, void, ptr, ptr) + +DEF_HELPER_FLAGS_4(crypto_aese, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_aesd, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_aesmc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_aesimc, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_sha1su0, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1c, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1p, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha1m, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha1h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha1su1, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_sha256h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha256h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha256su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha256su1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_sha512h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha512h2, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(crypto_sha512su0, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sha512su1, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_sm3tt1a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt1b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt2a, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3tt2b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3partw1, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm3partw2, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_sm4e, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(crypto_sm4ekey, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(crypto_rax1, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) +DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32) + +DEF_HELPER_FLAGS_5(gvec_qrdmlah_s16, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_qrdmlsh_s16, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_qrdmlah_s32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_qrdmlsh_s32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(sve2_sqrdmlah_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlah_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlah_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlah_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(sve2_sqrdmlsh_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_sdot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_udot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sdot_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_udot_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usdot_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_sdot_idx_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_udot_idx_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sdot_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_udot_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sudot_idx_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usdot_idx_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_fcaddh, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcadds, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcaddd, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(gvec_fcmlah, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fcmlah_idx, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fcmlas, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fcmlas_idx, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fcmlad, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_sstoh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_sitos, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_ustoh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_uitos, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_tosszh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_tosizs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_touszh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_touizs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vcvt_sf, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_uf, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_fu, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vcvt_sh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_uh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_hu, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vcvt_sd, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_ud, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_ds, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rz_du, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sd, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ud, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_ss, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_us, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_sh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vcvt_rm_uh, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vrint_rm_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vrint_rm_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_vrintx_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_vrintx_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_frecpe_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frecpe_rpres_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frecpe_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_frsqrte_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frsqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frsqrte_rpres_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_frsqrte_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_fcgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcgt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcgt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_fcge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcge0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcge0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_fceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fceq0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fceq0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_fcle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcle0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fcle0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_fclt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fclt0_s, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(gvec_fclt0_d, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fadd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fadd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fadd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fsub_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fsub_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fsub_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmul_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmul_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmul_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_ah_fabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ah_fabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ah_fabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fceq_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fceq_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fceq_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fcge_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcge_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcge_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fcgt_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcgt_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fcgt_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_facge_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_facge_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_facge_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_facgt_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_facgt_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_facgt_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmax_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmax_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmax_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmin_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmin_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmin_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmaxnum_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxnum_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxnum_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fminnum_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminnum_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminnum_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_recps_nf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_recps_nf_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_rsqrts_nf_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_rsqrts_nf_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmla_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmla_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmls_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmls_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_vfma_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_vfma_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_vfma_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_vfms_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_vfms_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_vfms_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_ah_vfms_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ah_vfms_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ah_vfms_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_ftsmul_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ftsmul_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_ftsmul_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmul_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmul_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmul_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmla_nf_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmla_nf_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmls_nf_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmls_nf_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(gvec_fmla_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fmla_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fmla_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(gvec_fmls_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fmls_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_fmls_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_ah_fmls_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_uqadd_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqadd_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqadd_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqadd_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqadd_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqadd_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqadd_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqadd_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqsub_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqsub_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqsub_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uqsub_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqsub_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqsub_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqsub_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sqsub_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usqadd_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usqadd_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usqadd_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usqadd_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_suqadd_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_suqadd_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_suqadd_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_suqadd_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_fmlal_a32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_a64, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a32, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmlal_idx_a64, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_2(frint32_s, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(frint64_s, TCG_CALL_NO_RWG, f32, f32, fpst) +DEF_HELPER_FLAGS_2(frint32_d, TCG_CALL_NO_RWG, f64, f64, fpst) +DEF_HELPER_FLAGS_2(frint64_d, TCG_CALL_NO_RWG, f64, f64, fpst) + +DEF_HELPER_FLAGS_3(gvec_ceq0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ceq0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_clt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_clt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cle0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cle0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cgt0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cgt0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cge0_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_cge0_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_smulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_smulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_smulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_smulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_umulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_umulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_umulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_umulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_sshl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sshl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_ushl_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_ushl_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_pmul_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_pmull_q, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(neon_pmull_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_ssra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ssra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_usra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_usra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_srshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_urshr_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_urshr_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_srsra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_srsra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_ursra_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursra_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_sri_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sri_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_sli_b, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_h, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_sli_d, TCG_CALL_NO_RWG, void, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_sabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uabd_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uabd_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_saba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_saba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uaba_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uaba_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_mul_idx_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_mul_idx_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_mul_idx_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_mla_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_mla_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_mla_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_mls_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_mls_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_mls_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqdmulh_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqdmulh_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqrdmulh_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqrdmulh_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqdmulh_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqdmulh_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqrdmulh_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqrdmulh_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqrdmlah_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqrdmlah_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(neon_sqrdmlsh_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(neon_sqrdmlsh_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sve2_sqdmulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqdmulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqdmulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqdmulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqdmulh_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(sve2_sqrdmulh_idx_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_6(sve2_fmlal_zzzw_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(sve2_fmlal_zzxw_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(gvec_xar_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_smmla_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_ummla_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_usmmla_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_6(gvec_bfdot, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_6(gvec_bfdot_idx, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_6(gvec_bfmmla, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_6(gvec_bfmlal, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_6(gvec_bfmlal_idx, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_sclamp_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_sclamp_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_uclamp_b, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_h, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_s, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_5(gvec_uclamp_d, TCG_CALL_NO_RWG, + void, ptr, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_5(gvec_faddp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_faddp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_faddp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fmaxnump_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxnump_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fmaxnump_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_5(gvec_fminnump_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminnump_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_5(gvec_fminnump_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, fpst, i32) + +DEF_HELPER_FLAGS_4(gvec_addp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_addp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_addp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_addp_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_smaxp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_smaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_smaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_sminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_sminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_umaxp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_umaxp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_umaxp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_4(gvec_uminp_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uminp_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_uminp_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) + +DEF_HELPER_FLAGS_3(gvec_urecpe_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) +DEF_HELPER_FLAGS_3(gvec_ursqrte_s, TCG_CALL_NO_RWG, void, ptr, ptr, i32) From f9fba6ddfc854f427e00d62c1e4888ce9a1a7c34 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:30 -0700 Subject: [PATCH 0911/2760] target/arm/debug_helper: only include common helpers Avoid pulling helper.h which contains TARGET_AARCH64. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-17-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/debug_helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index de7999f6a9..cad0a5db70 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -11,10 +11,12 @@ #include "internals.h" #include "cpu-features.h" #include "cpregs.h" -#include "exec/helper-proto.h" #include "exec/watchpoint.h" #include "system/tcg.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + #ifdef CONFIG_TCG /* Return the Exception Level targeted by debug exceptions. */ static int arm_debug_target_el(CPUARMState *env) From 61dcfb2ef255d17a23262170457568af52fb0516 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:31 -0700 Subject: [PATCH 0912/2760] target/arm/debug_helper: remove target_ulong MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-18-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/debug_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/debug_helper.c b/target/arm/debug_helper.c index cad0a5db70..69fb1d0d9f 100644 --- a/target/arm/debug_helper.c +++ b/target/arm/debug_helper.c @@ -380,7 +380,7 @@ bool arm_debug_check_breakpoint(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; - target_ulong pc; + vaddr pc; int n; /* From 64961a801500035b9a039c474b6225e0cfd3f44e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:32 -0700 Subject: [PATCH 0913/2760] target/arm/debug_helper: compile file twice (user, system) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-19-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index de214fe5d5..48a6bf5935 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -1,7 +1,6 @@ arm_ss = ss.source_set() arm_common_ss = ss.source_set() arm_ss.add(files( - 'debug_helper.c', 'gdbstub.c', 'helper.c', 'vfp_fpscr.c', @@ -29,11 +28,18 @@ arm_system_ss.add(files( arm_user_ss = ss.source_set() arm_user_ss.add(files('cpu.c')) arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files( - 'cpu32-stubs.c')) + 'cpu32-stubs.c', +)) +arm_user_ss.add(files( + 'debug_helper.c', +)) arm_common_system_ss.add(files('cpu.c'), capstone) arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) +arm_common_system_ss.add(files( + 'debug_helper.c', +)) subdir('hvf') From 2fdfdeb2f2a46ee5b96918dfd18cdeedf3bba013 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:33 -0700 Subject: [PATCH 0914/2760] target/arm/helper: restrict include to common helpers Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-20-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 4a2d1ecbfe..3795dccd16 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -12,7 +12,6 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "exec/helper-proto.h" #include "exec/page-protection.h" #include "exec/mmap-lock.h" #include "qemu/main-loop.h" @@ -35,6 +34,9 @@ #include "cpregs.h" #include "target/arm/gtimer.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ static void switch_mode(CPUARMState *env, int mode); From d626a26dd1ce0ede8e5e5a1c73f089f5e711f9e8 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:34 -0700 Subject: [PATCH 0915/2760] target/arm/helper: replace target_ulong by vaddr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-21-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 3795dccd16..d2607107eb 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -10621,7 +10621,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; unsigned int new_el = env->exception.target_el; - target_ulong addr = env->cp15.vbar_el[new_el]; + vaddr addr = env->cp15.vbar_el[new_el]; unsigned int new_mode = aarch64_pstate_mode(new_el, true); unsigned int old_mode; unsigned int cur_el = arm_current_el(env); From 8eb048210e150d9f4fb7225f598de605a3633f67 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:35 -0700 Subject: [PATCH 0916/2760] target/arm/helper: expose aarch64 cpu registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit associated define_arm_cp_regs are guarded by "cpu_isar_feature(aa64_*)", so it's safe to expose that code for arm target (32 bit). Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-22-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index d2607107eb..92a975bbf7 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -6590,7 +6590,6 @@ static const ARMCPRegInfo zcr_reginfo[] = { .writefn = zcr_write, .raw_writefn = raw_write }, }; -#ifdef TARGET_AARCH64 static CPAccessResult access_tpidr2(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -6824,7 +6823,6 @@ static const ARMCPRegInfo nmi_reginfo[] = { .writefn = aa64_allint_write, .readfn = aa64_allint_read, .resetfn = arm_cp_reset_ignore }, }; -#endif /* TARGET_AARCH64 */ static void define_pmu_regs(ARMCPU *cpu) { @@ -7016,7 +7014,6 @@ static const ARMCPRegInfo lor_reginfo[] = { .type = ARM_CP_CONST, .resetvalue = 0 }, }; -#ifdef TARGET_AARCH64 static CPAccessResult access_pauth(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -7509,8 +7506,6 @@ static const ARMCPRegInfo nv2_reginfo[] = { .fieldoffset = offsetof(CPUARMState, cp15.vncr_el2) }, }; -#endif /* TARGET_AARCH64 */ - static CPAccessResult access_predinv(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) { @@ -8951,7 +8946,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_one_arm_cp_reg(cpu, &hcrx_el2_reginfo); } -#ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_sme, cpu)) { define_arm_cp_regs(cpu, sme_reginfo); } @@ -9012,7 +9006,6 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (cpu_isar_feature(aa64_nmi, cpu)) { define_arm_cp_regs(cpu, nmi_reginfo); } -#endif if (cpu_isar_feature(any_predinv, cpu)) { define_arm_cp_regs(cpu, predinv_reginfo); From 15e9ed7d7c376175285fe7694ef99b0a4c90f5b2 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:36 -0700 Subject: [PATCH 0917/2760] target/arm/helper: remove remaining TARGET_AARCH64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They were hiding aarch64_sve_narrow_vq and aarch64_sve_change_el, which we can expose safely. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-23-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index 92a975bbf7..aae8554e8f 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -29,6 +29,7 @@ #include "qemu/guest-random.h" #ifdef CONFIG_TCG #include "accel/tcg/probe.h" +#include "accel/tcg/getpc.h" #include "semihosting/common-semi.h" #endif #include "cpregs.h" @@ -6565,9 +6566,7 @@ static void zcr_write(CPUARMState *env, const ARMCPRegInfo *ri, */ new_len = sve_vqm1_for_el(env, cur_el); if (new_len < old_len) { -#ifdef TARGET_AARCH64 aarch64_sve_narrow_vq(env, new_len + 1); -#endif } } @@ -10625,9 +10624,7 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs) * Note that new_el can never be 0. If cur_el is 0, then * el0_a64 is is_a64(), else el0_a64 is ignored. */ -#ifdef TARGET_AARCH64 aarch64_sve_change_el(env, cur_el, new_el, is_a64(env)); -#endif } if (cur_el < new_el) { @@ -11418,7 +11415,6 @@ ARMMMUIdx arm_mmu_idx(CPUARMState *env) return arm_mmu_idx_el(env, arm_current_el(env)); } -#ifdef TARGET_AARCH64 /* * The manual says that when SVE is enabled and VQ is widened the * implementation is allowed to zero the previously inaccessible @@ -11530,12 +11526,9 @@ void aarch64_sve_change_el(CPUARMState *env, int old_el, /* When changing vector length, clear inaccessible state. */ if (new_len < old_len) { -#ifdef TARGET_AARCH64 aarch64_sve_narrow_vq(env, new_len + 1); -#endif } } -#endif #ifndef CONFIG_USER_ONLY ARMSecuritySpace arm_security_space(CPUARMState *env) From 9cf590f214c77faa98f9d315519de0961187b8ff Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:37 -0700 Subject: [PATCH 0918/2760] target/arm/helper: compile file twice (user, system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-24-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 48a6bf5935..c8c80c3f96 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -2,7 +2,6 @@ arm_ss = ss.source_set() arm_common_ss = ss.source_set() arm_ss.add(files( 'gdbstub.c', - 'helper.c', 'vfp_fpscr.c', )) arm_ss.add(zlib) @@ -32,6 +31,7 @@ arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files( )) arm_user_ss.add(files( 'debug_helper.c', + 'helper.c', )) arm_common_system_ss.add(files('cpu.c'), capstone) @@ -39,6 +39,7 @@ arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) arm_common_system_ss.add(files( 'debug_helper.c', + 'helper.c', )) subdir('hvf') From d4952244a9ce67a4fc85962ea50e8be0ec140e1e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:38 -0700 Subject: [PATCH 0919/2760] target/arm/vfp_fpscr: compile file twice (user, system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-25-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index c8c80c3f96..06d479570e 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -2,7 +2,6 @@ arm_ss = ss.source_set() arm_common_ss = ss.source_set() arm_ss.add(files( 'gdbstub.c', - 'vfp_fpscr.c', )) arm_ss.add(zlib) @@ -32,6 +31,7 @@ arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files( arm_user_ss.add(files( 'debug_helper.c', 'helper.c', + 'vfp_fpscr.c', )) arm_common_system_ss.add(files('cpu.c'), capstone) @@ -40,6 +40,7 @@ arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( arm_common_system_ss.add(files( 'debug_helper.c', 'helper.c', + 'vfp_fpscr.c', )) subdir('hvf') From 89356e123bfe09459bf0c596d6dce660971f6541 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:39 -0700 Subject: [PATCH 0920/2760] target/arm/arch_dump: remove TARGET_AARCH64 conditionals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Associated code is protected by cpu_isar_feature(aa64*) Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-26-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/arch_dump.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/arm/arch_dump.c b/target/arm/arch_dump.c index c40df4e7fd..1dd79849c1 100644 --- a/target/arm/arch_dump.c +++ b/target/arm/arch_dump.c @@ -143,7 +143,6 @@ static int aarch64_write_elf64_prfpreg(WriteCoreDumpFunction f, return 0; } -#ifdef TARGET_AARCH64 static off_t sve_zreg_offset(uint32_t vq, int n) { off_t off = sizeof(struct aarch64_user_sve_header); @@ -231,7 +230,6 @@ static int aarch64_write_elf64_sve(WriteCoreDumpFunction f, return 0; } -#endif int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, DumpState *s) @@ -273,11 +271,9 @@ int arm_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, return ret; } -#ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_sve, cpu)) { ret = aarch64_write_elf64_sve(f, env, cpuid, s); } -#endif return ret; } @@ -451,11 +447,9 @@ ssize_t cpu_get_note_size(int class, int machine, int nr_cpus) if (class == ELFCLASS64) { note_size = AARCH64_PRSTATUS_NOTE_SIZE; note_size += AARCH64_PRFPREG_NOTE_SIZE; -#ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_sve, cpu)) { note_size += AARCH64_SVE_NOTE_SIZE(&cpu->env); } -#endif } else { note_size = ARM_PRSTATUS_NOTE_SIZE; if (cpu_isar_feature(aa32_vfp_simd, cpu)) { From 55bb7a9ad097419b5406ed1e816339ed652f3017 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:40 -0700 Subject: [PATCH 0921/2760] target/arm/arch_dump: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-27-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 06d479570e..95a2b077dd 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -15,7 +15,6 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( arm_system_ss = ss.source_set() arm_common_system_ss = ss.source_set() arm_system_ss.add(files( - 'arch_dump.c', 'arm-powerctl.c', 'arm-qmp-cmds.c', 'cortex-regs.c', @@ -38,6 +37,7 @@ arm_common_system_ss.add(files('cpu.c'), capstone) arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) arm_common_system_ss.add(files( + 'arch_dump.c', 'debug_helper.c', 'helper.c', 'vfp_fpscr.c', From 262a5ce86ebfd7975ed6b5075a512d33e0ef1d1d Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:41 -0700 Subject: [PATCH 0922/2760] target/arm/arm-powerctl: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-28-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 95a2b077dd..7db573f4a9 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -15,7 +15,6 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( arm_system_ss = ss.source_set() arm_common_system_ss = ss.source_set() arm_system_ss.add(files( - 'arm-powerctl.c', 'arm-qmp-cmds.c', 'cortex-regs.c', 'machine.c', @@ -38,6 +37,7 @@ arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) arm_common_system_ss.add(files( 'arch_dump.c', + 'arm-powerctl.c', 'debug_helper.c', 'helper.c', 'vfp_fpscr.c', From 7d5df02e7a5a8cd3673850db8eace624314a363c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:42 -0700 Subject: [PATCH 0923/2760] target/arm/cortex-regs: compile file once (system) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-29-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 7db573f4a9..6e0327b6f5 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -16,7 +16,6 @@ arm_system_ss = ss.source_set() arm_common_system_ss = ss.source_set() arm_system_ss.add(files( 'arm-qmp-cmds.c', - 'cortex-regs.c', 'machine.c', 'ptw.c', )) @@ -38,6 +37,7 @@ arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( arm_common_system_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', + 'cortex-regs.c', 'debug_helper.c', 'helper.c', 'vfp_fpscr.c', From 03bc7858fd87fc622b2671b319c2de8aad7aefd5 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:43 -0700 Subject: [PATCH 0924/2760] target/arm/ptw: replace target_ulong with int64_t MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sextract64 returns a signed value. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-30-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 89979c07e5..68ec3f5e75 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -1660,7 +1660,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, uint64_t ttbr; hwaddr descaddr, indexmask, indexmask_grainsize; uint32_t tableattrs; - target_ulong page_size; + uint64_t page_size; uint64_t attrs; int32_t stride; int addrsize, inputsize, outputsize; @@ -1733,7 +1733,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, * validation to do here. */ if (inputsize < addrsize) { - target_ulong top_bits = sextract64(address, inputsize, + uint64_t top_bits = sextract64(address, inputsize, addrsize - inputsize); if (-top_bits != param.select) { /* The gap between the two regions is a Translation fault */ From bdfbf92c34acec649fa7d8cd0389c2b6629c88ad Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:44 -0700 Subject: [PATCH 0925/2760] target/arm/ptw: replace TARGET_AARCH64 by CONFIG_ATOMIC64 from arm_casq_ptw This function needs 64 bit compare exchange, so we hide implementation for hosts not supporting it (some 32 bit target, which don't run 64 bit guests anyway). Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-31-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/ptw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/ptw.c b/target/arm/ptw.c index 68ec3f5e75..44170d831c 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -737,7 +737,7 @@ static uint64_t arm_casq_ptw(CPUARMState *env, uint64_t old_val, uint64_t new_val, S1Translate *ptw, ARMMMUFaultInfo *fi) { -#if defined(TARGET_AARCH64) && defined(CONFIG_TCG) +#if defined(CONFIG_ATOMIC64) && defined(CONFIG_TCG) uint64_t cur_val; void *host = ptw->out_host; From aeacf43ae6f59139ab16adad7cd8c8e9f443536d Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:45 -0700 Subject: [PATCH 0926/2760] target/arm/ptw: compile file once (system) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-32-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 6e0327b6f5..151184da71 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -17,7 +17,6 @@ arm_common_system_ss = ss.source_set() arm_system_ss.add(files( 'arm-qmp-cmds.c', 'machine.c', - 'ptw.c', )) arm_user_ss = ss.source_set() @@ -40,6 +39,7 @@ arm_common_system_ss.add(files( 'cortex-regs.c', 'debug_helper.c', 'helper.c', + 'ptw.c', 'vfp_fpscr.c', )) From f86d42205c2eba2486fd305679f5963bb97b0371 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:46 -0700 Subject: [PATCH 0927/2760] target/arm/meson: accelerator files are not needed in user mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-33-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 151184da71..29a36fb3c5 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -5,9 +5,6 @@ arm_ss.add(files( )) arm_ss.add(zlib) -arm_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'), if_false: files('kvm-stub.c')) -arm_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) - arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'cpu64.c', 'gdbstub64.c')) @@ -18,6 +15,8 @@ arm_system_ss.add(files( 'arm-qmp-cmds.c', 'machine.c', )) +arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'), if_false: files('kvm-stub.c')) +arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) arm_user_ss = ss.source_set() arm_user_ss.add(files('cpu.c')) From cee0762c2b6236639979ba42a179d9d015057d94 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:47 -0700 Subject: [PATCH 0928/2760] target/arm/kvm-stub: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-34-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 29a36fb3c5..bb1c09676d 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -15,7 +15,7 @@ arm_system_ss.add(files( 'arm-qmp-cmds.c', 'machine.c', )) -arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c'), if_false: files('kvm-stub.c')) +arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c')) arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) arm_user_ss = ss.source_set() @@ -32,6 +32,7 @@ arm_user_ss.add(files( arm_common_system_ss.add(files('cpu.c'), capstone) arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) +arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) arm_common_system_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', From d31eaa5bdbd5cf05d8313beb7149c33c4a6d750e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:48 -0700 Subject: [PATCH 0929/2760] target/arm/machine: reduce migration include to avoid target specific definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-35-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/machine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index 978249fb71..f7956898fa 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -6,7 +6,8 @@ #include "kvm_arm.h" #include "internals.h" #include "cpu-features.h" -#include "migration/cpu.h" +#include "migration/qemu-file-types.h" +#include "migration/vmstate.h" #include "target/arm/gtimer.h" static bool vfp_needed(void *opaque) From cb9f95996a5d2941da5a41cc168145aca3051a55 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:49 -0700 Subject: [PATCH 0930/2760] target/arm/machine: remove TARGET_AARCH64 from migration state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This exposes two new subsections for arm: vmstate_sve and vmstate_za. Those sections have a ".needed" callback, which already allow to skip them when not needed. vmstate_sve .needed is checking cpu_isar_feature(aa64_sve, cpu). vmstate_za .needed is checking ZA flag in cpu->env.svcr. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-36-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/machine.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/target/arm/machine.c b/target/arm/machine.c index f7956898fa..868246a98c 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -241,7 +241,6 @@ static const VMStateDescription vmstate_iwmmxt = { } }; -#ifdef TARGET_AARCH64 /* The expression ARM_MAX_VQ - 2 is 0 for pure AArch32 build, * and ARMPredicateReg is actively empty. This triggers errors * in the expansion of the VMSTATE macros. @@ -321,7 +320,6 @@ static const VMStateDescription vmstate_za = { VMSTATE_END_OF_LIST() } }; -#endif /* AARCH64 */ static bool serror_needed(void *opaque) { @@ -1102,10 +1100,8 @@ const VMStateDescription vmstate_arm_cpu = { &vmstate_pmsav7, &vmstate_pmsav8, &vmstate_m_security, -#ifdef TARGET_AARCH64 &vmstate_sve, &vmstate_za, -#endif &vmstate_serror, &vmstate_irq_line_state, &vmstate_wfxt_timer, From 1dfe5a0c2e3da5d315cb45dbd7336bf20ea9a0ae Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:50 -0700 Subject: [PATCH 0931/2760] target/arm/machine: move cpu_post_load kvm bits to kvm_arm_cpu_post_load function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-37-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm.c | 13 ++++++++++++- target/arm/kvm_arm.h | 4 +++- target/arm/machine.c | 8 +------- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 82668d6438..a2791aa866 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -938,13 +938,24 @@ void kvm_arm_cpu_pre_save(ARMCPU *cpu) } } -void kvm_arm_cpu_post_load(ARMCPU *cpu) +bool kvm_arm_cpu_post_load(ARMCPU *cpu) { + if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) { + return false; + } + /* Note that it's OK for the TCG side not to know about + * every register in the list; KVM is authoritative if + * we're using it. + */ + write_list_to_cpustate(cpu); + /* KVM virtual time adjustment */ if (cpu->kvm_adjvtime) { cpu->kvm_vtime = *kvm_arm_get_cpreg_ptr(cpu, KVM_REG_ARM_TIMER_CNT); cpu->kvm_vtime_dirty = true; } + + return true; } void kvm_arm_reset_vcpu(ARMCPU *cpu) diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index b638e09a68..c4178d1327 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -83,8 +83,10 @@ void kvm_arm_cpu_pre_save(ARMCPU *cpu); * @cpu: ARMCPU * * Called from cpu_post_load() to update KVM CPU state from the cpreg list. + * + * Returns: true on success, or false if write_list_to_kvmstate failed. */ -void kvm_arm_cpu_post_load(ARMCPU *cpu); +bool kvm_arm_cpu_post_load(ARMCPU *cpu); /** * kvm_arm_reset_vcpu: diff --git a/target/arm/machine.c b/target/arm/machine.c index 868246a98c..e442d48524 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -976,15 +976,9 @@ static int cpu_post_load(void *opaque, int version_id) } if (kvm_enabled()) { - if (!write_list_to_kvmstate(cpu, KVM_PUT_FULL_STATE)) { + if (!kvm_arm_cpu_post_load(cpu)) { return -1; } - /* Note that it's OK for the TCG side not to know about - * every register in the list; KVM is authoritative if - * we're using it. - */ - write_list_to_cpustate(cpu); - kvm_arm_cpu_post_load(cpu); } else { if (!write_list_to_cpustate(cpu)) { return -1; From 1388256782014a7f6c730332f3561c6e1f94cc80 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:51 -0700 Subject: [PATCH 0932/2760] target/arm/kvm-stub: add missing stubs Those become needed once kvm_enabled can't be known at compile time. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-38-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm-stub.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/target/arm/kvm-stub.c b/target/arm/kvm-stub.c index 4806365cdc..34e57fab01 100644 --- a/target/arm/kvm-stub.c +++ b/target/arm/kvm-stub.c @@ -109,3 +109,13 @@ void arm_cpu_kvm_set_irq(void *arm_cpu, int irq, int level) { g_assert_not_reached(); } + +void kvm_arm_cpu_pre_save(ARMCPU *cpu) +{ + g_assert_not_reached(); +} + +bool kvm_arm_cpu_post_load(ARMCPU *cpu) +{ + g_assert_not_reached(); +} From 2c5058cc1eb77ed5340448aa6dea13ae4f4f1593 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:52 -0700 Subject: [PATCH 0933/2760] target/arm/machine: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-39-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index bb1c09676d..b404fa5486 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -13,7 +13,6 @@ arm_system_ss = ss.source_set() arm_common_system_ss = ss.source_set() arm_system_ss.add(files( 'arm-qmp-cmds.c', - 'machine.c', )) arm_system_ss.add(when: 'CONFIG_KVM', if_true: files('hyp_gdbstub.c', 'kvm.c')) arm_system_ss.add(when: 'CONFIG_HVF', if_true: files('hyp_gdbstub.c')) @@ -39,6 +38,7 @@ arm_common_system_ss.add(files( 'cortex-regs.c', 'debug_helper.c', 'helper.c', + 'machine.c', 'ptw.c', 'vfp_fpscr.c', )) From 368b42f6dd64521b9282ddefa9e267eca621271c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:53 -0700 Subject: [PATCH 0934/2760] target/arm/tcg/vec_internal: use forward declaration for CPUARMState Needed so this header can be included without requiring cpu.h. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-40-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/vec_internal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index 6b93b5aeb9..c02f9c37f8 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -22,6 +22,8 @@ #include "fpu/softfloat.h" +typedef struct CPUArchState CPUARMState; + /* * Note that vector data is stored in host-endian 64-bit chunks, * so addressing units smaller than that needs a host-endian fixup. From 9f8d002499e06f60878f803cb6ad70f1220a3ce4 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:54 -0700 Subject: [PATCH 0935/2760] target/arm/tcg/crypto_helper: compile file once Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-41-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/crypto_helper.c | 6 ++++-- target/arm/tcg/meson.build | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/crypto_helper.c b/target/arm/tcg/crypto_helper.c index 7cadd61e12..3428bd1bf0 100644 --- a/target/arm/tcg/crypto_helper.c +++ b/target/arm/tcg/crypto_helper.c @@ -10,14 +10,16 @@ */ #include "qemu/osdep.h" +#include "qemu/bitops.h" -#include "cpu.h" -#include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "crypto/aes-round.h" #include "crypto/sm4.h" #include "vec_internal.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + union CRYPTO_STATE { uint8_t bytes[16]; uint32_t words[4]; diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index dd12ccedb1..2f73eefe38 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -30,7 +30,6 @@ arm_ss.add(files( 'translate-mve.c', 'translate-neon.c', 'translate-vfp.c', - 'crypto_helper.c', 'hflags.c', 'iwmmxt_helper.c', 'm_helper.c', @@ -63,3 +62,7 @@ arm_system_ss.add(files( arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c')) arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c')) + +arm_common_ss.add(files( + 'crypto_helper.c', +)) From 12ae629d231b01e065b60288e82573842654054c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:55 -0700 Subject: [PATCH 0936/2760] target/arm/tcg/hflags: compile file twice (system, user) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-42-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/hflags.c | 4 +++- target/arm/tcg/meson.build | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index fd407a7b28..1ccec63bbd 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -9,11 +9,13 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "exec/helper-proto.h" #include "exec/translation-block.h" #include "accel/tcg/cpu-ops.h" #include "cpregs.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + static inline bool fgt_svc(CPUARMState *env, int el) { /* diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 2f73eefe38..cee00b24cd 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -30,7 +30,6 @@ arm_ss.add(files( 'translate-mve.c', 'translate-neon.c', 'translate-vfp.c', - 'hflags.c', 'iwmmxt_helper.c', 'm_helper.c', 'mve_helper.c', @@ -66,3 +65,10 @@ arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c')) arm_common_ss.add(files( 'crypto_helper.c', )) + +arm_common_system_ss.add(files( + 'hflags.c', +)) +arm_user_ss.add(files( + 'hflags.c', +)) From d5f8252cd15bf0dc3ac458e7e78427905966cfbf Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:56 -0700 Subject: [PATCH 0937/2760] target/arm/tcg/iwmmxt_helper: compile file twice (system, user) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-43-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/iwmmxt_helper.c | 4 +++- target/arm/tcg/meson.build | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/iwmmxt_helper.c b/target/arm/tcg/iwmmxt_helper.c index 610b1b2103..ba054b6b4d 100644 --- a/target/arm/tcg/iwmmxt_helper.c +++ b/target/arm/tcg/iwmmxt_helper.c @@ -22,7 +22,9 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/helper-proto.h" + +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" /* iwMMXt macros extracted from GNU gdb. */ diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index cee00b24cd..02dfe768c5 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -30,7 +30,6 @@ arm_ss.add(files( 'translate-mve.c', 'translate-neon.c', 'translate-vfp.c', - 'iwmmxt_helper.c', 'm_helper.c', 'mve_helper.c', 'neon_helper.c', @@ -68,7 +67,9 @@ arm_common_ss.add(files( arm_common_system_ss.add(files( 'hflags.c', + 'iwmmxt_helper.c', )) arm_user_ss.add(files( 'hflags.c', + 'iwmmxt_helper.c', )) From b586c86a8ea1bbf2bc7070153b38b8c75ff8b979 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:57 -0700 Subject: [PATCH 0938/2760] target/arm/tcg/neon_helper: compile file twice (system, user) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-44-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/meson.build | 3 ++- target/arm/tcg/neon_helper.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 02dfe768c5..af786196d2 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -32,7 +32,6 @@ arm_ss.add(files( 'translate-vfp.c', 'm_helper.c', 'mve_helper.c', - 'neon_helper.c', 'op_helper.c', 'tlb_helper.c', 'vec_helper.c', @@ -68,8 +67,10 @@ arm_common_ss.add(files( arm_common_system_ss.add(files( 'hflags.c', 'iwmmxt_helper.c', + 'neon_helper.c', )) arm_user_ss.add(files( 'hflags.c', 'iwmmxt_helper.c', + 'neon_helper.c', )) diff --git a/target/arm/tcg/neon_helper.c b/target/arm/tcg/neon_helper.c index e2cc7cf4ee..2cc8241f1e 100644 --- a/target/arm/tcg/neon_helper.c +++ b/target/arm/tcg/neon_helper.c @@ -9,11 +9,13 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/helper-proto.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" #include "vec_internal.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + #define SIGNBIT (uint32_t)0x80000000 #define SIGNBIT64 ((uint64_t)1 << 63) From cbf565b00fb350eb2d2b79fce437ee88060fd3f9 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:58 -0700 Subject: [PATCH 0939/2760] target/arm/tcg/tlb_helper: compile file twice (system, user) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-45-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/meson.build | 3 ++- target/arm/tcg/tlb_helper.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index af786196d2..49c8f4390a 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -33,7 +33,6 @@ arm_ss.add(files( 'm_helper.c', 'mve_helper.c', 'op_helper.c', - 'tlb_helper.c', 'vec_helper.c', 'tlb-insns.c', 'arith_helper.c', @@ -68,9 +67,11 @@ arm_common_system_ss.add(files( 'hflags.c', 'iwmmxt_helper.c', 'neon_helper.c', + 'tlb_helper.c', )) arm_user_ss.add(files( 'hflags.c', 'iwmmxt_helper.c', 'neon_helper.c', + 'tlb_helper.c', )) diff --git a/target/arm/tcg/tlb_helper.c b/target/arm/tcg/tlb_helper.c index d9e6c827d4..23c72a99f5 100644 --- a/target/arm/tcg/tlb_helper.c +++ b/target/arm/tcg/tlb_helper.c @@ -9,8 +9,9 @@ #include "cpu.h" #include "internals.h" #include "cpu-features.h" -#include "exec/helper-proto.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" /* * Returns true if the stage 1 translation regime is using LPAE format page From c04f6b5908bb1eff09955e89c239ff0c03de4754 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:04:59 -0700 Subject: [PATCH 0940/2760] target/arm/helper: restrict define_tlb_insn_regs to system target Allows to include target/arm/tcg/tlb-insns.c only for system targets. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-46-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index aae8554e8f..7631210287 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -7764,7 +7764,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, not_v8_cp_reginfo); } +#ifndef CONFIG_USER_ONLY define_tlb_insn_regs(cpu); +#endif if (arm_feature(env, ARM_FEATURE_V6)) { /* The ID registers all have impdef reset values */ From 31f4a08971d84bf97cf598a67d95ba8338adad1e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:05:00 -0700 Subject: [PATCH 0941/2760] target/arm/tcg/tlb-insns: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit aarch64 specific code is guarded by cpu_isar_feature(aa64*), so it's safe to expose it. Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250512180502.2395029-47-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/meson.build | 2 +- target/arm/tcg/tlb-insns.c | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 49c8f4390a..5d32658540 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -34,7 +34,6 @@ arm_ss.add(files( 'mve_helper.c', 'op_helper.c', 'vec_helper.c', - 'tlb-insns.c', 'arith_helper.c', 'vfp_helper.c', )) @@ -68,6 +67,7 @@ arm_common_system_ss.add(files( 'iwmmxt_helper.c', 'neon_helper.c', 'tlb_helper.c', + 'tlb-insns.c', )) arm_user_ss.add(files( 'hflags.c', diff --git a/target/arm/tcg/tlb-insns.c b/target/arm/tcg/tlb-insns.c index 0407ad5542..95c26c6d46 100644 --- a/target/arm/tcg/tlb-insns.c +++ b/target/arm/tcg/tlb-insns.c @@ -35,7 +35,6 @@ static CPAccessResult access_ttlbis(CPUARMState *env, const ARMCPRegInfo *ri, return CP_ACCESS_OK; } -#ifdef TARGET_AARCH64 /* Check for traps from EL1 due to HCR_EL2.TTLB or TTLBOS. */ static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri, bool isread) @@ -46,7 +45,6 @@ static CPAccessResult access_ttlbos(CPUARMState *env, const ARMCPRegInfo *ri, } return CP_ACCESS_OK; } -#endif /* IS variants of TLB operations must affect all cores */ static void tlbiall_is_write(CPUARMState *env, const ARMCPRegInfo *ri, @@ -802,7 +800,6 @@ static const ARMCPRegInfo tlbi_el3_cp_reginfo[] = { .writefn = tlbi_aa64_vae3_write }, }; -#ifdef TARGET_AARCH64 typedef struct { uint64_t base; uint64_t length; @@ -1270,8 +1267,6 @@ static const ARMCPRegInfo tlbi_rme_reginfo[] = { .writefn = tlbi_aa64_paallos_write }, }; -#endif - void define_tlb_insn_regs(ARMCPU *cpu) { CPUARMState *env = &cpu->env; @@ -1299,7 +1294,6 @@ void define_tlb_insn_regs(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_EL3)) { define_arm_cp_regs(cpu, tlbi_el3_cp_reginfo); } -#ifdef TARGET_AARCH64 if (cpu_isar_feature(aa64_tlbirange, cpu)) { define_arm_cp_regs(cpu, tlbirange_reginfo); } @@ -1309,5 +1303,4 @@ void define_tlb_insn_regs(ARMCPU *cpu) if (cpu_isar_feature(aa64_rme, cpu)) { define_arm_cp_regs(cpu, tlbi_rme_reginfo); } -#endif } From c0b623cb1c0d2de64631486d391c55f2e8874eda Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:05:01 -0700 Subject: [PATCH 0942/2760] target/arm/tcg/arith_helper: compile file once Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-48-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/arith_helper.c | 5 +++-- target/arm/tcg/meson.build | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/target/arm/tcg/arith_helper.c b/target/arm/tcg/arith_helper.c index 9a555c7966..670139819d 100644 --- a/target/arm/tcg/arith_helper.c +++ b/target/arm/tcg/arith_helper.c @@ -6,11 +6,12 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "qemu/osdep.h" -#include "cpu.h" -#include "exec/helper-proto.h" #include "qemu/crc32c.h" #include /* for crc32 */ +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + /* * Note that signed overflow is undefined in C. The following routines are * careful to use unsigned types where modulo arithmetic is required. diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 5d32658540..7502c5cded 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -34,7 +34,6 @@ arm_ss.add(files( 'mve_helper.c', 'op_helper.c', 'vec_helper.c', - 'arith_helper.c', 'vfp_helper.c', )) @@ -59,6 +58,7 @@ arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c')) arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c')) arm_common_ss.add(files( + 'arith_helper.c', 'crypto_helper.c', )) From 9eb5427ac0d56ca050e34776b6de428892609bd5 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Mon, 12 May 2025 11:05:02 -0700 Subject: [PATCH 0943/2760] target/arm/tcg/vfp_helper: compile file twice (system, user) Reviewed-by: Richard Henderson Signed-off-by: Pierrick Bouvier Message-id: 20250512180502.2395029-49-pierrick.bouvier@linaro.org Signed-off-by: Peter Maydell --- target/arm/tcg/meson.build | 3 ++- target/arm/tcg/vfp_helper.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 7502c5cded..2d1502ba88 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -34,7 +34,6 @@ arm_ss.add(files( 'mve_helper.c', 'op_helper.c', 'vec_helper.c', - 'vfp_helper.c', )) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( @@ -68,10 +67,12 @@ arm_common_system_ss.add(files( 'neon_helper.c', 'tlb_helper.c', 'tlb-insns.c', + 'vfp_helper.c', )) arm_user_ss.add(files( 'hflags.c', 'iwmmxt_helper.c', 'neon_helper.c', 'tlb_helper.c', + 'vfp_helper.c', )) diff --git a/target/arm/tcg/vfp_helper.c b/target/arm/tcg/vfp_helper.c index b32e2f4e27..b1324c5c0a 100644 --- a/target/arm/tcg/vfp_helper.c +++ b/target/arm/tcg/vfp_helper.c @@ -19,12 +19,14 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/helper-proto.h" #include "internals.h" #include "cpu-features.h" #include "fpu/softfloat.h" #include "qemu/log.h" +#define HELPER_H "tcg/helper.h" +#include "exec/helper-proto.h.inc" + /* * Set the float_status behaviour to match the Arm defaults: * * tininess-before-rounding From c33159dec79069514f78faecfe268439226b0f5b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:18 -0500 Subject: [PATCH 0944/2760] block: Expand block status mode from bool to flags This patch is purely mechanical, changing bool want_zero into an unsigned int for bitwise-or of flags. As of this patch, all implementations are unchanged (the old want_zero==true is now mode==BDRV_WANT_PRECISE which is a superset of BDRV_WANT_ZERO); but the callers in io.c that used to pass want_zero==false are now prepared for future driver changes that can now distinguish bewteen BDRV_WANT_ZERO vs. BDRV_WANT_ALLOCATED. The next patch will actually change the file-posix driver along those lines, now that we have more-specific hints. As for the background why this patch is useful: right now, the file-posix driver recognizes that if allocation is being queried, the entire image can be reported as allocated (there is no backing file to refer to) - but this throws away information on whether the entire image reads as zero (trivially true if lseek(SEEK_HOLE) at offset 0 returns -ENXIO, a bit more complicated to prove if the raw file was created with 'qemu-img create' since we intentionally allocate a small chunk of all-zero data to help with alignment probing). Later patches will add a generic algorithm for seeing if an entire file reads as zeroes. Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-16-eblake@redhat.com> --- block/blkdebug.c | 6 ++-- block/copy-before-write.c | 4 +-- block/coroutines.h | 4 +-- block/file-posix.c | 4 +-- block/gluster.c | 4 +-- block/io.c | 51 ++++++++++++++++---------------- block/iscsi.c | 6 ++-- block/nbd.c | 4 +-- block/null.c | 6 ++-- block/parallels.c | 6 ++-- block/qcow.c | 2 +- block/qcow2.c | 6 ++-- block/qed.c | 6 ++-- block/quorum.c | 4 +-- block/raw-format.c | 4 +-- block/rbd.c | 6 ++-- block/snapshot-access.c | 4 +-- block/vdi.c | 4 +-- block/vmdk.c | 2 +- block/vpc.c | 2 +- block/vvfat.c | 6 ++-- include/block/block-common.h | 11 +++++++ include/block/block_int-common.h | 27 +++++++++-------- include/block/block_int-io.h | 4 +-- tests/unit/test-block-iothread.c | 2 +- 25 files changed, 99 insertions(+), 86 deletions(-) diff --git a/block/blkdebug.c b/block/blkdebug.c index 1c1967f8e0..c54aee0c84 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -751,9 +751,9 @@ blkdebug_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) } static int coroutine_fn GRAPH_RDLOCK -blkdebug_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, - BlockDriverState **file) +blkdebug_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, + int64_t *map, BlockDriverState **file) { int err; diff --git a/block/copy-before-write.c b/block/copy-before-write.c index 00af0b18ac..36d5d3ed9b 100644 --- a/block/copy-before-write.c +++ b/block/copy-before-write.c @@ -291,8 +291,8 @@ cbw_co_preadv_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes, } static int coroutine_fn GRAPH_RDLOCK -cbw_co_snapshot_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, int64_t bytes, +cbw_co_snapshot_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { diff --git a/block/coroutines.h b/block/coroutines.h index 79e5efbf75..892646bb7a 100644 --- a/block/coroutines.h +++ b/block/coroutines.h @@ -47,7 +47,7 @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_common_block_status_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, - bool want_zero, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, @@ -78,7 +78,7 @@ int co_wrapper_mixed_bdrv_rdlock bdrv_common_block_status_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, - bool want_zero, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, diff --git a/block/file-posix.c b/block/file-posix.c index ef52ed9169..805a1a2949 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3273,7 +3273,7 @@ static int find_allocation(BlockDriverState *bs, off_t start, * well exceed it. */ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, - bool want_zero, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, @@ -3289,7 +3289,7 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, return ret; } - if (!want_zero) { + if (mode != BDRV_WANT_PRECISE) { *pnum = bytes; *map = offset; *file = bs; diff --git a/block/gluster.c b/block/gluster.c index 8712aa606a..1a2ef53e9b 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1461,7 +1461,7 @@ exit: * (Based on raw_co_block_status() from file-posix.c.) */ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, - bool want_zero, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, @@ -1478,7 +1478,7 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, return ret; } - if (!want_zero) { + if (mode != BDRV_WANT_PRECISE) { *pnum = bytes; *map = offset; *file = bs; diff --git a/block/io.c b/block/io.c index 6d98b0abb9..b5b143cd1b 100644 --- a/block/io.c +++ b/block/io.c @@ -2364,10 +2364,8 @@ int bdrv_flush_all(void) * Drivers not implementing the functionality are assumed to not support * backing files, hence all their sectors are reported as allocated. * - * If 'want_zero' is true, the caller is querying for mapping - * purposes, with a focus on valid BDRV_BLOCK_OFFSET_VALID, _DATA, and - * _ZERO where possible; otherwise, the result favors larger 'pnum', - * with a focus on accurate BDRV_BLOCK_ALLOCATED. + * 'mode' serves as a hint as to which results are favored; see the + * BDRV_WANT_* macros for details. * * If 'offset' is beyond the end of the disk image the return value is * BDRV_BLOCK_EOF and 'pnum' is set to 0. @@ -2387,7 +2385,7 @@ int bdrv_flush_all(void) * set to the host mapping and BDS corresponding to the guest offset. */ static int coroutine_fn GRAPH_RDLOCK -bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, +bdrv_co_do_block_status(BlockDriverState *bs, unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { @@ -2476,7 +2474,7 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, local_file = bs; local_map = aligned_offset; } else { - ret = bs->drv->bdrv_co_block_status(bs, want_zero, aligned_offset, + ret = bs->drv->bdrv_co_block_status(bs, mode, aligned_offset, aligned_bytes, pnum, &local_map, &local_file); @@ -2488,10 +2486,10 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, * the cache requires an RCU update, so double check here to avoid * such an update if possible. * - * Check want_zero, because we only want to update the cache when we + * Check mode, because we only want to update the cache when we * have accurate information about what is zero and what is data. */ - if (want_zero && + if (mode == BDRV_WANT_PRECISE && ret == (BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID) && QLIST_EMPTY(&bs->children)) { @@ -2548,7 +2546,7 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, if (ret & BDRV_BLOCK_RAW) { assert(ret & BDRV_BLOCK_OFFSET_VALID && local_file); - ret = bdrv_co_do_block_status(local_file, want_zero, local_map, + ret = bdrv_co_do_block_status(local_file, mode, local_map, *pnum, pnum, &local_map, &local_file); goto out; } @@ -2560,7 +2558,7 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, if (!cow_bs) { ret |= BDRV_BLOCK_ZERO; - } else if (want_zero) { + } else if (mode == BDRV_WANT_PRECISE) { int64_t size2 = bdrv_co_getlength(cow_bs); if (size2 >= 0 && offset >= size2) { @@ -2569,14 +2567,14 @@ bdrv_co_do_block_status(BlockDriverState *bs, bool want_zero, } } - if (want_zero && ret & BDRV_BLOCK_RECURSE && + if (mode == BDRV_WANT_PRECISE && ret & BDRV_BLOCK_RECURSE && local_file && local_file != bs && (ret & BDRV_BLOCK_DATA) && !(ret & BDRV_BLOCK_ZERO) && (ret & BDRV_BLOCK_OFFSET_VALID)) { int64_t file_pnum; int ret2; - ret2 = bdrv_co_do_block_status(local_file, want_zero, local_map, + ret2 = bdrv_co_do_block_status(local_file, mode, local_map, *pnum, &file_pnum, NULL, NULL); if (ret2 >= 0) { /* Ignore errors. This is just providing extra information, it @@ -2627,7 +2625,7 @@ int coroutine_fn bdrv_co_common_block_status_above(BlockDriverState *bs, BlockDriverState *base, bool include_base, - bool want_zero, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, @@ -2654,7 +2652,7 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, return 0; } - ret = bdrv_co_do_block_status(bs, want_zero, offset, bytes, pnum, + ret = bdrv_co_do_block_status(bs, mode, offset, bytes, pnum, map, file); ++*depth; if (ret < 0 || *pnum == 0 || ret & BDRV_BLOCK_ALLOCATED || bs == base) { @@ -2671,7 +2669,7 @@ bdrv_co_common_block_status_above(BlockDriverState *bs, for (p = bdrv_filter_or_cow_bs(bs); include_base || p != base; p = bdrv_filter_or_cow_bs(p)) { - ret = bdrv_co_do_block_status(p, want_zero, offset, bytes, pnum, + ret = bdrv_co_do_block_status(p, mode, offset, bytes, pnum, map, file); ++*depth; if (ret < 0) { @@ -2734,7 +2732,8 @@ int coroutine_fn bdrv_co_block_status_above(BlockDriverState *bs, BlockDriverState **file) { IO_CODE(); - return bdrv_co_common_block_status_above(bs, base, false, true, offset, + return bdrv_co_common_block_status_above(bs, base, false, + BDRV_WANT_PRECISE, offset, bytes, pnum, map, file, NULL); } @@ -2765,8 +2764,9 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, return 1; } - ret = bdrv_co_common_block_status_above(bs, NULL, false, false, offset, - bytes, &pnum, NULL, NULL, NULL); + ret = bdrv_co_common_block_status_above(bs, NULL, false, BDRV_WANT_ZERO, + offset, bytes, &pnum, NULL, NULL, + NULL); if (ret < 0) { return ret; @@ -2782,9 +2782,9 @@ int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t dummy; IO_CODE(); - ret = bdrv_co_common_block_status_above(bs, bs, true, false, offset, - bytes, pnum ? pnum : &dummy, NULL, - NULL, NULL); + ret = bdrv_co_common_block_status_above(bs, bs, true, BDRV_WANT_ALLOCATED, + offset, bytes, pnum ? pnum : &dummy, + NULL, NULL, NULL); if (ret < 0) { return ret; } @@ -2817,7 +2817,8 @@ int coroutine_fn bdrv_co_is_allocated_above(BlockDriverState *bs, int ret; IO_CODE(); - ret = bdrv_co_common_block_status_above(bs, base, include_base, false, + ret = bdrv_co_common_block_status_above(bs, base, include_base, + BDRV_WANT_ALLOCATED, offset, bytes, pnum, NULL, NULL, &depth); if (ret < 0) { @@ -3698,8 +3699,8 @@ bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes, } int coroutine_fn -bdrv_co_snapshot_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, int64_t bytes, +bdrv_co_snapshot_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { @@ -3717,7 +3718,7 @@ bdrv_co_snapshot_block_status(BlockDriverState *bs, } bdrv_inc_in_flight(bs); - ret = drv->bdrv_co_snapshot_block_status(bs, want_zero, offset, bytes, + ret = drv->bdrv_co_snapshot_block_status(bs, mode, offset, bytes, pnum, map, file); bdrv_dec_in_flight(bs); diff --git a/block/iscsi.c b/block/iscsi.c index 2f0f4dac09..15b96ee880 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -694,9 +694,9 @@ out_unlock: static int coroutine_fn iscsi_co_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, - int64_t *map, + unsigned int mode, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file) { IscsiLun *iscsilun = bs->opaque; diff --git a/block/nbd.c b/block/nbd.c index 887841bc81..d5a2b21c6d 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -1397,8 +1397,8 @@ nbd_client_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes) } static int coroutine_fn GRAPH_RDLOCK nbd_client_co_block_status( - BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, - int64_t *pnum, int64_t *map, BlockDriverState **file) + BlockDriverState *bs, unsigned int mode, int64_t offset, + int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { int ret, request_ret; NBDExtent64 extent = { 0 }; diff --git a/block/null.c b/block/null.c index dc0b1fdbd9..4e448d593d 100644 --- a/block/null.c +++ b/block/null.c @@ -227,9 +227,9 @@ static int null_reopen_prepare(BDRVReopenState *reopen_state, } static int coroutine_fn null_co_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, - int64_t *map, + unsigned int mode, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file) { BDRVNullState *s = bs->opaque; diff --git a/block/parallels.c b/block/parallels.c index 347ca127f3..3a375e2a8a 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -416,9 +416,9 @@ parallels_co_flush_to_os(BlockDriverState *bs) } static int coroutine_fn GRAPH_RDLOCK -parallels_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, - BlockDriverState **file) +parallels_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, + int64_t *map, BlockDriverState **file) { BDRVParallelsState *s = bs->opaque; int count; diff --git a/block/qcow.c b/block/qcow.c index da8ad4d243..8a3e7591a9 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -530,7 +530,7 @@ get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate, } static int coroutine_fn GRAPH_RDLOCK -qcow_co_block_status(BlockDriverState *bs, bool want_zero, +qcow_co_block_status(BlockDriverState *bs, unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { diff --git a/block/qcow2.c b/block/qcow2.c index 7774e7f090..66fba89b41 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -2141,9 +2141,9 @@ static void qcow2_join_options(QDict *options, QDict *old_options) } static int coroutine_fn GRAPH_RDLOCK -qcow2_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t count, int64_t *pnum, int64_t *map, - BlockDriverState **file) +qcow2_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t count, int64_t *pnum, + int64_t *map, BlockDriverState **file) { BDRVQcow2State *s = bs->opaque; uint64_t host_offset; diff --git a/block/qed.c b/block/qed.c index ac24449ffb..4a36fb3929 100644 --- a/block/qed.c +++ b/block/qed.c @@ -833,9 +833,9 @@ fail: } static int coroutine_fn GRAPH_RDLOCK -bdrv_qed_co_block_status(BlockDriverState *bs, bool want_zero, int64_t pos, - int64_t bytes, int64_t *pnum, int64_t *map, - BlockDriverState **file) +bdrv_qed_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t pos, int64_t bytes, int64_t *pnum, + int64_t *map, BlockDriverState **file) { BDRVQEDState *s = bs->opaque; size_t len = MIN(bytes, SIZE_MAX); diff --git a/block/quorum.c b/block/quorum.c index 30747a6df9..ed8ce801ee 100644 --- a/block/quorum.c +++ b/block/quorum.c @@ -1226,7 +1226,7 @@ static void quorum_child_perm(BlockDriverState *bs, BdrvChild *c, * region contains zeroes, and BDRV_BLOCK_DATA otherwise. */ static int coroutine_fn GRAPH_RDLOCK -quorum_co_block_status(BlockDriverState *bs, bool want_zero, +quorum_co_block_status(BlockDriverState *bs, unsigned int mode, int64_t offset, int64_t count, int64_t *pnum, int64_t *map, BlockDriverState **file) { @@ -1238,7 +1238,7 @@ quorum_co_block_status(BlockDriverState *bs, bool want_zero, for (i = 0; i < s->num_children; i++) { int64_t bytes; ret = bdrv_co_common_block_status_above(s->children[i]->bs, NULL, false, - want_zero, offset, count, + mode, offset, count, &bytes, NULL, NULL, NULL); if (ret < 0) { quorum_report_bad(QUORUM_OP_TYPE_READ, offset, count, diff --git a/block/raw-format.c b/block/raw-format.c index e08526e2ec..df16ac1ea2 100644 --- a/block/raw-format.c +++ b/block/raw-format.c @@ -283,8 +283,8 @@ fail: } static int coroutine_fn GRAPH_RDLOCK -raw_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, +raw_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { BDRVRawState *s = bs->opaque; diff --git a/block/rbd.c b/block/rbd.c index 7446e66659..951cd63f9a 100644 --- a/block/rbd.c +++ b/block/rbd.c @@ -1503,9 +1503,9 @@ static int qemu_rbd_diff_iterate_cb(uint64_t offs, size_t len, } static int coroutine_fn qemu_rbd_co_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, - int64_t *map, + unsigned int mode, + int64_t offset, int64_t bytes, + int64_t *pnum, int64_t *map, BlockDriverState **file) { BDRVRBDState *s = bs->opaque; diff --git a/block/snapshot-access.c b/block/snapshot-access.c index 71ac83c01f..17ed2402db 100644 --- a/block/snapshot-access.c +++ b/block/snapshot-access.c @@ -41,11 +41,11 @@ snapshot_access_co_preadv_part(BlockDriverState *bs, static int coroutine_fn GRAPH_RDLOCK snapshot_access_co_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, + unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { - return bdrv_co_snapshot_block_status(bs->file->bs, want_zero, offset, + return bdrv_co_snapshot_block_status(bs->file->bs, mode, offset, bytes, pnum, map, file); } diff --git a/block/vdi.c b/block/vdi.c index a2da6ecab0..3ddc62a569 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -523,8 +523,8 @@ static int vdi_reopen_prepare(BDRVReopenState *state, } static int coroutine_fn GRAPH_RDLOCK -vdi_co_block_status(BlockDriverState *bs, bool want_zero, int64_t offset, - int64_t bytes, int64_t *pnum, int64_t *map, +vdi_co_block_status(BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { BDRVVdiState *s = (BDRVVdiState *)bs->opaque; diff --git a/block/vmdk.c b/block/vmdk.c index 2adec49912..9c7ab037e1 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -1777,7 +1777,7 @@ static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent, } static int coroutine_fn GRAPH_RDLOCK -vmdk_co_block_status(BlockDriverState *bs, bool want_zero, +vmdk_co_block_status(BlockDriverState *bs, unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) { diff --git a/block/vpc.c b/block/vpc.c index 0309e319f6..801ff5793f 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -726,7 +726,7 @@ fail: } static int coroutine_fn GRAPH_RDLOCK -vpc_co_block_status(BlockDriverState *bs, bool want_zero, +vpc_co_block_status(BlockDriverState *bs, unsigned int mode, int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file) diff --git a/block/vvfat.c b/block/vvfat.c index 91d69b3cc8..814796d918 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -3134,9 +3134,9 @@ vvfat_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes, } static int coroutine_fn vvfat_co_block_status(BlockDriverState *bs, - bool want_zero, int64_t offset, - int64_t bytes, int64_t *n, - int64_t *map, + unsigned int mode, + int64_t offset, int64_t bytes, + int64_t *n, int64_t *map, BlockDriverState **file) { *n = bytes; diff --git a/include/block/block-common.h b/include/block/block-common.h index 0b831ef87b..c8c626daea 100644 --- a/include/block/block-common.h +++ b/include/block/block-common.h @@ -333,6 +333,17 @@ typedef enum { #define BDRV_BLOCK_RECURSE 0x40 #define BDRV_BLOCK_COMPRESSED 0x80 +/* + * Block status hints: the bitwise-or of these flags emphasize what + * the caller hopes to learn, and some drivers may be able to give + * faster answers by doing less work when the hint permits. + */ +#define BDRV_WANT_ZERO BDRV_BLOCK_ZERO +#define BDRV_WANT_OFFSET_VALID BDRV_BLOCK_OFFSET_VALID +#define BDRV_WANT_ALLOCATED BDRV_BLOCK_ALLOCATED +#define BDRV_WANT_PRECISE (BDRV_WANT_ZERO | BDRV_WANT_OFFSET_VALID | \ + BDRV_WANT_OFFSET_VALID) + typedef QTAILQ_HEAD(BlockReopenQueue, BlockReopenQueueEntry) BlockReopenQueue; typedef struct BDRVReopenState { diff --git a/include/block/block_int-common.h b/include/block/block_int-common.h index 0d8187f656..2982dd3118 100644 --- a/include/block/block_int-common.h +++ b/include/block/block_int-common.h @@ -604,15 +604,16 @@ struct BlockDriver { * according to the current layer, and should only need to set * BDRV_BLOCK_DATA, BDRV_BLOCK_ZERO, BDRV_BLOCK_OFFSET_VALID, * and/or BDRV_BLOCK_RAW; if the current layer defers to a backing - * layer, the result should be 0 (and not BDRV_BLOCK_ZERO). See - * block.h for the overall meaning of the bits. As a hint, the - * flag want_zero is true if the caller cares more about precise - * mappings (favor accurate _OFFSET_VALID/_ZERO) or false for - * overall allocation (favor larger *pnum, perhaps by reporting - * _DATA instead of _ZERO). The block layer guarantees input - * clamped to bdrv_getlength() and aligned to request_alignment, - * as well as non-NULL pnum, map, and file; in turn, the driver - * must return an error or set pnum to an aligned non-zero value. + * layer, the result should be 0 (and not BDRV_BLOCK_ZERO). The + * caller will synthesize BDRV_BLOCK_ALLOCATED based on the + * non-zero results. See block.h for the overall meaning of the + * bits. As a hint, the flags in @mode may include a bitwise-or + * of BDRV_WANT_ALLOCATED, BDRV_WANT_OFFSET_VALID, or + * BDRV_WANT_ZERO based on what the caller is looking for in the + * results. The block layer guarantees input clamped to + * bdrv_getlength() and aligned to request_alignment, as well as + * non-NULL pnum, map, and file; in turn, the driver must return + * an error or set pnum to an aligned non-zero value. * * Note that @bytes is just a hint on how big of a region the * caller wants to inspect. It is not a limit on *pnum. @@ -624,8 +625,8 @@ struct BlockDriver { * to clamping *pnum for return to its caller. */ int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_block_status)( - BlockDriverState *bs, - bool want_zero, int64_t offset, int64_t bytes, int64_t *pnum, + BlockDriverState *bs, unsigned int mode, + int64_t offset, int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); /* @@ -649,8 +650,8 @@ struct BlockDriver { QEMUIOVector *qiov, size_t qiov_offset); int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_snapshot_block_status)( - BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, - int64_t *pnum, int64_t *map, BlockDriverState **file); + BlockDriverState *bs, unsigned int mode, int64_t offset, + int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); int coroutine_fn GRAPH_RDLOCK_PTR (*bdrv_co_pdiscard_snapshot)( BlockDriverState *bs, int64_t offset, int64_t bytes); diff --git a/include/block/block_int-io.h b/include/block/block_int-io.h index 4a7cf2b4fd..4f94eb3c5a 100644 --- a/include/block/block_int-io.h +++ b/include/block/block_int-io.h @@ -38,8 +38,8 @@ int coroutine_fn GRAPH_RDLOCK bdrv_co_preadv_snapshot(BdrvChild *child, int64_t offset, int64_t bytes, QEMUIOVector *qiov, size_t qiov_offset); int coroutine_fn GRAPH_RDLOCK bdrv_co_snapshot_block_status( - BlockDriverState *bs, bool want_zero, int64_t offset, int64_t bytes, - int64_t *pnum, int64_t *map, BlockDriverState **file); + BlockDriverState *bs, unsigned int mode, int64_t offset, + int64_t bytes, int64_t *pnum, int64_t *map, BlockDriverState **file); int coroutine_fn GRAPH_RDLOCK bdrv_co_pdiscard_snapshot(BlockDriverState *bs, int64_t offset, int64_t bytes); diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 2b358eaaa8..e26b3be593 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -63,7 +63,7 @@ bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact, } static int coroutine_fn bdrv_test_co_block_status(BlockDriverState *bs, - bool want_zero, + unsigned int mode, int64_t offset, int64_t count, int64_t *pnum, int64_t *map, BlockDriverState **file) From a6a0a7fb0e327d17594c971b4a39de14e025b415 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:19 -0500 Subject: [PATCH 0945/2760] file-posix, gluster: Handle zero block status hint better Although the previous patch to change 'bool want_zero' into a bitmask made no semantic change, it is now time to differentiate. When the caller specifically wants to know what parts of the file read as zero, we need to use lseek and actually reporting holes, rather than short-circuiting and advertising full allocation. This change will be utilized in later patches to let mirroring optimize for the case when the destination already reads as zeroes. Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-17-eblake@redhat.com> --- block/file-posix.c | 3 ++- block/gluster.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index 805a1a2949..ec95b74869 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -3289,7 +3289,8 @@ static int coroutine_fn raw_co_block_status(BlockDriverState *bs, return ret; } - if (mode != BDRV_WANT_PRECISE) { + if (!(mode & BDRV_WANT_ZERO)) { + /* There is no backing file - all bytes are allocated in this file. */ *pnum = bytes; *map = offset; *file = bs; diff --git a/block/gluster.c b/block/gluster.c index 1a2ef53e9b..89abd40f31 100644 --- a/block/gluster.c +++ b/block/gluster.c @@ -1478,7 +1478,7 @@ static int coroutine_fn qemu_gluster_co_block_status(BlockDriverState *bs, return ret; } - if (mode != BDRV_WANT_PRECISE) { + if (!(mode & BDRV_WANT_ZERO)) { *pnum = bytes; *map = offset; *file = bs; From 31bf15d97dd1d205a3b264675f9a1b3bd1939068 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:20 -0500 Subject: [PATCH 0946/2760] block: Let bdrv_co_is_zero_fast consolidate adjacent extents Some BDS drivers have a cap on how much block status they can supply in one query (for example, NBD talking to an older server cannot inspect more than 4G per query; and qcow2 tends to cap its answers rather than cross a cluster boundary of an L1 table). Although the existing callers of bdrv_co_is_zero_fast are not passing in that large of a 'bytes' parameter, an upcoming caller wants to query the entire image at once, and will thus benefit from being able to treat adjacent zero regions in a coalesced manner, rather than claiming the region is non-zero merely because pnum was truncated and didn't match the incoming bytes. While refactoring this into a loop, note that there is no need to assign pnum prior to calling bdrv_co_common_block_status_above() (it is guaranteed to be assigned deeper in the callstack). Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-18-eblake@redhat.com> --- block/io.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/block/io.c b/block/io.c index b5b143cd1b..50dc0e193f 100644 --- a/block/io.c +++ b/block/io.c @@ -2751,28 +2751,31 @@ int coroutine_fn bdrv_co_block_status(BlockDriverState *bs, int64_t offset, * by @offset and @bytes is known to read as zeroes. * Return 1 if that is the case, 0 otherwise and -errno on error. * This test is meant to be fast rather than accurate so returning 0 - * does not guarantee non-zero data. + * does not guarantee non-zero data; but a return of 1 is reliable. */ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes) { int ret; - int64_t pnum = bytes; + int64_t pnum; IO_CODE(); - if (!bytes) { - return 1; + while (bytes) { + ret = bdrv_co_common_block_status_above(bs, NULL, false, + BDRV_WANT_ZERO, offset, bytes, + &pnum, NULL, NULL, NULL); + + if (ret < 0) { + return ret; + } + if (!(ret & BDRV_BLOCK_ZERO)) { + return 0; + } + offset += pnum; + bytes -= pnum; } - ret = bdrv_co_common_block_status_above(bs, NULL, false, BDRV_WANT_ZERO, - offset, bytes, &pnum, NULL, NULL, - NULL); - - if (ret < 0) { - return ret; - } - - return (pnum == bytes) && (ret & BDRV_BLOCK_ZERO); + return 1; } int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, From 52726096707c5c8b90597c445de897fa64d56e73 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:21 -0500 Subject: [PATCH 0947/2760] block: Add new bdrv_co_is_all_zeroes() function There are some optimizations that require knowing if an image starts out as reading all zeroes, such as making blockdev-mirror faster by skipping the copying of source zeroes to the destination. The existing bdrv_co_is_zero_fast() is a good building block for answering this question, but it tends to give an answer of 0 for a file we just created via QMP 'blockdev-create' or similar (such as 'qemu-img create -f raw'). Why? Because file-posix.c insists on allocating a tiny header to any file rather than leaving it 100% sparse, due to some filesystems that are unable to answer alignment probes on a hole. But teaching file-posix.c to read the tiny header doesn't scale - the problem of a small header is also visible when libvirt sets up an NBD client to a just-created file on a migration destination host. So, we need a wrapper function that handles a bit more complexity in a common manner for all block devices - when the BDS is mostly a hole, but has a small non-hole header, it is still worth the time to read that header and check if it reads as all zeroes before giving up and returning a pessimistic answer. Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-19-eblake@redhat.com> --- block/io.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/block/block-io.h | 2 ++ 2 files changed, 64 insertions(+) diff --git a/block/io.c b/block/io.c index 50dc0e193f..4fd7768f9c 100644 --- a/block/io.c +++ b/block/io.c @@ -38,10 +38,14 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" #include "system/replay.h" +#include "qemu/units.h" /* Maximum bounce buffer for copy-on-read and write zeroes, in bytes */ #define MAX_BOUNCE_BUFFER (32768 << BDRV_SECTOR_BITS) +/* Maximum read size for checking if data reads as zero, in bytes */ +#define MAX_ZERO_CHECK_BUFFER (128 * KiB) + static void coroutine_fn GRAPH_RDLOCK bdrv_parent_cb_resize(BlockDriverState *bs); @@ -2778,6 +2782,64 @@ int coroutine_fn bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, return 1; } +/* + * Check @bs (and its backing chain) to see if the entire image is known + * to read as zeroes. + * Return 1 if that is the case, 0 otherwise and -errno on error. + * This test is meant to be fast rather than accurate so returning 0 + * does not guarantee non-zero data; however, a return of 1 is reliable, + * and this function can report 1 in more cases than bdrv_co_is_zero_fast. + */ +int coroutine_fn bdrv_co_is_all_zeroes(BlockDriverState *bs) +{ + int ret; + int64_t pnum, bytes; + char *buf; + QEMUIOVector local_qiov; + IO_CODE(); + + bytes = bdrv_co_getlength(bs); + if (bytes < 0) { + return bytes; + } + + /* First probe - see if the entire image reads as zero */ + ret = bdrv_co_common_block_status_above(bs, NULL, false, BDRV_WANT_ZERO, + 0, bytes, &pnum, NULL, NULL, + NULL); + if (ret < 0) { + return ret; + } + if (ret & BDRV_BLOCK_ZERO) { + return bdrv_co_is_zero_fast(bs, pnum, bytes - pnum); + } + + /* + * Because of the way 'blockdev-create' works, raw files tend to + * be created with a non-sparse region at the front to make + * alignment probing easier. If the block starts with only a + * small allocated region, it is still worth the effort to see if + * the rest of the image is still sparse, coupled with manually + * reading the first region to see if it reads zero after all. + */ + if (pnum > MAX_ZERO_CHECK_BUFFER) { + return 0; + } + ret = bdrv_co_is_zero_fast(bs, pnum, bytes - pnum); + if (ret <= 0) { + return ret; + } + /* Only the head of the image is unknown, and it's small. Read it. */ + buf = qemu_blockalign(bs, pnum); + qemu_iovec_init_buf(&local_qiov, buf, pnum); + ret = bdrv_driver_preadv(bs, 0, pnum, &local_qiov, 0, 0); + if (ret >= 0) { + ret = buffer_is_zero(buf, pnum); + } + qemu_vfree(buf); + return ret; +} + int coroutine_fn bdrv_co_is_allocated(BlockDriverState *bs, int64_t offset, int64_t bytes, int64_t *pnum) { diff --git a/include/block/block-io.h b/include/block/block-io.h index b49e0537dd..b99cc98d26 100644 --- a/include/block/block-io.h +++ b/include/block/block-io.h @@ -161,6 +161,8 @@ bdrv_is_allocated_above(BlockDriverState *bs, BlockDriverState *base, int coroutine_fn GRAPH_RDLOCK bdrv_co_is_zero_fast(BlockDriverState *bs, int64_t offset, int64_t bytes); +int coroutine_fn GRAPH_RDLOCK +bdrv_co_is_all_zeroes(BlockDriverState *bs); int GRAPH_RDLOCK bdrv_apply_auto_read_only(BlockDriverState *bs, const char *errmsg, From eb89627899bb84148d272394e885725eff456ae9 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:22 -0500 Subject: [PATCH 0948/2760] iotests: Improve iotest 194 to mirror data Mirroring a completely sparse image to a sparse destination should be practically instantaneous. It isn't yet, but the test will be more realistic if it has some non-zero to mirror as well as the holes. Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-20-eblake@redhat.com> --- tests/qemu-iotests/194 | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index c0ce82dd25..d0b9c084f5 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -34,6 +34,7 @@ with iotests.FilePath('source.img') as source_img_path, \ img_size = '1G' iotests.qemu_img_create('-f', iotests.imgfmt, source_img_path, img_size) + iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 512M 1M', source_img_path) iotests.qemu_img_create('-f', iotests.imgfmt, dest_img_path, img_size) iotests.log('Launching VMs...') From 870f8963cf1a84f8ec929b05a6d68906974a76c5 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:23 -0500 Subject: [PATCH 0949/2760] mirror: Minor refactoring Commit 5791ba52 (v9.2) pre-initialized ret in mirror_dirty_init to silence a false positive compiler warning, even though in all code paths where ret is used, it was guaranteed to be reassigned beforehand. But since the function returns -errno, and -1 is not always the right errno, it's better to initialize to -EIO. An upcoming patch wants to track two bitmaps in do_sync_target_write(); this will be easier if the current variables related to the dirty bitmap are renamed. Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-21-eblake@redhat.com> --- block/mirror.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index a53582f17b..34c6c5252e 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -841,7 +841,7 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) int64_t offset; BlockDriverState *bs; BlockDriverState *target_bs = blk_bs(s->target); - int ret = -1; + int ret = -EIO; int64_t count; bdrv_graph_co_rdlock(); @@ -1341,7 +1341,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, { int ret; size_t qiov_offset = 0; - int64_t bitmap_offset, bitmap_end; + int64_t dirty_bitmap_offset, dirty_bitmap_end; if (!QEMU_IS_ALIGNED(offset, job->granularity) && bdrv_dirty_bitmap_get(job->dirty_bitmap, offset)) @@ -1388,11 +1388,11 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, * Tails are either clean or shrunk, so for bitmap resetting * we safely align the range down. */ - bitmap_offset = QEMU_ALIGN_UP(offset, job->granularity); - bitmap_end = QEMU_ALIGN_DOWN(offset + bytes, job->granularity); - if (bitmap_offset < bitmap_end) { - bdrv_reset_dirty_bitmap(job->dirty_bitmap, bitmap_offset, - bitmap_end - bitmap_offset); + dirty_bitmap_offset = QEMU_ALIGN_UP(offset, job->granularity); + dirty_bitmap_end = QEMU_ALIGN_DOWN(offset + bytes, job->granularity); + if (dirty_bitmap_offset < dirty_bitmap_end) { + bdrv_reset_dirty_bitmap(job->dirty_bitmap, dirty_bitmap_offset, + dirty_bitmap_end - dirty_bitmap_offset); } job_progress_increase_remaining(&job->common.job, bytes); @@ -1430,10 +1430,10 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, * at function start, and they must be still dirty, as we've locked * the region for in-flight op. */ - bitmap_offset = QEMU_ALIGN_DOWN(offset, job->granularity); - bitmap_end = QEMU_ALIGN_UP(offset + bytes, job->granularity); - bdrv_set_dirty_bitmap(job->dirty_bitmap, bitmap_offset, - bitmap_end - bitmap_offset); + dirty_bitmap_offset = QEMU_ALIGN_DOWN(offset, job->granularity); + dirty_bitmap_end = QEMU_ALIGN_UP(offset + bytes, job->granularity); + bdrv_set_dirty_bitmap(job->dirty_bitmap, dirty_bitmap_offset, + dirty_bitmap_end - dirty_bitmap_offset); qatomic_set(&job->actively_synced, false); action = mirror_error_action(job, false, -ret); From 9474d97bd7421b4fe7c806ab0949697514d11e88 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:24 -0500 Subject: [PATCH 0950/2760] mirror: Pass full sync mode rather than bool to internals Out of the five possible values for MirrorSyncMode, INCREMENTAL and BITMAP are already rejected up front in mirror_start, leaving NONE, TOP, and FULL as the remaining values that the code was collapsing into a single bool is_none_mode. Furthermore, mirror_dirty_init() is only reachable for modes TOP and FULL, as further guided by s->zero_target. However, upcoming patches want to further optimize the pre-zeroing pass of a sync=full mirror in mirror_dirty_init(), while avoiding that pass on a sync=top action. Instead of throwing away context by collapsing these two values into s->is_none_mode=false, it is better to pass s->sync_mode throughout the entire operation. For active commit, the desired semantics match sync mode TOP. Signed-off-by: Eric Blake Message-ID: <20250509204341.3553601-22-eblake@redhat.com> Reviewed-by: Sunny Zhu Reviewed-by: Stefan Hajnoczi --- block/mirror.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 34c6c5252e..2599b75d09 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -51,7 +51,7 @@ typedef struct MirrorBlockJob { BlockDriverState *to_replace; /* Used to block operations on the drive-mirror-replace target */ Error *replace_blocker; - bool is_none_mode; + MirrorSyncMode sync_mode; BlockMirrorBackingMode backing_mode; /* Whether the target image requires explicit zero-initialization */ bool zero_target; @@ -723,9 +723,10 @@ static int mirror_exit_common(Job *job) &error_abort); if (!abort && s->backing_mode == MIRROR_SOURCE_BACKING_CHAIN) { - BlockDriverState *backing = s->is_none_mode ? src : s->base; + BlockDriverState *backing; BlockDriverState *unfiltered_target = bdrv_skip_filters(target_bs); + backing = s->sync_mode == MIRROR_SYNC_MODE_NONE ? src : s->base; if (bdrv_cow_bs(unfiltered_target) != backing) { bdrv_set_backing_hd(unfiltered_target, backing, &local_err); if (local_err) { @@ -1020,7 +1021,7 @@ static int coroutine_fn mirror_run(Job *job, Error **errp) mirror_free_init(s); s->last_pause_ns = qemu_clock_get_ns(QEMU_CLOCK_REALTIME); - if (!s->is_none_mode) { + if (s->sync_mode != MIRROR_SYNC_MODE_NONE) { ret = mirror_dirty_init(s); if (ret < 0 || job_is_cancelled(&s->common.job)) { goto immediate_exit; @@ -1711,6 +1712,7 @@ static BlockJob *mirror_start_job( int creation_flags, BlockDriverState *target, const char *replaces, int64_t speed, uint32_t granularity, int64_t buf_size, + MirrorSyncMode sync_mode, BlockMirrorBackingMode backing_mode, bool zero_target, BlockdevOnError on_source_error, @@ -1719,7 +1721,7 @@ static BlockJob *mirror_start_job( BlockCompletionFunc *cb, void *opaque, const BlockJobDriver *driver, - bool is_none_mode, BlockDriverState *base, + BlockDriverState *base, bool auto_complete, const char *filter_node_name, bool is_mirror, MirrorCopyMode copy_mode, bool base_ro, @@ -1878,7 +1880,7 @@ static BlockJob *mirror_start_job( s->replaces = g_strdup(replaces); s->on_source_error = on_source_error; s->on_target_error = on_target_error; - s->is_none_mode = is_none_mode; + s->sync_mode = sync_mode; s->backing_mode = backing_mode; s->zero_target = zero_target; qatomic_set(&s->copy_mode, copy_mode); @@ -2015,7 +2017,6 @@ void mirror_start(const char *job_id, BlockDriverState *bs, bool unmap, const char *filter_node_name, MirrorCopyMode copy_mode, Error **errp) { - bool is_none_mode; BlockDriverState *base; GLOBAL_STATE_CODE(); @@ -2028,14 +2029,13 @@ void mirror_start(const char *job_id, BlockDriverState *bs, } bdrv_graph_rdlock_main_loop(); - is_none_mode = mode == MIRROR_SYNC_MODE_NONE; base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL; bdrv_graph_rdunlock_main_loop(); mirror_start_job(job_id, bs, creation_flags, target, replaces, - speed, granularity, buf_size, backing_mode, zero_target, - on_source_error, on_target_error, unmap, NULL, NULL, - &mirror_job_driver, is_none_mode, base, false, + speed, granularity, buf_size, mode, backing_mode, + zero_target, on_source_error, on_target_error, unmap, + NULL, NULL, &mirror_job_driver, base, false, filter_node_name, true, copy_mode, false, errp); } @@ -2061,9 +2061,9 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, job = mirror_start_job( job_id, bs, creation_flags, base, NULL, speed, 0, 0, - MIRROR_LEAVE_BACKING_CHAIN, false, + MIRROR_SYNC_MODE_TOP, MIRROR_LEAVE_BACKING_CHAIN, false, on_error, on_error, true, cb, opaque, - &commit_active_job_driver, false, base, auto_complete, + &commit_active_job_driver, base, auto_complete, filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, base_read_only, errp); if (!job) { From d17a34bfb94bda3a89d7320ae67255ded1d8c939 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:25 -0500 Subject: [PATCH 0951/2760] mirror: Allow QMP override to declare target already zero QEMU has an optimization for a just-created drive-mirror destination that is not possible for blockdev-mirror (which can't create the destination) - any time we know the destination starts life as all zeroes, we can skip a pre-zeroing pass on the destination. Recent patches have added an improved heuristic for detecting if a file contains all zeroes, and we plan to use that heuristic in upcoming patches. But since a heuristic cannot quickly detect all scenarios, and there may be cases where the caller is aware of information that QEMU cannot learn quickly, it makes sense to have a way to tell QEMU to assume facts about the destination that can make the mirror operation faster. Given our existing example of "qemu-img convert --target-is-zero", it is time to expose this override in QMP for blockdev-mirror as well. This patch results in some slight redundancy between the older s->zero_target (set any time mode==FULL and the destination image was not just created - ie. clear if drive-mirror is asking to skip the pre-zero pass) and the newly-introduced s->target_is_zero (in addition to the QMP override, it is set when drive-mirror creates the destination image); this will be cleaned up in the next patch. There is also a subtlety that we must consider. When drive-mirror is passing target_is_zero on behalf of a just-created image, we know the image is sparse (skipping the pre-zeroing keeps it that way), so it doesn't matter whether the destination also has "discard":"unmap" and "detect-zeroes":"unmap". But now that we are letting the user set the knob for target-is-zero, if the user passes a pre-existing file that is fully allocated, it is fine to leave the file fully allocated under "detect-zeroes":"on", but if the file is open with "detect-zeroes":"unmap", we should really be trying harder to punch holes in the destination for every region of zeroes copied from the source. The easiest way to do this is to still run the pre-zeroing pass (turning the entire destination file sparse before populating just the allocated portions of the source), even though that currently results in double I/O to the portions of the file that are allocated. A later patch will add further optimizations to reduce redundant zeroing I/O during the mirror operation. Since "target-is-zero":true is designed for optimizations, it is okay to silently ignore the parameter rather than erroring if the user ever sets the parameter in a scenario where the mirror job can't exploit it (for example, when doing "sync":"top" instead of "sync":"full", we can't pre-zero, so setting the parameter won't make a speed difference). Signed-off-by: Eric Blake Acked-by: Markus Armbruster Message-ID: <20250509204341.3553601-23-eblake@redhat.com> Reviewed-by: Sunny Zhu Reviewed-by: Stefan Hajnoczi --- block/mirror.c | 27 ++++++++++++++++++++++---- blockdev.c | 18 ++++++++++------- include/block/block_int-global-state.h | 3 ++- qapi/block-core.json | 8 +++++++- tests/unit/test-block-iothread.c | 2 +- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 2599b75d09..4dcb50c81a 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -55,6 +55,8 @@ typedef struct MirrorBlockJob { BlockMirrorBackingMode backing_mode; /* Whether the target image requires explicit zero-initialization */ bool zero_target; + /* Whether the target should be assumed to be already zero initialized */ + bool target_is_zero; /* * To be accesssed with atomics. Written only under the BQL (required by the * current implementation of mirror_change()). @@ -844,12 +846,26 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) BlockDriverState *target_bs = blk_bs(s->target); int ret = -EIO; int64_t count; + bool punch_holes = + target_bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && + bdrv_can_write_zeroes_with_unmap(target_bs); bdrv_graph_co_rdlock(); bs = s->mirror_top_bs->backing->bs; bdrv_graph_co_rdunlock(); - if (s->zero_target) { + if (s->zero_target && (!s->target_is_zero || punch_holes)) { + /* + * Here, we are in FULL mode; our goal is to avoid writing + * zeroes if the destination already reads as zero, except + * when we are trying to punch holes. This is possible if + * zeroing happened externally (s->target_is_zero) or if we + * have a fast way to pre-zero the image (the dirty bitmap + * will be populated later by the non-zero portions, the same + * as for TOP mode). If pre-zeroing is not fast, or we need + * to punch holes, then our only recourse is to write the + * entire image. + */ if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); return 0; @@ -1714,7 +1730,7 @@ static BlockJob *mirror_start_job( uint32_t granularity, int64_t buf_size, MirrorSyncMode sync_mode, BlockMirrorBackingMode backing_mode, - bool zero_target, + bool zero_target, bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, @@ -1883,6 +1899,7 @@ static BlockJob *mirror_start_job( s->sync_mode = sync_mode; s->backing_mode = backing_mode; s->zero_target = zero_target; + s->target_is_zero = target_is_zero; qatomic_set(&s->copy_mode, copy_mode); s->base = base; s->base_overlay = bdrv_find_overlay(bs, base); @@ -2011,7 +2028,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, int creation_flags, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, - bool zero_target, + bool zero_target, bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, const char *filter_node_name, @@ -2034,7 +2051,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs, mirror_start_job(job_id, bs, creation_flags, target, replaces, speed, granularity, buf_size, mode, backing_mode, - zero_target, on_source_error, on_target_error, unmap, + zero_target, + target_is_zero, on_source_error, on_target_error, unmap, NULL, NULL, &mirror_job_driver, base, false, filter_node_name, true, copy_mode, false, errp); } @@ -2062,6 +2080,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, job = mirror_start_job( job_id, bs, creation_flags, base, NULL, speed, 0, 0, MIRROR_SYNC_MODE_TOP, MIRROR_LEAVE_BACKING_CHAIN, false, + false, on_error, on_error, true, cb, opaque, &commit_active_job_driver, base, auto_complete, filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, diff --git a/blockdev.c b/blockdev.c index 818ec42511..97128feb27 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2804,7 +2804,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, const char *replaces, enum MirrorSyncMode sync, BlockMirrorBackingMode backing_mode, - bool zero_target, + bool zero_target, bool target_is_zero, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, bool has_buf_size, int64_t buf_size, @@ -2915,11 +2915,10 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, /* pass the node name to replace to mirror start since it's loose coupling * and will allow to check whether the node still exist at mirror completion */ - mirror_start(job_id, bs, target, - replaces, job_flags, + mirror_start(job_id, bs, target, replaces, job_flags, speed, granularity, buf_size, sync, backing_mode, zero_target, - on_source_error, on_target_error, unmap, filter_node_name, - copy_mode, errp); + target_is_zero, on_source_error, on_target_error, unmap, + filter_node_name, copy_mode, errp); } void qmp_drive_mirror(DriveMirror *arg, Error **errp) @@ -2934,6 +2933,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) int64_t size; const char *format = arg->format; bool zero_target; + bool target_is_zero; int ret; bs = qmp_get_root_bs(arg->device, errp); @@ -3050,6 +3050,8 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL && (arg->mode == NEW_IMAGE_MODE_EXISTING || !bdrv_has_zero_init(target_bs))); + target_is_zero = (arg->mode != NEW_IMAGE_MODE_EXISTING && + bdrv_has_zero_init(target_bs)); bdrv_graph_rdunlock_main_loop(); @@ -3061,7 +3063,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) blockdev_mirror_common(arg->job_id, bs, target_bs, arg->replaces, arg->sync, - backing_mode, zero_target, + backing_mode, zero_target, target_is_zero, arg->has_speed, arg->speed, arg->has_granularity, arg->granularity, arg->has_buf_size, arg->buf_size, @@ -3091,6 +3093,7 @@ void qmp_blockdev_mirror(const char *job_id, bool has_copy_mode, MirrorCopyMode copy_mode, bool has_auto_finalize, bool auto_finalize, bool has_auto_dismiss, bool auto_dismiss, + bool has_target_is_zero, bool target_is_zero, Error **errp) { BlockDriverState *bs; @@ -3121,7 +3124,8 @@ void qmp_blockdev_mirror(const char *job_id, blockdev_mirror_common(job_id, bs, target_bs, replaces, sync, backing_mode, - zero_target, has_speed, speed, + zero_target, has_target_is_zero && target_is_zero, + has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, has_on_source_error, on_source_error, diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h index 0d93783763..62a6c7e8e2 100644 --- a/include/block/block_int-global-state.h +++ b/include/block/block_int-global-state.h @@ -140,6 +140,7 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, * @mode: Whether to collapse all images in the chain to the target. * @backing_mode: How to establish the target's backing chain after completion. * @zero_target: Whether the target should be explicitly zero-initialized + * @target_is_zero: Whether the target already is zero-initialized. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. * @unmap: Whether to unmap target where source sectors only contain zeroes. @@ -159,7 +160,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, int creation_flags, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, - bool zero_target, + bool zero_target, bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, const char *filter_node_name, diff --git a/qapi/block-core.json b/qapi/block-core.json index 91c70e24a7..b4115113d4 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2542,6 +2542,11 @@ # disappear from the query list without user intervention. # Defaults to true. (Since 3.1) # +# @target-is-zero: Assume the destination reads as all zeroes before +# the mirror started. Setting this to true can speed up the +# mirror. Setting this to true when the destination is not +# actually all zero can corrupt the destination. (Since 10.1) +# # Since: 2.6 # # .. qmp-example:: @@ -2561,7 +2566,8 @@ '*on-target-error': 'BlockdevOnError', '*filter-node-name': 'str', '*copy-mode': 'MirrorCopyMode', - '*auto-finalize': 'bool', '*auto-dismiss': 'bool' }, + '*auto-finalize': 'bool', '*auto-dismiss': 'bool', + '*target-is-zero': 'bool'}, 'allow-preconfig': true } ## diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index e26b3be593..54aed8252c 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -755,7 +755,7 @@ static void test_propagate_mirror(void) /* Start a mirror job */ mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, - MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, + MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, &error_abort); From 253b43a29077de9266351e120c600a73b82e9c49 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:26 -0500 Subject: [PATCH 0952/2760] mirror: Drop redundant zero_target parameter The two callers to a mirror job (drive-mirror and blockdev-mirror) set zero_target precisely when sync mode == FULL, with the one exception that drive-mirror skips zeroing the target if it was newly created and reads as zero. But given the previous patch, that exception is equally captured by target_is_zero. Meanwhile, there is another slight wrinkle, fortunately caught by iotest 185: if the caller uses "sync":"top" but the source has no backing file, the code in blockdev.c was changing sync to be FULL, but only after it had set zero_target=false. In mirror.c, prior to recent patches, this didn't matter: the only places that inspected sync were setting is_none_mode (both TOP and FULL had set that to false), and mirror_start() setting base = mode == MIRROR_SYNC_MODE_TOP ? bdrv_backing_chain_next(bs) : NULL. But now that we are passing sync around, the slammed sync mode would result in a new pre-zeroing pass even when the user had passed "sync":"top" in an effort to skip pre-zeroing. Fortunately, the assignment of base when bs has no backing chain still works out to NULL if we don't slam things. So with the forced change of sync ripped out of blockdev.c, the sync mode is passed through the full callstack unmolested, and we can now reliably reconstruct the same settings as what used to be passed in by zero_target=false, without the redundant parameter. Signed-off-by: Eric Blake Message-ID: <20250509204341.3553601-24-eblake@redhat.com> Reviewed-by: Sunny Zhu Reviewed-by: Stefan Hajnoczi [eblake: Fix regression in iotest 185] Signed-off-by: Eric Blake --- block/mirror.c | 13 +++++-------- blockdev.c | 19 ++++--------------- include/block/block_int-global-state.h | 3 +-- tests/unit/test-block-iothread.c | 2 +- 4 files changed, 11 insertions(+), 26 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 4dcb50c81a..d04db85883 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -53,8 +53,6 @@ typedef struct MirrorBlockJob { Error *replace_blocker; MirrorSyncMode sync_mode; BlockMirrorBackingMode backing_mode; - /* Whether the target image requires explicit zero-initialization */ - bool zero_target; /* Whether the target should be assumed to be already zero initialized */ bool target_is_zero; /* @@ -854,7 +852,9 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) bs = s->mirror_top_bs->backing->bs; bdrv_graph_co_rdunlock(); - if (s->zero_target && (!s->target_is_zero || punch_holes)) { + if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { + /* In TOP mode, there is no benefit to a pre-zeroing pass. */ + } else if (!s->target_is_zero || punch_holes) { /* * Here, we are in FULL mode; our goal is to avoid writing * zeroes if the destination already reads as zero, except @@ -1730,7 +1730,7 @@ static BlockJob *mirror_start_job( uint32_t granularity, int64_t buf_size, MirrorSyncMode sync_mode, BlockMirrorBackingMode backing_mode, - bool zero_target, bool target_is_zero, + bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, @@ -1898,7 +1898,6 @@ static BlockJob *mirror_start_job( s->on_target_error = on_target_error; s->sync_mode = sync_mode; s->backing_mode = backing_mode; - s->zero_target = zero_target; s->target_is_zero = target_is_zero; qatomic_set(&s->copy_mode, copy_mode); s->base = base; @@ -2028,7 +2027,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, int creation_flags, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, - bool zero_target, bool target_is_zero, + bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, const char *filter_node_name, @@ -2051,7 +2050,6 @@ void mirror_start(const char *job_id, BlockDriverState *bs, mirror_start_job(job_id, bs, creation_flags, target, replaces, speed, granularity, buf_size, mode, backing_mode, - zero_target, target_is_zero, on_source_error, on_target_error, unmap, NULL, NULL, &mirror_job_driver, base, false, filter_node_name, true, copy_mode, false, errp); @@ -2080,7 +2078,6 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, job = mirror_start_job( job_id, bs, creation_flags, base, NULL, speed, 0, 0, MIRROR_SYNC_MODE_TOP, MIRROR_LEAVE_BACKING_CHAIN, false, - false, on_error, on_error, true, cb, opaque, &commit_active_job_driver, base, auto_complete, filter_node_name, false, MIRROR_COPY_MODE_BACKGROUND, diff --git a/blockdev.c b/blockdev.c index 97128feb27..21443b4514 100644 --- a/blockdev.c +++ b/blockdev.c @@ -2804,7 +2804,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, const char *replaces, enum MirrorSyncMode sync, BlockMirrorBackingMode backing_mode, - bool zero_target, bool target_is_zero, + bool target_is_zero, bool has_speed, int64_t speed, bool has_granularity, uint32_t granularity, bool has_buf_size, int64_t buf_size, @@ -2871,10 +2871,6 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, return; } - if (!bdrv_backing_chain_next(bs) && sync == MIRROR_SYNC_MODE_TOP) { - sync = MIRROR_SYNC_MODE_FULL; - } - if (!replaces) { /* We want to mirror from @bs, but keep implicit filters on top */ unfiltered_bs = bdrv_skip_implicit_filters(bs); @@ -2916,7 +2912,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs, * and will allow to check whether the node still exist at mirror completion */ mirror_start(job_id, bs, target, replaces, job_flags, - speed, granularity, buf_size, sync, backing_mode, zero_target, + speed, granularity, buf_size, sync, backing_mode, target_is_zero, on_source_error, on_target_error, unmap, filter_node_name, copy_mode, errp); } @@ -2932,7 +2928,6 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) int flags; int64_t size; const char *format = arg->format; - bool zero_target; bool target_is_zero; int ret; @@ -3047,9 +3042,6 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) } bdrv_graph_rdlock_main_loop(); - zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL && - (arg->mode == NEW_IMAGE_MODE_EXISTING || - !bdrv_has_zero_init(target_bs))); target_is_zero = (arg->mode != NEW_IMAGE_MODE_EXISTING && bdrv_has_zero_init(target_bs)); bdrv_graph_rdunlock_main_loop(); @@ -3063,7 +3055,7 @@ void qmp_drive_mirror(DriveMirror *arg, Error **errp) blockdev_mirror_common(arg->job_id, bs, target_bs, arg->replaces, arg->sync, - backing_mode, zero_target, target_is_zero, + backing_mode, target_is_zero, arg->has_speed, arg->speed, arg->has_granularity, arg->granularity, arg->has_buf_size, arg->buf_size, @@ -3100,7 +3092,6 @@ void qmp_blockdev_mirror(const char *job_id, BlockDriverState *target_bs; AioContext *aio_context; BlockMirrorBackingMode backing_mode = MIRROR_LEAVE_BACKING_CHAIN; - bool zero_target; int ret; bs = qmp_get_root_bs(device, errp); @@ -3113,8 +3104,6 @@ void qmp_blockdev_mirror(const char *job_id, return; } - zero_target = (sync == MIRROR_SYNC_MODE_FULL); - aio_context = bdrv_get_aio_context(bs); ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp); @@ -3124,7 +3113,7 @@ void qmp_blockdev_mirror(const char *job_id, blockdev_mirror_common(job_id, bs, target_bs, replaces, sync, backing_mode, - zero_target, has_target_is_zero && target_is_zero, + has_target_is_zero && target_is_zero, has_speed, speed, has_granularity, granularity, has_buf_size, buf_size, diff --git a/include/block/block_int-global-state.h b/include/block/block_int-global-state.h index 62a6c7e8e2..e7c8f1a856 100644 --- a/include/block/block_int-global-state.h +++ b/include/block/block_int-global-state.h @@ -139,7 +139,6 @@ BlockJob *commit_active_start(const char *job_id, BlockDriverState *bs, * @buf_size: The amount of data that can be in flight at one time. * @mode: Whether to collapse all images in the chain to the target. * @backing_mode: How to establish the target's backing chain after completion. - * @zero_target: Whether the target should be explicitly zero-initialized * @target_is_zero: Whether the target already is zero-initialized. * @on_source_error: The action to take upon error reading from the source. * @on_target_error: The action to take upon error writing to the target. @@ -160,7 +159,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs, int creation_flags, int64_t speed, uint32_t granularity, int64_t buf_size, MirrorSyncMode mode, BlockMirrorBackingMode backing_mode, - bool zero_target, bool target_is_zero, + bool target_is_zero, BlockdevOnError on_source_error, BlockdevOnError on_target_error, bool unmap, const char *filter_node_name, diff --git a/tests/unit/test-block-iothread.c b/tests/unit/test-block-iothread.c index 54aed8252c..e26b3be593 100644 --- a/tests/unit/test-block-iothread.c +++ b/tests/unit/test-block-iothread.c @@ -755,7 +755,7 @@ static void test_propagate_mirror(void) /* Start a mirror job */ mirror_start("job0", src, target, NULL, JOB_DEFAULT, 0, 0, 0, - MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, false, + MIRROR_SYNC_MODE_NONE, MIRROR_OPEN_BACKING_CHAIN, false, BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT, false, "filter_node", MIRROR_COPY_MODE_BACKGROUND, &error_abort); From 181a63667adf16c35b57e446def3e41c70f1fea6 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:27 -0500 Subject: [PATCH 0953/2760] mirror: Skip pre-zeroing destination if it is already zero When doing a sync=full mirroring, we can skip pre-zeroing the destination if it already reads as zeroes and we are not also trying to punch holes due to detect-zeroes. With this patch, there are fewer scenarios that have to pass in an explicit target-is-zero, while still resulting in a sparse destination remaining sparse. A later patch will then further improve things to skip writing to the destination for parts of the image where the source is zero; but even with just this patch, it is possible to see a difference for any source that does not report itself as fully allocated, coupled with a destination BDS that can quickly report that it already reads as zero. (For a source that reports as fully allocated, such as a file, the rest of mirror_dirty_init() still sets the entire dirty bitmap to true, so even though we avoided the pre-zeroing, we are not yet avoiding all redundant I/O). Iotest 194 detects the difference made by this patch: for a file source (where block status reports the entire image as allocated, and therefore we end up writing zeroes everywhere in the destination anyways), the job length remains the same. But for a qcow2 source and a destination that reads as all zeroes, the dirty bitmap changes to just tracking the allocated portions of the source, which results in faster completion and smaller job statistics. For the test to pass with both ./check -file and -qcow2, a new python filter is needed to mask out the now-varying job amounts (this matches the shell filters _filter_block_job_{offset,len} in common.filter). A later test will also be added which further validates expected sparseness, so it does not matter that 194 is no longer explicitly looking at how many bytes were copied. Signed-off-by: Eric Blake Message-ID: <20250509204341.3553601-25-eblake@redhat.com> Reviewed-by: Sunny Zhu Reviewed-by: Stefan Hajnoczi --- block/mirror.c | 24 ++++++++++++++++-------- tests/qemu-iotests/194 | 6 ++++-- tests/qemu-iotests/194.out | 4 ++-- tests/qemu-iotests/iotests.py | 12 +++++++++++- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index d04db85883..bca99ec206 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -848,23 +848,31 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) target_bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && bdrv_can_write_zeroes_with_unmap(target_bs); + /* Determine if the image is already zero, regardless of sync mode. */ bdrv_graph_co_rdlock(); bs = s->mirror_top_bs->backing->bs; + if (s->target_is_zero) { + ret = 1; + } else { + ret = bdrv_co_is_all_zeroes(target_bs); + } bdrv_graph_co_rdunlock(); - if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { + /* Determine if a pre-zeroing pass is necessary. */ + if (ret < 0) { + return ret; + } else if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { /* In TOP mode, there is no benefit to a pre-zeroing pass. */ - } else if (!s->target_is_zero || punch_holes) { + } else if (ret == 0 || punch_holes) { /* * Here, we are in FULL mode; our goal is to avoid writing * zeroes if the destination already reads as zero, except * when we are trying to punch holes. This is possible if - * zeroing happened externally (s->target_is_zero) or if we - * have a fast way to pre-zero the image (the dirty bitmap - * will be populated later by the non-zero portions, the same - * as for TOP mode). If pre-zeroing is not fast, or we need - * to punch holes, then our only recourse is to write the - * entire image. + * zeroing happened externally (ret > 0) or if we have a fast + * way to pre-zero the image (the dirty bitmap will be + * populated later by the non-zero portions, the same as for + * TOP mode). If pre-zeroing is not fast, or we need to punch + * holes, then our only recourse is to write the entire image. */ if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); diff --git a/tests/qemu-iotests/194 b/tests/qemu-iotests/194 index d0b9c084f5..e114c0b269 100755 --- a/tests/qemu-iotests/194 +++ b/tests/qemu-iotests/194 @@ -62,7 +62,8 @@ with iotests.FilePath('source.img') as source_img_path, \ iotests.log('Waiting for `drive-mirror` to complete...') iotests.log(source_vm.event_wait('BLOCK_JOB_READY'), - filters=[iotests.filter_qmp_event]) + filters=[iotests.filter_qmp_event, + iotests.filter_block_job]) iotests.log('Starting migration...') capabilities = [{'capability': 'events', 'state': True}, @@ -88,7 +89,8 @@ with iotests.FilePath('source.img') as source_img_path, \ while True: event2 = source_vm.event_wait('BLOCK_JOB_COMPLETED') - iotests.log(event2, filters=[iotests.filter_qmp_event]) + iotests.log(event2, filters=[iotests.filter_qmp_event, + iotests.filter_block_job]) if event2['event'] == 'BLOCK_JOB_COMPLETED': iotests.log('Stopping the NBD server on destination...') iotests.log(dest_vm.qmp('nbd-server-stop')) diff --git a/tests/qemu-iotests/194.out b/tests/qemu-iotests/194.out index 6940e809cd..d02655a514 100644 --- a/tests/qemu-iotests/194.out +++ b/tests/qemu-iotests/194.out @@ -7,7 +7,7 @@ Launching NBD server on destination... Starting `drive-mirror` on source... {"return": {}} Waiting for `drive-mirror` to complete... -{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"device": "mirror-job0", "len": "LEN", "offset": "OFFSET", "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Starting migration... {"return": {}} {"execute": "migrate-start-postcopy", "arguments": {}} @@ -18,7 +18,7 @@ Starting migration... {"data": {"status": "completed"}, "event": "MIGRATION", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Gracefully ending the `drive-mirror` job on source... {"return": {}} -{"data": {"device": "mirror-job0", "len": 1073741824, "offset": 1073741824, "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} +{"data": {"device": "mirror-job0", "len": "LEN", "offset": "OFFSET", "speed": 0, "type": "mirror"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}} Stopping the NBD server on destination... {"return": {}} Wait for migration completion on target... diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 7292c8b342..05274772ce 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -601,13 +601,23 @@ def filter_chown(msg): return chown_re.sub("chown UID:GID", msg) def filter_qmp_event(event): - '''Filter a QMP event dict''' + '''Filter the timestamp of a QMP event dict''' event = dict(event) if 'timestamp' in event: event['timestamp']['seconds'] = 'SECS' event['timestamp']['microseconds'] = 'USECS' return event +def filter_block_job(event): + '''Filter the offset and length of a QMP block job event dict''' + event = dict(event) + if 'data' in event: + if 'offset' in event['data']: + event['data']['offset'] = 'OFFSET' + if 'len' in event['data']: + event['data']['len'] = 'LEN' + return event + def filter_qmp(qmsg, filter_fn): '''Given a string filter, filter a QMP object's values. filter_fn takes a (key, value) pair.''' From 7e277545b90874171128804e256a538fb0e8dd7e Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:28 -0500 Subject: [PATCH 0954/2760] mirror: Skip writing zeroes when target is already zero When mirroring, the goal is to ensure that the destination reads the same as the source; this goal is met whether the destination is sparse or fully-allocated (except when explicitly punching holes, then merely reading zero is not enough to know if it is sparse, so we still want to punch the hole). Avoiding a redundant write to zero (whether in the background because the zero cluster was marked in the dirty bitmap, or in the foreground because the guest is writing zeroes) when the destination already reads as zero makes mirroring faster, and avoids allocating the destination merely because the source reports as allocated. The effect is especially pronounced when the source is a raw file. That's because when the source is a qcow2 file, the dirty bitmap only visits the portions of the source that are allocated, which tend to be non-zero. But when the source is a raw file, bdrv_co_is_allocated_above() reports the entire file as allocated so mirror_dirty_init sets the entire dirty bitmap, and it is only later during mirror_iteration that we change to consulting the more precise bdrv_co_block_status_above() to learn where the source reads as zero. Remember that since a mirror operation can write a cluster more than once (every time the guest changes the source, the destination is also changed to keep up), and the guest can change whether a given cluster reads as zero, is discarded, or has non-zero data over the course of the mirror operation, we can't take the shortcut of relying on s->target_is_zero (which is static for the life of the job) in mirror_co_zero() to see if the destination is already zero, because that information may be stale. Any solution we use must be dynamic in the face of the guest writing or discarding a cluster while the mirror has been ongoing. We could just teach mirror_co_zero() to do a block_status() probe of the destination, and skip the zeroes if the destination already reads as zero, but we know from past experience that extra block_status() calls are not always cheap (tmpfs, anyone?), especially when they are random access rather than linear. Use of block_status() of the source by the background task in a linear fashion is not our bottleneck (it's a background task, after all); but since mirroring can be done while the source is actively being changed, we don't want a slow block_status() of the destination to occur on the hot path of the guest trying to do random-access writes to the source. So this patch takes a slightly different approach: any time we have to track dirty clusters, we can also track which clusters are known to read as zero. For sync=TOP or when we are punching holes from "detect-zeroes":"unmap", the zero bitmap starts out empty, but prevents a second write zero to a cluster that was already zero by an earlier pass; for sync=FULL when we are not punching holes, the zero bitmap starts out full if the destination reads as zero during initialization. Either way, I/O to the destination can now avoid redundant write zero to a cluster that already reads as zero, all without having to do a block_status() per write on the destination. With this patch, if I create a raw sparse destination file, connect it with QMP 'blockdev-add' while leaving it at the default "discard": "ignore", then run QMP 'blockdev-mirror' with "sync": "full", the destination remains sparse rather than fully allocated. Meanwhile, a destination image that is already fully allocated remains so unless it was opened with "detect-zeroes": "unmap". And any time writing zeroes is skipped, the job counters are not incremented. Signed-off-by: Eric Blake Message-ID: <20250509204341.3553601-26-eblake@redhat.com> Reviewed-by: Stefan Hajnoczi --- block/mirror.c | 107 ++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 14 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index bca99ec206..724318f037 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -73,6 +73,7 @@ typedef struct MirrorBlockJob { size_t buf_size; int64_t bdev_length; unsigned long *cow_bitmap; + unsigned long *zero_bitmap; BdrvDirtyBitmap *dirty_bitmap; BdrvDirtyBitmapIter *dbi; uint8_t *buf; @@ -108,9 +109,12 @@ struct MirrorOp { int64_t offset; uint64_t bytes; - /* The pointee is set by mirror_co_read(), mirror_co_zero(), and - * mirror_co_discard() before yielding for the first time */ + /* + * These pointers are set by mirror_co_read(), mirror_co_zero(), and + * mirror_co_discard() before yielding for the first time + */ int64_t *bytes_handled; + bool *io_skipped; bool is_pseudo_op; bool is_active_write; @@ -408,15 +412,34 @@ static void coroutine_fn mirror_co_read(void *opaque) static void coroutine_fn mirror_co_zero(void *opaque) { MirrorOp *op = opaque; - int ret; + bool write_needed = true; + int ret = 0; op->s->in_flight++; op->s->bytes_in_flight += op->bytes; *op->bytes_handled = op->bytes; op->is_in_flight = true; - ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes, - op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0); + if (op->s->zero_bitmap) { + unsigned long end = DIV_ROUND_UP(op->offset + op->bytes, + op->s->granularity); + assert(QEMU_IS_ALIGNED(op->offset, op->s->granularity)); + assert(QEMU_IS_ALIGNED(op->bytes, op->s->granularity) || + op->offset + op->bytes == op->s->bdev_length); + if (find_next_zero_bit(op->s->zero_bitmap, end, + op->offset / op->s->granularity) == end) { + write_needed = false; + *op->io_skipped = true; + } + } + if (write_needed) { + ret = blk_co_pwrite_zeroes(op->s->target, op->offset, op->bytes, + op->s->unmap ? BDRV_REQ_MAY_UNMAP : 0); + } + if (ret >= 0 && op->s->zero_bitmap) { + bitmap_set(op->s->zero_bitmap, op->offset / op->s->granularity, + DIV_ROUND_UP(op->bytes, op->s->granularity)); + } mirror_write_complete(op, ret); } @@ -435,29 +458,43 @@ static void coroutine_fn mirror_co_discard(void *opaque) } static unsigned mirror_perform(MirrorBlockJob *s, int64_t offset, - unsigned bytes, MirrorMethod mirror_method) + unsigned bytes, MirrorMethod mirror_method, + bool *io_skipped) { MirrorOp *op; Coroutine *co; int64_t bytes_handled = -1; + assert(QEMU_IS_ALIGNED(offset, s->granularity)); + assert(QEMU_IS_ALIGNED(bytes, s->granularity) || + offset + bytes == s->bdev_length); op = g_new(MirrorOp, 1); *op = (MirrorOp){ .s = s, .offset = offset, .bytes = bytes, .bytes_handled = &bytes_handled, + .io_skipped = io_skipped, }; qemu_co_queue_init(&op->waiting_requests); switch (mirror_method) { case MIRROR_METHOD_COPY: + if (s->zero_bitmap) { + bitmap_clear(s->zero_bitmap, offset / s->granularity, + DIV_ROUND_UP(bytes, s->granularity)); + } co = qemu_coroutine_create(mirror_co_read, op); break; case MIRROR_METHOD_ZERO: + /* s->zero_bitmap handled in mirror_co_zero */ co = qemu_coroutine_create(mirror_co_zero, op); break; case MIRROR_METHOD_DISCARD: + if (s->zero_bitmap) { + bitmap_clear(s->zero_bitmap, offset / s->granularity, + DIV_ROUND_UP(bytes, s->granularity)); + } co = qemu_coroutine_create(mirror_co_discard, op); break; default: @@ -568,6 +605,7 @@ static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s) int ret = -1; int64_t io_bytes; int64_t io_bytes_acct; + bool io_skipped = false; MirrorMethod mirror_method = MIRROR_METHOD_COPY; assert(!(offset % s->granularity)); @@ -611,8 +649,10 @@ static void coroutine_fn GRAPH_UNLOCKED mirror_iteration(MirrorBlockJob *s) } io_bytes = mirror_clip_bytes(s, offset, io_bytes); - io_bytes = mirror_perform(s, offset, io_bytes, mirror_method); - if (mirror_method != MIRROR_METHOD_COPY && write_zeroes_ok) { + io_bytes = mirror_perform(s, offset, io_bytes, mirror_method, + &io_skipped); + if (io_skipped || + (mirror_method != MIRROR_METHOD_COPY && write_zeroes_ok)) { io_bytes_acct = 0; } else { io_bytes_acct = io_bytes; @@ -847,8 +887,10 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) bool punch_holes = target_bs->detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP && bdrv_can_write_zeroes_with_unmap(target_bs); + int64_t bitmap_length = DIV_ROUND_UP(s->bdev_length, s->granularity); /* Determine if the image is already zero, regardless of sync mode. */ + s->zero_bitmap = bitmap_new(bitmap_length); bdrv_graph_co_rdlock(); bs = s->mirror_top_bs->backing->bs; if (s->target_is_zero) { @@ -862,7 +904,14 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) if (ret < 0) { return ret; } else if (s->sync_mode == MIRROR_SYNC_MODE_TOP) { - /* In TOP mode, there is no benefit to a pre-zeroing pass. */ + /* + * In TOP mode, there is no benefit to a pre-zeroing pass, but + * the zero bitmap can be set if the destination already reads + * as zero and we are not punching holes. + */ + if (ret > 0 && !punch_holes) { + bitmap_set(s->zero_bitmap, 0, bitmap_length); + } } else if (ret == 0 || punch_holes) { /* * Here, we are in FULL mode; our goal is to avoid writing @@ -871,8 +920,9 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) * zeroing happened externally (ret > 0) or if we have a fast * way to pre-zero the image (the dirty bitmap will be * populated later by the non-zero portions, the same as for - * TOP mode). If pre-zeroing is not fast, or we need to punch - * holes, then our only recourse is to write the entire image. + * TOP mode). If pre-zeroing is not fast, then our only + * recourse is to mark the entire image dirty. The act of + * pre-zeroing will populate the zero bitmap. */ if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); @@ -883,6 +933,7 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) for (offset = 0; offset < s->bdev_length; ) { int bytes = MIN(s->bdev_length - offset, QEMU_ALIGN_DOWN(INT_MAX, s->granularity)); + bool ignored; mirror_throttle(s); @@ -898,12 +949,15 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) continue; } - mirror_perform(s, offset, bytes, MIRROR_METHOD_ZERO); + mirror_perform(s, offset, bytes, MIRROR_METHOD_ZERO, &ignored); offset += bytes; } mirror_wait_for_all_io(s); s->initial_zeroing_ongoing = false; + } else { + /* In FULL mode, and image already reads as zero. */ + bitmap_set(s->zero_bitmap, 0, bitmap_length); } /* First part, loop on the sectors and initialize the dirty bitmap. */ @@ -1188,6 +1242,7 @@ immediate_exit: assert(s->in_flight == 0); qemu_vfree(s->buf); g_free(s->cow_bitmap); + g_free(s->zero_bitmap); g_free(s->in_flight_bitmap); bdrv_dirty_iter_free(s->dbi); @@ -1367,6 +1422,7 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, int ret; size_t qiov_offset = 0; int64_t dirty_bitmap_offset, dirty_bitmap_end; + int64_t zero_bitmap_offset, zero_bitmap_end; if (!QEMU_IS_ALIGNED(offset, job->granularity) && bdrv_dirty_bitmap_get(job->dirty_bitmap, offset)) @@ -1410,8 +1466,9 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, } /* - * Tails are either clean or shrunk, so for bitmap resetting - * we safely align the range down. + * Tails are either clean or shrunk, so for dirty bitmap resetting + * we safely align the range narrower. But for zero bitmap, round + * range wider for checking or clearing, and narrower for setting. */ dirty_bitmap_offset = QEMU_ALIGN_UP(offset, job->granularity); dirty_bitmap_end = QEMU_ALIGN_DOWN(offset + bytes, job->granularity); @@ -1419,22 +1476,44 @@ do_sync_target_write(MirrorBlockJob *job, MirrorMethod method, bdrv_reset_dirty_bitmap(job->dirty_bitmap, dirty_bitmap_offset, dirty_bitmap_end - dirty_bitmap_offset); } + zero_bitmap_offset = offset / job->granularity; + zero_bitmap_end = DIV_ROUND_UP(offset + bytes, job->granularity); job_progress_increase_remaining(&job->common.job, bytes); job->active_write_bytes_in_flight += bytes; switch (method) { case MIRROR_METHOD_COPY: + if (job->zero_bitmap) { + bitmap_clear(job->zero_bitmap, zero_bitmap_offset, + zero_bitmap_end - zero_bitmap_offset); + } ret = blk_co_pwritev_part(job->target, offset, bytes, qiov, qiov_offset, flags); break; case MIRROR_METHOD_ZERO: + if (job->zero_bitmap) { + if (find_next_zero_bit(job->zero_bitmap, zero_bitmap_end, + zero_bitmap_offset) == zero_bitmap_end) { + ret = 0; + break; + } + } assert(!qiov); ret = blk_co_pwrite_zeroes(job->target, offset, bytes, flags); + if (job->zero_bitmap && ret >= 0) { + bitmap_set(job->zero_bitmap, dirty_bitmap_offset / job->granularity, + (dirty_bitmap_end - dirty_bitmap_offset) / + job->granularity); + } break; case MIRROR_METHOD_DISCARD: + if (job->zero_bitmap) { + bitmap_clear(job->zero_bitmap, zero_bitmap_offset, + zero_bitmap_end - zero_bitmap_offset); + } assert(!qiov); ret = blk_co_pdiscard(job->target, offset, bytes); break; From be9bac072ede6e6aa27079f59efcf17b56bd7b26 Mon Sep 17 00:00:00 2001 From: Andrey Drobyshev Date: Fri, 9 May 2025 15:40:29 -0500 Subject: [PATCH 0955/2760] iotests/common.rc: add disk_usage function Move the definition from iotests/250 to common.rc. This is used to detect real disk usage of sparse files. In particular, we want to use it for checking subclusters-based discards. Signed-off-by: Andrey Drobyshev Reviewed-by: Alexander Ivanov Reviewed-by: Alberto Garcia Message-ID: <20240913163942.423050-6-andrey.drobyshev@virtuozzo.com> Signed-off-by: Eric Blake Reviewed-by: Stefan Hajnoczi Message-ID: <20250509204341.3553601-27-eblake@redhat.com> --- tests/qemu-iotests/250 | 5 ----- tests/qemu-iotests/common.rc | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/qemu-iotests/250 b/tests/qemu-iotests/250 index af48f83aba..c0a0dbc0ff 100755 --- a/tests/qemu-iotests/250 +++ b/tests/qemu-iotests/250 @@ -52,11 +52,6 @@ _unsupported_imgopts data_file # bdrv_co_truncate(bs->file) call in qcow2_co_truncate(), which might succeed # anyway. -disk_usage() -{ - du --block-size=1 $1 | awk '{print $1}' -} - size=2100M _make_test_img -o "cluster_size=1M,preallocation=metadata" $size diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 95c12577dd..237f746af8 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -140,6 +140,12 @@ _optstr_add() fi } +# report real disk usage for sparse files +disk_usage() +{ + du --block-size=1 "$1" | awk '{print $1}' +} + # Set the variables to the empty string to turn Valgrind off # for specific processes, e.g. # $ VALGRIND_QEMU_IO= ./check -qcow2 -valgrind 015 From c0ddcb2cbc146e64f666eaae4edc7b5db7e5814d Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 9 May 2025 15:40:30 -0500 Subject: [PATCH 0956/2760] tests: Add iotest mirror-sparse for recent patches Prove that blockdev-mirror can now result in sparse raw destination files, regardless of whether the source is raw or qcow2. By making this a separate test, it was possible to test effects of individual patches for the various pieces that all have to work together for a sparse mirror to be successful. Note that ./check -file produces different job lengths than ./check -qcow2 (the test uses a filter to normalize); that's because when deciding how much of the image to be mirrored, the code looks at how much of the source image was allocated (for qcow2, this is only the written clusters; for raw, it is the entire file). But the important part is that the destination file ends up smaller than 3M, rather than the 20M it used to be before this patch series. Signed-off-by: Eric Blake Message-ID: <20250509204341.3553601-28-eblake@redhat.com> Reviewed-by: Stefan Hajnoczi --- tests/qemu-iotests/tests/mirror-sparse | 125 +++++++ tests/qemu-iotests/tests/mirror-sparse.out | 365 +++++++++++++++++++++ 2 files changed, 490 insertions(+) create mode 100755 tests/qemu-iotests/tests/mirror-sparse create mode 100644 tests/qemu-iotests/tests/mirror-sparse.out diff --git a/tests/qemu-iotests/tests/mirror-sparse b/tests/qemu-iotests/tests/mirror-sparse new file mode 100755 index 0000000000..8c52a4e244 --- /dev/null +++ b/tests/qemu-iotests/tests/mirror-sparse @@ -0,0 +1,125 @@ +#!/usr/bin/env bash +# group: rw auto quick +# +# Test blockdev-mirror with raw sparse destination +# +# Copyright (C) 2025 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +seq="$(basename $0)" +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img + _cleanup_qemu +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +cd .. +. ./common.rc +. ./common.filter +. ./common.qemu + +_supported_fmt qcow2 raw # Format of the source. dst is always raw file +_supported_proto file +_supported_os Linux + +echo +echo "=== Initial image setup ===" +echo + +TEST_IMG="$TEST_IMG.base" _make_test_img 20M +$QEMU_IO -c 'w 8M 2M' -f $IMGFMT "$TEST_IMG.base" | _filter_qemu_io + +_launch_qemu \ + -blockdev '{"driver":"file", "cache":{"direct":true, "no-flush":false}, + "filename":"'"$TEST_IMG.base"'", "node-name":"src-file"}' \ + -blockdev '{"driver":"'$IMGFMT'", "node-name":"src", "file":"src-file"}' +h1=$QEMU_HANDLE +_send_qemu_cmd $h1 '{"execute": "qmp_capabilities"}' 'return' + +# Check several combinations; most should result in a sparse destination; +# the destination should only be fully allocated if pre-allocated +# and not punching holes due to detect-zeroes +# do_test creation discard zeroes result +do_test() { + creation=$1 + discard=$2 + zeroes=$3 + expected=$4 + +echo +echo "=== Testing creation=$creation discard=$discard zeroes=$zeroes ===" +echo + +rm -f $TEST_IMG +if test $creation = external; then + truncate --size=20M $TEST_IMG +else + _send_qemu_cmd $h1 '{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"'$TEST_IMG'", + "size":'$((20*1024*1024))', "preallocation":"'$creation'"}, + "job-id":"job1"}}' 'concluded' + _send_qemu_cmd $h1 '{"execute": "job-dismiss", "arguments": + {"id": "job1"}}' 'return' +fi +_send_qemu_cmd $h1 '{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"'$TEST_IMG'", "aio":"threads", + "auto-read-only":true, "discard":"'$discard'", + "detect-zeroes":"'$zeroes'"}}' 'return' +_send_qemu_cmd $h1 '{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}}' 'return' +_timed_wait_for $h1 '"ready"' +_send_qemu_cmd $h1 '{"execute": "job-complete", "arguments": + {"id":"job2"}}' 'return' \ + | _filter_block_job_offset | _filter_block_job_len +_send_qemu_cmd $h1 '{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}}' 'return' \ + | _filter_block_job_offset | _filter_block_job_len +$QEMU_IMG compare -U -f $IMGFMT -F raw $TEST_IMG.base $TEST_IMG +result=$(disk_usage $TEST_IMG) +if test $result -lt $((3*1024*1024)); then + actual=sparse +elif test $result = $((20*1024*1024)); then + actual=full +else + actual=unknown +fi +echo "Destination is $actual; expected $expected" +} + +do_test external ignore off sparse +do_test external unmap off sparse +do_test external unmap unmap sparse +do_test off ignore off sparse +do_test off unmap off sparse +do_test off unmap unmap sparse +do_test full ignore off full +do_test full unmap off sparse +do_test full unmap unmap sparse + +_send_qemu_cmd $h1 '{"execute":"quit"}' '' + +# success, all done +echo '*** done' +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/tests/mirror-sparse.out b/tests/qemu-iotests/tests/mirror-sparse.out new file mode 100644 index 0000000000..2103b891c3 --- /dev/null +++ b/tests/qemu-iotests/tests/mirror-sparse.out @@ -0,0 +1,365 @@ +QA output created by mirror-sparse + +=== Initial image setup === + +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=20971520 +wrote 2097152/2097152 bytes at offset 8388608 +2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +{"execute": "qmp_capabilities"} +{"return": {}} + +=== Testing creation=external discard=ignore zeroes=off === + +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"ignore", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=external discard=unmap zeroes=off === + +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=external discard=unmap zeroes=unmap === + +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"unmap"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=off discard=ignore zeroes=off === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"off"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"ignore", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=off discard=unmap zeroes=off === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"off"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=off discard=unmap zeroes=unmap === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"off"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"unmap"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=full discard=ignore zeroes=off === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"full"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"ignore", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is full; expected full + +=== Testing creation=full discard=unmap zeroes=off === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"full"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"off"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse + +=== Testing creation=full discard=unmap zeroes=unmap === + +{"execute": "blockdev-create", "arguments": + {"options": {"driver":"file", "filename":"TEST_DIR/t.IMGFMT", + "size":20971520, "preallocation":"full"}, + "job-id":"job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job1"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job1"}} +{"execute": "job-dismiss", "arguments": + {"id": "job1"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job1"}} +{"return": {}} +{"execute": "blockdev-add", "arguments": + {"node-name": "dst", "driver":"file", + "filename":"TEST_DIR/t.IMGFMT", "aio":"threads", + "auto-read-only":true, "discard":"unmap", + "detect-zeroes":"unmap"}} +{"return": {}} +{"execute":"blockdev-mirror", "arguments": + {"sync":"full", "device":"src", "target":"dst", + "job-id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job2"}} +{"return": {}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "ready", "id": "job2"}} +{"execute": "job-complete", "arguments": + {"id":"job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_READY", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"return": {}} +{"execute": "blockdev-del", "arguments": + {"node-name": "dst"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job2", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job2"}} +{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job2"}} +{"return": {}} +Images are identical. +Destination is sparse; expected sparse +{"execute":"quit"} +*** done From aff46b4bf556430dd3c12fa39a457f0487bb0053 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Tue, 13 May 2025 17:00:45 -0500 Subject: [PATCH 0957/2760] mirror: Reduce I/O when destination is detect-zeroes:unmap If we are going to punch holes in the mirror destination even for the portions where the source image is unallocated, it is nicer to treat the entire image as dirty and punch as we go, rather than pre-zeroing the entire image just to re-do I/O to the allocated portions of the image. Signed-off-by: Eric Blake Message-ID: <20250513220142.535200-2-eblake@redhat.com> Reviewed-by: Stefan Hajnoczi --- block/mirror.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/block/mirror.c b/block/mirror.c index 724318f037..c2c5099c95 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -920,11 +920,16 @@ static int coroutine_fn GRAPH_UNLOCKED mirror_dirty_init(MirrorBlockJob *s) * zeroing happened externally (ret > 0) or if we have a fast * way to pre-zero the image (the dirty bitmap will be * populated later by the non-zero portions, the same as for - * TOP mode). If pre-zeroing is not fast, then our only - * recourse is to mark the entire image dirty. The act of - * pre-zeroing will populate the zero bitmap. + * TOP mode). If pre-zeroing is not fast, or we need to visit + * the entire image in order to punch holes even in the + * non-allocated regions of the source, then just mark the + * entire image dirty and leave the zero bitmap clear at this + * point in time. Otherwise, it can be faster to pre-zero the + * image now, even if we re-write the allocated portions of + * the disk later, and the pre-zero pass will populate the + * zero bitmap. */ - if (!bdrv_can_write_zeroes_with_unmap(target_bs)) { + if (!bdrv_can_write_zeroes_with_unmap(target_bs) || punch_holes) { bdrv_set_dirty_bitmap(s->dirty_bitmap, 0, s->bdev_length); return 0; } From 0b1c23a582f7bc721a9b858c289a8d165152a6a0 Mon Sep 17 00:00:00 2001 From: Klaus Jensen Date: Wed, 7 May 2025 09:30:55 +0200 Subject: [PATCH 0958/2760] hw/nvme: fix nvme hotplugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit cd59f50ab017 caused a regression on nvme hotplugging for devices with an implicit nvm subsystem. The nvme-subsys device was incorrectly left with being marked as non-hotpluggable. Fix this. Cc: qemu-stable@nongnu.org Reported-by: Stéphane Graber Tested-by: Stéphane Graber Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2950 Fixes: cd59f50ab017 ("hw/nvme: always initialize a subsystem") Reviewed-by: Keith Busch Signed-off-by: Klaus Jensen --- hw/nvme/subsys.c | 1 - 1 file changed, 1 deletion(-) diff --git a/hw/nvme/subsys.c b/hw/nvme/subsys.c index 38271d78c8..777e1c620f 100644 --- a/hw/nvme/subsys.c +++ b/hw/nvme/subsys.c @@ -226,7 +226,6 @@ static void nvme_subsys_class_init(ObjectClass *oc, const void *data) dc->realize = nvme_subsys_realize; dc->desc = "Virtual NVMe subsystem"; - dc->hotpluggable = false; device_class_set_props(dc, nvme_subsystem_props); } From 923976dfe367b0bfed45ff660c369f3fe65604a7 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 17 May 2025 13:12:07 +0200 Subject: [PATCH 0959/2760] target/hppa: Copy instruction code into fr1 on FPU assist fault The hardware stores the instruction code in the lower bits of the FP exception register #1 on FP assist traps. This fixes the FP exception handler on Linux, as the Linux kernel uses the value to decide on the correct signal which should be pushed into userspace (see decode_fpu() in Linux kernel). Signed-off-by: Helge Deller --- target/hppa/int_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/hppa/int_helper.c b/target/hppa/int_helper.c index 7d48643bb6..191ae19404 100644 --- a/target/hppa/int_helper.c +++ b/target/hppa/int_helper.c @@ -177,6 +177,10 @@ void hppa_cpu_do_interrupt(CPUState *cs) } } env->cr[CR_IIR] = ldl_phys(cs->as, paddr); + if (i == EXCP_ASSIST) { + /* stuff insn code into bits of FP exception register #1 */ + env->fr[0] |= (env->cr[CR_IIR] & 0x03ffffff); + } } break; From b4b49cf39dba5f993ad925f204cb820aacfc8e45 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 17 May 2025 13:20:17 +0200 Subject: [PATCH 0960/2760] linux-user/hppa: Send proper si_code on SIGFPE exception Improve the linux-user emulation to send the correct si_code depending on overflow (TARGET_FPE_FLTOVF), underflow (TARGET_FPE_FLTUND), ... Note that the hardware stores the relevant flags in FP exception register #1, which is actually the lower 32-bits of the 64-bit fr[0] register in qemu. Signed-off-by: Helge Deller --- linux-user/hppa/cpu_loop.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/linux-user/hppa/cpu_loop.c b/linux-user/hppa/cpu_loop.c index 890e758cd1..9abaad5ef8 100644 --- a/linux-user/hppa/cpu_loop.c +++ b/linux-user/hppa/cpu_loop.c @@ -112,7 +112,7 @@ static abi_ulong hppa_lws(CPUHPPAState *env) void cpu_loop(CPUHPPAState *env) { CPUState *cs = env_cpu(env); - abi_ulong ret; + abi_ulong ret, si_code = 0; int trapnr; while (1) { @@ -169,7 +169,15 @@ void cpu_loop(CPUHPPAState *env) force_sig_fault(TARGET_SIGFPE, TARGET_FPE_CONDTRAP, env->iaoq_f); break; case EXCP_ASSIST: - force_sig_fault(TARGET_SIGFPE, 0, env->iaoq_f); + #define set_si_code(mask, val) \ + if (env->fr[0] & mask) { si_code = val; } + set_si_code(R_FPSR_FLG_I_MASK, TARGET_FPE_FLTRES); + set_si_code(R_FPSR_FLG_U_MASK, TARGET_FPE_FLTUND); + set_si_code(R_FPSR_FLG_O_MASK, TARGET_FPE_FLTOVF); + set_si_code(R_FPSR_FLG_Z_MASK, TARGET_FPE_FLTDIV); + set_si_code(R_FPSR_FLG_V_MASK, TARGET_FPE_FLTINV); + #undef set_si_code + force_sig_fault(TARGET_SIGFPE, si_code, env->iaoq_f); break; case EXCP_BREAK: force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->iaoq_f); From ebd394948de4e868cb8fc5b265a8a18f0935dce1 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sat, 17 May 2025 13:27:48 +0200 Subject: [PATCH 0961/2760] target/hppa: Fix FPE exceptions Implement FP exception register #1 (lower 32-bits of 64-bit fr[0]). A proper implementation is necessary to allow the Linux kernel in system mode and the qemu linux-user to send proper si_code values on SIGFPE signal. Always set the T-bit on taken exception, and merge over- and underflow in system mode to just set overflow bit to mimic the behaviour I tested on a physical machine. The test program below can be used to verify correct behaviour. Note that behaviour on SIGFPE may vary on different platforms. The program should always detect the correct signal, but it may or may not be able to sucessfully continue afterwards. #define _GNU_SOURCE #include #include #include #include static void fpe_func(int sig, siginfo_t *i, void *v) { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGFPE); sigprocmask(SIG_UNBLOCK, &set, NULL); printf("GOT signal %d with si_code %ld\n", sig, i->si_code); } int main(int argc, char *argv[]) { struct sigaction action = { .sa_sigaction = fpe_func, .sa_flags = SA_RESTART|SA_SIGINFO }; sigaction(SIGFPE, &action, 0); feenableexcept(FE_OVERFLOW | FE_UNDERFLOW); double x = DBL_MIN; return printf("%lf\n", argc > 1 ? 1.7976931348623158E308*1.7976931348623158E308 : x / 10); } Signed-off-by: Helge Deller --- target/hppa/fpu_helper.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/target/hppa/fpu_helper.c b/target/hppa/fpu_helper.c index a62d9d3083..294ce0a970 100644 --- a/target/hppa/fpu_helper.c +++ b/target/hppa/fpu_helper.c @@ -95,7 +95,8 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) { uint32_t soft_exp = get_float_exception_flags(&env->fp_status); uint32_t hard_exp = 0; - uint32_t shadow = env->fr0_shadow; + uint32_t shadow = env->fr0_shadow & 0x3ffffff; + uint32_t fr1 = 0; if (likely(soft_exp == 0)) { env->fr[0] = (uint64_t)shadow << 32; @@ -108,9 +109,22 @@ static void update_fr0_op(CPUHPPAState *env, uintptr_t ra) hard_exp |= CONVERT_BIT(soft_exp, float_flag_overflow, R_FPSR_ENA_O_MASK); hard_exp |= CONVERT_BIT(soft_exp, float_flag_divbyzero, R_FPSR_ENA_Z_MASK); hard_exp |= CONVERT_BIT(soft_exp, float_flag_invalid, R_FPSR_ENA_V_MASK); - shadow |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); + if (hard_exp & shadow) { + shadow = FIELD_DP32(shadow, FPSR, T, 1); + /* fill exception register #1, which is lower 32-bits of fr[0] */ +#if !defined(CONFIG_USER_ONLY) + if (hard_exp & (R_FPSR_ENA_O_MASK | R_FPSR_ENA_U_MASK)) { + /* over- and underflow both set overflow flag only */ + fr1 = FIELD_DP32(fr1, FPSR, C, 1); + fr1 = FIELD_DP32(fr1, FPSR, FLG_O, 1); + } else +#endif + { + fr1 |= hard_exp << (R_FPSR_FLAGS_SHIFT - R_FPSR_ENABLES_SHIFT); + } + } env->fr0_shadow = shadow; - env->fr[0] = (uint64_t)shadow << 32; + env->fr[0] = (uint64_t)shadow << 32 | fr1; if (hard_exp & shadow) { hppa_dynamic_excp(env, EXCP_ASSIST, ra); From d2a88aca766697e8490504313d23002c3315ee93 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Sat, 22 Mar 2025 10:01:37 +0530 Subject: [PATCH 0962/2760] hw/riscv/virt: Add the BDF of IOMMU to RISCVVirtState structure When the IOMMU is implemented as a PCI device, its BDF is created locally in virt.c. However, the same BDF is also required in virt-acpi-build.c to support ACPI. Therefore, make this information part of the global RISCVVirtState structure so that it can be accessed outside of virt.c as well. Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Message-ID: <20250322043139.2003479-2-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 1 + include/hw/riscv/virt.h | 1 + 2 files changed, 2 insertions(+) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index be1bf0f646..5958ad1f7d 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1117,6 +1117,7 @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) qemu_fdt_setprop_cells(fdt, pci_node, "iommu-map", 0, iommu_phandle, 0, bdf, bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf); + s->pci_iommu_bdf = bdf; } static void finalize_fdt(RISCVVirtState *s) diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 48a14bea2e..7b4c2c8b7d 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -63,6 +63,7 @@ struct RISCVVirtState { const MemMapEntry *memmap; struct GPEXHost *gpex_host; OnOffAuto iommu_sys; + uint16_t pci_iommu_bdf; }; enum { From cd18dbbf9d23f309f3e46c38b99213dbe3d48d17 Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Sat, 22 Mar 2025 10:01:38 +0530 Subject: [PATCH 0963/2760] hw/riscv/virt-acpi-build: Add support for RIMT RISC-V IO Mapping Table (RIMT) is a new static ACPI table used to communicate IOMMU information to the OS. Add support for creating this table when the IOMMU is present. The specification is frozen and available at [1]. [1] - https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf Signed-off-by: Sunil V L Reviewed-by: Daniel Henrique Barboza Message-ID: <20250322043139.2003479-3-sunilvl@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt-acpi-build.c | 215 +++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 1ad6800508..1eef2fb4eb 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -198,6 +198,32 @@ acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_append(scope, dev); } +/* + * Add DSDT entry for the IOMMU platform device. + * ACPI ID for IOMMU is defined in the section 6.2 of RISC-V BRS spec. + * https://github.com/riscv-non-isa/riscv-brs/releases/download/v0.8/riscv-brs-spec.pdf + */ +static void acpi_dsdt_add_iommu_sys(Aml *scope, const MemMapEntry *iommu_memmap, + uint32_t iommu_irq) +{ + uint32_t i; + + Aml *dev = aml_device("IMU0"); + aml_append(dev, aml_name_decl("_HID", aml_string("RSCV0004"))); + aml_append(dev, aml_name_decl("_UID", aml_int(0))); + + Aml *crs = aml_resource_template(); + aml_append(crs, aml_memory32_fixed(iommu_memmap->base, + iommu_memmap->size, AML_READ_WRITE)); + for (i = iommu_irq; i < iommu_irq + 4; i++) { + aml_append(crs, aml_interrupt(AML_CONSUMER, AML_EDGE, AML_ACTIVE_LOW, + AML_EXCLUSIVE, &i, 1)); + } + + aml_append(dev, aml_name_decl("_CRS", crs)); + aml_append(scope, dev); +} + /* * Serial Port Console Redirection Table (SPCR) * Rev: 1.10 @@ -450,6 +476,9 @@ static void build_dsdt(GArray *table_data, } acpi_dsdt_add_uart(scope, &memmap[VIRT_UART0], UART0_IRQ); + if (virt_is_iommu_sys_enabled(s)) { + acpi_dsdt_add_iommu_sys(scope, &memmap[VIRT_IOMMU_SYS], IOMMU_SYS_IRQ); + } if (socket_count == 1) { virtio_acpi_dsdt_add(scope, memmap[VIRT_VIRTIO].base, @@ -602,6 +631,187 @@ static void build_madt(GArray *table_data, acpi_table_end(linker, &table); } +#define ID_MAPPING_ENTRY_SIZE 20 +#define IOMMU_ENTRY_SIZE 40 +#define RISCV_INTERRUPT_WIRE_OFFSSET 40 +#define ROOT_COMPLEX_ENTRY_SIZE 20 +#define RIMT_NODE_OFFSET 48 + +/* + * ID Mapping Structure + */ +static void build_rimt_id_mapping(GArray *table_data, uint32_t source_id_base, + uint32_t num_ids, uint32_t dest_id_base) +{ + /* Source ID Base */ + build_append_int_noprefix(table_data, source_id_base, 4); + /* Number of IDs */ + build_append_int_noprefix(table_data, num_ids, 4); + /* Destination Device ID Base */ + build_append_int_noprefix(table_data, source_id_base, 4); + /* Destination IOMMU Offset */ + build_append_int_noprefix(table_data, dest_id_base, 4); + /* Flags */ + build_append_int_noprefix(table_data, 0, 4); +} + +struct AcpiRimtIdMapping { + uint32_t source_id_base; + uint32_t num_ids; +}; +typedef struct AcpiRimtIdMapping AcpiRimtIdMapping; + +/* Build the rimt ID mapping to IOMMU for a given PCI host bridge */ +static int rimt_host_bridges(Object *obj, void *opaque) +{ + GArray *idmap_blob = opaque; + + if (object_dynamic_cast(obj, TYPE_PCI_HOST_BRIDGE)) { + PCIBus *bus = PCI_HOST_BRIDGE(obj)->bus; + + if (bus && !pci_bus_bypass_iommu(bus)) { + int min_bus, max_bus; + + pci_bus_range(bus, &min_bus, &max_bus); + + AcpiRimtIdMapping idmap = { + .source_id_base = min_bus << 8, + .num_ids = (max_bus - min_bus + 1) << 8, + }; + g_array_append_val(idmap_blob, idmap); + } + } + + return 0; +} + +static int rimt_idmap_compare(gconstpointer a, gconstpointer b) +{ + AcpiRimtIdMapping *idmap_a = (AcpiRimtIdMapping *)a; + AcpiRimtIdMapping *idmap_b = (AcpiRimtIdMapping *)b; + + return idmap_a->source_id_base - idmap_b->source_id_base; +} + +/* + * RISC-V IO Mapping Table (RIMT) + * https://github.com/riscv-non-isa/riscv-acpi-rimt/releases/download/v0.99/rimt-spec.pdf + */ +static void build_rimt(GArray *table_data, BIOSLinker *linker, + RISCVVirtState *s) +{ + int i, nb_nodes, rc_mapping_count; + size_t node_size, iommu_offset = 0; + uint32_t id = 0; + g_autoptr(GArray) iommu_idmaps = g_array_new(false, true, + sizeof(AcpiRimtIdMapping)); + + AcpiTable table = { .sig = "RIMT", .rev = 1, .oem_id = s->oem_id, + .oem_table_id = s->oem_table_id }; + + acpi_table_begin(&table, table_data); + + object_child_foreach_recursive(object_get_root(), + rimt_host_bridges, iommu_idmaps); + + /* Sort the ID mapping by Source ID Base*/ + g_array_sort(iommu_idmaps, rimt_idmap_compare); + + nb_nodes = 2; /* RC, IOMMU */ + rc_mapping_count = iommu_idmaps->len; + /* Number of RIMT Nodes */ + build_append_int_noprefix(table_data, nb_nodes, 4); + + /* Offset to Array of RIMT Nodes */ + build_append_int_noprefix(table_data, RIMT_NODE_OFFSET, 4); + build_append_int_noprefix(table_data, 0, 4); /* Reserved */ + + iommu_offset = table_data->len - table.table_offset; + /* IOMMU Device Structure */ + build_append_int_noprefix(table_data, 0, 1); /* Type - IOMMU*/ + build_append_int_noprefix(table_data, 1, 1); /* Revision */ + node_size = IOMMU_ENTRY_SIZE; + build_append_int_noprefix(table_data, node_size, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, id++, 2); /* ID */ + if (virt_is_iommu_sys_enabled(s)) { + /* Hardware ID */ + build_append_int_noprefix(table_data, 'R', 1); + build_append_int_noprefix(table_data, 'S', 1); + build_append_int_noprefix(table_data, 'C', 1); + build_append_int_noprefix(table_data, 'V', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '4', 1); + /* Base Address */ + build_append_int_noprefix(table_data, + s->memmap[VIRT_IOMMU_SYS].base, 8); + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + } else { + /* Hardware ID */ + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '1', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '0', 1); + build_append_int_noprefix(table_data, '1', 1); + build_append_int_noprefix(table_data, '4', 1); + + build_append_int_noprefix(table_data, 0, 8); /* Base Address */ + build_append_int_noprefix(table_data, 1, 4); /* Flags */ + } + + build_append_int_noprefix(table_data, 0, 4); /* Proximity Domain */ + build_append_int_noprefix(table_data, 0, 2); /* PCI Segment number */ + /* PCIe B/D/F */ + if (virt_is_iommu_sys_enabled(s)) { + build_append_int_noprefix(table_data, 0, 2); + } else { + build_append_int_noprefix(table_data, s->pci_iommu_bdf, 2); + } + /* Number of interrupt wires */ + build_append_int_noprefix(table_data, 0, 2); + /* Interrupt wire array offset */ + build_append_int_noprefix(table_data, RISCV_INTERRUPT_WIRE_OFFSSET, 2); + + /* PCIe Root Complex Node */ + build_append_int_noprefix(table_data, 1, 1); /* Type */ + build_append_int_noprefix(table_data, 1, 1); /* Revision */ + node_size = ROOT_COMPLEX_ENTRY_SIZE + + ID_MAPPING_ENTRY_SIZE * rc_mapping_count; + build_append_int_noprefix(table_data, node_size, 2); /* Length */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + build_append_int_noprefix(table_data, id++, 2); /* ID */ + build_append_int_noprefix(table_data, 0, 4); /* Flags */ + build_append_int_noprefix(table_data, 0, 2); /* Reserved */ + /* PCI Segment number */ + build_append_int_noprefix(table_data, 0, 2); + /* ID mapping array offset */ + build_append_int_noprefix(table_data, ROOT_COMPLEX_ENTRY_SIZE, 2); + /* Number of ID mappings */ + build_append_int_noprefix(table_data, rc_mapping_count, 2); + + /* Output Reference */ + AcpiRimtIdMapping *range; + + /* ID mapping array */ + for (i = 0; i < iommu_idmaps->len; i++) { + range = &g_array_index(iommu_idmaps, AcpiRimtIdMapping, i); + if (virt_is_iommu_sys_enabled(s)) { + range->source_id_base = 0; + } else { + range->source_id_base = s->pci_iommu_bdf + 1; + } + range->num_ids = 0xffff - s->pci_iommu_bdf; + build_rimt_id_mapping(table_data, range->source_id_base, + range->num_ids, iommu_offset); + } + + acpi_table_end(linker, &table); +} + /* * ACPI spec, Revision 6.5+ * 5.2.16 System Resource Affinity Table (SRAT) @@ -679,6 +889,11 @@ static void virt_acpi_build(RISCVVirtState *s, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_rhct(tables_blob, tables->linker, s); + if (virt_is_iommu_sys_enabled(s) || s->pci_iommu_bdf) { + acpi_add_table(table_offsets, tables_blob); + build_rimt(tables_blob, tables->linker, s); + } + acpi_add_table(table_offsets, tables_blob); spcr_setup(tables_blob, tables->linker, s); From 4541d205f03cf1529439f68d2ec5056685189399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lefort?= Date: Thu, 13 Mar 2025 20:30:07 +0100 Subject: [PATCH 0964/2760] target/riscv: pmp: don't allow RLB to bypass rule privileges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When Smepmp is supported, mseccfg.RLB allows bypassing locks when writing CSRs but should not affect interpretation of actual PMP rules. This is not the case with the current implementation where pmp_hart_has_privs calls pmp_is_locked which implements mseccfg.RLB bypass. This commit implements the correct behavior by removing mseccfg.RLB bypass from pmp_is_locked. RLB bypass when writing CSRs is implemented by adding a new pmp_is_readonly function that calls pmp_is_locked and check mseccfg.RLB. pmp_write_cfg and pmpaddr_csr_write are changed to use this new function. Signed-off-by: Loïc Lefort Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: LIU Zhiwei  Message-ID: <20250313193011.720075-2-loic@rivosinc.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index c13a117e3f..d8e2949aaf 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -46,11 +46,6 @@ static inline uint8_t pmp_get_a_field(uint8_t cfg) */ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) { - /* mseccfg.RLB is set */ - if (MSECCFG_RLB_ISSET(env)) { - return 0; - } - if (env->pmp_state.pmp[pmp_index].cfg_reg & PMP_LOCK) { return 1; } @@ -63,6 +58,15 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 0; } +/* + * Check whether a PMP is locked for writing or not. + * (i.e. has LOCK flag and mseccfg.RLB is unset) + */ +static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index) +{ + return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env); +} + /* * Count the number of active rules. */ @@ -91,39 +95,38 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - bool locked = true; + bool readonly = true; if (riscv_cpu_cfg(env)->ext_smepmp) { /* mseccfg.RLB is set */ if (MSECCFG_RLB_ISSET(env)) { - locked = false; + readonly = false; } /* mseccfg.MML is not set */ - if (!MSECCFG_MML_ISSET(env) && !pmp_is_locked(env, pmp_index)) { - locked = false; + if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) { + readonly = false; } /* mseccfg.MML is set */ if (MSECCFG_MML_ISSET(env)) { /* not adding execute bit */ if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { - locked = false; + readonly = false; } /* shared region and not adding X bit */ if ((val & PMP_LOCK) != PMP_LOCK && (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { - locked = false; + readonly = false; } } } else { - if (!pmp_is_locked(env, pmp_index)) { - locked = false; - } + readonly = pmp_is_readonly(env, pmp_index); } - if (locked) { - qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - locked\n"); + if (readonly) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - read only\n"); } else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) { /* If !mseccfg.MML then ignore writes with encoding RW=01 */ if ((val & PMP_WRITE) && !(val & PMP_READ) && @@ -525,14 +528,14 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg; is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg); - if (pmp_is_locked(env, addr_index + 1) && is_next_cfg_tor) { + if (pmp_is_readonly(env, addr_index + 1) && is_next_cfg_tor) { qemu_log_mask(LOG_GUEST_ERROR, - "ignoring pmpaddr write - pmpcfg + 1 locked\n"); + "ignoring pmpaddr write - pmpcfg+1 read only\n"); return; } } - if (!pmp_is_locked(env, addr_index)) { + if (!pmp_is_readonly(env, addr_index)) { if (env->pmp_state.pmp[addr_index].addr_reg != val) { env->pmp_state.pmp[addr_index].addr_reg = val; pmp_update_rule_addr(env, addr_index); @@ -543,7 +546,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, } } else { qemu_log_mask(LOG_GUEST_ERROR, - "ignoring pmpaddr write - locked\n"); + "ignoring pmpaddr write - read only\n"); } } else { qemu_log_mask(LOG_GUEST_ERROR, From 915b203745540e908943758f78f5da49e0a15e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lefort?= Date: Thu, 13 Mar 2025 20:30:08 +0100 Subject: [PATCH 0965/2760] target/riscv: pmp: move Smepmp operation conversion into a function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Loïc Lefort Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-ID: <20250313193011.720075-3-loic@rivosinc.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index d8e2949aaf..3afa16917e 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -32,6 +32,15 @@ static bool pmp_write_cfg(CPURISCVState *env, uint32_t addr_index, uint8_t val); static uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t addr_index); +/* + * Convert the PMP permissions to match the truth table in the Smepmp spec. + */ +static inline uint8_t pmp_get_smepmp_operation(uint8_t cfg) +{ + return ((cfg & PMP_LOCK) >> 4) | ((cfg & PMP_READ) << 2) | + (cfg & PMP_WRITE) | ((cfg & PMP_EXEC) >> 2); +} + /* * Accessor method to extract address matching type 'a field' from cfg reg */ @@ -356,16 +365,6 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, const uint8_t a_field = pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg); - /* - * Convert the PMP permissions to match the truth table in the - * Smepmp spec. - */ - const uint8_t smepmp_operation = - ((env->pmp_state.pmp[i].cfg_reg & PMP_LOCK) >> 4) | - ((env->pmp_state.pmp[i].cfg_reg & PMP_READ) << 2) | - (env->pmp_state.pmp[i].cfg_reg & PMP_WRITE) | - ((env->pmp_state.pmp[i].cfg_reg & PMP_EXEC) >> 2); - if (((s + e) == 2) && (PMP_AMATCH_OFF != a_field)) { /* * If the PMP entry is not off and the address is in range, @@ -384,6 +383,9 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr, /* * If mseccfg.MML Bit set, do the enhanced pmp priv check */ + const uint8_t smepmp_operation = + pmp_get_smepmp_operation(env->pmp_state.pmp[i].cfg_reg); + if (mode == PRV_M) { switch (smepmp_operation) { case 0: From 19cf1a7d9e59b71bf8d6571d4747e5c82667c3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lefort?= Date: Thu, 13 Mar 2025 20:30:09 +0100 Subject: [PATCH 0966/2760] target/riscv: pmp: fix checks on writes to pmpcfg in Smepmp MML mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With Machine Mode Lockdown (mseccfg.MML) set and RLB not set, checks on pmpcfg writes would match the wrong cases of Smepmp truth table. The existing code allows writes for the following cases: - L=1, X=0: cases 8, 10, 12, 14 - L=0, RWX!=WX: cases 0-2, 4-6 This leaves cases 3, 7, 9, 11, 13, 15 for which writes are ignored. From the Smepmp specification: "Adding a rule with executable privileges that either is M-mode-only or a locked Shared-Region is not possible (...)" This description matches cases 9-11, 13 of the truth table. This commit implements an explicit check for these cases by using pmp_get_epmp_operation to convert between PMP configuration and Smepmp truth table cases. Signed-off-by: Loïc Lefort Reviewed-by: Daniel Henrique Barboza Reviewed-by: LIU Zhiwei Message-ID: <20250313193011.720075-4-loic@rivosinc.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/pmp.c | 79 +++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 3afa16917e..8fc313990a 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -76,6 +76,44 @@ static int pmp_is_readonly(CPURISCVState *env, uint32_t pmp_index) return pmp_is_locked(env, pmp_index) && !MSECCFG_RLB_ISSET(env); } +/* + * Check whether `val` is an invalid Smepmp config value + */ +static int pmp_is_invalid_smepmp_cfg(CPURISCVState *env, uint8_t val) +{ + /* No check if mseccfg.MML is not set or if mseccfg.RLB is set */ + if (!MSECCFG_MML_ISSET(env) || MSECCFG_RLB_ISSET(env)) { + return 0; + } + + /* + * Adding a rule with executable privileges that either is M-mode-only + * or a locked Shared-Region is not possible + */ + switch (pmp_get_smepmp_operation(val)) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 12: + case 14: + case 15: + return 0; + case 9: + case 10: + case 11: + case 13: + return 1; + default: + g_assert_not_reached(); + } +} + /* * Count the number of active rules. */ @@ -104,44 +142,13 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { - bool readonly = true; - - if (riscv_cpu_cfg(env)->ext_smepmp) { - /* mseccfg.RLB is set */ - if (MSECCFG_RLB_ISSET(env)) { - readonly = false; - } - - /* mseccfg.MML is not set */ - if (!MSECCFG_MML_ISSET(env) && !pmp_is_readonly(env, pmp_index)) { - readonly = false; - } - - /* mseccfg.MML is set */ - if (MSECCFG_MML_ISSET(env)) { - /* not adding execute bit */ - if ((val & PMP_LOCK) != 0 && (val & PMP_EXEC) != PMP_EXEC) { - readonly = false; - } - /* shared region and not adding X bit */ - if ((val & PMP_LOCK) != PMP_LOCK && - (val & 0x7) != (PMP_WRITE | PMP_EXEC)) { - readonly = false; - } - } - } else { - readonly = pmp_is_readonly(env, pmp_index); - } - - if (readonly) { + if (pmp_is_readonly(env, pmp_index)) { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - read only\n"); - } else if (env->pmp_state.pmp[pmp_index].cfg_reg != val) { - /* If !mseccfg.MML then ignore writes with encoding RW=01 */ - if ((val & PMP_WRITE) && !(val & PMP_READ) && - !MSECCFG_MML_ISSET(env)) { - return false; - } + } else if (pmp_is_invalid_smepmp_cfg(env, val)) { + qemu_log_mask(LOG_GUEST_ERROR, + "ignoring pmpcfg write - invalid\n"); + } else { env->pmp_state.pmp[pmp_index].cfg_reg = val; pmp_update_rule_addr(env, pmp_index); return true; From 0c60c531f53544117f96d508fd9918f78ecf0df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lefort?= Date: Thu, 13 Mar 2025 20:30:10 +0100 Subject: [PATCH 0967/2760] target/riscv: pmp: exit csr writes early if value was not changed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Loïc Lefort Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-ID: <20250313193011.720075-5-loic@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 8fc313990a..4070e21ea3 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -142,6 +142,11 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index) static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val) { if (pmp_index < MAX_RISCV_PMPS) { + if (env->pmp_state.pmp[pmp_index].cfg_reg == val) { + /* no change */ + return false; + } + if (pmp_is_readonly(env, pmp_index)) { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpcfg write - read only\n"); @@ -529,6 +534,11 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, bool is_next_cfg_tor = false; if (addr_index < MAX_RISCV_PMPS) { + if (env->pmp_state.pmp[addr_index].addr_reg == val) { + /* no change */ + return; + } + /* * In TOR mode, need to check the lock bit of the next pmp * (if there is a next). @@ -545,14 +555,12 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index, } if (!pmp_is_readonly(env, addr_index)) { - if (env->pmp_state.pmp[addr_index].addr_reg != val) { - env->pmp_state.pmp[addr_index].addr_reg = val; - pmp_update_rule_addr(env, addr_index); - if (is_next_cfg_tor) { - pmp_update_rule_addr(env, addr_index + 1); - } - tlb_flush(env_cpu(env)); + env->pmp_state.pmp[addr_index].addr_reg = val; + pmp_update_rule_addr(env, addr_index); + if (is_next_cfg_tor) { + pmp_update_rule_addr(env, addr_index + 1); } + tlb_flush(env_cpu(env)); } else { qemu_log_mask(LOG_GUEST_ERROR, "ignoring pmpaddr write - read only\n"); From 986222f0f994671190a94836a373fd64992cd271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Lefort?= Date: Thu, 13 Mar 2025 20:30:11 +0100 Subject: [PATCH 0968/2760] target/riscv: pmp: remove redundant check in pmp_is_locked MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove useless check in pmp_is_locked, the function will return 0 in either case. Signed-off-by: Loïc Lefort Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-ID: <20250313193011.720075-6-loic@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/pmp.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 4070e21ea3..5af295e410 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -59,11 +59,6 @@ static inline int pmp_is_locked(CPURISCVState *env, uint32_t pmp_index) return 1; } - /* Top PMP has no 'next' to check */ - if ((pmp_index + 1u) >= MAX_RISCV_PMPS) { - return 0; - } - return 0; } From 28c12c1f2f50d7f7f1ebfc587c4777ecd50aac5b Mon Sep 17 00:00:00 2001 From: Paolo Savini Date: Wed, 12 Mar 2025 15:55:47 +0000 Subject: [PATCH 0969/2760] Generate strided vector loads/stores with tcg nodes. This commit improves the performance of QEMU when emulating strided vector loads and stores by substituting the call for the helper function with the generation of equivalent TCG operations. Signed-off-by: Paolo Savini Reviewed-by: Daniel Henrique Barboza Message-ID: <20250312155547.289642-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 327 ++++++++++++++++++++---- 1 file changed, 275 insertions(+), 52 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index b9883a5d32..7079f758ad 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -802,32 +802,286 @@ GEN_VEXT_TRANS(vlm_v, MO_8, vlm_v, ld_us_mask_op, ld_us_mask_check) GEN_VEXT_TRANS(vsm_v, MO_8, vsm_v, st_us_mask_op, st_us_mask_check) /* - *** stride load and store + * MAXSZ returns the maximum vector size can be operated in bytes, + * which is used in GVEC IR when vl_eq_vlmax flag is set to true + * to accelerate vector operation. */ -typedef void gen_helper_ldst_stride(TCGv_ptr, TCGv_ptr, TCGv, - TCGv, TCGv_env, TCGv_i32); - -static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, - uint32_t data, gen_helper_ldst_stride *fn, - DisasContext *s) +static inline uint32_t MAXSZ(DisasContext *s) { - TCGv_ptr dest, mask; - TCGv base, stride; - TCGv_i32 desc; + int max_sz = s->cfg_ptr->vlenb << 3; + return max_sz >> (3 - s->lmul); +} - dest = tcg_temp_new_ptr(); - mask = tcg_temp_new_ptr(); - base = get_gpr(s, rs1, EXT_NONE); - stride = get_gpr(s, rs2, EXT_NONE); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, - s->cfg_ptr->vlenb, data)); +static inline uint32_t get_log2(uint32_t a) +{ + uint32_t i = 0; + for (; a > 0;) { + a >>= 1; + i++; + } + return i; +} - tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - tcg_gen_addi_ptr(mask, tcg_env, vreg_ofs(s, 0)); +typedef void gen_tl_ldst(TCGv, TCGv_ptr, tcg_target_long); + +/* + * Simulate the strided load/store main loop: + * + * for (i = env->vstart; i < env->vl; env->vstart = ++i) { + * k = 0; + * while (k < nf) { + * if (!vm && !vext_elem_mask(v0, i)) { + * vext_set_elems_1s(vd, vma, (i + k * max_elems) * esz, + * (i + k * max_elems + 1) * esz); + * k++; + * continue; + * } + * target_ulong addr = base + stride * i + (k << log2_esz); + * ldst(env, adjust_addr(env, addr), i + k * max_elems, vd, ra); + * k++; + * } + * } + */ +static void gen_ldst_stride_main_loop(DisasContext *s, TCGv dest, uint32_t rs1, + uint32_t rs2, uint32_t vm, uint32_t nf, + gen_tl_ldst *ld_fn, gen_tl_ldst *st_fn, + bool is_load) +{ + TCGv addr = tcg_temp_new(); + TCGv base = get_gpr(s, rs1, EXT_NONE); + TCGv stride = get_gpr(s, rs2, EXT_NONE); + + TCGv i = tcg_temp_new(); + TCGv i_esz = tcg_temp_new(); + TCGv k = tcg_temp_new(); + TCGv k_esz = tcg_temp_new(); + TCGv k_max = tcg_temp_new(); + TCGv mask = tcg_temp_new(); + TCGv mask_offs = tcg_temp_new(); + TCGv mask_offs_64 = tcg_temp_new(); + TCGv mask_elem = tcg_temp_new(); + TCGv mask_offs_rem = tcg_temp_new(); + TCGv vreg = tcg_temp_new(); + TCGv dest_offs = tcg_temp_new(); + TCGv stride_offs = tcg_temp_new(); + + uint32_t max_elems = MAXSZ(s) >> s->sew; + + TCGLabel *start = gen_new_label(); + TCGLabel *end = gen_new_label(); + TCGLabel *start_k = gen_new_label(); + TCGLabel *inc_k = gen_new_label(); + TCGLabel *end_k = gen_new_label(); + + MemOp atomicity = MO_ATOM_NONE; + if (s->sew == 0) { + atomicity = MO_ATOM_NONE; + } else { + atomicity = MO_ATOM_IFALIGN_PAIR; + } mark_vs_dirty(s); - fn(dest, mask, base, stride, tcg_env, desc); + tcg_gen_addi_tl(mask, (TCGv)tcg_env, vreg_ofs(s, 0)); + + /* Start of outer loop. */ + tcg_gen_mov_tl(i, cpu_vstart); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, i, cpu_vl, end); + tcg_gen_shli_tl(i_esz, i, s->sew); + /* Start of inner loop. */ + tcg_gen_movi_tl(k, 0); + gen_set_label(start_k); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end_k); + /* + * If we are in mask agnostic regime and the operation is not unmasked we + * set the inactive elements to 1. + */ + if (!vm && s->vma) { + TCGLabel *active_element = gen_new_label(); + /* (i + k * max_elems) * esz */ + tcg_gen_shli_tl(mask_offs, k, get_log2(max_elems << s->sew)); + tcg_gen_add_tl(mask_offs, mask_offs, i_esz); + + /* + * Check whether the i bit of the mask is 0 or 1. + * + * static inline int vext_elem_mask(void *v0, int index) + * { + * int idx = index / 64; + * int pos = index % 64; + * return (((uint64_t *)v0)[idx] >> pos) & 1; + * } + */ + tcg_gen_shri_tl(mask_offs_64, mask_offs, 3); + tcg_gen_add_tl(mask_offs_64, mask_offs_64, mask); + tcg_gen_ld_i64((TCGv_i64)mask_elem, (TCGv_ptr)mask_offs_64, 0); + tcg_gen_rem_tl(mask_offs_rem, mask_offs, tcg_constant_tl(8)); + tcg_gen_shr_tl(mask_elem, mask_elem, mask_offs_rem); + tcg_gen_andi_tl(mask_elem, mask_elem, 1); + tcg_gen_brcond_tl(TCG_COND_NE, mask_elem, tcg_constant_tl(0), + active_element); + /* + * Set masked-off elements in the destination vector register to 1s. + * Store instructions simply skip this bit as memory ops access memory + * only for active elements. + */ + if (is_load) { + tcg_gen_shli_tl(mask_offs, mask_offs, s->sew); + tcg_gen_add_tl(mask_offs, mask_offs, dest); + st_fn(tcg_constant_tl(-1), (TCGv_ptr)mask_offs, 0); + } + tcg_gen_br(inc_k); + gen_set_label(active_element); + } + /* + * The element is active, calculate the address with stride: + * target_ulong addr = base + stride * i + (k << log2_esz); + */ + tcg_gen_mul_tl(stride_offs, stride, i); + tcg_gen_shli_tl(k_esz, k, s->sew); + tcg_gen_add_tl(stride_offs, stride_offs, k_esz); + tcg_gen_add_tl(addr, base, stride_offs); + /* Calculate the offset in the dst/src vector register. */ + tcg_gen_shli_tl(k_max, k, get_log2(max_elems)); + tcg_gen_add_tl(dest_offs, i, k_max); + tcg_gen_shli_tl(dest_offs, dest_offs, s->sew); + tcg_gen_add_tl(dest_offs, dest_offs, dest); + if (is_load) { + tcg_gen_qemu_ld_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); + st_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + } else { + ld_fn((TCGv)vreg, (TCGv_ptr)dest_offs, 0); + tcg_gen_qemu_st_tl(vreg, addr, s->mem_idx, MO_LE | s->sew | atomicity); + } + /* + * We don't execute the load/store above if the element was inactive. + * We jump instead directly to incrementing k and continuing the loop. + */ + if (!vm && s->vma) { + gen_set_label(inc_k); + } + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start_k); + /* End of the inner loop. */ + gen_set_label(end_k); + + tcg_gen_addi_tl(i, i, 1); + tcg_gen_mov_tl(cpu_vstart, i); + tcg_gen_br(start); + + /* End of the outer loop. */ + gen_set_label(end); + + return; +} + + +/* + * Set the tail bytes of the strided loads/stores to 1: + * + * for (k = 0; k < nf; ++k) { + * cnt = (k * max_elems + vl) * esz; + * tot = (k * max_elems + max_elems) * esz; + * for (i = cnt; i < tot; i += esz) { + * store_1s(-1, vd[vl+i]); + * } + * } + */ +static void gen_ldst_stride_tail_loop(DisasContext *s, TCGv dest, uint32_t nf, + gen_tl_ldst *st_fn) +{ + TCGv i = tcg_temp_new(); + TCGv k = tcg_temp_new(); + TCGv tail_cnt = tcg_temp_new(); + TCGv tail_tot = tcg_temp_new(); + TCGv tail_addr = tcg_temp_new(); + + TCGLabel *start = gen_new_label(); + TCGLabel *end = gen_new_label(); + TCGLabel *start_i = gen_new_label(); + TCGLabel *end_i = gen_new_label(); + + uint32_t max_elems_b = MAXSZ(s); + uint32_t esz = 1 << s->sew; + + /* Start of the outer loop. */ + tcg_gen_movi_tl(k, 0); + tcg_gen_shli_tl(tail_cnt, cpu_vl, s->sew); + tcg_gen_movi_tl(tail_tot, max_elems_b); + tcg_gen_add_tl(tail_addr, dest, tail_cnt); + gen_set_label(start); + tcg_gen_brcond_tl(TCG_COND_GE, k, tcg_constant_tl(nf), end); + /* Start of the inner loop. */ + tcg_gen_mov_tl(i, tail_cnt); + gen_set_label(start_i); + tcg_gen_brcond_tl(TCG_COND_GE, i, tail_tot, end_i); + /* store_1s(-1, vd[vl+i]); */ + st_fn(tcg_constant_tl(-1), (TCGv_ptr)tail_addr, 0); + tcg_gen_addi_tl(tail_addr, tail_addr, esz); + tcg_gen_addi_tl(i, i, esz); + tcg_gen_br(start_i); + /* End of the inner loop. */ + gen_set_label(end_i); + /* Update the counts */ + tcg_gen_addi_tl(tail_cnt, tail_cnt, max_elems_b); + tcg_gen_addi_tl(tail_tot, tail_cnt, max_elems_b); + tcg_gen_addi_tl(k, k, 1); + tcg_gen_br(start); + /* End of the outer loop. */ + gen_set_label(end); + + return; +} + +static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, + uint32_t data, DisasContext *s, bool is_load) +{ + if (!s->vstart_eq_zero) { + return false; + } + + TCGv dest = tcg_temp_new(); + + uint32_t nf = FIELD_EX32(data, VDATA, NF); + uint32_t vm = FIELD_EX32(data, VDATA, VM); + + /* Destination register and mask register */ + tcg_gen_addi_tl(dest, (TCGv)tcg_env, vreg_ofs(s, vd)); + + /* + * Select the appropriate load/tore to retrieve data from the vector + * register given a specific sew. + */ + static gen_tl_ldst * const ld_fns[4] = { + tcg_gen_ld8u_tl, tcg_gen_ld16u_tl, + tcg_gen_ld32u_tl, tcg_gen_ld_tl + }; + + static gen_tl_ldst * const st_fns[4] = { + tcg_gen_st8_tl, tcg_gen_st16_tl, + tcg_gen_st32_tl, tcg_gen_st_tl + }; + + gen_tl_ldst *ld_fn = ld_fns[s->sew]; + gen_tl_ldst *st_fn = st_fns[s->sew]; + + if (ld_fn == NULL || st_fn == NULL) { + return false; + } + + mark_vs_dirty(s); + + gen_ldst_stride_main_loop(s, dest, rs1, rs2, vm, nf, ld_fn, st_fn, is_load); + + tcg_gen_movi_tl(cpu_vstart, 0); + + /* + * Set the tail bytes to 1 if tail agnostic: + */ + if (s->vta != 0 && is_load) { + gen_ldst_stride_tail_loop(s, dest, nf, st_fn); + } finalize_rvv_inst(s); return true; @@ -836,16 +1090,6 @@ static bool ldst_stride_trans(uint32_t vd, uint32_t rs1, uint32_t rs2, static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) { uint32_t data = 0; - gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] = { - gen_helper_vlse8_v, gen_helper_vlse16_v, - gen_helper_vlse32_v, gen_helper_vlse64_v - }; - - fn = fns[eew]; - if (fn == NULL) { - return false; - } uint8_t emul = vext_get_emul(s, eew); data = FIELD_DP32(data, VDATA, VM, a->vm); @@ -853,7 +1097,7 @@ static bool ld_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) data = FIELD_DP32(data, VDATA, NF, a->nf); data = FIELD_DP32(data, VDATA, VTA, s->vta); data = FIELD_DP32(data, VDATA, VMA, s->vma); - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, true); } static bool ld_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -871,23 +1115,13 @@ GEN_VEXT_TRANS(vlse64_v, MO_64, rnfvm, ld_stride_op, ld_stride_check) static bool st_stride_op(DisasContext *s, arg_rnfvm *a, uint8_t eew) { uint32_t data = 0; - gen_helper_ldst_stride *fn; - static gen_helper_ldst_stride * const fns[4] = { - /* masked stride store */ - gen_helper_vsse8_v, gen_helper_vsse16_v, - gen_helper_vsse32_v, gen_helper_vsse64_v - }; uint8_t emul = vext_get_emul(s, eew); data = FIELD_DP32(data, VDATA, VM, a->vm); data = FIELD_DP32(data, VDATA, LMUL, emul); data = FIELD_DP32(data, VDATA, NF, a->nf); - fn = fns[eew]; - if (fn == NULL) { - return false; - } - return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, fn, s); + return ldst_stride_trans(a->rd, a->rs1, a->rs2, data, s, false); } static bool st_stride_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) @@ -1169,17 +1403,6 @@ GEN_LDST_WHOLE_TRANS(vs8r_v, 8) *** Vector Integer Arithmetic Instructions */ -/* - * MAXSZ returns the maximum vector size can be operated in bytes, - * which is used in GVEC IR when vl_eq_vlmax flag is set to true - * to accelerate vector operation. - */ -static inline uint32_t MAXSZ(DisasContext *s) -{ - int max_sz = s->cfg_ptr->vlenb * 8; - return max_sz >> (3 - s->lmul); -} - static bool opivv_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && From 4c1a39eebc6a9f1db816ff6c23e3d42ba52e2601 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:33 +0100 Subject: [PATCH 0970/2760] hw/misc: Add MPFS system reset support Signed-off-by: Sebastian Huber Acked-by: Alistair Francis Message-ID: <20250319061342.26435-2-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- hw/misc/mchp_pfsoc_sysreg.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/misc/mchp_pfsoc_sysreg.c b/hw/misc/mchp_pfsoc_sysreg.c index bfa78d3d2f..f47c835f80 100644 --- a/hw/misc/mchp_pfsoc_sysreg.c +++ b/hw/misc/mchp_pfsoc_sysreg.c @@ -27,7 +27,9 @@ #include "hw/irq.h" #include "hw/sysbus.h" #include "hw/misc/mchp_pfsoc_sysreg.h" +#include "system/runstate.h" +#define MSS_RESET_CR 0x18 #define ENVM_CR 0xb8 #define MESSAGE_INT 0x118c @@ -56,6 +58,11 @@ static void mchp_pfsoc_sysreg_write(void *opaque, hwaddr offset, { MchpPfSoCSysregState *s = opaque; switch (offset) { + case MSS_RESET_CR: + if (value == 0xdead) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } + break; case MESSAGE_INT: qemu_irq_lower(s->irq); break; From cae44a92ab23811deeefa0a44b1bdec6cfa8e4b9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:34 +0100 Subject: [PATCH 0971/2760] hw/riscv: More flexible FDT placement for MPFS If the kernel entry is in the high DRAM area, place the FDT into this area. Signed-off-by: Sebastian Huber Reviewed-by: Alistair Francis Message-ID: <20250319061342.26435-3-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- hw/riscv/microchip_pfsoc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index e39ee657cd..6bb44e3ac5 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -626,8 +626,15 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) kernel_entry = boot_info.image_low_addr; /* Compute the fdt load address in dram */ - fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, - memmap[MICROCHIP_PFSOC_DRAM_LO].size, + hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + + if (kernel_entry - kernel_ram_base >= kernel_ram_size) { + kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; + kernel_ram_size = mem_high_size; + } + + fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); From 0c2ca9e4d139acc762325d994614a42dba31be6a Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:35 +0100 Subject: [PATCH 0972/2760] hw/riscv: Make FDT optional for MPFS Real-time kernels such as RTEMS or Zephyr may use a static device tree built into the kernel image. Do not require to use the -dtb option if -kernel is used for the microchip-icicle-kit machine. Issue a warning if no device tree is provided by the user since the machine does not generate one. Signed-off-by: Sebastian Huber Reviewed-by: Alistair Francis Message-ID: <20250319061342.26435-4-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- hw/riscv/microchip_pfsoc.c | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 6bb44e3ac5..b8a8d5251d 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -516,7 +516,6 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) uint64_t mem_low_size, mem_high_size; hwaddr firmware_load_addr; const char *firmware_name; - bool kernel_as_payload = false; target_ulong firmware_end_addr, kernel_start_addr; uint64_t kernel_entry; uint64_t fdt_load_addr; @@ -589,25 +588,12 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) * * This ensures backwards compatibility with how we used to expose -bios * to users but allows them to run through direct kernel booting as well. - * - * When -kernel is used for direct boot, -dtb must be present to provide - * a valid device tree for the board, as we don't generate device tree. */ - if (machine->kernel_filename && machine->dtb) { - int fdt_size; - machine->fdt = load_device_tree(machine->dtb, &fdt_size); - if (!machine->fdt) { - error_report("load_device_tree() failed"); - exit(1); - } - + if (machine->kernel_filename) { firmware_name = RISCV64_BIOS_BIN; firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; - kernel_as_payload = true; - } - - if (!kernel_as_payload) { + } else { firmware_name = BIOS_FILENAME; firmware_load_addr = RESET_VECTOR; } @@ -617,7 +603,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) &firmware_load_addr, NULL); riscv_boot_info_init(&boot_info, &s->soc.u_cpus); - if (kernel_as_payload) { + if (machine->kernel_filename) { kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); @@ -625,19 +611,33 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) true, NULL); kernel_entry = boot_info.image_low_addr; - /* Compute the fdt load address in dram */ - hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; - hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + if (machine->dtb) { + int fdt_size; + machine->fdt = load_device_tree(machine->dtb, &fdt_size); + if (!machine->fdt) { + error_report("load_device_tree() failed"); + exit(1); + } - if (kernel_entry - kernel_ram_base >= kernel_ram_size) { - kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; - kernel_ram_size = mem_high_size; + /* Compute the FDT load address in DRAM */ + hwaddr kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + hwaddr kernel_ram_size = memmap[MICROCHIP_PFSOC_DRAM_LO].size; + + if (kernel_entry - kernel_ram_base >= kernel_ram_size) { + kernel_ram_base = memmap[MICROCHIP_PFSOC_DRAM_HI].base; + kernel_ram_size = mem_high_size; + } + + fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, + machine, &boot_info); + riscv_load_fdt(fdt_load_addr, machine->fdt); + } else { + warn_report_once("The QEMU microchip-icicle-kit machine does not " + "generate a device tree, so no device tree is " + "being provided to the guest."); + fdt_load_addr = 0; } - fdt_load_addr = riscv_compute_fdt_addr(kernel_ram_base, kernel_ram_size, - machine, &boot_info); - riscv_load_fdt(fdt_load_addr, machine->fdt); - /* Load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, memmap[MICROCHIP_PFSOC_ENVM_DATA].base, From 6dd6f11710c713bd21ac67ab93f6db33169c6b4d Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:36 +0100 Subject: [PATCH 0973/2760] hw/riscv: Allow direct start of kernel for MPFS Further customize the -bios and -kernel options behaviour for the microchip-icicle-kit machine. If "-bios none -kernel filename" is specified, then do not load a firmware and instead only load and start the kernel image. For test runs, use an approach similar to riscv_find_and_load_firmware(). Signed-off-by: Sebastian Huber Reviewed-by: Alistair Francis Message-ID: <20250319061342.26435-5-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- hw/riscv/microchip_pfsoc.c | 59 +++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index b8a8d5251d..6e5b17c05f 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -578,29 +578,47 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } /* - * We follow the following table to select which payload we execute. + * We follow the following table to select which firmware we use. * - * -bios | -kernel | payload - * -------+------------+-------- - * N | N | HSS - * Y | don't care | HSS - * N | Y | kernel - * - * This ensures backwards compatibility with how we used to expose -bios - * to users but allows them to run through direct kernel booting as well. + * -bios | -kernel | firmware + * --------------+------------+-------- + * none | N | error + * none | Y | kernel + * NULL, default | N | BIOS_FILENAME + * NULL, default | Y | RISCV64_BIOS_BIN + * other | don't care | other */ + if (machine->firmware && !strcmp(machine->firmware, "none")) { + if (!machine->kernel_filename) { + error_report("for -bios none, a kernel is required"); + exit(1); + } - if (machine->kernel_filename) { - firmware_name = RISCV64_BIOS_BIN; - firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + firmware_name = NULL; + firmware_load_addr = RESET_VECTOR; + } else if (!machine->firmware || !strcmp(machine->firmware, "default")) { + if (machine->kernel_filename) { + firmware_name = RISCV64_BIOS_BIN; + firmware_load_addr = memmap[MICROCHIP_PFSOC_DRAM_LO].base; + } else { + firmware_name = BIOS_FILENAME; + firmware_load_addr = RESET_VECTOR; + } } else { - firmware_name = BIOS_FILENAME; + firmware_name = machine->firmware; firmware_load_addr = RESET_VECTOR; } - /* Load the firmware */ - firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, - &firmware_load_addr, NULL); + /* Load the firmware if necessary */ + firmware_end_addr = firmware_load_addr; + if (firmware_name) { + char *filename = riscv_find_firmware(firmware_name, NULL); + if (filename) { + firmware_end_addr = riscv_load_firmware(filename, + &firmware_load_addr, NULL); + g_free(filename); + } + } riscv_boot_info_init(&boot_info, &s->soc.u_cpus); if (machine->kernel_filename) { @@ -638,8 +656,15 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) fdt_load_addr = 0; } + hwaddr start_addr; + if (firmware_name) { + start_addr = firmware_load_addr; + } else { + start_addr = kernel_entry; + } + /* Load the reset vector */ - riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, firmware_load_addr, + riscv_setup_rom_reset_vec(machine, &s->soc.u_cpus, start_addr, memmap[MICROCHIP_PFSOC_ENVM_DATA].base, memmap[MICROCHIP_PFSOC_ENVM_DATA].size, kernel_entry, fdt_load_addr); From e40b75fe5c94c6656e8ffcb0b9559b09882fa01b Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:37 +0100 Subject: [PATCH 0974/2760] hw/riscv: Configurable MPFS CLINT timebase freq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property enables the setting of the CLINT timebase frequency through the command line, for example: -machine microchip-icicle-kit,clint-timebase-frequency=10000000 Signed-off-by: Sebastian Huber Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-ID: <20250319061342.26435-6-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- hw/riscv/microchip_pfsoc.c | 49 +++++++++++++++++++++++++++--- include/hw/riscv/microchip_pfsoc.h | 1 + 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index 6e5b17c05f..2e74783fce 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -39,6 +39,7 @@ #include "qemu/units.h" #include "qemu/cutils.h" #include "qapi/error.h" +#include "qapi/visitor.h" #include "hw/boards.h" #include "hw/loader.h" #include "hw/sysbus.h" @@ -61,9 +62,6 @@ #define BIOS_FILENAME "hss.bin" #define RESET_VECTOR 0x20220000 -/* CLINT timebase frequency */ -#define CLINT_TIMEBASE_FREQ 1000000 - /* GEM version */ #define GEM_REVISION 0x0107010c @@ -193,6 +191,7 @@ static void microchip_pfsoc_soc_instance_init(Object *obj) static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); + MicrochipIcicleKitState *iks = MICROCHIP_ICICLE_KIT_MACHINE(ms); MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); const MemMapEntry *memmap = microchip_pfsoc_memmap; MemoryRegion *system_memory = get_system_memory(); @@ -253,7 +252,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) memmap[MICROCHIP_PFSOC_CLINT].base + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, - CLINT_TIMEBASE_FREQ, false); + iks->clint_timebase_freq, false); /* L2 cache controller */ create_unimplemented_device("microchip.pfsoc.l2cc", @@ -671,6 +670,40 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) } } +static void microchip_icicle_kit_set_clint_timebase_freq(Object *obj, + Visitor *v, + const char *name, + void *opaque, + Error **errp) +{ + MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); + uint32_t value; + + if (!visit_type_uint32(v, name, &value, errp)) { + return; + } + + s->clint_timebase_freq = value; +} + +static void microchip_icicle_kit_get_clint_timebase_freq(Object *obj, + Visitor *v, + const char *name, + void *opaque, + Error **errp) +{ + MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(obj); + uint32_t value = s->clint_timebase_freq; + + visit_type_uint32(v, name, &value, errp); +} + +static void microchip_icicle_kit_machine_instance_init(Object *obj) +{ + MicrochipIcicleKitState *m = MICROCHIP_ICICLE_KIT_MACHINE(obj); + m->clint_timebase_freq = 1000000; +} + static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, const void *data) { @@ -693,12 +726,20 @@ static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, * See memory_tests() in mss_ddr.c in the HSS source code. */ mc->default_ram_size = 1537 * MiB; + + object_class_property_add(oc, "clint-timebase-frequency", "uint32_t", + microchip_icicle_kit_get_clint_timebase_freq, + microchip_icicle_kit_set_clint_timebase_freq, + NULL, NULL); + object_class_property_set_description(oc, "clint-timebase-frequency", + "Set CLINT timebase frequency in Hz."); } static const TypeInfo microchip_icicle_kit_machine_typeinfo = { .name = MACHINE_TYPE_NAME("microchip-icicle-kit"), .parent = TYPE_MACHINE, .class_init = microchip_icicle_kit_machine_class_init, + .instance_init = microchip_icicle_kit_machine_instance_init, .instance_size = sizeof(MicrochipIcicleKitState), }; diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h index daef086da6..7ca9b976c1 100644 --- a/include/hw/riscv/microchip_pfsoc.h +++ b/include/hw/riscv/microchip_pfsoc.h @@ -67,6 +67,7 @@ typedef struct MicrochipIcicleKitState { MachineState parent_obj; /*< public >*/ + uint32_t clint_timebase_freq; MicrochipPFSoCState soc; } MicrochipIcicleKitState; From dd07ab1121ffd7003ae2cffde3046acd3123bbbd Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 19 Mar 2025 07:13:38 +0100 Subject: [PATCH 0975/2760] hw/riscv: microchip_pfsoc: Rework documentation Mention that running the HSS no longer works. Document the changed boot options. Reorder documentation blocks. Update URLs. Signed-off-by: Sebastian Huber Reviewed-by: Alistair Francis Message-ID: <20250319061342.26435-7-sebastian.huber@embedded-brains.de> Signed-off-by: Alistair Francis --- docs/system/riscv/microchip-icicle-kit.rst | 126 +++++++-------------- 1 file changed, 44 insertions(+), 82 deletions(-) diff --git a/docs/system/riscv/microchip-icicle-kit.rst b/docs/system/riscv/microchip-icicle-kit.rst index 40798b1aae..9809e94b84 100644 --- a/docs/system/riscv/microchip-icicle-kit.rst +++ b/docs/system/riscv/microchip-icicle-kit.rst @@ -5,10 +5,10 @@ Microchip PolarFire SoC Icicle Kit integrates a PolarFire SoC, with one SiFive's E51 plus four U54 cores and many on-chip peripherals and an FPGA. For more details about Microchip PolarFire SoC, please see: -https://www.microsemi.com/product-directory/soc-fpgas/5498-polarfire-soc-fpga +https://www.microchip.com/en-us/products/fpgas-and-plds/system-on-chip-fpgas/polarfire-soc-fpgas The Icicle Kit board information can be found here: -https://www.microsemi.com/existing-parts/parts/152514 +https://www.microchip.com/en-us/development-tool/mpfs-icicle-kit-es Supported devices ----------------- @@ -26,95 +26,48 @@ The ``microchip-icicle-kit`` machine supports the following devices: * 2 GEM Ethernet controllers * 1 SDHC storage controller +The memory is set to 1537 MiB by default. A sanity check on RAM size is +performed in the machine init routine to prompt user to increase the RAM size +to > 1537 MiB when less than 1537 MiB RAM is detected. + Boot options ------------ -The ``microchip-icicle-kit`` machine can start using the standard -bios -functionality for loading its BIOS image, aka Hart Software Services (HSS_). -HSS loads the second stage bootloader U-Boot from an SD card. Then a kernel -can be loaded from U-Boot. It also supports direct kernel booting via the --kernel option along with the device tree blob via -dtb. When direct kernel -boot is used, the OpenSBI fw_dynamic BIOS image is used to boot a payload -like U-Boot or OS kernel directly. +The ``microchip-icicle-kit`` machine provides some options to run a firmware +(BIOS) or a kernel image. QEMU follows below truth table to select the +firmware: -The user provided DTB should have the following requirements: - -* The /cpus node should contain at least one subnode for E51 and the number - of subnodes should match QEMU's ``-smp`` option -* The /memory reg size should match QEMU’s selected ram_size via ``-m`` -* Should contain a node for the CLINT device with a compatible string - "riscv,clint0" - -QEMU follows below truth table to select which payload to execute: - -===== ========== ========== ======= --bios -kernel -dtb payload -===== ========== ========== ======= - N N don't care HSS - Y don't care don't care HSS - N Y Y kernel -===== ========== ========== ======= - -The memory is set to 1537 MiB by default which is the minimum required high -memory size by HSS. A sanity check on ram size is performed in the machine -init routine to prompt user to increase the RAM size to > 1537 MiB when less -than 1537 MiB ram is detected. - -Running HSS ------------ - -HSS 2020.12 release is tested at the time of writing. To build an HSS image -that can be booted by the ``microchip-icicle-kit`` machine, type the following -in the HSS source tree: - -.. code-block:: bash - - $ export CROSS_COMPILE=riscv64-linux- - $ cp boards/mpfs-icicle-kit-es/def_config .config - $ make BOARD=mpfs-icicle-kit-es - -Download the official SD card image released by Microchip and prepare it for -QEMU usage: - -.. code-block:: bash - - $ wget ftp://ftpsoc.microsemi.com/outgoing/core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz - $ gunzip core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic.gz - $ qemu-img resize core-image-minimal-dev-icicle-kit-es-sd-20201009141623.rootfs.wic 4G - -Then we can boot the machine by: - -.. code-block:: bash - - $ qemu-system-riscv64 -M microchip-icicle-kit -smp 5 \ - -bios path/to/hss.bin -sd path/to/sdcard.img \ - -nic user,model=cadence_gem \ - -nic tap,ifname=tap,model=cadence_gem,script=no \ - -display none -serial stdio \ - -chardev socket,id=serial1,path=serial1.sock,server=on,wait=on \ - -serial chardev:serial1 - -With above command line, current terminal session will be used for the first -serial port. Open another terminal window, and use ``minicom`` to connect the -second serial port. - -.. code-block:: bash - - $ minicom -D unix\#serial1.sock - -HSS output is on the first serial port (stdio) and U-Boot outputs on the -second serial port. U-Boot will automatically load the Linux kernel from -the SD card image. +============= =========== ====================================== +-bios -kernel firmware +============= =========== ====================================== +none N this is an error +none Y the kernel image +NULL, default N hss.bin +NULL, default Y opensbi-riscv64-generic-fw_dynamic.bin +other don't care the BIOS image +============= =========== ====================================== Direct Kernel Boot ------------------ -Sometimes we just want to test booting a new kernel, and transforming the -kernel image to the format required by the HSS bootflow is tedious. We can -use '-kernel' for direct kernel booting just like other RISC-V machines do. +Use the ``-kernel`` option to directly run a kernel image. When a direct +kernel boot is requested, a device tree blob may be specified via the ``-dtb`` +option. Unlike other QEMU machines, this machine does not generate a device +tree for the kernel. It shall be provided by the user. The user provided DTB +should meet the following requirements: -In this mode, the OpenSBI fw_dynamic BIOS image for 'generic' platform is -used to boot an S-mode payload like U-Boot or OS kernel directly. +* The ``/cpus`` node should contain at least one subnode for E51 and the number + of subnodes should match QEMU's ``-smp`` option. + +* The ``/memory`` reg size should match QEMU’s selected RAM size via the ``-m`` + option. + +* It should contain a node for the CLINT device with a compatible string + "riscv,clint0". + +When ``-bios`` is not specified or set to ``default``, the OpenSBI +``fw_dynamic`` BIOS image for the ``generic`` platform is used to boot an +S-mode payload like U-Boot or OS kernel directly. For example, the following commands show building a U-Boot image from U-Boot mainline v2021.07 for the Microchip Icicle Kit board: @@ -146,4 +99,13 @@ CAVEATS: ``u-boot.bin`` has to be used which does contain one. To use the ELF image, we need to change to CONFIG_OF_EMBED or CONFIG_OF_PRIOR_STAGE. +Running HSS +----------- + +The machine ``microchip-icicle-kit`` used to run the Hart Software Services +(HSS_), however, the HSS development progressed and the QEMU machine +implementation lacks behind. Currently, running the HSS no longer works. +There is missing support in the clock and memory controller devices. In +particular, reading from the SD card does not work. + .. _HSS: https://github.com/polarfire-soc/hart-software-services From 9425790aceffc09b730a072cc3fc174d1b084f62 Mon Sep 17 00:00:00 2001 From: Paolo Savini Date: Thu, 13 Mar 2025 15:23:30 +0000 Subject: [PATCH 0976/2760] target/riscv: use tcg ops generation to emulate whole reg rvv loads/stores. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch replaces the use of a helper function with direct tcg ops generation in order to emulate whole register loads and stores. This is done in order to improve the performance of QEMU. We still use the helper function when vstart is not 0 at the beginning of the emulation of the whole register load or store or when we would end up generating partial loads or stores of vector elements (e.g. emulating 64 bits element loads with pairs of 32 bits loads on hosts with 32 bits registers). The latter condition ensures that we are not surprised by a trap in mid-element and consecutively that we can update vstart correctly. We also use the helper function when it performs better than tcg for specific combinations of vector length, number of fields and element size. Signed-off-by: Paolo Savini Reviewed-by: Daniel Henrique Barboza Reviewed-by: Richard Handerson Reviewed-by: Max Chou Reviewed-by: "Alex Bennée" Message-ID: <20250313152330.398396-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 151 +++++++++++++++++------- 1 file changed, 106 insertions(+), 45 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 7079f758ad..4ca7b15da1 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1334,25 +1334,86 @@ GEN_VEXT_TRANS(vle64ff_v, MO_64, r2nfvm, ldff_op, ld_us_check) typedef void gen_helper_ldst_whole(TCGv_ptr, TCGv, TCGv_env, TCGv_i32); static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, - gen_helper_ldst_whole *fn, - DisasContext *s) + uint32_t log2_esz, gen_helper_ldst_whole *fn, + DisasContext *s, bool is_load) { - TCGv_ptr dest; - TCGv base; - TCGv_i32 desc; - - uint32_t data = FIELD_DP32(0, VDATA, NF, nf); - data = FIELD_DP32(data, VDATA, VM, 1); - dest = tcg_temp_new_ptr(); - desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, - s->cfg_ptr->vlenb, data)); - - base = get_gpr(s, rs1, EXT_NONE); - tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); - mark_vs_dirty(s); - fn(dest, base, tcg_env, desc); + /* + * Load/store multiple bytes per iteration. + * When possible do this atomically. + * Update vstart with the number of processed elements. + * Use the helper function if either: + * - vstart is not 0. + * - the target has 32 bit registers and we are loading/storing 64 bit long + * elements. This is to ensure that we process every element with a single + * memory instruction. + */ + + bool use_helper_fn = !(s->vstart_eq_zero) || + (TCG_TARGET_REG_BITS == 32 && log2_esz == 3); + + if (!use_helper_fn) { + TCGv addr = tcg_temp_new(); + uint32_t size = s->cfg_ptr->vlenb * nf; + TCGv_i64 t8 = tcg_temp_new_i64(); + TCGv_i32 t4 = tcg_temp_new_i32(); + MemOp atomicity = MO_ATOM_NONE; + if (log2_esz == 0) { + atomicity = MO_ATOM_NONE; + } else { + atomicity = MO_ATOM_IFALIGN_PAIR; + } + if (TCG_TARGET_REG_BITS == 64) { + for (int i = 0; i < size; i += 8) { + addr = get_address(s, rs1, i); + if (is_load) { + tcg_gen_qemu_ld_i64(t8, addr, s->mem_idx, + MO_LE | MO_64 | atomicity); + tcg_gen_st_i64(t8, tcg_env, vreg_ofs(s, vd) + i); + } else { + tcg_gen_ld_i64(t8, tcg_env, vreg_ofs(s, vd) + i); + tcg_gen_qemu_st_i64(t8, addr, s->mem_idx, + MO_LE | MO_64 | atomicity); + } + if (i == size - 8) { + tcg_gen_movi_tl(cpu_vstart, 0); + } else { + tcg_gen_addi_tl(cpu_vstart, cpu_vstart, 8 >> log2_esz); + } + } + } else { + for (int i = 0; i < size; i += 4) { + addr = get_address(s, rs1, i); + if (is_load) { + tcg_gen_qemu_ld_i32(t4, addr, s->mem_idx, + MO_LE | MO_32 | atomicity); + tcg_gen_st_i32(t4, tcg_env, vreg_ofs(s, vd) + i); + } else { + tcg_gen_ld_i32(t4, tcg_env, vreg_ofs(s, vd) + i); + tcg_gen_qemu_st_i32(t4, addr, s->mem_idx, + MO_LE | MO_32 | atomicity); + } + if (i == size - 4) { + tcg_gen_movi_tl(cpu_vstart, 0); + } else { + tcg_gen_addi_tl(cpu_vstart, cpu_vstart, 4 >> log2_esz); + } + } + } + } else { + TCGv_ptr dest; + TCGv base; + TCGv_i32 desc; + uint32_t data = FIELD_DP32(0, VDATA, NF, nf); + data = FIELD_DP32(data, VDATA, VM, 1); + dest = tcg_temp_new_ptr(); + desc = tcg_constant_i32(simd_desc(s->cfg_ptr->vlenb, + s->cfg_ptr->vlenb, data)); + base = get_gpr(s, rs1, EXT_NONE); + tcg_gen_addi_ptr(dest, tcg_env, vreg_ofs(s, vd)); + fn(dest, base, tcg_env, desc); + } finalize_rvv_inst(s); return true; @@ -1362,42 +1423,42 @@ static bool ldst_whole_trans(uint32_t vd, uint32_t rs1, uint32_t nf, * load and store whole register instructions ignore vtype and vl setting. * Thus, we don't need to check vill bit. (Section 7.9) */ -#define GEN_LDST_WHOLE_TRANS(NAME, ARG_NF) \ -static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ -{ \ - if (require_rvv(s) && \ - QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ - return ldst_whole_trans(a->rd, a->rs1, ARG_NF, \ - gen_helper_##NAME, s); \ - } \ - return false; \ +#define GEN_LDST_WHOLE_TRANS(NAME, ETYPE, ARG_NF, IS_LOAD) \ +static bool trans_##NAME(DisasContext *s, arg_##NAME * a) \ +{ \ + if (require_rvv(s) && \ + QEMU_IS_ALIGNED(a->rd, ARG_NF)) { \ + return ldst_whole_trans(a->rd, a->rs1, ARG_NF, ctzl(sizeof(ETYPE)), \ + gen_helper_##NAME, s, IS_LOAD); \ + } \ + return false; \ } -GEN_LDST_WHOLE_TRANS(vl1re8_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re16_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re32_v, 1) -GEN_LDST_WHOLE_TRANS(vl1re64_v, 1) -GEN_LDST_WHOLE_TRANS(vl2re8_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re16_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re32_v, 2) -GEN_LDST_WHOLE_TRANS(vl2re64_v, 2) -GEN_LDST_WHOLE_TRANS(vl4re8_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re16_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re32_v, 4) -GEN_LDST_WHOLE_TRANS(vl4re64_v, 4) -GEN_LDST_WHOLE_TRANS(vl8re8_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re16_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re32_v, 8) -GEN_LDST_WHOLE_TRANS(vl8re64_v, 8) +GEN_LDST_WHOLE_TRANS(vl1re8_v, int8_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re16_v, int16_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re32_v, int32_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl1re64_v, int64_t, 1, true) +GEN_LDST_WHOLE_TRANS(vl2re8_v, int8_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re16_v, int16_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re32_v, int32_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl2re64_v, int64_t, 2, true) +GEN_LDST_WHOLE_TRANS(vl4re8_v, int8_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re16_v, int16_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re32_v, int32_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl4re64_v, int64_t, 4, true) +GEN_LDST_WHOLE_TRANS(vl8re8_v, int8_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re16_v, int16_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re32_v, int32_t, 8, true) +GEN_LDST_WHOLE_TRANS(vl8re64_v, int64_t, 8, true) /* * The vector whole register store instructions are encoded similar to * unmasked unit-stride store of elements with EEW=8. */ -GEN_LDST_WHOLE_TRANS(vs1r_v, 1) -GEN_LDST_WHOLE_TRANS(vs2r_v, 2) -GEN_LDST_WHOLE_TRANS(vs4r_v, 4) -GEN_LDST_WHOLE_TRANS(vs8r_v, 8) +GEN_LDST_WHOLE_TRANS(vs1r_v, int8_t, 1, false) +GEN_LDST_WHOLE_TRANS(vs2r_v, int8_t, 2, false) +GEN_LDST_WHOLE_TRANS(vs4r_v, int8_t, 4, false) +GEN_LDST_WHOLE_TRANS(vs8r_v, int8_t, 8, false) /* *** Vector Integer Arithmetic Instructions From d887736225984fcb3926e3f32f3cdc332c03ba8f Mon Sep 17 00:00:00 2001 From: Paolo Savini Date: Thu, 13 Mar 2025 12:39:26 +0000 Subject: [PATCH 0977/2760] Expand the probe_pages helper function to handle probe flags. This commit expands the probe_pages helper function in target/riscv/vector_helper.c to handle also the cases in which we need access to the flags raised while probing the memory and the host address. This is done in order to provide a unified interface to probe_access and probe_access_flags. The new version of probe_pages can now act as a regular call to probe_access as before and as a call to probe_access_flags. In the latter case the user need to pass pointers to flags and host address and a boolean value for nonfault. The flags and host address will be set and made available as for a direct call to probe_access_flags. Signed-off-by: Paolo Savini Reviewed-by: Daniel Henrique Barboza Message-ID: <20250313123926.374878-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 59 +++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 8eea3e6df0..3aec9a7731 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -117,25 +117,42 @@ static inline uint32_t vext_max_elems(uint32_t desc, uint32_t log2_esz) * It will trigger an exception if there is no mapping in TLB * and page table walk can't fill the TLB entry. Then the guest * software can return here after process the exception or never return. + * + * This function can also be used when direct access to probe_access_flags is + * needed in order to access the flags. If a pointer to a flags operand is + * provided the function will call probe_access_flags instead, use nonfault + * and update host and flags. */ -static void probe_pages(CPURISCVState *env, target_ulong addr, - target_ulong len, uintptr_t ra, - MMUAccessType access_type) +static void probe_pages(CPURISCVState *env, target_ulong addr, target_ulong len, + uintptr_t ra, MMUAccessType access_type, int mmu_index, + void **host, int *flags, bool nonfault) { target_ulong pagelen = -(addr | TARGET_PAGE_MASK); target_ulong curlen = MIN(pagelen, len); - int mmu_index = riscv_env_mmu_index(env, false); - probe_access(env, adjust_addr(env, addr), curlen, access_type, - mmu_index, ra); - if (len > curlen) { - addr += curlen; - curlen = len - curlen; + if (flags != NULL) { + *flags = probe_access_flags(env, adjust_addr(env, addr), curlen, + access_type, mmu_index, nonfault, host, ra); + } else { probe_access(env, adjust_addr(env, addr), curlen, access_type, mmu_index, ra); } + + if (len > curlen) { + addr += curlen; + curlen = len - curlen; + if (flags != NULL) { + *flags = probe_access_flags(env, adjust_addr(env, addr), curlen, + access_type, mmu_index, nonfault, + host, ra); + } else { + probe_access(env, adjust_addr(env, addr), curlen, access_type, + mmu_index, ra); + } + } } + static inline void vext_set_elem_mask(void *v0, int index, uint8_t value) { @@ -335,8 +352,8 @@ vext_page_ldst_us(CPURISCVState *env, void *vd, target_ulong addr, MMUAccessType access_type = is_load ? MMU_DATA_LOAD : MMU_DATA_STORE; /* Check page permission/pmp/watchpoint/etc. */ - flags = probe_access_flags(env, adjust_addr(env, addr), size, access_type, - mmu_index, true, &host, ra); + probe_pages(env, addr, size, ra, access_type, mmu_index, &host, &flags, + true); if (flags == 0) { if (nf == 1) { @@ -635,7 +652,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, uint32_t vma = vext_vma(desc); target_ulong addr, addr_probe, addr_i, offset, remain, page_split, elems; int mmu_index = riscv_env_mmu_index(env, false); - int flags; + int flags, probe_flags; void *host; VSTART_CHECK_EARLY_EXIT(env, env->vl); @@ -649,15 +666,15 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, } /* Check page permission/pmp/watchpoint/etc. */ - flags = probe_access_flags(env, adjust_addr(env, addr), elems * msize, - MMU_DATA_LOAD, mmu_index, true, &host, ra); + probe_pages(env, addr, elems * msize, ra, MMU_DATA_LOAD, mmu_index, &host, + &flags, true); /* If we are crossing a page check also the second page. */ if (env->vl > elems) { addr_probe = addr + (elems << log2_esz); - flags |= probe_access_flags(env, adjust_addr(env, addr_probe), - elems * msize, MMU_DATA_LOAD, mmu_index, - true, &host, ra); + probe_pages(env, addr_probe, elems * msize, ra, MMU_DATA_LOAD, + mmu_index, &host, &probe_flags, true); + flags |= probe_flags; } if (flags & ~TLB_WATCHPOINT) { @@ -669,16 +686,16 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, addr_i = adjust_addr(env, base + i * (nf << log2_esz)); if (i == 0) { /* Allow fault on first element. */ - probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD); + probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD, + mmu_index, &host, NULL, false); } else { remain = nf << log2_esz; while (remain > 0) { offset = -(addr_i | TARGET_PAGE_MASK); /* Probe nonfault on subsequent elements. */ - flags = probe_access_flags(env, addr_i, offset, - MMU_DATA_LOAD, mmu_index, true, - &host, 0); + probe_pages(env, addr_i, offset, 0, MMU_DATA_LOAD, + mmu_index, &host, &flags, true); /* * Stop if invalid (unmapped) or mmio (transaction may From 56cde18d048e1e1f889e31f7553e1f39f03eeec5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 10 Apr 2025 18:17:22 +0200 Subject: [PATCH 0978/2760] hw/riscv: Fix type conflict of GLib function pointers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtest_set_command_cb passed to g_once should match GThreadFunc, which it does not. But using g_once is actually unnecessary, because the function is called by riscv_harts_realize() under the Big QEMU Lock. Reported-by: Kohei Tokunaga Signed-off-by: Paolo Bonzini Reviewed-by: Alistair Francis Reviewed-by: Kohei Tokunaga Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250410161722.595634-1-pbonzini@redhat.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- hw/riscv/riscv_hart.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index ac6539bd3e..333083a4f1 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -104,8 +104,11 @@ static bool csr_qtest_callback(CharBackend *chr, gchar **words) static void riscv_cpu_register_csr_qtest_callback(void) { - static GOnce once; - g_once(&once, (GThreadFunc)qtest_set_command_cb, csr_qtest_callback); + static bool first = true; + if (first) { + first = false; + qtest_set_command_cb(csr_qtest_callback); + } } #endif From ad63158bdb33dab5704ea1cf740d2ea0387175df Mon Sep 17 00:00:00 2001 From: Ziqiao Kong Date: Tue, 15 Apr 2025 16:02:54 +0800 Subject: [PATCH 0979/2760] target/riscv: fix endless translation loop on big endian systems On big endian systems, pte and updated_pte hold big endian host data while pte_pa points to little endian target data. This means the branch at cpu_helper.c:1669 will be always satisfied and restart translation, causing an endless translation loop. The correctness of this patch can be deduced by: old_pte will hold value either from cpu_to_le32/64(pte) or cpu_to_le32/64(updated_pte), both of wich is litte endian. After that, an in-place conversion by le32/64_to_cpu(old_pte) ensures that old_pte now is in native endian, same with pte. Therefore, the endianness of the both side of if (old_pte != pte) is correct. Signed-off-by: Ziqiao Kong Reviewed-by: Alistair Francis Reviewed-by: Richard Henderson Message-ID: <20250415080254.3667878-2-ziqiaokong@gmail.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/cpu_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d5039f69a9..2ed69d7c2d 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1566,9 +1566,11 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical, target_ulong *pte_pa = qemu_map_ram_ptr(mr->ram_block, addr1); target_ulong old_pte; if (riscv_cpu_sxl(env) == MXL_RV32) { - old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, pte, updated_pte); + old_pte = qatomic_cmpxchg((uint32_t *)pte_pa, cpu_to_le32(pte), cpu_to_le32(updated_pte)); + old_pte = le32_to_cpu(old_pte); } else { - old_pte = qatomic_cmpxchg(pte_pa, pte, updated_pte); + old_pte = qatomic_cmpxchg(pte_pa, cpu_to_le64(pte), cpu_to_le64(updated_pte)); + old_pte = le64_to_cpu(old_pte); } if (old_pte != pte) { goto restart; From 22b448ccc6611a59d4aa54419f4d88c1f343cb35 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Thu, 17 Apr 2025 15:22:06 +0800 Subject: [PATCH 0980/2760] common-user/host/riscv: use tail pseudoinstruction for calling tail The j pseudoinstruction maps to a JAL instruction, which can only handle a jump to somewhere with a signed 20-bit destination. In case of static linking and LTO'ing this easily leads to "relocation truncated to fit" error. Switch to use tail pseudoinstruction, which is the standard way to tail-call a function in medium code model (emits AUIPC+JALR). Signed-off-by: Icenowy Zheng Reviewed-by: Richard Henderson Message-ID: <20250417072206.364008-1-uwu@icenowy.me> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- common-user/host/riscv/safe-syscall.inc.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common-user/host/riscv/safe-syscall.inc.S b/common-user/host/riscv/safe-syscall.inc.S index dfe83c300e..c8b81e33d0 100644 --- a/common-user/host/riscv/safe-syscall.inc.S +++ b/common-user/host/riscv/safe-syscall.inc.S @@ -69,11 +69,11 @@ safe_syscall_end: /* code path setting errno */ 0: neg a0, a0 - j safe_syscall_set_errno_tail + tail safe_syscall_set_errno_tail /* code path when we didn't execute the syscall */ 2: li a0, QEMU_ERESTARTSYS - j safe_syscall_set_errno_tail + tail safe_syscall_set_errno_tail .cfi_endproc .size safe_syscall_base, .-safe_syscall_base From 3e8d1e4a628bb234c0b5d1ccd510900047181dbd Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 8 Apr 2025 18:39:29 +0800 Subject: [PATCH 0981/2760] target/riscv: rvv: Source vector registers cannot overlap mask register Add the relevant ISA paragraphs explaining why source (and destination) registers cannot overlap the mask register. Signed-off-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Reviewed-by: Max Chou Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-2-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 29 ++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 4ca7b15da1..2110392d1c 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -100,10 +100,33 @@ static bool require_scale_rvfmin(DisasContext *s) } } -/* Destination vector register group cannot overlap source mask register. */ -static bool require_vm(int vm, int vd) +/* + * Source and destination vector register groups cannot overlap source mask + * register: + * + * A vector register cannot be used to provide source operands with more than + * one EEW for a single instruction. A mask register source is considered to + * have EEW=1 for this constraint. An encoding that would result in the same + * vector register being read with two or more different EEWs, including when + * the vector register appears at different positions within two or more vector + * register groups, is reserved. + * (Section 5.2) + * + * A destination vector register group can overlap a source vector + * register group only if one of the following holds: + * 1. The destination EEW equals the source EEW. + * 2. The destination EEW is smaller than the source EEW and the overlap + * is in the lowest-numbered part of the source register group. + * 3. The destination EEW is greater than the source EEW, the source EMUL + * is at least 1, and the overlap is in the highest-numbered part of + * the destination register group. + * For the purpose of determining register group overlap constraints, mask + * elements have EEW=1. + * (Section 5.2) + */ +static bool require_vm(int vm, int v) { - return (vm != 0 || vd != 0); + return (vm != 0 || v != 0); } static bool require_nf(int vd, int nf, int lmul) From b0450a101d6c88789d0e8df2bcbef61bc7cd159a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 8 Apr 2025 18:39:30 +0800 Subject: [PATCH 0982/2760] target/riscv: rvv: Add CHECK arg to GEN_OPFVF_WIDEN_TRANS Signed-off-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Reviewed-by: Max Chou Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-3-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 2110392d1c..d8333d8311 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2687,10 +2687,10 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) } /* OPFVF with WIDEN */ -#define GEN_OPFVF_WIDEN_TRANS(NAME) \ +#define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ { \ - if (opfvf_widen_check(s, a)) { \ + if (CHECK(s, a)) { \ uint32_t data = 0; \ static gen_helper_opfvf *const fns[2] = { \ gen_helper_##NAME##_h, gen_helper_##NAME##_w, \ @@ -2706,8 +2706,8 @@ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ return false; \ } -GEN_OPFVF_WIDEN_TRANS(vfwadd_vf) -GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) +GEN_OPFVF_WIDEN_TRANS(vfwadd_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwsub_vf, opfvf_widen_check) static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) { @@ -2789,7 +2789,7 @@ GEN_OPFVF_TRANS(vfrdiv_vf, opfvf_check) /* Vector Widening Floating-Point Multiply */ GEN_OPFVV_WIDEN_TRANS(vfwmul_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmul_vf) +GEN_OPFVF_WIDEN_TRANS(vfwmul_vf, opfvf_widen_check) /* Vector Single-Width Floating-Point Fused Multiply-Add Instructions */ GEN_OPFVV_TRANS(vfmacc_vv, opfvv_check) @@ -2814,10 +2814,10 @@ GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf) -GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf) -GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf) -GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf) +GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_widen_check) /* Vector Floating-Point Square-Root Instruction */ From 629c2a8dd7506e1cb9b6b7127604641632ac453f Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:31 +0800 Subject: [PATCH 0983/2760] target/riscv: rvv: Apply vext_check_input_eew to vrgather instructions to check mismatched input EEWs encoding constraint According to the v spec, a vector register cannot be used to provide source operands with more than one EEW for a single instruction. The vs1 EEW of vrgatherei16.vv is 16. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-4-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 32 +++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index d8333d8311..04367e1bec 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -379,6 +379,35 @@ static bool vext_check_ld_index(DisasContext *s, int vd, int vs2, return ret; } +/* + * Check whether a vector register is used to provide source operands with + * more than one EEW for the vector instruction. + * Returns true if the instruction has valid encoding + * Returns false if encoding violates the mismatched input EEWs constraint + */ +static bool vext_check_input_eew(DisasContext *s, int vs1, uint8_t eew_vs1, + int vs2, uint8_t eew_vs2, int vm) +{ + bool is_valid = true; + int8_t emul_vs1 = eew_vs1 - s->sew + s->lmul; + int8_t emul_vs2 = eew_vs2 - s->sew + s->lmul; + + /* When vm is 0, vs1 & vs2(EEW!=1) group can't overlap v0 (EEW=1) */ + if ((vs1 != -1 && !require_vm(vm, vs1)) || + (vs2 != -1 && !require_vm(vm, vs2))) { + is_valid = false; + } + + /* When eew_vs1 != eew_vs2, check whether vs1 and vs2 are overlapped */ + if ((vs1 != -1 && vs2 != -1) && (eew_vs1 != eew_vs2) && + is_overlapped(vs1, 1 << MAX(emul_vs1, 0), + vs2, 1 << MAX(emul_vs2, 0))) { + is_valid = false; + } + + return is_valid; +} + static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) { return require_vm(vm, vd) && @@ -3733,6 +3762,7 @@ static bool vrgather_vv_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, a->rs1, s->sew, a->rs2, s->sew, a->vm) && require_align(a->rd, s->lmul) && require_align(a->rs1, s->lmul) && require_align(a->rs2, s->lmul) && @@ -3745,6 +3775,7 @@ static bool vrgatherei16_vv_check(DisasContext *s, arg_rmrr *a) int8_t emul = MO_16 - s->sew + s->lmul; return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, a->rs1, MO_16, a->rs2, s->sew, a->vm) && (emul >= -3 && emul <= 3) && require_align(a->rd, s->lmul) && require_align(a->rs1, emul) && @@ -3764,6 +3795,7 @@ static bool vrgather_vx_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && vext_check_isa_ill(s) && + vext_check_input_eew(s, -1, MO_64, a->rs2, s->sew, a->vm) && require_align(a->rd, s->lmul) && require_align(a->rs2, s->lmul) && (a->rd != a->rs2) && From fbeaf35838768086b435833cb4dc5182c73ec2bc Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:32 +0800 Subject: [PATCH 0984/2760] target/riscv: rvv: Apply vext_check_input_eew to OPIVI/OPIVX/OPFVF(vext_check_ss) instructions Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-5-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 04367e1bec..b1e1db04a0 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -412,7 +412,8 @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) { return require_vm(vm, vd) && require_align(vd, s->lmul) && - require_align(vs, s->lmul); + require_align(vs, s->lmul) && + vext_check_input_eew(s, vs, s->sew, -1, s->sew, vm); } /* From fda68acb7761af40df78db18e44ca1ff20195fe0 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:33 +0800 Subject: [PATCH 0985/2760] target/riscv: rvv: Apply vext_check_input_eew to OPIVV/OPFVV(vext_check_sss) instructions Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-6-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index b1e1db04a0..5de50422c9 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -432,6 +432,7 @@ static bool vext_check_ss(DisasContext *s, int vd, int vs, int vm) static bool vext_check_sss(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ss(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) && require_align(vs1, s->lmul); } From b5480a693e3e657108746721ffe434b3bb6e7a72 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:34 +0800 Subject: [PATCH 0986/2760] target/riscv: rvv: Apply vext_check_input_eew to vector slide instructions(OPIVI/OPIVX) Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-7-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 5de50422c9..841692701c 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -638,7 +638,9 @@ static bool vext_check_slide(DisasContext *s, int vd, int vs2, { bool ret = require_align(vs2, s->lmul) && require_align(vd, s->lmul) && - require_vm(vm, vd); + require_vm(vm, vd) && + vext_check_input_eew(s, -1, 0, vs2, s->sew, vm); + if (is_over) { ret &= (vd != vs2); } From 411eefd56a3921ddbfdbadca596e1a8593ce834c Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:35 +0800 Subject: [PATCH 0987/2760] target/riscv: rvv: Apply vext_check_input_eew to vector integer extension instructions(OPMVV) Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-8-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 841692701c..954f03291b 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -3943,7 +3943,9 @@ static bool int_ext_check(DisasContext *s, arg_rmr *a, uint8_t div) require_align(a->rd, s->lmul) && require_align(a->rs2, s->lmul - div) && require_vm(a->vm, a->rd) && - require_noover(a->rd, s->lmul, a->rs2, s->lmul - div); + require_noover(a->rd, s->lmul, a->rs2, s->lmul - div) && + vext_check_input_eew(s, -1, 0, a->rs2, s->sew, a->vm); + return ret; } From 1f090a229f85e662394267680408bd31fd0a99c9 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:36 +0800 Subject: [PATCH 0988/2760] target/riscv: rvv: Apply vext_check_input_eew to vector narrow/widen instructions Handle the overlap of source registers with different EEWs. The vd of vector widening mul-add instructions is one of the input operands. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-9-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvbf16.c.inc | 9 ++- target/riscv/insn_trans/trans_rvv.c.inc | 77 +++++++++++++++++----- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvbf16.c.inc b/target/riscv/insn_trans/trans_rvbf16.c.inc index 0a9cd1ec31..066dc364c5 100644 --- a/target/riscv/insn_trans/trans_rvbf16.c.inc +++ b/target/riscv/insn_trans/trans_rvbf16.c.inc @@ -119,8 +119,11 @@ static bool trans_vfwmaccbf16_vv(DisasContext *ctx, arg_vfwmaccbf16_vv *a) REQUIRE_FPU; REQUIRE_ZVFBFWMA(ctx); + uint8_t sew = ctx->sew; if (require_rvv(ctx) && vext_check_isa_ill(ctx) && (ctx->sew == MO_16) && - vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm)) { + vext_check_dss(ctx, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs1, sew, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) { uint32_t data = 0; gen_set_rm_chkfrm(ctx, RISCV_FRM_DYN); @@ -146,8 +149,10 @@ static bool trans_vfwmaccbf16_vf(DisasContext *ctx, arg_vfwmaccbf16_vf *a) REQUIRE_FPU; REQUIRE_ZVFBFWMA(ctx); + uint8_t sew = ctx->sew; if (require_rvv(ctx) && (ctx->sew == MO_16) && vext_check_isa_ill(ctx) && - vext_check_ds(ctx, a->rd, a->rs2, a->vm)) { + vext_check_ds(ctx, a->rd, a->rs2, a->vm) && + vext_check_input_eew(ctx, a->rd, sew + 1, a->rs2, sew, a->vm)) { uint32_t data = 0; gen_set_rm(ctx, RISCV_FRM_DYN); diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 954f03291b..1d2b46fc44 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -528,6 +528,7 @@ static bool vext_narrow_check_common(DisasContext *s, int vd, int vs2, static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) { return vext_wide_check_common(s, vd, vm) && + vext_check_input_eew(s, vs, s->sew, -1, 0, vm) && require_align(vs, s->lmul) && require_noover(vd, s->lmul + 1, vs, s->lmul); } @@ -535,6 +536,7 @@ static bool vext_check_ds(DisasContext *s, int vd, int vs, int vm) static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) { return vext_wide_check_common(s, vd, vm) && + vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm) && require_align(vs, s->lmul + 1); } @@ -553,6 +555,7 @@ static bool vext_check_dd(DisasContext *s, int vd, int vs, int vm) static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ds(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew, vm) && require_align(vs1, s->lmul) && require_noover(vd, s->lmul + 1, vs1, s->lmul); } @@ -575,12 +578,14 @@ static bool vext_check_dss(DisasContext *s, int vd, int vs1, int vs2, int vm) static bool vext_check_dds(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_ds(s, vd, vs1, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) && require_align(vs2, s->lmul + 1); } static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) { - bool ret = vext_narrow_check_common(s, vd, vs, vm); + bool ret = vext_narrow_check_common(s, vd, vs, vm) && + vext_check_input_eew(s, vs, s->sew + 1, -1, 0, vm); if (vd != vs) { ret &= require_noover(vd, s->lmul, vs, s->lmul + 1); } @@ -603,6 +608,7 @@ static bool vext_check_sd(DisasContext *s, int vd, int vs, int vm) static bool vext_check_sds(DisasContext *s, int vd, int vs1, int vs2, int vm) { return vext_check_sd(s, vd, vs2, vm) && + vext_check_input_eew(s, vs1, s->sew, vs2, s->sew + 1, vm) && require_align(vs1, s->lmul); } @@ -1815,6 +1821,16 @@ static bool opivv_widen_check(DisasContext *s, arg_rmrr *a) vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); } +/* OPIVV with overwrite and WIDEN */ +static bool opivv_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + vext_check_isa_ill(s) && + vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + static bool do_opivv_widen(DisasContext *s, arg_rmrr *a, gen_helper_gvec_4_ptr *fn, bool (*checkfn)(DisasContext *, arg_rmrr *)) @@ -1862,6 +1878,14 @@ static bool opivx_widen_check(DisasContext *s, arg_rmrr *a) vext_check_ds(s, a->rd, a->rs2, a->vm); } +static bool opivx_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + vext_check_isa_ill(s) && + vext_check_ds(s, a->rd, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + #define GEN_OPIVX_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ { \ @@ -2333,13 +2357,13 @@ GEN_OPIVX_TRANS(vmadd_vx, opivx_check) GEN_OPIVX_TRANS(vnmsub_vx, opivx_check) /* Vector Widening Integer Multiply-Add Instructions */ -GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_widen_check) -GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_widen_check) -GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_widen_check) -GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmaccu_vv, opivv_overwrite_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmacc_vv, opivv_overwrite_widen_check) +GEN_OPIVV_WIDEN_TRANS(vwmaccsu_vv, opivv_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccu_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmacc_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccsu_vx, opivx_overwrite_widen_check) +GEN_OPIVX_WIDEN_TRANS(vwmaccus_vx, opivx_overwrite_widen_check) /* Vector Integer Merge and Move Instructions */ static bool trans_vmv_v_v(DisasContext *s, arg_vmv_v_v *a) @@ -2680,6 +2704,17 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); } +static bool opfvv_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + require_rvf(s) && + require_scale_rvf(s) && + vext_check_isa_ill(s) && + vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs1, s->sew, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + /* OPFVV with WIDEN */ #define GEN_OPFVV_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ @@ -2719,6 +2754,16 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) vext_check_ds(s, a->rd, a->rs2, a->vm); } +static bool opfvf_overwrite_widen_check(DisasContext *s, arg_rmrr *a) +{ + return require_rvv(s) && + require_rvf(s) && + require_scale_rvf(s) && + vext_check_isa_ill(s) && + vext_check_ds(s, a->rd, a->rs2, a->vm) && + vext_check_input_eew(s, a->rd, s->sew + 1, a->rs2, s->sew, a->vm); +} + /* OPFVF with WIDEN */ #define GEN_OPFVF_WIDEN_TRANS(NAME, CHECK) \ static bool trans_##NAME(DisasContext *s, arg_rmrr *a) \ @@ -2843,14 +2888,14 @@ GEN_OPFVF_TRANS(vfmsub_vf, opfvf_check) GEN_OPFVF_TRANS(vfnmsub_vf, opfvf_check) /* Vector Widening Floating-Point Fused Multiply-Add Instructions */ -GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_widen_check) -GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_widen_check) -GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwmacc_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmacc_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwmsac_vv, opfvv_overwrite_widen_check) +GEN_OPFVV_WIDEN_TRANS(vfwnmsac_vv, opfvv_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmacc_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmacc_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwmsac_vf, opfvf_overwrite_widen_check) +GEN_OPFVF_WIDEN_TRANS(vfwnmsac_vf, opfvf_overwrite_widen_check) /* Vector Floating-Point Square-Root Instruction */ From db21c3eb05504c4cedaad4f7b19e588361b02385 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:37 +0800 Subject: [PATCH 0989/2760] target/riscv: rvv: Apply vext_check_input_eew to vector indexed load/store instructions Handle the overlap of source registers with different EEWs. Co-authored-by: Anton Blanchard Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-10-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn_trans/trans_rvv.c.inc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 1d2b46fc44..2b6077ac06 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -1277,7 +1277,8 @@ static bool ld_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) { return require_rvv(s) && vext_check_isa_ill(s) && - vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew); + vext_check_ld_index(s, a->rd, a->rs2, a->nf, a->vm, eew) && + vext_check_input_eew(s, -1, 0, a->rs2, eew, a->vm); } GEN_VEXT_TRANS(vlxei8_v, MO_8, rnfvm, ld_index_op, ld_index_check) @@ -1329,7 +1330,8 @@ static bool st_index_check(DisasContext *s, arg_rnfvm* a, uint8_t eew) { return require_rvv(s) && vext_check_isa_ill(s) && - vext_check_st_index(s, a->rd, a->rs2, a->nf, eew); + vext_check_st_index(s, a->rd, a->rs2, a->nf, eew) && + vext_check_input_eew(s, a->rd, s->sew, a->rs2, eew, a->vm); } GEN_VEXT_TRANS(vsxei8_v, MO_8, rnfvm, st_index_op, st_index_check) From 8539a1244bf240d28917effb88a140eb58e45e88 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Tue, 8 Apr 2025 18:39:38 +0800 Subject: [PATCH 0990/2760] target/riscv: Fix the rvv reserved encoding of unmasked instructions According to the v spec, the encodings of vcomoress.vm and vector mask-register logical instructions with vm=0 are reserved. Reviewed-by: Daniel Henrique Barboza Signed-off-by: Max Chou Message-ID: <20250408103938.3623486-11-max.chou@sifive.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/insn32.decode | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode index 6d1a13c826..cd23b1f3a9 100644 --- a/target/riscv/insn32.decode +++ b/target/riscv/insn32.decode @@ -703,14 +703,14 @@ vfredmax_vs 000111 . ..... ..... 001 ..... 1010111 @r_vm # Vector widening ordered and unordered float reduction sum vfwredusum_vs 110001 . ..... ..... 001 ..... 1010111 @r_vm vfwredosum_vs 110011 . ..... ..... 001 ..... 1010111 @r_vm -vmand_mm 011001 - ..... ..... 010 ..... 1010111 @r -vmnand_mm 011101 - ..... ..... 010 ..... 1010111 @r -vmandn_mm 011000 - ..... ..... 010 ..... 1010111 @r -vmxor_mm 011011 - ..... ..... 010 ..... 1010111 @r -vmor_mm 011010 - ..... ..... 010 ..... 1010111 @r -vmnor_mm 011110 - ..... ..... 010 ..... 1010111 @r -vmorn_mm 011100 - ..... ..... 010 ..... 1010111 @r -vmxnor_mm 011111 - ..... ..... 010 ..... 1010111 @r +vmand_mm 011001 1 ..... ..... 010 ..... 1010111 @r +vmnand_mm 011101 1 ..... ..... 010 ..... 1010111 @r +vmandn_mm 011000 1 ..... ..... 010 ..... 1010111 @r +vmxor_mm 011011 1 ..... ..... 010 ..... 1010111 @r +vmor_mm 011010 1 ..... ..... 010 ..... 1010111 @r +vmnor_mm 011110 1 ..... ..... 010 ..... 1010111 @r +vmorn_mm 011100 1 ..... ..... 010 ..... 1010111 @r +vmxnor_mm 011111 1 ..... ..... 010 ..... 1010111 @r vcpop_m 010000 . ..... 10000 010 ..... 1010111 @r2_vm vfirst_m 010000 . ..... 10001 010 ..... 1010111 @r2_vm vmsbf_m 010100 . ..... 00001 010 ..... 1010111 @r2_vm @@ -732,7 +732,7 @@ vrgather_vv 001100 . ..... ..... 000 ..... 1010111 @r_vm vrgatherei16_vv 001110 . ..... ..... 000 ..... 1010111 @r_vm vrgather_vx 001100 . ..... ..... 100 ..... 1010111 @r_vm vrgather_vi 001100 . ..... ..... 011 ..... 1010111 @r_vm -vcompress_vm 010111 - ..... ..... 010 ..... 1010111 @r +vcompress_vm 010111 1 ..... ..... 010 ..... 1010111 @r vmv1r_v 100111 1 ..... 00000 011 ..... 1010111 @r2rd vmv2r_v 100111 1 ..... 00001 011 ..... 1010111 @r2rd vmv4r_v 100111 1 ..... 00011 011 ..... 1010111 @r2rd From 2669b696e243b64f8ea1a6468dcee255de99f08d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 14 Apr 2025 21:30:06 +0000 Subject: [PATCH 0991/2760] target/riscv: Fix vslidedown with rvv_ta_all_1s vslidedown always zeroes elements past vl, where it should use the tail policy. Signed-off-by: Anton Blanchard Reviewed-by: Alistair Francis Message-ID: <20250414213006.3509058-1-antonb@tenstorrent.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/vector_helper.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 3aec9a7731..5dc1c10012 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -5133,9 +5133,11 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ } \ \ for (i = i_max; i < vl; ++i) { \ - if (vm || vext_elem_mask(v0, i)) { \ - *((ETYPE *)vd + H(i)) = 0; \ + if (!vm && !vext_elem_mask(v0, i)) { \ + vext_set_elems_1s(vd, vma, i * esz, (i + 1) * esz); \ + continue; \ } \ + *((ETYPE *)vd + H(i)) = 0; \ } \ \ env->vstart = 0; \ From 355cdac7d86ca2bc1b3729a6dda0b98deb23a92b Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 22 Apr 2025 12:47:52 +1000 Subject: [PATCH 0992/2760] MAINTAINERS: Add common-user/host/riscv to RISC-V section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alistair Francis Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250422024752.2060289-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 57dddcc80d..7060cf49b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -328,6 +328,7 @@ F: include/hw/char/riscv_htif.h F: include/hw/riscv/ F: linux-user/host/riscv32/ F: linux-user/host/riscv64/ +F: common-user/host/riscv* F: tests/functional/test_riscv* F: tests/tcg/riscv64/ From 6c8954cb35b1898f94d0d1e60f1abc8d47ae9f02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:05 -0700 Subject: [PATCH 0993/2760] target/riscv: Pass ra to riscv_csr_write_fn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-2-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 3 +- target/riscv/csr.c | 226 +++++++++++++++++++++++---------------------- 2 files changed, 118 insertions(+), 111 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index c66ac3bc27..4265ce06ee 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -838,7 +838,8 @@ typedef RISCVException (*riscv_csr_predicate_fn)(CPURISCVState *env, typedef RISCVException (*riscv_csr_read_fn)(CPURISCVState *env, int csrno, target_ulong *ret_value); typedef RISCVException (*riscv_csr_write_fn)(CPURISCVState *env, int csrno, - target_ulong new_value); + target_ulong new_value, + uintptr_t ra); typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, diff --git a/target/riscv/csr.c b/target/riscv/csr.c index a32e1455c9..ba7620ef3d 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -830,13 +830,15 @@ static RISCVException seed(CPURISCVState *env, int csrno) } /* zicfiss CSR_SSP read and write */ -static int read_ssp(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_ssp(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->ssp; return RISCV_EXCP_NONE; } -static int write_ssp(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_ssp(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->ssp = val; return RISCV_EXCP_NONE; @@ -851,7 +853,7 @@ static RISCVException read_fflags(CPURISCVState *env, int csrno, } static RISCVException write_fflags(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -870,7 +872,7 @@ static RISCVException read_frm(CPURISCVState *env, int csrno, } static RISCVException write_frm(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -890,7 +892,7 @@ static RISCVException read_fcsr(CPURISCVState *env, int csrno, } static RISCVException write_fcsr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) if (riscv_has_ext(env, RVF)) { @@ -942,7 +944,7 @@ static RISCVException read_vxrm(CPURISCVState *env, int csrno, } static RISCVException write_vxrm(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -959,7 +961,7 @@ static RISCVException read_vxsat(CPURISCVState *env, int csrno, } static RISCVException write_vxsat(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -976,7 +978,7 @@ static RISCVException read_vstart(CPURISCVState *env, int csrno, } static RISCVException write_vstart(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -997,7 +999,7 @@ static RISCVException read_vcsr(CPURISCVState *env, int csrno, } static RISCVException write_vcsr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { #if !defined(CONFIG_USER_ONLY) env->mstatus |= MSTATUS_VS; @@ -1055,7 +1057,7 @@ static RISCVException read_mcyclecfg(CPURISCVState *env, int csrno, } static RISCVException write_mcyclecfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; @@ -1084,7 +1086,7 @@ static RISCVException read_mcyclecfgh(CPURISCVState *env, int csrno, } static RISCVException write_mcyclecfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MCYCLECFGH_BIT_MINH); @@ -1109,7 +1111,7 @@ static RISCVException read_minstretcfg(CPURISCVState *env, int csrno, } static RISCVException write_minstretcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t inh_avail_mask; @@ -1136,7 +1138,7 @@ static RISCVException read_minstretcfgh(CPURISCVState *env, int csrno, } static RISCVException write_minstretcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong inh_avail_mask = (target_ulong)(~MHPMEVENTH_FILTER_MASK | MINSTRETCFGH_BIT_MINH); @@ -1163,7 +1165,7 @@ static RISCVException read_mhpmevent(CPURISCVState *env, int csrno, } static RISCVException write_mhpmevent(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MCOUNTINHIBIT; uint64_t mhpmevt_val = val; @@ -1201,7 +1203,7 @@ static RISCVException read_mhpmeventh(CPURISCVState *env, int csrno, } static RISCVException write_mhpmeventh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int evt_index = csrno - CSR_MHPMEVENT3H + 3; uint64_t mhpmevth_val; @@ -1343,14 +1345,16 @@ static RISCVException riscv_pmu_write_ctrh(CPURISCVState *env, target_ulong val, return RISCV_EXCP_NONE; } -static int write_mhpmcounter(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounter(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { int ctr_idx = csrno - CSR_MCYCLE; return riscv_pmu_write_ctr(env, val, ctr_idx); } -static int write_mhpmcounterh(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mhpmcounterh(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { int ctr_idx = csrno - CSR_MCYCLEH; @@ -1661,7 +1665,7 @@ static RISCVException read_vstimecmph(CPURISCVState *env, int csrno, } static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (riscv_cpu_mxl(env) == MXL_RV32) { env->vstimecmp = deposit64(env->vstimecmp, 0, 32, (uint64_t)val); @@ -1676,7 +1680,7 @@ static RISCVException write_vstimecmp(CPURISCVState *env, int csrno, } static RISCVException write_vstimecmph(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vstimecmp = deposit64(env->vstimecmp, 32, 32, (uint64_t)val); riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp, @@ -1710,13 +1714,13 @@ static RISCVException read_stimecmph(CPURISCVState *env, int csrno, } static RISCVException write_stimecmp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (env->virt_enabled) { if (env->hvictl & HVICTL_VTI) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - return write_vstimecmp(env, csrno, val); + return write_vstimecmp(env, csrno, val, ra); } if (riscv_cpu_mxl(env) == MXL_RV32) { @@ -1731,13 +1735,13 @@ static RISCVException write_stimecmp(CPURISCVState *env, int csrno, } static RISCVException write_stimecmph(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (env->virt_enabled) { if (env->hvictl & HVICTL_VTI) { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; } - return write_vstimecmph(env, csrno, val); + return write_vstimecmph(env, csrno, val, ra); } env->stimecmp = deposit64(env->stimecmp, 32, 32, (uint64_t)val); @@ -1842,7 +1846,7 @@ static RISCVException read_zero(CPURISCVState *env, int csrno, } static RISCVException write_ignore(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return RISCV_EXCP_NONE; } @@ -1963,7 +1967,7 @@ static target_ulong legalize_mpp(CPURISCVState *env, target_ulong old_mpp, } static RISCVException write_mstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mstatus = env->mstatus; uint64_t mask = 0; @@ -2042,7 +2046,7 @@ static RISCVException read_mstatush(CPURISCVState *env, int csrno, } static RISCVException write_mstatush(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t valh = (uint64_t)val << 32; uint64_t mask = riscv_has_ext(env, RVH) ? MSTATUS_MPV | MSTATUS_GVA : 0; @@ -2096,7 +2100,7 @@ static RISCVException read_misa(CPURISCVState *env, int csrno, } static RISCVException write_misa(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); uint32_t orig_misa_ext = env->misa_ext; @@ -2160,7 +2164,7 @@ static RISCVException read_medeleg(CPURISCVState *env, int csrno, } static RISCVException write_medeleg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->medeleg = (env->medeleg & ~DELEGABLE_EXCPS) | (val & DELEGABLE_EXCPS); return RISCV_EXCP_NONE; @@ -2955,7 +2959,7 @@ static RISCVException read_mtvec(CPURISCVState *env, int csrno, } static RISCVException write_mtvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -2974,7 +2978,7 @@ static RISCVException read_mcountinhibit(CPURISCVState *env, int csrno, } static RISCVException write_mcountinhibit(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { int cidx; PMUCTRState *counter; @@ -3049,10 +3053,9 @@ static RISCVException read_scountinhibit(CPURISCVState *env, int csrno, } static RISCVException write_scountinhibit(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { - write_mcountinhibit(env, csrno, val & env->mcounteren); - return RISCV_EXCP_NONE; + return write_mcountinhibit(env, csrno, val & env->mcounteren, ra); } static RISCVException read_mcounteren(CPURISCVState *env, int csrno, @@ -3063,7 +3066,7 @@ static RISCVException read_mcounteren(CPURISCVState *env, int csrno, } static RISCVException write_mcounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -3097,7 +3100,7 @@ static RISCVException read_mscratch(CPURISCVState *env, int csrno, } static RISCVException write_mscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mscratch = val; return RISCV_EXCP_NONE; @@ -3111,7 +3114,7 @@ static RISCVException read_mepc(CPURISCVState *env, int csrno, } static RISCVException write_mepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mepc = val; return RISCV_EXCP_NONE; @@ -3125,7 +3128,7 @@ static RISCVException read_mcause(CPURISCVState *env, int csrno, } static RISCVException write_mcause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mcause = val; return RISCV_EXCP_NONE; @@ -3139,7 +3142,7 @@ static RISCVException read_mtval(CPURISCVState *env, int csrno, } static RISCVException write_mtval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtval = val; return RISCV_EXCP_NONE; @@ -3154,9 +3157,9 @@ static RISCVException read_menvcfg(CPURISCVState *env, int csrno, } static RISCVException write_henvcfg(CPURISCVState *env, int csrno, - target_ulong val); + target_ulong val, uintptr_t ra); static RISCVException write_menvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE | @@ -3188,9 +3191,7 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno, } } env->menvcfg = (env->menvcfg & ~mask) | (val & mask); - write_henvcfg(env, CSR_HENVCFG, env->henvcfg); - - return RISCV_EXCP_NONE; + return write_henvcfg(env, CSR_HENVCFG, env->henvcfg, ra); } static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, @@ -3201,9 +3202,9 @@ static RISCVException read_menvcfgh(CPURISCVState *env, int csrno, } static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, - target_ulong val); + target_ulong val, uintptr_t ra); static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { const RISCVCPUConfig *cfg = riscv_cpu_cfg(env); uint64_t mask = (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) | @@ -3218,9 +3219,7 @@ static RISCVException write_menvcfgh(CPURISCVState *env, int csrno, } env->menvcfg = (env->menvcfg & ~mask) | (valh & mask); - write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32); - - return RISCV_EXCP_NONE; + return write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32, ra); } static RISCVException read_senvcfg(CPURISCVState *env, int csrno, @@ -3238,7 +3237,7 @@ static RISCVException read_senvcfg(CPURISCVState *env, int csrno, } static RISCVException write_senvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = SENVCFG_FIOM | SENVCFG_CBIE | SENVCFG_CBCFE | SENVCFG_CBZE; RISCVException ret; @@ -3295,7 +3294,7 @@ static RISCVException read_henvcfg(CPURISCVState *env, int csrno, } static RISCVException write_henvcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE; RISCVException ret; @@ -3350,7 +3349,7 @@ static RISCVException read_henvcfgh(CPURISCVState *env, int csrno, } static RISCVException write_henvcfgh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE | HENVCFG_ADUE | HENVCFG_DTE); @@ -3388,7 +3387,7 @@ static RISCVException write_mstateen(CPURISCVState *env, int csrno, } static RISCVException write_mstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; if (!riscv_has_ext(env, RVF)) { @@ -3420,7 +3419,7 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno, } static RISCVException write_mstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_mstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -3447,7 +3446,7 @@ static RISCVException write_mstateenh(CPURISCVState *env, int csrno, } static RISCVException write_mstateen0h(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -3463,7 +3462,7 @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno, } static RISCVException write_mstateenh_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_mstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -3492,7 +3491,7 @@ static RISCVException write_hstateen(CPURISCVState *env, int csrno, } static RISCVException write_hstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -3521,7 +3520,7 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno, } static RISCVException write_hstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_hstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -3552,7 +3551,7 @@ static RISCVException write_hstateenh(CPURISCVState *env, int csrno, } static RISCVException write_hstateen0h(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -3564,7 +3563,7 @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno, } static RISCVException write_hstateenh_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_hstateenh(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -3603,7 +3602,7 @@ static RISCVException write_sstateen(CPURISCVState *env, int csrno, } static RISCVException write_sstateen0(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG; @@ -3615,7 +3614,7 @@ static RISCVException write_sstateen0(CPURISCVState *env, int csrno, } static RISCVException write_sstateen_1_3(CPURISCVState *env, int csrno, - target_ulong new_val) + target_ulong new_val, uintptr_t ra) { return write_sstateen(env, csrno, SMSTATEEN_STATEEN, new_val); } @@ -3866,7 +3865,7 @@ static RISCVException read_sstatus(CPURISCVState *env, int csrno, } static RISCVException write_sstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { target_ulong mask = (sstatus_v1_10_mask); @@ -3883,7 +3882,7 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno, mask |= SSTATUS_SDT; } target_ulong newval = (env->mstatus & ~mask) | (val & mask); - return write_mstatus(env, CSR_MSTATUS, newval); + return write_mstatus(env, CSR_MSTATUS, newval, ra); } static RISCVException rmw_vsie64(CPURISCVState *env, int csrno, @@ -4035,7 +4034,7 @@ static RISCVException read_stvec(CPURISCVState *env, int csrno, } static RISCVException write_stvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -4054,7 +4053,7 @@ static RISCVException read_scounteren(CPURISCVState *env, int csrno, } static RISCVException write_scounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -4088,7 +4087,7 @@ static RISCVException read_sscratch(CPURISCVState *env, int csrno, } static RISCVException write_sscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->sscratch = val; return RISCV_EXCP_NONE; @@ -4102,7 +4101,7 @@ static RISCVException read_sepc(CPURISCVState *env, int csrno, } static RISCVException write_sepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->sepc = val; return RISCV_EXCP_NONE; @@ -4116,7 +4115,7 @@ static RISCVException read_scause(CPURISCVState *env, int csrno, } static RISCVException write_scause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->scause = val; return RISCV_EXCP_NONE; @@ -4130,7 +4129,7 @@ static RISCVException read_stval(CPURISCVState *env, int csrno, } static RISCVException write_stval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->stval = val; return RISCV_EXCP_NONE; @@ -4270,7 +4269,7 @@ static RISCVException read_satp(CPURISCVState *env, int csrno, } static RISCVException write_satp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!riscv_cpu_cfg(env)->mmu) { return RISCV_EXCP_NONE; @@ -4492,7 +4491,7 @@ static RISCVException read_hstatus(CPURISCVState *env, int csrno, } static RISCVException write_hstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = (target_ulong)-1; if (!env_archcpu(env)->cfg.ext_svukte) { @@ -4524,7 +4523,7 @@ static RISCVException read_hedeleg(CPURISCVState *env, int csrno, } static RISCVException write_hedeleg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hedeleg = val & vs_delegable_excps; return RISCV_EXCP_NONE; @@ -4545,7 +4544,7 @@ static RISCVException read_hedelegh(CPURISCVState *env, int csrno, } static RISCVException write_hedelegh(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVException ret; ret = smstateen_acc_ok(env, 0, SMSTATEEN0_P1P13); @@ -4808,7 +4807,7 @@ static RISCVException read_hcounteren(CPURISCVState *env, int csrno, } static RISCVException write_hcounteren(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { RISCVCPU *cpu = env_archcpu(env); @@ -4828,7 +4827,7 @@ static RISCVException read_hgeie(CPURISCVState *env, int csrno, } static RISCVException write_hgeie(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* Only GEILEN:1 bits implemented and BIT0 is never implemented */ val &= ((((target_ulong)1) << env->geilen) - 1) << 1; @@ -4847,7 +4846,7 @@ static RISCVException read_htval(CPURISCVState *env, int csrno, } static RISCVException write_htval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->htval = val; return RISCV_EXCP_NONE; @@ -4861,7 +4860,7 @@ static RISCVException read_htinst(CPURISCVState *env, int csrno, } static RISCVException write_htinst(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return RISCV_EXCP_NONE; } @@ -4883,7 +4882,7 @@ static RISCVException read_hgatp(CPURISCVState *env, int csrno, } static RISCVException write_hgatp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hgatp = legalize_xatp(env, env->hgatp, val); return RISCV_EXCP_NONE; @@ -4901,7 +4900,7 @@ static RISCVException read_htimedelta(CPURISCVState *env, int csrno, } static RISCVException write_htimedelta(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; @@ -4933,7 +4932,7 @@ static RISCVException read_htimedeltah(CPURISCVState *env, int csrno, } static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!env->rdtime_fn) { return RISCV_EXCP_ILLEGAL_INST; @@ -4957,7 +4956,7 @@ static RISCVException read_hvictl(CPURISCVState *env, int csrno, } static RISCVException write_hvictl(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->hvictl = val & HVICTL_VALID_MASK; return RISCV_EXCP_NONE; @@ -5022,7 +5021,7 @@ static RISCVException read_hviprio1(CPURISCVState *env, int csrno, } static RISCVException write_hviprio1(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 0, env->hviprio, val); } @@ -5034,7 +5033,7 @@ static RISCVException read_hviprio1h(CPURISCVState *env, int csrno, } static RISCVException write_hviprio1h(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 4, env->hviprio, val); } @@ -5046,7 +5045,7 @@ static RISCVException read_hviprio2(CPURISCVState *env, int csrno, } static RISCVException write_hviprio2(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 8, env->hviprio, val); } @@ -5058,7 +5057,7 @@ static RISCVException read_hviprio2h(CPURISCVState *env, int csrno, } static RISCVException write_hviprio2h(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { return write_hvipriox(env, 12, env->hviprio, val); } @@ -5072,7 +5071,7 @@ static RISCVException read_vsstatus(CPURISCVState *env, int csrno, } static RISCVException write_vsstatus(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint64_t mask = (target_ulong)-1; if ((val & VSSTATUS64_UXL) == 0) { @@ -5097,7 +5096,7 @@ static RISCVException read_vstvec(CPURISCVState *env, int csrno, } static RISCVException write_vstvec(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { /* bits [1:0] encode mode; 0 = direct, 1 = vectored, 2 >= reserved */ if ((val & 3) < 2) { @@ -5116,7 +5115,7 @@ static RISCVException read_vsscratch(CPURISCVState *env, int csrno, } static RISCVException write_vsscratch(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsscratch = val; return RISCV_EXCP_NONE; @@ -5130,7 +5129,7 @@ static RISCVException read_vsepc(CPURISCVState *env, int csrno, } static RISCVException write_vsepc(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsepc = val; return RISCV_EXCP_NONE; @@ -5144,7 +5143,7 @@ static RISCVException read_vscause(CPURISCVState *env, int csrno, } static RISCVException write_vscause(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vscause = val; return RISCV_EXCP_NONE; @@ -5158,7 +5157,7 @@ static RISCVException read_vstval(CPURISCVState *env, int csrno, } static RISCVException write_vstval(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vstval = val; return RISCV_EXCP_NONE; @@ -5172,7 +5171,7 @@ static RISCVException read_vsatp(CPURISCVState *env, int csrno, } static RISCVException write_vsatp(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->vsatp = legalize_xatp(env, env->vsatp, val); return RISCV_EXCP_NONE; @@ -5186,7 +5185,7 @@ static RISCVException read_mtval2(CPURISCVState *env, int csrno, } static RISCVException write_mtval2(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtval2 = val; return RISCV_EXCP_NONE; @@ -5200,7 +5199,7 @@ static RISCVException read_mtinst(CPURISCVState *env, int csrno, } static RISCVException write_mtinst(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->mtinst = val; return RISCV_EXCP_NONE; @@ -5215,7 +5214,7 @@ static RISCVException read_mseccfg(CPURISCVState *env, int csrno, } static RISCVException write_mseccfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { mseccfg_csr_write(env, val); return RISCV_EXCP_NONE; @@ -5231,7 +5230,7 @@ static RISCVException read_pmpcfg(CPURISCVState *env, int csrno, } static RISCVException write_pmpcfg(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { uint32_t reg_index = csrno - CSR_PMPCFG0; @@ -5247,7 +5246,7 @@ static RISCVException read_pmpaddr(CPURISCVState *env, int csrno, } static RISCVException write_pmpaddr(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { pmpaddr_csr_write(env, csrno - CSR_PMPADDR0, val); return RISCV_EXCP_NONE; @@ -5261,7 +5260,7 @@ static RISCVException read_tselect(CPURISCVState *env, int csrno, } static RISCVException write_tselect(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { tselect_csr_write(env, val); return RISCV_EXCP_NONE; @@ -5285,7 +5284,7 @@ static RISCVException read_tdata(CPURISCVState *env, int csrno, } static RISCVException write_tdata(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { if (!tdata_available(env, csrno - CSR_TDATA1)) { return RISCV_EXCP_ILLEGAL_INST; @@ -5310,7 +5309,7 @@ static RISCVException read_mcontext(CPURISCVState *env, int csrno, } static RISCVException write_mcontext(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { bool rv32 = riscv_cpu_mxl(env) == MXL_RV32 ? true : false; int32_t mask; @@ -5334,43 +5333,50 @@ static RISCVException read_mnscratch(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static int write_mnscratch(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnscratch(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mnscratch = val; return RISCV_EXCP_NONE; } -static int read_mnepc(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mnepc(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mnepc; return RISCV_EXCP_NONE; } -static int write_mnepc(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnepc(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mnepc = val; return RISCV_EXCP_NONE; } -static int read_mncause(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mncause(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mncause; return RISCV_EXCP_NONE; } -static int write_mncause(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mncause(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { env->mncause = val; return RISCV_EXCP_NONE; } -static int read_mnstatus(CPURISCVState *env, int csrno, target_ulong *val) +static RISCVException read_mnstatus(CPURISCVState *env, int csrno, + target_ulong *val) { *val = env->mnstatus; return RISCV_EXCP_NONE; } -static int write_mnstatus(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException write_mnstatus(CPURISCVState *env, int csrno, + target_ulong val, uintptr_t ra) { target_ulong mask = (MNSTATUS_NMIE | MNSTATUS_MNPP); @@ -5540,7 +5546,7 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, if (write_mask) { new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { - ret = csr_ops[csrno].write(env, csrno, new_value); + ret = csr_ops[csrno].write(env, csrno, new_value, 0); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -5603,7 +5609,7 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, } } else if (csr_ops[csrno].write) { /* avoids having to write wrappers for all registers */ - ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value)); + ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), 0); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -5714,7 +5720,7 @@ static RISCVException read_jvt(CPURISCVState *env, int csrno, } static RISCVException write_jvt(CPURISCVState *env, int csrno, - target_ulong val) + target_ulong val, uintptr_t ra) { env->jvt = val; return RISCV_EXCP_NONE; From bfc7936f42bac551bd859b8f32fb1f24dfcfc611 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:06 -0700 Subject: [PATCH 0994/2760] target/riscv: Pass ra to riscv_csrrw_do64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-3-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index ba7620ef3d..22149bd3fc 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -5516,7 +5516,8 @@ static inline RISCVException riscv_csrrw_check(CPURISCVState *env, static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, - target_ulong write_mask) + target_ulong write_mask, + uintptr_t ra) { RISCVException ret; target_ulong old_value = 0; @@ -5546,7 +5547,7 @@ static RISCVException riscv_csrrw_do64(CPURISCVState *env, int csrno, if (write_mask) { new_value = (old_value & ~write_mask) | (new_value & write_mask); if (csr_ops[csrno].write) { - ret = csr_ops[csrno].write(env, csrno, new_value, 0); + ret = csr_ops[csrno].write(env, csrno, new_value, ra); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -5569,7 +5570,7 @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno, return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, 0, 0); + return riscv_csrrw_do64(env, csrno, ret_value, 0, 0, 0); } RISCVException riscv_csrrw(CPURISCVState *env, int csrno, @@ -5581,7 +5582,7 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno, return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask); + return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, 0); } static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, @@ -5647,9 +5648,7 @@ RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, * accesses */ target_ulong old_value; - ret = riscv_csrrw_do64(env, csrno, &old_value, - (target_ulong)0, - (target_ulong)0); + ret = riscv_csrrw_do64(env, csrno, &old_value, 0, 0, 0); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } @@ -5681,7 +5680,7 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, target_ulong old_value; ret = riscv_csrrw_do64(env, csrno, &old_value, int128_getlo(new_value), - int128_getlo(write_mask)); + int128_getlo(write_mask), 0); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } From c26c4afd0ffde4f79216975ac34f419d0fcf6795 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:07 -0700 Subject: [PATCH 0995/2760] target/riscv: Pass ra to riscv_csrrw_do128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-4-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 22149bd3fc..8af0304a36 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -5588,7 +5588,7 @@ RISCVException riscv_csrrw(CPURISCVState *env, int csrno, static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, Int128 *ret_value, Int128 new_value, - Int128 write_mask) + Int128 write_mask, uintptr_t ra) { RISCVException ret; Int128 old_value; @@ -5610,7 +5610,7 @@ static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, } } else if (csr_ops[csrno].write) { /* avoids having to write wrappers for all registers */ - ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), 0); + ret = csr_ops[csrno].write(env, csrno, int128_getlo(new_value), ra); if (ret != RISCV_EXCP_NONE) { return ret; } @@ -5637,7 +5637,7 @@ RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, if (csr_ops[csrno].read128) { return riscv_csrrw_do128(env, csrno, ret_value, - int128_zero(), int128_zero()); + int128_zero(), int128_zero(), 0); } /* @@ -5667,7 +5667,8 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, } if (csr_ops[csrno].read128) { - return riscv_csrrw_do128(env, csrno, ret_value, new_value, write_mask); + return riscv_csrrw_do128(env, csrno, ret_value, + new_value, write_mask, 0); } /* From f1304836ea9399253c67b09513fca30f9f4b223e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:08 -0700 Subject: [PATCH 0996/2760] target/riscv: Pass ra to riscv_csrrw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-5-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- hw/riscv/riscv_hart.c | 2 +- target/riscv/cpu.h | 8 ++++---- target/riscv/csr.c | 8 ++++---- target/riscv/op_helper.c | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index 333083a4f1..7f2676008c 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -72,7 +72,7 @@ static void csr_call(char *cmd, uint64_t cpu_num, int csrno, uint64_t *val) ret = riscv_csrr(env, csrno, (target_ulong *)val); } else if (strcmp(cmd, "set_csr") == 0) { ret = riscv_csrrw(env, csrno, NULL, *(target_ulong *)val, - MAKE_64BIT_MASK(0, TARGET_LONG_BITS)); + MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0); } g_assert(ret == RISCV_EXCP_NONE); diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 4265ce06ee..f674e93a4f 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -813,8 +813,8 @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno, target_ulong *ret_value); RISCVException riscv_csrrw(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask); + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask, uintptr_t ra); RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, @@ -823,13 +823,13 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, static inline void riscv_csr_write(CPURISCVState *env, int csrno, target_ulong val) { - riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS)); + riscv_csrrw(env, csrno, NULL, val, MAKE_64BIT_MASK(0, TARGET_LONG_BITS), 0); } static inline target_ulong riscv_csr_read(CPURISCVState *env, int csrno) { target_ulong val = 0; - riscv_csrrw(env, csrno, &val, 0, 0); + riscv_csrrw(env, csrno, &val, 0, 0, 0); return val; } diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 8af0304a36..807a891e7d 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -5574,15 +5574,15 @@ RISCVException riscv_csrr(CPURISCVState *env, int csrno, } RISCVException riscv_csrrw(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) + target_ulong *ret_value, target_ulong new_value, + target_ulong write_mask, uintptr_t ra) { RISCVException ret = riscv_csrrw_check(env, csrno, true); if (ret != RISCV_EXCP_NONE) { return ret; } - return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, 0); + return riscv_csrrw_do64(env, csrno, ret_value, new_value, write_mask, ra); } static RISCVException riscv_csrrw_do128(CPURISCVState *env, int csrno, @@ -5704,7 +5704,7 @@ RISCVException riscv_csrrw_debug(CPURISCVState *env, int csrno, if (!write_mask) { ret = riscv_csrr(env, csrno, ret_value); } else { - ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask); + ret = riscv_csrrw(env, csrno, ret_value, new_value, write_mask, 0); } #if !defined(CONFIG_USER_ONLY) env->debugger = false; diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 05316f2088..0672101637 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -71,7 +71,7 @@ target_ulong helper_csrr(CPURISCVState *env, int csr) void helper_csrw(CPURISCVState *env, int csr, target_ulong src) { target_ulong mask = env->xl == MXL_RV32 ? UINT32_MAX : (target_ulong)-1; - RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask); + RISCVException ret = riscv_csrrw(env, csr, NULL, src, mask, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -82,7 +82,7 @@ target_ulong helper_csrrw(CPURISCVState *env, int csr, target_ulong src, target_ulong write_mask) { target_ulong val = 0; - RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask); + RISCVException ret = riscv_csrrw(env, csr, &val, src, write_mask, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); From 9ef792a78db6b89619c3ccc77ceb3e9d6271dd02 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:09 -0700 Subject: [PATCH 0997/2760] target/riscv: Pass ra to riscv_csrrw_i128 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-6-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 4 ++-- target/riscv/csr.c | 8 ++++---- target/riscv/op_helper.c | 9 +++++---- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f674e93a4f..ff7ba2a0a1 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -848,8 +848,8 @@ typedef RISCVException (*riscv_csr_op_fn)(CPURISCVState *env, int csrno, RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, Int128 *ret_value); RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, - Int128 *ret_value, - Int128 new_value, Int128 write_mask); + Int128 *ret_value, Int128 new_value, + Int128 write_mask, uintptr_t ra); typedef RISCVException (*riscv_csr_read128_fn)(CPURISCVState *env, int csrno, Int128 *ret_value); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 807a891e7d..53458491da 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -5656,8 +5656,8 @@ RISCVException riscv_csrr_i128(CPURISCVState *env, int csrno, } RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, - Int128 *ret_value, - Int128 new_value, Int128 write_mask) + Int128 *ret_value, Int128 new_value, + Int128 write_mask, uintptr_t ra) { RISCVException ret; @@ -5668,7 +5668,7 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, if (csr_ops[csrno].read128) { return riscv_csrrw_do128(env, csrno, ret_value, - new_value, write_mask, 0); + new_value, write_mask, ra); } /* @@ -5681,7 +5681,7 @@ RISCVException riscv_csrrw_i128(CPURISCVState *env, int csrno, target_ulong old_value; ret = riscv_csrrw_do64(env, csrno, &old_value, int128_getlo(new_value), - int128_getlo(write_mask), 0); + int128_getlo(write_mask), ra); if (ret == RISCV_EXCP_NONE && ret_value) { *ret_value = int128_make64(old_value); } diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 0672101637..557807ba4b 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -108,7 +108,7 @@ void helper_csrw_i128(CPURISCVState *env, int csr, { RISCVException ret = riscv_csrrw_i128(env, csr, NULL, int128_make128(srcl, srch), - UINT128_MAX); + UINT128_MAX, GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); @@ -116,13 +116,14 @@ void helper_csrw_i128(CPURISCVState *env, int csr, } target_ulong helper_csrrw_i128(CPURISCVState *env, int csr, - target_ulong srcl, target_ulong srch, - target_ulong maskl, target_ulong maskh) + target_ulong srcl, target_ulong srch, + target_ulong maskl, target_ulong maskh) { Int128 rv = int128_zero(); RISCVException ret = riscv_csrrw_i128(env, csr, &rv, int128_make128(srcl, srch), - int128_make128(maskl, maskh)); + int128_make128(maskl, maskh), + GETPC()); if (ret != RISCV_EXCP_NONE) { riscv_raise_exception(env, ret, GETPC()); From dd9953a5541441d283d0e5c53dffaf3938d6e097 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:10 -0700 Subject: [PATCH 0998/2760] target/riscv: Move insn_len to internals.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-7-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- target/riscv/internals.h | 5 +++++ target/riscv/translate.c | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/riscv/internals.h b/target/riscv/internals.h index 213aff31d8..4570bd50be 100644 --- a/target/riscv/internals.h +++ b/target/riscv/internals.h @@ -201,4 +201,9 @@ static inline target_ulong adjust_addr_virt(CPURISCVState *env, return adjust_addr_body(env, addr, true); } +static inline int insn_len(uint16_t first_word) +{ + return (first_word & 3) == 3 ? 4 : 2; +} + #endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 85128f997b..0d4f7d601c 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1209,11 +1209,6 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) /* The specification allows for longer insns, but not supported by qemu. */ #define MAX_INSN_LEN 4 -static inline int insn_len(uint16_t first_word) -{ - return (first_word & 3) == 3 ? 4 : 2; -} - const RISCVDecoder decoder_table[] = { { always_true_p, decode_insn32 }, { has_xthead_p, decode_xthead}, From 7b069906b6ac47dc905d187c72f07ef82b400501 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 25 Apr 2025 08:23:11 -0700 Subject: [PATCH 0999/2760] target/riscv: Fix write_misa vs aligned next_pc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not examine a random host return address, but properly compute the next pc for the guest cpu. Fixes: f18637cd611 ("RISC-V: Add misa runtime write support") Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Message-ID: <20250425152311.804338-8-richard.henderson@linaro.org> [ Changes by AF: - Change `& ~3` to `& 3` ] Signed-off-by: Alistair Francis --- target/riscv/csr.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 53458491da..288edeedea 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -30,6 +30,8 @@ #include "accel/tcg/getpc.h" #include "qemu/guest-random.h" #include "qapi/error.h" +#include "tcg/insn-start-words.h" +#include "internals.h" #include /* CSR function table public API */ @@ -2099,6 +2101,19 @@ static RISCVException read_misa(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static target_ulong get_next_pc(CPURISCVState *env, uintptr_t ra) +{ + uint64_t data[INSN_START_WORDS]; + + /* Outside of a running cpu, env contains the next pc. */ + if (ra == 0 || !cpu_unwind_state_data(env_cpu(env), ra, data)) { + return env->pc; + } + + /* Within unwind data, [0] is pc and [1] is the opcode. */ + return data[0] + insn_len(data[1]); +} + static RISCVException write_misa(CPURISCVState *env, int csrno, target_ulong val, uintptr_t ra) { @@ -2114,11 +2129,8 @@ static RISCVException write_misa(CPURISCVState *env, int csrno, /* Mask extensions that are not supported by this hart */ val &= env->misa_ext_mask; - /* - * Suppress 'C' if next instruction is not aligned - * TODO: this should check next_pc - */ - if ((val & RVC) && (GETPC() & ~3) != 0) { + /* Suppress 'C' if next instruction is not aligned. */ + if ((val & RVC) && (get_next_pc(env, ra) & 3) != 0) { val &= ~RVC; } From 73f81da0a3628180409a0ae90ece19534bcdf09b Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:13 -0300 Subject: [PATCH 1000/2760] target/riscv/kvm: minor fixes/tweaks Remove an unused 'KVMScratchCPU' pointer argument in kvm_riscv_check_sbi_dbcn_support(). Put kvm_riscv_reset_regs_csr() after kvm_riscv_put_regs_csr(). This will make a future patch diff easier to read, when changes in kvm_riscv_reset_regs_csr() and kvm_riscv_get_regs_csr() will be made. Fixes: a6b53378f5 ("target/riscv/kvm: implement SBI debug console (DBCN) calls") Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20250429124421.223883-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 75724b6af4..cad54b720a 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -613,19 +613,6 @@ static int kvm_riscv_put_regs_core(CPUState *cs) return ret; } -static void kvm_riscv_reset_regs_csr(CPURISCVState *env) -{ - env->mstatus = 0; - env->mie = 0; - env->stvec = 0; - env->sscratch = 0; - env->sepc = 0; - env->scause = 0; - env->stval = 0; - env->mip = 0; - env->satp = 0; -} - static int kvm_riscv_get_regs_csr(CPUState *cs) { CPURISCVState *env = &RISCV_CPU(cs)->env; @@ -660,6 +647,19 @@ static int kvm_riscv_put_regs_csr(CPUState *cs) return 0; } +static void kvm_riscv_reset_regs_csr(CPURISCVState *env) +{ + env->mstatus = 0; + env->mie = 0; + env->stvec = 0; + env->sscratch = 0; + env->sepc = 0; + env->scause = 0; + env->stval = 0; + env->mip = 0; + env->satp = 0; +} + static int kvm_riscv_get_regs_fp(CPUState *cs) { int ret = 0; @@ -1078,7 +1078,6 @@ static int uint64_cmp(const void *a, const void *b) } static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu, - KVMScratchCPU *kvmcpu, struct kvm_reg_list *reglist) { struct kvm_reg_list *reg_search; @@ -1197,7 +1196,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) kvm_riscv_read_vlenb(cpu, kvmcpu, reglist); } - kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist); + kvm_riscv_check_sbi_dbcn_support(cpu, reglist); } static void riscv_init_kvm_registers(Object *cpu_obj) From 906af6de9462c5192547cca0beac2c134659a437 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:14 -0300 Subject: [PATCH 1001/2760] target/riscv/kvm: fix leak in kvm_riscv_init_multiext_cfg() 'reglist' is being g-malloc'ed but never freed. Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20250429124421.223883-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index cad54b720a..86eb3c2e3b 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1119,10 +1119,10 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { + g_autofree struct kvm_reg_list *reglist = NULL; KVMCPUConfig *multi_ext_cfg; struct kvm_one_reg reg; struct kvm_reg_list rl_struct; - struct kvm_reg_list *reglist; uint64_t val, reg_id, *reg_search; int i, ret; From b6096103494506514d9bfa442f62fef36ffc8fba Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:15 -0300 Subject: [PATCH 1002/2760] target/riscv/kvm: turn u32/u64 reg functions into macros This change is motivated by a future change w.r.t CSRs management. We want to handle them the same way as KVM extensions, i.e. a static array with KVMCPUConfig objs that will be read/write during init and so on. But to do that properly we must be able to declare a static array that hold KVM regs. C does not allow to init static arrays and use functions as initializers, e.g. we can't do: .kvm_reg_id = kvm_riscv_reg_id_ulong(...) When instantiating the array. We can do that with macros though, so our goal is turn kvm_riscv_reg_ulong() in a macro. It is cleaner to turn every other reg_id_*() function in macros, and ulong will end up using the macros for u32 and u64, so we'll start with them. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20250429124421.223883-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 86eb3c2e3b..b037cb2781 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -58,6 +58,12 @@ void riscv_kvm_aplic_request(void *opaque, int irq, int level) static bool cap_has_mp_state; +#define KVM_RISCV_REG_ID_U32(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U32 | \ + type | idx) + +#define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \ + type | idx) + static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, uint64_t idx) { @@ -76,16 +82,6 @@ static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, return id; } -static uint64_t kvm_riscv_reg_id_u32(uint64_t type, uint64_t idx) -{ - return KVM_REG_RISCV | KVM_REG_SIZE_U32 | type | idx; -} - -static uint64_t kvm_riscv_reg_id_u64(uint64_t type, uint64_t idx) -{ - return KVM_REG_RISCV | KVM_REG_SIZE_U64 | type | idx; -} - static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) { uint64_t size_ctz = __builtin_ctz(size_b); @@ -119,12 +115,12 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ KVM_REG_RISCV_CONFIG_REG(name)) -#define RISCV_TIMER_REG(name) kvm_riscv_reg_id_u64(KVM_REG_RISCV_TIMER, \ +#define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \ KVM_REG_RISCV_TIMER_REG(name)) -#define RISCV_FP_F_REG(idx) kvm_riscv_reg_id_u32(KVM_REG_RISCV_FP_F, idx) +#define RISCV_FP_F_REG(idx) KVM_RISCV_REG_ID_U32(KVM_REG_RISCV_FP_F, idx) -#define RISCV_FP_D_REG(idx) kvm_riscv_reg_id_u64(KVM_REG_RISCV_FP_D, idx) +#define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx) #define RISCV_VECTOR_CSR_REG(env, name) \ kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ From 11766e17616a5a4181d4a63f88adf67ac52c553b Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:16 -0300 Subject: [PATCH 1003/2760] target/riscv/kvm: turn kvm_riscv_reg_id_ulong() into a macro We need the reg_id_ulong() helper to be a macro to be able to create a static array of KVMCPUConfig that will hold CSR information. Despite the amount of changes all of them are tedious/trivial: - replace instances of "kvm_riscv_reg_id_ulong" with "KVM_RISCV_REG_ID_ULONG"; - RISCV_CORE_REG(), RISCV_CSR_REG(), RISCV_CONFIG_REG() and RISCV_VECTOR_CSR_REG() only receives one 'name' arg. Remove unneeded 'env' variables when applicable. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20250429124421.223883-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 99 ++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 58 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index b037cb2781..509c875a19 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -64,23 +64,11 @@ static bool cap_has_mp_state; #define KVM_RISCV_REG_ID_U64(type, idx) (KVM_REG_RISCV | KVM_REG_SIZE_U64 | \ type | idx) -static uint64_t kvm_riscv_reg_id_ulong(CPURISCVState *env, uint64_t type, - uint64_t idx) -{ - uint64_t id = KVM_REG_RISCV | type | idx; - - switch (riscv_cpu_mxl(env)) { - case MXL_RV32: - id |= KVM_REG_SIZE_U32; - break; - case MXL_RV64: - id |= KVM_REG_SIZE_U64; - break; - default: - g_assert_not_reached(); - } - return id; -} +#if defined(TARGET_RISCV64) +#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U64(type, idx) +#else +#define KVM_RISCV_REG_ID_ULONG(type, idx) KVM_RISCV_REG_ID_U32(type, idx) +#endif static uint64_t kvm_encode_reg_size_id(uint64_t id, size_t size_b) { @@ -103,16 +91,16 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, return kvm_encode_reg_size_id(id, size_b); } -#define RISCV_CORE_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, \ +#define RISCV_CORE_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, \ KVM_REG_RISCV_CORE_REG(name)) -#define RISCV_CSR_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CSR, \ +#define RISCV_CSR_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CSR, \ KVM_REG_RISCV_CSR_REG(name)) -#define RISCV_CONFIG_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, \ +#define RISCV_CONFIG_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, \ KVM_REG_RISCV_CONFIG_REG(name)) #define RISCV_TIMER_REG(name) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_TIMER, \ @@ -122,13 +110,13 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, #define RISCV_FP_D_REG(idx) KVM_RISCV_REG_ID_U64(KVM_REG_RISCV_FP_D, idx) -#define RISCV_VECTOR_CSR_REG(env, name) \ - kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_VECTOR, \ +#define RISCV_VECTOR_CSR_REG(name) \ + KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \ KVM_REG_RISCV_VECTOR_CSR_REG(name)) #define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ do { \ - int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(csr), ®); \ if (_ret) { \ return _ret; \ } \ @@ -136,7 +124,7 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, #define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ do { \ - int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(env, csr), ®); \ + int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(csr), ®); \ if (_ret) { \ return _ret; \ } \ @@ -244,7 +232,7 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) /* If we're here we're going to disable the MISA bit */ reg = 0; - id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, misa_cfg->kvm_reg_id); ret = kvm_set_one_reg(cs, id, ®); if (ret != 0) { @@ -430,7 +418,6 @@ static KVMCPUConfig kvm_sbi_dbcn = { static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) { - CPURISCVState *env = &cpu->env; uint64_t id, reg; int i, ret; @@ -441,7 +428,7 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) continue; } - id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg); ret = kvm_set_one_reg(cs, id, ®); @@ -566,14 +553,14 @@ static int kvm_riscv_get_regs_core(CPUState *cs) target_ulong reg; CPURISCVState *env = &RISCV_CPU(cs)->env; - ret = kvm_get_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + ret = kvm_get_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); if (ret) { return ret; } env->pc = reg; for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); + uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); ret = kvm_get_one_reg(cs, id, ®); if (ret) { return ret; @@ -592,13 +579,13 @@ static int kvm_riscv_put_regs_core(CPUState *cs) CPURISCVState *env = &RISCV_CPU(cs)->env; reg = env->pc; - ret = kvm_set_one_reg(cs, RISCV_CORE_REG(env, regs.pc), ®); + ret = kvm_set_one_reg(cs, RISCV_CORE_REG(regs.pc), ®); if (ret) { return ret; } for (i = 1; i < 32; i++) { - uint64_t id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CORE, i); + uint64_t id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CORE, i); reg = env->gpr[i]; ret = kvm_set_one_reg(cs, id, ®); if (ret) { @@ -796,26 +783,26 @@ static int kvm_riscv_get_regs_vector(CPUState *cs) return 0; } - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®); if (ret) { return ret; } env->vstart = reg; - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®); if (ret) { return ret; } env->vl = reg; - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®); if (ret) { return ret; } env->vtype = reg; if (kvm_v_vlenb.supported) { - ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + ret = kvm_get_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®); if (ret) { return ret; } @@ -853,26 +840,26 @@ static int kvm_riscv_put_regs_vector(CPUState *cs) } reg = env->vstart; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vstart), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vstart), ®); if (ret) { return ret; } reg = env->vl; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vl), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vl), ®); if (ret) { return ret; } reg = env->vtype; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vtype), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vtype), ®); if (ret) { return ret; } if (kvm_v_vlenb.supported) { reg = cpu->cfg.vlenb; - ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(env, vlenb), ®); + ret = kvm_set_one_reg(cs, RISCV_VECTOR_CSR_REG(vlenb), ®); for (int i = 0; i < 32; i++) { /* @@ -951,25 +938,24 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch) static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { - CPURISCVState *env = &cpu->env; struct kvm_one_reg reg; int ret; - reg.id = RISCV_CONFIG_REG(env, mvendorid); + reg.id = RISCV_CONFIG_REG(mvendorid); reg.addr = (uint64_t)&cpu->cfg.mvendorid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve mvendorid from host, error %d", ret); } - reg.id = RISCV_CONFIG_REG(env, marchid); + reg.id = RISCV_CONFIG_REG(marchid); reg.addr = (uint64_t)&cpu->cfg.marchid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { error_report("Unable to retrieve marchid from host, error %d", ret); } - reg.id = RISCV_CONFIG_REG(env, mimpid); + reg.id = RISCV_CONFIG_REG(mimpid); reg.addr = (uint64_t)&cpu->cfg.mimpid; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); if (ret != 0) { @@ -984,7 +970,7 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, struct kvm_one_reg reg; int ret; - reg.id = RISCV_CONFIG_REG(env, isa); + reg.id = RISCV_CONFIG_REG(isa); reg.addr = (uint64_t)&env->misa_ext_mask; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -1001,11 +987,10 @@ static void kvm_riscv_init_misa_ext_mask(RISCVCPU *cpu, static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, KVMCPUConfig *cbomz_cfg) { - CPURISCVState *env = &cpu->env; struct kvm_one_reg reg; int ret; - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, cbomz_cfg->kvm_reg_id); reg.addr = (uint64_t)kvmconfig_get_cfg_addr(cpu, cbomz_cfg); ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -1019,7 +1004,6 @@ static void kvm_riscv_read_cbomz_blksize(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { - CPURISCVState *env = &cpu->env; uint64_t val; int i, ret; @@ -1027,7 +1011,7 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, KVMCPUConfig *multi_ext_cfg = &kvm_multi_ext_cfgs[i]; struct kvm_one_reg reg; - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_ISA_EXT, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); @@ -1159,7 +1143,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) for (i = 0; i < ARRAY_SIZE(kvm_multi_ext_cfgs); i++) { multi_ext_cfg = &kvm_multi_ext_cfgs[i]; - reg_id = kvm_riscv_reg_id_ulong(&cpu->env, KVM_REG_RISCV_ISA_EXT, + reg_id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_ISA_EXT, multi_ext_cfg->kvm_reg_id); reg_search = bsearch(®_id, reglist->reg, reglist->n, sizeof(uint64_t), uint64_cmp); @@ -1338,12 +1322,11 @@ void kvm_arch_init_irq_routing(KVMState *s) static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) { - CPURISCVState *env = &cpu->env; target_ulong reg; uint64_t id; int ret; - id = RISCV_CONFIG_REG(env, mvendorid); + id = RISCV_CONFIG_REG(mvendorid); /* * cfg.mvendorid is an uint32 but a target_ulong will * be written. Assign it to a target_ulong var to avoid @@ -1355,13 +1338,13 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) return ret; } - id = RISCV_CONFIG_REG(env, marchid); + id = RISCV_CONFIG_REG(marchid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.marchid); if (ret != 0) { return ret; } - id = RISCV_CONFIG_REG(env, mimpid); + id = RISCV_CONFIG_REG(mimpid); ret = kvm_set_one_reg(cs, id, &cpu->cfg.mimpid); return ret; @@ -1911,7 +1894,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) if (cpu->cfg.ext_zicbom && riscv_cpu_option_set(kvm_cbom_blocksize.name)) { - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, kvm_cbom_blocksize.kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); @@ -1930,7 +1913,7 @@ void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp) if (cpu->cfg.ext_zicboz && riscv_cpu_option_set(kvm_cboz_blocksize.name)) { - reg.id = kvm_riscv_reg_id_ulong(env, KVM_REG_RISCV_CONFIG, + reg.id = KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_CONFIG, kvm_cboz_blocksize.kvm_reg_id); reg.addr = (uint64_t)&val; ret = ioctl(kvmcpu.cpufd, KVM_GET_ONE_REG, ®); From d3b6f1742c36e3a3c1e74cb60646ee98a4e39ea3 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:17 -0300 Subject: [PATCH 1004/2760] target/riscv/kvm: add kvm_csr_cfgs[] At this moment we're not checking if the host has support for any specific CSR before doing get/put regs. This will cause problems if the host KVM doesn't support it (see [1] as an example). We'll use the same approach done with the CPU extensions: read all known KVM CSRs during init() to check for availability, then read/write them if they are present. This will be made by either using get-reglist or by directly reading the CSRs. For now we'll just convert the CSRs to use a kvm_csr_cfg[] array, reusing the same KVMCPUConfig abstraction we use for extensions, and use the array in (get|put)_csr_regs() instead of manually listing them. A lot of boilerplate will be added but at least we'll automate the get/put procedure for CSRs, i.e. adding a new CSR in the future will be a matter of adding it in kvm_csr_regs[] and everything else will be taken care of. Despite all the code changes no behavioral change is made. [1] https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0SYAw@mail.gmail.com/ Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Message-ID: <20250429124421.223883-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/cpu.h | 1 + target/riscv/kvm/kvm-cpu.c | 121 ++++++++++++++++++++++++++----------- 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index ff7ba2a0a1..b56d3afa69 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -75,6 +75,7 @@ const char *riscv_get_misa_ext_name(uint32_t bit); const char *riscv_get_misa_ext_description(uint32_t bit); #define CPU_CFG_OFFSET(_prop) offsetof(struct RISCVCPUConfig, _prop) +#define ENV_CSR_OFFSET(_csr) offsetof(CPURISCVState, _csr) typedef struct riscv_cpu_profile { struct riscv_cpu_profile *u_parent; diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 509c875a19..3740514bba 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -114,22 +114,6 @@ static uint64_t kvm_riscv_vector_reg_id(RISCVCPU *cpu, KVM_RISCV_REG_ID_ULONG(KVM_REG_RISCV_VECTOR, \ KVM_REG_RISCV_VECTOR_CSR_REG(name)) -#define KVM_RISCV_GET_CSR(cs, env, csr, reg) \ - do { \ - int _ret = kvm_get_one_reg(cs, RISCV_CSR_REG(csr), ®); \ - if (_ret) { \ - return _ret; \ - } \ - } while (0) - -#define KVM_RISCV_SET_CSR(cs, env, csr, reg) \ - do { \ - int _ret = kvm_set_one_reg(cs, RISCV_CSR_REG(csr), ®); \ - if (_ret) { \ - return _ret; \ - } \ - } while (0) - #define KVM_RISCV_GET_TIMER(cs, name, reg) \ do { \ int ret = kvm_get_one_reg(cs, RISCV_TIMER_REG(name), ®); \ @@ -251,6 +235,53 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) } } +#define KVM_CSR_CFG(_name, _env_prop, reg_id) \ + {.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \ + .kvm_reg_id = reg_id} + +static KVMCPUConfig kvm_csr_cfgs[] = { + KVM_CSR_CFG("sstatus", mstatus, RISCV_CSR_REG(sstatus)), + KVM_CSR_CFG("sie", mie, RISCV_CSR_REG(sie)), + KVM_CSR_CFG("stvec", stvec, RISCV_CSR_REG(stvec)), + KVM_CSR_CFG("sscratch", sscratch, RISCV_CSR_REG(sscratch)), + KVM_CSR_CFG("sepc", sepc, RISCV_CSR_REG(sepc)), + KVM_CSR_CFG("scause", scause, RISCV_CSR_REG(scause)), + KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), + KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), + KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), +}; + +static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + return (void *)&cpu->env + csr_cfg->offset; +} + +static uint32_t kvm_cpu_csr_get_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg); + return *val32; +} + +static uint64_t kvm_cpu_csr_get_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) +{ + uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg); + return *val64; +} + +static void kvm_cpu_csr_set_u32(RISCVCPU *cpu, KVMCPUConfig *csr_cfg, + uint32_t val) +{ + uint32_t *val32 = kvmconfig_get_env_addr(cpu, csr_cfg); + *val32 = val; +} + +static void kvm_cpu_csr_set_u64(RISCVCPU *cpu, KVMCPUConfig *csr_cfg, + uint64_t val) +{ + uint64_t *val64 = kvmconfig_get_env_addr(cpu, csr_cfg); + *val64 = val; +} + #define KVM_EXT_CFG(_name, _prop, _reg_id) \ {.name = _name, .offset = CPU_CFG_OFFSET(_prop), \ .kvm_reg_id = _reg_id} @@ -598,34 +629,52 @@ static int kvm_riscv_put_regs_core(CPUState *cs) static int kvm_riscv_get_regs_csr(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + uint64_t reg; + int i, ret; - KVM_RISCV_GET_CSR(cs, env, sstatus, env->mstatus); - KVM_RISCV_GET_CSR(cs, env, sie, env->mie); - KVM_RISCV_GET_CSR(cs, env, stvec, env->stvec); - KVM_RISCV_GET_CSR(cs, env, sscratch, env->sscratch); - KVM_RISCV_GET_CSR(cs, env, sepc, env->sepc); - KVM_RISCV_GET_CSR(cs, env, scause, env->scause); - KVM_RISCV_GET_CSR(cs, env, stval, env->stval); - KVM_RISCV_GET_CSR(cs, env, sip, env->mip); - KVM_RISCV_GET_CSR(cs, env, satp, env->satp); + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + + ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®); + if (ret) { + return ret; + } + + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + kvm_cpu_csr_set_u32(cpu, csr_cfg, reg); + } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + kvm_cpu_csr_set_u64(cpu, csr_cfg, reg); + } else { + g_assert_not_reached(); + } + } return 0; } static int kvm_riscv_put_regs_csr(CPUState *cs) { - CPURISCVState *env = &RISCV_CPU(cs)->env; + RISCVCPU *cpu = RISCV_CPU(cs); + uint64_t reg; + int i, ret; - KVM_RISCV_SET_CSR(cs, env, sstatus, env->mstatus); - KVM_RISCV_SET_CSR(cs, env, sie, env->mie); - KVM_RISCV_SET_CSR(cs, env, stvec, env->stvec); - KVM_RISCV_SET_CSR(cs, env, sscratch, env->sscratch); - KVM_RISCV_SET_CSR(cs, env, sepc, env->sepc); - KVM_RISCV_SET_CSR(cs, env, scause, env->scause); - KVM_RISCV_SET_CSR(cs, env, stval, env->stval); - KVM_RISCV_SET_CSR(cs, env, sip, env->mip); - KVM_RISCV_SET_CSR(cs, env, satp, env->satp); + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); + } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + reg = kvm_cpu_csr_get_u64(cpu, csr_cfg); + } else { + g_assert_not_reached(); + } + + ret = kvm_set_one_reg(cs, csr_cfg->kvm_reg_id, ®); + if (ret) { + return ret; + } + } return 0; } From f396c217a53d9b7960dd002fbb07cfe1d46b27aa Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:18 -0300 Subject: [PATCH 1005/2760] target/riscv/kvm: do not read unavailable CSRs [1] reports that commit 4db19d5b21 broke a KVM guest running kernel 6.6. This happens because the kernel does not know 'senvcfg', making it unable to boot because QEMU is reading/wriiting it without any checks. After converting the CSRs to do "automated" get/put reg procedures in the previous patch we can now scan for availability. Two functions are created: - kvm_riscv_read_csr_cfg_legacy() will check if the CSR exists by brute forcing KVM_GET_ONE_REG in each one of them, interpreting an EINVAL return as indication that the CSR isn't available. This will be use in absence of KVM_GET_REG_LIST; - kvm_riscv_read_csr_cfg() will use the existing result of get_reg_list to check if the CSRs ids are present. kvm_riscv_init_multiext_cfg() is now kvm_riscv_init_cfg() to reflect that the function is also dealing with CSRs. [1] https://lore.kernel.org/qemu-riscv/CABJz62OfUDHYkQ0T3rGHStQprf1c7_E0qBLbLKhfv=+jb0SYAw@mail.gmail.com/ Fixes: 4db19d5b21 ("target/riscv/kvm: add missing KVM CSRs") Reported-by: Andrea Bolognani Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Message-ID: <20250429124421.223883-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis Cc: qemu-stable@nongnu.org --- target/riscv/kvm/kvm-cpu.c | 62 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 3740514bba..344616c1cc 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -636,6 +636,10 @@ static int kvm_riscv_get_regs_csr(CPUState *cs) for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + if (!csr_cfg->supported) { + continue; + } + ret = kvm_get_one_reg(cs, csr_cfg->kvm_reg_id, ®); if (ret) { return ret; @@ -662,6 +666,10 @@ static int kvm_riscv_put_regs_csr(CPUState *cs) for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + if (!csr_cfg->supported) { + continue; + } + if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { @@ -1090,6 +1098,32 @@ static void kvm_riscv_read_multiext_legacy(RISCVCPU *cpu, } } +static void kvm_riscv_read_csr_cfg_legacy(KVMScratchCPU *kvmcpu) +{ + uint64_t val; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + struct kvm_one_reg reg; + + reg.id = csr_cfg->kvm_reg_id; + reg.addr = (uint64_t)&val; + ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, ®); + if (ret != 0) { + if (errno == EINVAL) { + csr_cfg->supported = false; + } else { + error_report("Unable to read KVM CSR %s: %s", + csr_cfg->name, strerror(errno)); + exit(EXIT_FAILURE); + } + } else { + csr_cfg->supported = true; + } + } +} + static int uint64_cmp(const void *a, const void *b) { uint64_t val1 = *(const uint64_t *)a; @@ -1146,7 +1180,26 @@ static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, } } -static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) +static void kvm_riscv_read_csr_cfg(struct kvm_reg_list *reglist) +{ + struct kvm_reg_list *reg_search; + uint64_t reg_id; + + for (int i = 0; i < ARRAY_SIZE(kvm_csr_cfgs); i++) { + KVMCPUConfig *csr_cfg = &kvm_csr_cfgs[i]; + + reg_id = csr_cfg->kvm_reg_id; + reg_search = bsearch(®_id, reglist->reg, reglist->n, + sizeof(uint64_t), uint64_cmp); + if (!reg_search) { + continue; + } + + csr_cfg->supported = true; + } +} + +static void kvm_riscv_init_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) { g_autofree struct kvm_reg_list *reglist = NULL; KVMCPUConfig *multi_ext_cfg; @@ -1163,7 +1216,9 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) * (EINVAL). Use read_legacy() in this case. */ if (errno == EINVAL) { - return kvm_riscv_read_multiext_legacy(cpu, kvmcpu); + kvm_riscv_read_multiext_legacy(cpu, kvmcpu); + kvm_riscv_read_csr_cfg_legacy(kvmcpu); + return; } else if (errno != E2BIG) { /* * E2BIG is an expected error message for the API since we @@ -1226,6 +1281,7 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) } kvm_riscv_check_sbi_dbcn_support(cpu, reglist); + kvm_riscv_read_csr_cfg(reglist); } static void riscv_init_kvm_registers(Object *cpu_obj) @@ -1239,7 +1295,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj) kvm_riscv_init_machine_ids(cpu, &kvmcpu); kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu); - kvm_riscv_init_multiext_cfg(cpu, &kvmcpu); + kvm_riscv_init_cfg(cpu, &kvmcpu); kvm_riscv_destroy_scratch_vcpu(&kvmcpu); } From 86b8c3821496898cd3bd8eaa1bac71f5c784a2db Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:19 -0300 Subject: [PATCH 1006/2760] target/riscv/kvm: add senvcfg CSR We're missing the senvcfg CSRs which is already present in the KVM UAPI. Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Acked-by: Alistair Francis Message-ID: <20250429124421.223883-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 344616c1cc..0e34382163 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -249,6 +249,7 @@ static KVMCPUConfig kvm_csr_cfgs[] = { KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), + KVM_CSR_CFG("senvcfg", senvcfg, RISCV_CSR_REG(senvcfg)), }; static void *kvmconfig_get_env_addr(RISCVCPU *cpu, KVMCPUConfig *csr_cfg) @@ -698,6 +699,7 @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env) env->stval = 0; env->mip = 0; env->satp = 0; + env->senvcfg = 0; } static int kvm_riscv_get_regs_fp(CPUState *cs) From 775ac57e0a54b9127bd2ad005675772870cd1932 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:20 -0300 Subject: [PATCH 1007/2760] target/riscv/kvm: read/write KVM regs via env size We're going to add support for scounteren in the next patch. KVM defines as a target_ulong CSR, while QEMU defines env->scounteren as a 32 bit field. This will cause the current code to read/write a 64 bit CSR in a 32 bit field when running in a 64 bit CPU. To prevent that, change the current logic to honor the size of the QEMU storage instead of the KVM CSR reg. Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Andrew Jones Message-ID: <20250429124421.223883-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 0e34382163..ca171d5457 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -135,6 +135,7 @@ typedef struct KVMCPUConfig { const char *description; target_ulong offset; uint64_t kvm_reg_id; + uint32_t prop_size; bool user_set; bool supported; } KVMCPUConfig; @@ -237,6 +238,7 @@ static void kvm_riscv_update_cpu_misa_ext(RISCVCPU *cpu, CPUState *cs) #define KVM_CSR_CFG(_name, _env_prop, reg_id) \ {.name = _name, .offset = ENV_CSR_OFFSET(_env_prop), \ + .prop_size = sizeof(((CPURISCVState *)0)->_env_prop), \ .kvm_reg_id = reg_id} static KVMCPUConfig kvm_csr_cfgs[] = { @@ -646,9 +648,9 @@ static int kvm_riscv_get_regs_csr(CPUState *cs) return ret; } - if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { - kvm_cpu_csr_set_u32(cpu, csr_cfg, reg); - } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + if (csr_cfg->prop_size == sizeof(uint32_t)) { + kvm_cpu_csr_set_u32(cpu, csr_cfg, (uint32_t)reg); + } else if (csr_cfg->prop_size == sizeof(uint64_t)) { kvm_cpu_csr_set_u64(cpu, csr_cfg, reg); } else { g_assert_not_reached(); @@ -671,9 +673,9 @@ static int kvm_riscv_put_regs_csr(CPUState *cs) continue; } - if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint32_t)) { + if (csr_cfg->prop_size == sizeof(uint32_t)) { reg = kvm_cpu_csr_get_u32(cpu, csr_cfg); - } else if (KVM_REG_SIZE(csr_cfg->kvm_reg_id) == sizeof(uint64_t)) { + } else if (csr_cfg->prop_size == sizeof(uint64_t)) { reg = kvm_cpu_csr_get_u64(cpu, csr_cfg); } else { g_assert_not_reached(); From 8ab99a05f34bab3f9fae49299ee407ead78f0470 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:44:21 -0300 Subject: [PATCH 1008/2760] target/riscv/kvm: add scounteren CSR Add support for the scounteren KVM CSR. Note that env->scounteren is a 32 bit and all KVM CSRs are target_ulong, so scounteren will be capped to 32 bits read/writes. Reported-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Message-ID: <20250429124421.223883-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index ca171d5457..82f9728636 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -251,6 +251,7 @@ static KVMCPUConfig kvm_csr_cfgs[] = { KVM_CSR_CFG("stval", stval, RISCV_CSR_REG(stval)), KVM_CSR_CFG("sip", mip, RISCV_CSR_REG(sip)), KVM_CSR_CFG("satp", satp, RISCV_CSR_REG(satp)), + KVM_CSR_CFG("scounteren", scounteren, RISCV_CSR_REG(scounteren)), KVM_CSR_CFG("senvcfg", senvcfg, RISCV_CSR_REG(senvcfg)), }; @@ -701,6 +702,7 @@ static void kvm_riscv_reset_regs_csr(CPURISCVState *env) env->stval = 0; env->mip = 0; env->satp = 0; + env->scounteren = 0; env->senvcfg = 0; } From 221e96cb7ae4535bcef7d54d1620a44be88b655e Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:03 -0300 Subject: [PATCH 1009/2760] hw/riscv/virt.c: enforce s->memmap use in machine_init() Throughout the code we're accessing the board memmap, most of the time, by accessing it statically via 'virt_memmap'. This static map is also assigned in the machine state in s->memmap. We're also passing it as a variable to some fdt functions, which is unorthodox since we can spare a function argument by accessing it statically or via the machine state. All the current forms are valid but not all of the are scalable. In the future we will version this board, and then all this code will need rework because it should point to the updated memmap. In this case, we'll want to assign the adequate versioned memmap once during init, in s->memmap like it is being done today, and the rest of the code will access the updated map via s->memmap. We're also enforcing the pattern of using s->memmap instead of assigning it to a temp variable 'memmap'. Code is copy/pasted around all the time and being consistent is important. We'll start these rather mechanical changes with virt_machine_init(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: Joel Stanley Message-ID: <20250429125811.224803-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 5958ad1f7d..0200679240 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1522,7 +1522,6 @@ static void virt_machine_done(Notifier *notifier, void *data) static void virt_machine_init(MachineState *machine) { - const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); @@ -1530,6 +1529,8 @@ static void virt_machine_init(MachineState *machine) int i, base_hartid, hart_count; int socket_count = riscv_socket_count(machine); + s->memmap = virt_memmap; + /* Check socket count limit */ if (VIRT_SOCKETS_MAX < socket_count) { error_report("number of sockets/nodes should be less than %d", @@ -1577,7 +1578,7 @@ static void virt_machine_init(MachineState *machine) if (virt_aclint_allowed() && s->have_aclint) { if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { /* Per-socket ACLINT MTIMER */ - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + i * RISCV_ACLINT_DEFAULT_MTIMER_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, @@ -1586,28 +1587,28 @@ static void virt_machine_init(MachineState *machine) RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); } else { /* Per-socket ACLINT MSWI, MTIMER, and SSWI */ - riscv_aclint_swi_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size, + riscv_aclint_swi_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size, base_hartid, hart_count, false); - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size + + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); - riscv_aclint_swi_create(memmap[VIRT_ACLINT_SSWI].base + - i * memmap[VIRT_ACLINT_SSWI].size, + riscv_aclint_swi_create(s->memmap[VIRT_ACLINT_SSWI].base + + i * s->memmap[VIRT_ACLINT_SSWI].size, base_hartid, hart_count, true); } } else if (tcg_enabled()) { /* Per-socket SiFive CLINT */ riscv_aclint_swi_create( - memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, + s->memmap[VIRT_CLINT].base + i * s->memmap[VIRT_CLINT].size, base_hartid, hart_count, false); - riscv_aclint_mtimer_create(memmap[VIRT_CLINT].base + - i * memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, + riscv_aclint_mtimer_create(s->memmap[VIRT_CLINT].base + + i * s->memmap[VIRT_CLINT].size + RISCV_ACLINT_SWI_SIZE, RISCV_ACLINT_DEFAULT_MTIMER_SIZE, base_hartid, hart_count, RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME, RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, true); @@ -1615,11 +1616,11 @@ static void virt_machine_init(MachineState *machine) /* Per-socket interrupt controller */ if (s->aia_type == VIRT_AIA_TYPE_NONE) { - s->irqchip[i] = virt_create_plic(memmap, i, + s->irqchip[i] = virt_create_plic(s->memmap, i, base_hartid, hart_count); } else { s->irqchip[i] = virt_create_aia(s->aia_type, s->aia_guests, - memmap, i, base_hartid, + s->memmap, i, base_hartid, hart_count); } @@ -1641,8 +1642,8 @@ static void virt_machine_init(MachineState *machine) if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT, VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS, - memmap[VIRT_APLIC_S].base, - memmap[VIRT_IMSIC_S].base, + s->memmap[VIRT_APLIC_S].base, + s->memmap[VIRT_IMSIC_S].base, s->aia_guests); } @@ -1658,21 +1659,20 @@ static void virt_machine_init(MachineState *machine) virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; } else { virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; - virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; + virt_high_pcie_memmap.base = s->memmap[VIRT_DRAM].base + + machine->ram_size; virt_high_pcie_memmap.base = ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); } - s->memmap = virt_memmap; - /* register system main memory (actual RAM) */ - memory_region_add_subregion(system_memory, memmap[VIRT_DRAM].base, - machine->ram); + memory_region_add_subregion(system_memory, s->memmap[VIRT_DRAM].base, + machine->ram); /* boot rom */ memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", - memmap[VIRT_MROM].size, &error_fatal); - memory_region_add_subregion(system_memory, memmap[VIRT_MROM].base, + s->memmap[VIRT_MROM].size, &error_fatal); + memory_region_add_subregion(system_memory, s->memmap[VIRT_MROM].base, mask_rom); /* @@ -1683,12 +1683,12 @@ static void virt_machine_init(MachineState *machine) rom_set_fw(s->fw_cfg); /* SiFive Test MMIO device */ - sifive_test_create(memmap[VIRT_TEST].base); + sifive_test_create(s->memmap[VIRT_TEST].base); /* VirtIO MMIO devices */ for (i = 0; i < VIRTIO_COUNT; i++) { sysbus_create_simple("virtio-mmio", - memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, + s->memmap[VIRT_VIRTIO].base + i * s->memmap[VIRT_VIRTIO].size, qdev_get_gpio_in(virtio_irqchip, VIRTIO_IRQ + i)); } @@ -1696,11 +1696,11 @@ static void virt_machine_init(MachineState *machine) create_platform_bus(s, mmio_irqchip); - serial_mm_init(system_memory, memmap[VIRT_UART0].base, + serial_mm_init(system_memory, s->memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(mmio_irqchip, UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); - sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, + sysbus_create_simple("goldfish_rtc", s->memmap[VIRT_RTC].base, qdev_get_gpio_in(mmio_irqchip, RTC_IRQ)); for (i = 0; i < ARRAY_SIZE(s->flash); i++) { @@ -1718,7 +1718,7 @@ static void virt_machine_init(MachineState *machine) exit(1); } } else { - create_fdt(s, memmap); + create_fdt(s, s->memmap); } if (virt_is_iommu_sys_enabled(s)) { From fb8cf3fd98d7640d2ea3feca65fb40fba09a0235 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:04 -0300 Subject: [PATCH 1010/2760] hw/riscv/virt.c: remove trivial virt_memmap references We should use s->memmap instead of virt_memmap to be able to use an updated memmap when we start versioning the board. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 0200679240..843665a5bd 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -166,8 +166,8 @@ static void virt_flash_map1(PFlashCFI01 *flash, static void virt_flash_map(RISCVVirtState *s, MemoryRegion *sysmem) { - hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = s->memmap[VIRT_FLASH].base; virt_flash_map1(s->flash[0], flashbase, flashsize, sysmem); @@ -999,8 +999,8 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) { MachineState *ms = MACHINE(s); - hwaddr flashsize = virt_memmap[VIRT_FLASH].size / 2; - hwaddr flashbase = virt_memmap[VIRT_FLASH].base; + hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; + hwaddr flashbase = s->memmap[VIRT_FLASH].base; g_autofree char *name = g_strdup_printf("/flash@%" PRIx64, flashbase); qemu_fdt_add_subnode(ms->fdt, name); @@ -1035,7 +1035,7 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *pci_node = NULL; pci_node = g_strdup_printf("/soc/pci@%lx", - (long) virt_memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/virtio_iommu@%x,%x", pci_node, PCI_SLOT(bdf), PCI_FUNC(bdf)); iommu_phandle = qemu_fdt_alloc_phandle(fdt); @@ -1104,7 +1104,7 @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *pci_node = NULL; pci_node = g_strdup_printf("/soc/pci@%lx", - (long) virt_memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf); iommu_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, iommu_node); @@ -1126,24 +1126,24 @@ static void finalize_fdt(RISCVVirtState *s) uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint32_t iommu_sys_phandle = 1; - create_fdt_sockets(s, virt_memmap, &phandle, &irq_mmio_phandle, + create_fdt_sockets(s, s->memmap, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); - create_fdt_virtio(s, virt_memmap, irq_virtio_phandle); + create_fdt_virtio(s, s->memmap, irq_virtio_phandle); if (virt_is_iommu_sys_enabled(s)) { create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, &iommu_sys_phandle); } - create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle, + create_fdt_pcie(s, s->memmap, irq_pcie_phandle, msi_pcie_phandle, iommu_sys_phandle); - create_fdt_reset(s, virt_memmap, &phandle); + create_fdt_reset(s, s->memmap, &phandle); - create_fdt_uart(s, virt_memmap, irq_mmio_phandle); + create_fdt_uart(s, s->memmap, irq_mmio_phandle); - create_fdt_rtc(s, virt_memmap, irq_mmio_phandle); + create_fdt_rtc(s, s->memmap, irq_mmio_phandle); } static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) @@ -1361,14 +1361,13 @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) { DeviceState *dev; SysBusDevice *sysbus; - const MemMapEntry *memmap = virt_memmap; int i; MemoryRegion *sysmem = get_system_memory(); dev = qdev_new(TYPE_PLATFORM_BUS_DEVICE); dev->id = g_strdup(TYPE_PLATFORM_BUS_DEVICE); qdev_prop_set_uint32(dev, "num_irqs", VIRT_PLATFORM_BUS_NUM_IRQS); - qdev_prop_set_uint32(dev, "mmio_size", memmap[VIRT_PLATFORM_BUS].size); + qdev_prop_set_uint32(dev, "mmio_size", s->memmap[VIRT_PLATFORM_BUS].size); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); s->platform_bus_dev = dev; @@ -1379,7 +1378,7 @@ static void create_platform_bus(RISCVVirtState *s, DeviceState *irqchip) } memory_region_add_subregion(sysmem, - memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].base, sysbus_mmio_get_region(sysbus, 0)); } From 47e51e5d12740ebdcd797e4771b467ba8c2aba82 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:05 -0300 Subject: [PATCH 1011/2760] hw/riscv/virt.c: use s->memmap in virt_machine_done() Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 843665a5bd..b349b2b1cf 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1425,9 +1425,8 @@ static void virt_machine_done(Notifier *notifier, void *data) { RISCVVirtState *s = container_of(notifier, RISCVVirtState, machine_done); - const MemMapEntry *memmap = virt_memmap; MachineState *machine = MACHINE(s); - hwaddr start_addr = memmap[VIRT_DRAM].base; + hwaddr start_addr = s->memmap[VIRT_DRAM].base; target_ulong firmware_end_addr, kernel_start_addr; const char *firmware_name = riscv_default_firmware_name(&s->soc[0]); uint64_t fdt_load_addr; @@ -1471,14 +1470,14 @@ static void virt_machine_done(Notifier *notifier, void *data) * let's overwrite the address we jump to after reset to * the base of the flash. */ - start_addr = virt_memmap[VIRT_FLASH].base; + start_addr = s->memmap[VIRT_FLASH].base; } else { /* * Pflash was supplied but either KVM guest or bios is not none. * In this case, base of the flash would contain S-mode payload. */ riscv_setup_firmware_boot(machine); - kernel_entry = virt_memmap[VIRT_FLASH].base; + kernel_entry = s->memmap[VIRT_FLASH].base; } } @@ -1492,15 +1491,15 @@ static void virt_machine_done(Notifier *notifier, void *data) kernel_entry = boot_info.image_low_addr; } - fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, - memmap[VIRT_DRAM].size, + fdt_load_addr = riscv_compute_fdt_addr(s->memmap[VIRT_DRAM].base, + s->memmap[VIRT_DRAM].size, machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ riscv_setup_rom_reset_vec(machine, &s->soc[0], start_addr, - virt_memmap[VIRT_MROM].base, - virt_memmap[VIRT_MROM].size, kernel_entry, + s->memmap[VIRT_MROM].base, + s->memmap[VIRT_MROM].size, kernel_entry, fdt_load_addr); /* From 6418ff383d53e5872f2746d490885f0a551385a4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:06 -0300 Subject: [PATCH 1012/2760] hw/riscv/virt.c: add 'base' arg in create_fw_cfg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function can receive the value via s->memmap[VIRT_FW_CFG].base from the caller, avoiding the use of virt_memmap. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index b349b2b1cf..3d547f7c2b 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1262,9 +1262,8 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, return dev; } -static FWCfgState *create_fw_cfg(const MachineState *ms) +static FWCfgState *create_fw_cfg(const MachineState *ms, hwaddr base) { - hwaddr base = virt_memmap[VIRT_FW_CFG].base; FWCfgState *fw_cfg; fw_cfg = fw_cfg_init_mem_wide(base + 8, base, 8, base + 16, @@ -1677,7 +1676,7 @@ static void virt_machine_init(MachineState *machine) * Init fw_cfg. Must be done before riscv_load_fdt, otherwise the * device tree cannot be altered and we get FDT_ERR_NOSPACE. */ - s->fw_cfg = create_fw_cfg(machine); + s->fw_cfg = create_fw_cfg(machine, s->memmap[VIRT_FW_CFG].base); rom_set_fw(s->fw_cfg); /* SiFive Test MMIO device */ From 658e501969d948735669fcf82206a0ef92755f97 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:07 -0300 Subject: [PATCH 1013/2760] hw/riscv/virt.c: use s->memmap in create_fdt() path create_fdt(), create_fdt_flash() and create_fdt_fw_cfg() can access the memmap via their RISCVVirtState pointers. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 3d547f7c2b..8a703a0233 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -996,7 +996,7 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, } } -static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt_flash(RISCVVirtState *s) { MachineState *ms = MACHINE(s); hwaddr flashsize = s->memmap[VIRT_FLASH].size / 2; @@ -1011,11 +1011,11 @@ static void create_fdt_flash(RISCVVirtState *s, const MemMapEntry *memmap) qemu_fdt_setprop_cell(ms->fdt, name, "bank-width", 4); } -static void create_fdt_fw_cfg(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt_fw_cfg(RISCVVirtState *s) { MachineState *ms = MACHINE(s); - hwaddr base = memmap[VIRT_FW_CFG].base; - hwaddr size = memmap[VIRT_FW_CFG].size; + hwaddr base = s->memmap[VIRT_FW_CFG].base; + hwaddr size = s->memmap[VIRT_FW_CFG].size; g_autofree char *nodename = g_strdup_printf("/fw-cfg@%" PRIx64, base); qemu_fdt_add_subnode(ms->fdt, nodename); @@ -1146,7 +1146,7 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_rtc(s, s->memmap, irq_mmio_phandle); } -static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) +static void create_fdt(RISCVVirtState *s) { MachineState *ms = MACHINE(s); uint8_t rng_seed[32]; @@ -1173,7 +1173,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) * The "/soc/pci@..." node is needed for PCIE hotplugs * that might happen before finalize_fdt(). */ - name = g_strdup_printf("/soc/pci@%lx", (long) memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%lx", + (long) s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_add_subnode(ms->fdt, "/chosen"); @@ -1185,8 +1186,8 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap) qemu_fdt_add_subnode(ms->fdt, "/aliases"); - create_fdt_flash(s, memmap); - create_fdt_fw_cfg(s, memmap); + create_fdt_flash(s); + create_fdt_fw_cfg(s); create_fdt_pmu(s); } @@ -1715,7 +1716,7 @@ static void virt_machine_init(MachineState *machine) exit(1); } } else { - create_fdt(s, s->memmap); + create_fdt(s); } if (virt_is_iommu_sys_enabled(s)) { From 04c4f8d1ee373b9b8c413619f5600caa3e7b006c Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:08 -0300 Subject: [PATCH 1014/2760] hw/riscv/virt.c: use s->memmap in create_fdt_sockets() path create_fdt_sockets() and all its fdt helpers (create_fdt_socket_aplic(), create_fdt_imsic(), create_fdt_socket_plic(), create_fdt_socket_aclint() and create_fdt_socket_memory()) can use s->memmap from their RISCVVirtState pointer instead of having an extra memmap argument. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 89 ++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 8a703a0233..e66a46f524 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -301,14 +301,13 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, } } -static void create_fdt_socket_memory(RISCVVirtState *s, - const MemMapEntry *memmap, int socket) +static void create_fdt_socket_memory(RISCVVirtState *s, int socket) { g_autofree char *mem_name = NULL; uint64_t addr, size; MachineState *ms = MACHINE(s); - addr = memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); + addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); size = riscv_socket_mem_size(ms, socket); mem_name = g_strdup_printf("/memory@%lx", (long)addr); qemu_fdt_add_subnode(ms->fdt, mem_name); @@ -319,7 +318,7 @@ static void create_fdt_socket_memory(RISCVVirtState *s, } static void create_fdt_socket_clint(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *intc_phandles) { int cpu; @@ -340,21 +339,22 @@ static void create_fdt_socket_clint(RISCVVirtState *s, clint_cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER); } - clint_addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); + clint_addr = s->memmap[VIRT_CLINT].base + + (s->memmap[VIRT_CLINT].size * socket); clint_name = g_strdup_printf("/soc/clint@%lx", clint_addr); qemu_fdt_add_subnode(ms->fdt, clint_name); qemu_fdt_setprop_string_array(ms->fdt, clint_name, "compatible", (char **)&clint_compat, ARRAY_SIZE(clint_compat)); qemu_fdt_setprop_cells(ms->fdt, clint_name, "reg", - 0x0, clint_addr, 0x0, memmap[VIRT_CLINT].size); + 0x0, clint_addr, 0x0, s->memmap[VIRT_CLINT].size); qemu_fdt_setprop(ms->fdt, clint_name, "interrupts-extended", clint_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 4); riscv_socket_fdt_write_id(ms, clint_name, socket); } static void create_fdt_socket_aclint(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *intc_phandles) { int cpu; @@ -381,8 +381,10 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, aclint_cells_size = s->soc[socket].num_harts * sizeof(uint32_t) * 2; if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_CLINT].base + (memmap[VIRT_CLINT].size * socket); + addr = s->memmap[VIRT_CLINT].base + + (s->memmap[VIRT_CLINT].size * socket); name = g_strdup_printf("/soc/mswi@%lx", addr); + qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-mswi"); @@ -397,13 +399,13 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, } if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_CLINT].base + + addr = s->memmap[VIRT_CLINT].base + (RISCV_ACLINT_DEFAULT_MTIMER_SIZE * socket); size = RISCV_ACLINT_DEFAULT_MTIMER_SIZE; } else { - addr = memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + - (memmap[VIRT_CLINT].size * socket); - size = memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; + addr = s->memmap[VIRT_CLINT].base + RISCV_ACLINT_SWI_SIZE + + (s->memmap[VIRT_CLINT].size * socket); + size = s->memmap[VIRT_CLINT].size - RISCV_ACLINT_SWI_SIZE; } name = g_strdup_printf("/soc/mtimer@%lx", addr); qemu_fdt_add_subnode(ms->fdt, name); @@ -420,14 +422,15 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, g_free(name); if (s->aia_type != VIRT_AIA_TYPE_APLIC_IMSIC) { - addr = memmap[VIRT_ACLINT_SSWI].base + - (memmap[VIRT_ACLINT_SSWI].size * socket); + addr = s->memmap[VIRT_ACLINT_SSWI].base + + (s->memmap[VIRT_ACLINT_SSWI].size * socket); + name = g_strdup_printf("/soc/sswi@%lx", addr); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "riscv,aclint-sswi"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, addr, 0x0, memmap[VIRT_ACLINT_SSWI].size); + 0x0, addr, 0x0, s->memmap[VIRT_ACLINT_SSWI].size); qemu_fdt_setprop(ms->fdt, name, "interrupts-extended", aclint_sswi_cells, aclint_cells_size); qemu_fdt_setprop(ms->fdt, name, "interrupt-controller", NULL, 0); @@ -438,7 +441,7 @@ static void create_fdt_socket_aclint(RISCVVirtState *s, } static void create_fdt_socket_plic(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t *phandle, uint32_t *intc_phandles, uint32_t *plic_phandles) { @@ -452,7 +455,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s, }; plic_phandles[socket] = (*phandle)++; - plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); + plic_addr = s->memmap[VIRT_PLIC].base + + (s->memmap[VIRT_PLIC].size * socket); plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); qemu_fdt_add_subnode(ms->fdt, plic_name); qemu_fdt_setprop_cell(ms->fdt, plic_name, @@ -491,7 +495,7 @@ static void create_fdt_socket_plic(RISCVVirtState *s, } qemu_fdt_setprop_cells(ms->fdt, plic_name, "reg", - 0x0, plic_addr, 0x0, memmap[VIRT_PLIC].size); + 0x0, plic_addr, 0x0, s->memmap[VIRT_PLIC].size); qemu_fdt_setprop_cell(ms->fdt, plic_name, "riscv,ndev", VIRT_IRQCHIP_NUM_SOURCES - 1); riscv_socket_fdt_write_id(ms, plic_name, socket); @@ -500,8 +504,8 @@ static void create_fdt_socket_plic(RISCVVirtState *s, if (!socket) { platform_bus_add_all_fdt_nodes(ms->fdt, plic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, + s->memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); } } @@ -588,7 +592,7 @@ static void create_fdt_one_imsic(RISCVVirtState *s, hwaddr base_addr, qemu_fdt_setprop_cell(ms->fdt, imsic_name, "phandle", msi_phandle); } -static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_imsic(RISCVVirtState *s, uint32_t *phandle, uint32_t *intc_phandles, uint32_t *msi_m_phandle, uint32_t *msi_s_phandle) { @@ -597,12 +601,12 @@ static void create_fdt_imsic(RISCVVirtState *s, const MemMapEntry *memmap, if (!kvm_enabled()) { /* M-level IMSIC node */ - create_fdt_one_imsic(s, memmap[VIRT_IMSIC_M].base, intc_phandles, + create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_M].base, intc_phandles, *msi_m_phandle, true, 0); } /* S-level IMSIC node */ - create_fdt_one_imsic(s, memmap[VIRT_IMSIC_S].base, intc_phandles, + create_fdt_one_imsic(s, s->memmap[VIRT_IMSIC_S].base, intc_phandles, *msi_s_phandle, false, imsic_num_bits(s->aia_guests + 1)); @@ -679,7 +683,7 @@ static void create_fdt_one_aplic(RISCVVirtState *s, int socket, } static void create_fdt_socket_aplic(RISCVVirtState *s, - const MemMapEntry *memmap, int socket, + int socket, uint32_t msi_m_phandle, uint32_t msi_s_phandle, uint32_t *phandle, @@ -696,18 +700,19 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, if (!kvm_enabled()) { /* M-level APLIC node */ - aplic_addr = memmap[VIRT_APLIC_M].base + - (memmap[VIRT_APLIC_M].size * socket); - create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_M].size, + aplic_addr = s->memmap[VIRT_APLIC_M].base + + (s->memmap[VIRT_APLIC_M].size * socket); + create_fdt_one_aplic(s, socket, aplic_addr, + s->memmap[VIRT_APLIC_M].size, msi_m_phandle, intc_phandles, aplic_m_phandle, aplic_s_phandle, true, num_harts); } /* S-level APLIC node */ - aplic_addr = memmap[VIRT_APLIC_S].base + - (memmap[VIRT_APLIC_S].size * socket); - create_fdt_one_aplic(s, socket, aplic_addr, memmap[VIRT_APLIC_S].size, + aplic_addr = s->memmap[VIRT_APLIC_S].base + + (s->memmap[VIRT_APLIC_S].size * socket); + create_fdt_one_aplic(s, socket, aplic_addr, s->memmap[VIRT_APLIC_S].size, msi_s_phandle, intc_phandles, aplic_s_phandle, 0, false, num_harts); @@ -715,8 +720,8 @@ static void create_fdt_socket_aplic(RISCVVirtState *s, if (!socket) { g_autofree char *aplic_name = fdt_get_aplic_nodename(aplic_addr); platform_bus_add_all_fdt_nodes(ms->fdt, aplic_name, - memmap[VIRT_PLATFORM_BUS].base, - memmap[VIRT_PLATFORM_BUS].size, + s->memmap[VIRT_PLATFORM_BUS].base, + s->memmap[VIRT_PLATFORM_BUS].size, VIRT_PLATFORM_BUS_IRQ); } @@ -734,7 +739,7 @@ static void create_fdt_pmu(RISCVVirtState *s) riscv_pmu_generate_fdt_node(ms->fdt, hart.pmu_avail_ctrs, pmu_name); } -static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_sockets(RISCVVirtState *s, uint32_t *phandle, uint32_t *irq_mmio_phandle, uint32_t *irq_pcie_phandle, @@ -770,20 +775,20 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, create_fdt_socket_cpus(s, socket, clust_name, phandle, &intc_phandles[phandle_pos]); - create_fdt_socket_memory(s, memmap, socket); + create_fdt_socket_memory(s, socket); if (virt_aclint_allowed() && s->have_aclint) { - create_fdt_socket_aclint(s, memmap, socket, + create_fdt_socket_aclint(s, socket, &intc_phandles[phandle_pos]); } else if (tcg_enabled()) { - create_fdt_socket_clint(s, memmap, socket, + create_fdt_socket_clint(s, socket, &intc_phandles[phandle_pos]); } } if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { - create_fdt_imsic(s, memmap, phandle, intc_phandles, - &msi_m_phandle, &msi_s_phandle); + create_fdt_imsic(s, phandle, intc_phandles, + &msi_m_phandle, &msi_s_phandle); *msi_pcie_phandle = msi_s_phandle; } @@ -792,7 +797,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, * mode, we'll use only one APLIC instance. */ if (!virt_use_emulated_aplic(s->aia_type)) { - create_fdt_socket_aplic(s, memmap, 0, + create_fdt_socket_aplic(s, 0, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[0], xplic_phandles, ms->smp.cpus); @@ -806,11 +811,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, phandle_pos -= s->soc[socket].num_harts; if (s->aia_type == VIRT_AIA_TYPE_NONE) { - create_fdt_socket_plic(s, memmap, socket, phandle, + create_fdt_socket_plic(s, socket, phandle, &intc_phandles[phandle_pos], xplic_phandles); } else { - create_fdt_socket_aplic(s, memmap, socket, + create_fdt_socket_aplic(s, socket, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[phandle_pos], xplic_phandles, @@ -1126,7 +1131,7 @@ static void finalize_fdt(RISCVVirtState *s) uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; uint32_t iommu_sys_phandle = 1; - create_fdt_sockets(s, s->memmap, &phandle, &irq_mmio_phandle, + create_fdt_sockets(s, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); From a51a88fd5d2784c8f6eaaa386dbb5d621949f3e5 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:09 -0300 Subject: [PATCH 1015/2760] hw/riscv/virt.c: use s->memmap in create_fdt_virtio() create_fdt_virtio() can use s->memmap instead of having an extra argument for it. While we're at it rewrite it a little bit to avoid the clunky line in 'name' and code repetition: - declare 'virtio_base' out of the loop since it never changes; - declare a 'size' variable. Use it to calculate the address of the virtio device in an 'addr' variable; - use 'addr' in the 'name' g_strdup_printf(); - use 'addr' and 'size' when creating the 'reg' property. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-8-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e66a46f524..37bd720068 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -842,21 +842,24 @@ static void create_fdt_sockets(RISCVVirtState *s, riscv_socket_fdt_write_distance_matrix(ms); } -static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, - uint32_t irq_virtio_phandle) +static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle) { int i; MachineState *ms = MACHINE(s); + hwaddr virtio_base = s->memmap[VIRT_VIRTIO].base; for (i = 0; i < VIRTIO_COUNT; i++) { - g_autofree char *name = g_strdup_printf("/soc/virtio_mmio@%lx", - (long)(memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size)); + g_autofree char *name = NULL; + uint64_t size = s->memmap[VIRT_VIRTIO].size; + hwaddr addr = virtio_base + i * size; + + name = g_strdup_printf("/soc/virtio_mmio@%"HWADDR_PRIx, addr); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "virtio,mmio"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, - 0x0, memmap[VIRT_VIRTIO].size); + 0x0, addr, + 0x0, size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_virtio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -1135,7 +1138,7 @@ static void finalize_fdt(RISCVVirtState *s) &irq_pcie_phandle, &irq_virtio_phandle, &msi_pcie_phandle); - create_fdt_virtio(s, s->memmap, irq_virtio_phandle); + create_fdt_virtio(s, irq_virtio_phandle); if (virt_is_iommu_sys_enabled(s)) { create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, From 621e45271f53d09789155ea89e16cdee34988654 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:10 -0300 Subject: [PATCH 1016/2760] hw/riscv/virt.c: use s->memmap in finalize_fdt() functions Change create_fdt_pcie(), create_fdt_reset(), create_fdt_uart() and create_fdt_rtc() to use s->memmap in their logic. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-9-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 37bd720068..edb6973100 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -872,7 +872,7 @@ static void create_fdt_virtio(RISCVVirtState *s, uint32_t irq_virtio_phandle) } } -static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_pcie(RISCVVirtState *s, uint32_t irq_pcie_phandle, uint32_t msi_pcie_phandle, uint32_t iommu_sys_phandle) @@ -881,7 +881,7 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, MachineState *ms = MACHINE(s); name = g_strdup_printf("/soc/pci@%lx", - (long) memmap[VIRT_PCIE_ECAM].base); + (long) s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS); qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", @@ -892,19 +892,19 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(ms->fdt, name, "device_type", "pci"); qemu_fdt_setprop_cell(ms->fdt, name, "linux,pci-domain", 0); qemu_fdt_setprop_cells(ms->fdt, name, "bus-range", 0, - memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); + s->memmap[VIRT_PCIE_ECAM].size / PCIE_MMCFG_SIZE_MIN - 1); qemu_fdt_setprop(ms->fdt, name, "dma-coherent", NULL, 0); if (s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC) { qemu_fdt_setprop_cell(ms->fdt, name, "msi-parent", msi_pcie_phandle); } qemu_fdt_setprop_cells(ms->fdt, name, "reg", 0, - memmap[VIRT_PCIE_ECAM].base, 0, memmap[VIRT_PCIE_ECAM].size); + s->memmap[VIRT_PCIE_ECAM].base, 0, s->memmap[VIRT_PCIE_ECAM].size); qemu_fdt_setprop_sized_cells(ms->fdt, name, "ranges", 1, FDT_PCI_RANGE_IOPORT, 2, 0, - 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, + 2, s->memmap[VIRT_PCIE_PIO].base, 2, s->memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO, - 2, memmap[VIRT_PCIE_MMIO].base, - 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, + 2, s->memmap[VIRT_PCIE_MMIO].base, + 2, s->memmap[VIRT_PCIE_MMIO].base, 2, s->memmap[VIRT_PCIE_MMIO].size, 1, FDT_PCI_RANGE_MMIO_64BIT, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); @@ -918,8 +918,7 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); } -static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, - uint32_t *phandle) +static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) { char *name; uint32_t test_phandle; @@ -927,7 +926,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, test_phandle = (*phandle)++; name = g_strdup_printf("/soc/test@%lx", - (long)memmap[VIRT_TEST].base); + (long)s->memmap[VIRT_TEST].base); qemu_fdt_add_subnode(ms->fdt, name); { static const char * const compat[3] = { @@ -937,7 +936,7 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, (char **)&compat, ARRAY_SIZE(compat)); } qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_TEST].base, 0x0, memmap[VIRT_TEST].size); + 0x0, s->memmap[VIRT_TEST].base, 0x0, s->memmap[VIRT_TEST].size); qemu_fdt_setprop_cell(ms->fdt, name, "phandle", test_phandle); test_phandle = qemu_fdt_get_phandle(ms->fdt, name); g_free(name); @@ -959,18 +958,19 @@ static void create_fdt_reset(RISCVVirtState *s, const MemMapEntry *memmap, g_free(name); } -static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_uart(RISCVVirtState *s, uint32_t irq_mmio_phandle) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/serial@%lx", (long)memmap[VIRT_UART0].base); + name = g_strdup_printf("/soc/serial@%lx", + (long)s->memmap[VIRT_UART0].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_UART0].base, - 0x0, memmap[VIRT_UART0].size); + 0x0, s->memmap[VIRT_UART0].base, + 0x0, s->memmap[VIRT_UART0].size); qemu_fdt_setprop_cell(ms->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -983,18 +983,18 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap, qemu_fdt_setprop_string(ms->fdt, "/aliases", "serial0", name); } -static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap, +static void create_fdt_rtc(RISCVVirtState *s, uint32_t irq_mmio_phandle) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/rtc@%lx", (long)memmap[VIRT_RTC].base); + name = g_strdup_printf("/soc/rtc@%lx", (long)s->memmap[VIRT_RTC].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", - 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); + 0x0, s->memmap[VIRT_RTC].base, 0x0, s->memmap[VIRT_RTC].size); qemu_fdt_setprop_cell(ms->fdt, name, "interrupt-parent", irq_mmio_phandle); if (s->aia_type == VIRT_AIA_TYPE_NONE) { @@ -1144,14 +1144,14 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, &iommu_sys_phandle); } - create_fdt_pcie(s, s->memmap, irq_pcie_phandle, msi_pcie_phandle, + create_fdt_pcie(s, irq_pcie_phandle, msi_pcie_phandle, iommu_sys_phandle); - create_fdt_reset(s, s->memmap, &phandle); + create_fdt_reset(s, &phandle); - create_fdt_uart(s, s->memmap, irq_mmio_phandle); + create_fdt_uart(s, irq_mmio_phandle); - create_fdt_rtc(s, s->memmap, irq_mmio_phandle); + create_fdt_rtc(s, irq_mmio_phandle); } static void create_fdt(RISCVVirtState *s) From e7cb99bfd1afc5cf2265a122bcfeab36eff7489a Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 29 Apr 2025 09:58:11 -0300 Subject: [PATCH 1017/2760] hw/riscv/virt.c: remove 'long' casts in fmt strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can avoid the 'long' casts by using PRIx64 and HWADDR_PRIx on the fmt strings for uint64_t and hwaddr types. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Message-ID: <20250429125811.224803-10-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index edb6973100..0dcced1b49 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -304,12 +304,13 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, static void create_fdt_socket_memory(RISCVVirtState *s, int socket) { g_autofree char *mem_name = NULL; - uint64_t addr, size; + hwaddr addr; + uint64_t size; MachineState *ms = MACHINE(s); addr = s->memmap[VIRT_DRAM].base + riscv_socket_mem_offset(ms, socket); size = riscv_socket_mem_size(ms, socket); - mem_name = g_strdup_printf("/memory@%lx", (long)addr); + mem_name = g_strdup_printf("/memory@%"HWADDR_PRIx, addr); qemu_fdt_add_subnode(ms->fdt, mem_name); qemu_fdt_setprop_cells(ms->fdt, mem_name, "reg", addr >> 32, addr, size >> 32, size); @@ -880,8 +881,8 @@ static void create_fdt_pcie(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_setprop_cell(ms->fdt, name, "#address-cells", FDT_PCI_ADDR_CELLS); qemu_fdt_setprop_cell(ms->fdt, name, "#interrupt-cells", @@ -925,8 +926,8 @@ static void create_fdt_reset(RISCVVirtState *s, uint32_t *phandle) MachineState *ms = MACHINE(s); test_phandle = (*phandle)++; - name = g_strdup_printf("/soc/test@%lx", - (long)s->memmap[VIRT_TEST].base); + name = g_strdup_printf("/soc/test@%"HWADDR_PRIx, + s->memmap[VIRT_TEST].base); qemu_fdt_add_subnode(ms->fdt, name); { static const char * const compat[3] = { @@ -964,8 +965,8 @@ static void create_fdt_uart(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/serial@%lx", - (long)s->memmap[VIRT_UART0].base); + name = g_strdup_printf("/soc/serial@%"HWADDR_PRIx, + s->memmap[VIRT_UART0].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "ns16550a"); qemu_fdt_setprop_cells(ms->fdt, name, "reg", @@ -989,7 +990,8 @@ static void create_fdt_rtc(RISCVVirtState *s, g_autofree char *name = NULL; MachineState *ms = MACHINE(s); - name = g_strdup_printf("/soc/rtc@%lx", (long)s->memmap[VIRT_RTC].base); + name = g_strdup_printf("/soc/rtc@%"HWADDR_PRIx, + s->memmap[VIRT_RTC].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_setprop_string(ms->fdt, name, "compatible", "google,goldfish-rtc"); @@ -1042,8 +1044,8 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *iommu_node = NULL; g_autofree char *pci_node = NULL; - pci_node = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/virtio_iommu@%x,%x", pci_node, PCI_SLOT(bdf), PCI_FUNC(bdf)); iommu_phandle = qemu_fdt_alloc_phandle(fdt); @@ -1111,8 +1113,8 @@ static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) g_autofree char *iommu_node = NULL; g_autofree char *pci_node = NULL; - pci_node = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + pci_node = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); iommu_node = g_strdup_printf("%s/iommu@%x", pci_node, bdf); iommu_phandle = qemu_fdt_alloc_phandle(fdt); qemu_fdt_add_subnode(fdt, iommu_node); @@ -1181,8 +1183,8 @@ static void create_fdt(RISCVVirtState *s) * The "/soc/pci@..." node is needed for PCIE hotplugs * that might happen before finalize_fdt(). */ - name = g_strdup_printf("/soc/pci@%lx", - (long) s->memmap[VIRT_PCIE_ECAM].base); + name = g_strdup_printf("/soc/pci@%"HWADDR_PRIx, + s->memmap[VIRT_PCIE_ECAM].base); qemu_fdt_add_subnode(ms->fdt, name); qemu_fdt_add_subnode(ms->fdt, "/chosen"); From 5979f50fa9fdbb3fb49e2b498f84faa7503c8ed1 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 13 May 2025 23:16:51 -0400 Subject: [PATCH 1018/2760] i386/tcg: Make CPUID_HT and CPUID_EXT3_CMP_LEG supported Since commit c6bd2dd63420 ("i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() instead of cpu_x86_cpuid()") and commit 99a637a86f55 ("i386/cpu: Set and track CPUID_EXT3_CMP_LEG in env->features[FEAT_8000_0001_ECX]"), it gets warnings when booting the VM with vcpus >= 2 and with tcg: qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.01H:EDX.ht [bit 28] qemu-system-x86_64: warning: TCG doesn't support requested feature: CPUID.80000001H:ECX.cmp-legacy [bit 1] This is because, after the two commits, CPUID_HT and CPUID_EXT3_CMP_LEG are set in env->features[] when vcpus >=2 (in x86_cpu_expand_features()) later in x86_cpu_filter_features() it will check against the TCG supported bits. However, current TCG doesn't mark the two bits as supported, hence the warnings. Fix it by adding the two bits to the supported bits of TCG since multiple vcpus are supported by TCG. Fixes: c6bd2dd63420 ("i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() instead of cpu_x86_cpuid()") Fixes: 99a637a86f55 ("i386/cpu: Set and track CPUID_EXT3_CMP_LEG in env->features[FEAT_8000_0001_ECX]") Reported-by: Ewan Hai Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250514031652.838763-2-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index ec908d7d36..9689f6374e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -776,11 +776,12 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | \ CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \ CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \ - CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE) + CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_DE | \ + CPUID_HT) /* partly implemented: CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */ /* missing: - CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */ + CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_TM, CPUID_PBE */ /* * Kernel-only features that can be shown to usermode programs even if @@ -848,7 +849,8 @@ void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1, #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A | \ - CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES) + CPUID_EXT3_3DNOWPREFETCH | CPUID_EXT3_KERNEL_FEATURES | \ + CPUID_EXT3_CMP_LEG) #define TCG_EXT4_FEATURES 0 From 7a48612306768833f8cc87418a5a53e712f26ac1 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 13 May 2025 23:16:52 -0400 Subject: [PATCH 1019/2760] i386/hvf: Make CPUID_HT supported Since Commit c6bd2dd63420 ("i386/cpu: Set up CPUID_HT in x86_cpu_expand_features() instead of cpu_x86_cpuid()"), CPUID_HT will be set in env->features[] in x86_cpu_expand_features() when vcpus >= 2. Later in x86_cpu_filter_features() it will check against the HVF supported bits. It will trigger the warning like qemu-system-x86_64: warning: host doesn't support requested feature: CPUID.01H:EDX.ht [bit 28] Add CPUID_HT to HVF supported CPUID bits to fix it. Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250514031652.838763-3-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/hvf/x86_cpuid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/hvf/x86_cpuid.c b/target/i386/hvf/x86_cpuid.c index fa131b18c6..0798a0cbaf 100644 --- a/target/i386/hvf/x86_cpuid.c +++ b/target/i386/hvf/x86_cpuid.c @@ -73,7 +73,7 @@ uint32_t hvf_get_supported_cpuid(uint32_t func, uint32_t idx, CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | CPUID_PSE36 | CPUID_CLFLUSH | CPUID_MMX | - CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS; + CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS | CPUID_HT; ecx &= CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSSE3 | CPUID_EXT_FMA | CPUID_EXT_CX16 | CPUID_EXT_PCID | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_MOVBE | From e5894fd6f411c113e2b5f62811e96eeb5b084381 Mon Sep 17 00:00:00 2001 From: Rakesh Jeyasingh Date: Tue, 29 Apr 2025 22:33:53 +0530 Subject: [PATCH 1020/2760] hw/pci-host/gt64120: Fix endianness handling The GT-64120 PCI controller requires special handling where: 1. Host bridge(bus 0 ,device 0) must never be byte-swapped 2. Other devices follow MByteSwap bit in GT_PCI0_CMD The previous implementation incorrectly swapped all accesses, breaking host bridge detection (lspci -d 11ab:4620). Changes made: 1. Removed gt64120_update_pci_cfgdata_mapping() and moved data_mem initialization to gt64120_realize() for cleaner setup 2. Implemented custom read/write handlers that: - Preserve host bridge accesses (extract32(config_reg,11,13)==0) - apply swapping only for non-bridge devices in big-endian mode Fixes: 145e2198 ("hw/mips/gt64xxx_pci: Endian-swap using PCI_HOST_BRIDGE MemoryRegionOps") Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2826 Signed-off-by: Rakesh Jeyasingh Tested-by: Thomas Huth Link: https://lore.kernel.org/r/20250429170354.150581-2-rakeshjb010@gmail.com Signed-off-by: Paolo Bonzini --- hw/pci-host/gt64120.c | 82 +++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/hw/pci-host/gt64120.c b/hw/pci-host/gt64120.c index 56a6ef93b7..b12a25696c 100644 --- a/hw/pci-host/gt64120.c +++ b/hw/pci-host/gt64120.c @@ -320,38 +320,6 @@ static void gt64120_isd_mapping(GT64120State *s) memory_region_transaction_commit(); } -static void gt64120_update_pci_cfgdata_mapping(GT64120State *s) -{ - /* Indexed on MByteSwap bit, see Table 158: PCI_0 Command, Offset: 0xc00 */ - static const MemoryRegionOps *pci_host_data_ops[] = { - &pci_host_data_be_ops, &pci_host_data_le_ops - }; - PCIHostState *phb = PCI_HOST_BRIDGE(s); - - memory_region_transaction_begin(); - - /* - * The setting of the MByteSwap bit and MWordSwap bit in the PCI Internal - * Command Register determines how data transactions from the CPU to/from - * PCI are handled along with the setting of the Endianness bit in the CPU - * Configuration Register. See: - * - Table 16: 32-bit PCI Transaction Endianness - * - Table 158: PCI_0 Command, Offset: 0xc00 - */ - - if (memory_region_is_mapped(&phb->data_mem)) { - memory_region_del_subregion(&s->ISD_mem, &phb->data_mem); - object_unparent(OBJECT(&phb->data_mem)); - } - memory_region_init_io(&phb->data_mem, OBJECT(phb), - pci_host_data_ops[s->regs[GT_PCI0_CMD] & 1], - s, "pci-conf-data", 4); - memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2, - &phb->data_mem, 1); - - memory_region_transaction_commit(); -} - static void gt64120_pci_mapping(GT64120State *s) { memory_region_transaction_begin(); @@ -645,7 +613,6 @@ static void gt64120_writel(void *opaque, hwaddr addr, case GT_PCI0_CMD: case GT_PCI1_CMD: s->regs[saddr] = val & 0x0401fc0f; - gt64120_update_pci_cfgdata_mapping(s); break; case GT_PCI0_TOR: case GT_PCI0_BS_SCS10: @@ -1024,6 +991,48 @@ static const MemoryRegionOps isd_mem_ops = { }, }; +static bool bswap(const GT64120State *s) +{ + PCIHostState *phb = PCI_HOST_BRIDGE(s); + /*check for bus == 0 && device == 0, Bits 11:15 = Device , Bits 16:23 = Bus*/ + bool is_phb_dev0 = extract32(phb->config_reg, 11, 13) == 0; + bool le_mode = FIELD_EX32(s->regs[GT_PCI0_CMD], GT_PCI0_CMD, MByteSwap); + /* Only swap for non-bridge devices in big-endian mode */ + return !le_mode && !is_phb_dev0; +} + +static uint64_t gt64120_pci_data_read(void *opaque, hwaddr addr, unsigned size) +{ + GT64120State *s = opaque; + uint32_t val = pci_host_data_le_ops.read(opaque, addr, size); + + if (bswap(s)) { + val = bswap32(val); + } + return val; +} + +static void gt64120_pci_data_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + GT64120State *s = opaque; + + if (bswap(s)) { + val = bswap32(val); + } + pci_host_data_le_ops.write(opaque, addr, val, size); +} + +static const MemoryRegionOps gt64120_pci_data_ops = { + .read = gt64120_pci_data_read, + .write = gt64120_pci_data_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + static void gt64120_reset(DeviceState *dev) { GT64120State *s = GT64120_PCI_HOST_BRIDGE(dev); @@ -1178,7 +1187,6 @@ static void gt64120_reset(DeviceState *dev) gt64120_isd_mapping(s); gt64120_pci_mapping(s); - gt64120_update_pci_cfgdata_mapping(s); } static void gt64120_realize(DeviceState *dev, Error **errp) @@ -1202,6 +1210,12 @@ static void gt64120_realize(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGADDR << 2, &phb->conf_mem, 1); + memory_region_init_io(&phb->data_mem, OBJECT(phb), + >64120_pci_data_ops, + s, "pci-conf-data", 4); + memory_region_add_subregion_overlap(&s->ISD_mem, GT_PCI0_CFGDATA << 2, + &phb->data_mem, 1); + /* * The whole address space decoded by the GT-64120A doesn't generate From 560375cff3ccedabf1fe5ca1bc7a31b13fdc68e5 Mon Sep 17 00:00:00 2001 From: Rakesh Jeyasingh Date: Tue, 29 Apr 2025 22:33:54 +0530 Subject: [PATCH 1021/2760] hw/pci-host: Remove unused pci_host_data_be_ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pci_host_data_be_ops became unused after endianness fixes Suggested-by: Paolo Bonzini Signed-off-by: Rakesh Jeyasingh Reviewed-by: Philippe Mathieu-Daudé Tested-by: Thomas Huth Link: https://lore.kernel.org/r/20250429170354.150581-3-rakeshjb010@gmail.com Signed-off-by: Paolo Bonzini --- hw/pci/pci_host.c | 6 ------ include/hw/pci-host/dino.h | 4 ---- include/hw/pci/pci_host.h | 1 - 3 files changed, 11 deletions(-) diff --git a/hw/pci/pci_host.c b/hw/pci/pci_host.c index abe83bbab8..7179d99178 100644 --- a/hw/pci/pci_host.c +++ b/hw/pci/pci_host.c @@ -217,12 +217,6 @@ const MemoryRegionOps pci_host_data_le_ops = { .endianness = DEVICE_LITTLE_ENDIAN, }; -const MemoryRegionOps pci_host_data_be_ops = { - .read = pci_host_data_read, - .write = pci_host_data_write, - .endianness = DEVICE_BIG_ENDIAN, -}; - static bool pci_host_needed(void *opaque) { PCIHostState *s = opaque; diff --git a/include/hw/pci-host/dino.h b/include/hw/pci-host/dino.h index fd7975c798..5dc8cdf610 100644 --- a/include/hw/pci-host/dino.h +++ b/include/hw/pci-host/dino.h @@ -109,10 +109,6 @@ static const uint32_t reg800_keep_bits[DINO800_REGS] = { struct DinoState { PCIHostState parent_obj; - /* - * PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops, - * so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. - */ uint32_t config_reg_dino; /* keep original copy, including 2 lowest bits */ uint32_t iar0; diff --git a/include/hw/pci/pci_host.h b/include/hw/pci/pci_host.h index e52d8ec2cd..954dd446fa 100644 --- a/include/hw/pci/pci_host.h +++ b/include/hw/pci/pci_host.h @@ -68,6 +68,5 @@ uint32_t pci_data_read(PCIBus *s, uint32_t addr, unsigned len); extern const MemoryRegionOps pci_host_conf_le_ops; extern const MemoryRegionOps pci_host_conf_be_ops; extern const MemoryRegionOps pci_host_data_le_ops; -extern const MemoryRegionOps pci_host_data_be_ops; #endif /* PCI_HOST_H */ From a1b3e82773c4b9f438c2d77f9101fca760b347e6 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Fri, 16 May 2025 17:11:29 +0800 Subject: [PATCH 1022/2760] qapi/misc-target: Rename SGXEPCSection to SgxEpcSection QAPI requires strict PascalCase naming style, i.e., only the first letter of a single word is allowed to be uppercase, which could help with readability. Rename SGXEPCSection to SgxEpcSection. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250516091130.2374221-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/sgx.c | 18 +++++++++--------- qapi/misc-target.json | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index 5685c4fb80..3c601689eb 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -84,10 +84,10 @@ static uint64_t sgx_calc_section_metric(uint64_t low, uint64_t high) ((high & MAKE_64BIT_MASK(0, 20)) << 32); } -static SGXEPCSectionList *sgx_calc_host_epc_sections(void) +static SgxEpcSectionList *sgx_calc_host_epc_sections(void) { - SGXEPCSectionList *head = NULL, **tail = &head; - SGXEPCSection *section; + SgxEpcSectionList *head = NULL, **tail = &head; + SgxEpcSection *section; uint32_t i, type; uint32_t eax, ebx, ecx, edx; uint32_t j = 0; @@ -104,7 +104,7 @@ static SGXEPCSectionList *sgx_calc_host_epc_sections(void) break; } - section = g_new0(SGXEPCSection, 1); + section = g_new0(SgxEpcSection, 1); section->node = j++; section->size = sgx_calc_section_metric(ecx, edx); QAPI_LIST_APPEND(tail, section); @@ -183,17 +183,17 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) return info; } -static SGXEPCSectionList *sgx_get_epc_sections_list(void) +static SgxEpcSectionList *sgx_get_epc_sections_list(void) { GSList *device_list = sgx_epc_get_device_list(); - SGXEPCSectionList *head = NULL, **tail = &head; - SGXEPCSection *section; + SgxEpcSectionList *head = NULL, **tail = &head; + SgxEpcSection *section; for (; device_list; device_list = device_list->next) { DeviceState *dev = device_list->data; Object *obj = OBJECT(dev); - section = g_new0(SGXEPCSection, 1); + section = g_new0(SgxEpcSection, 1); section->node = object_property_get_uint(obj, SGX_EPC_NUMA_NODE_PROP, &error_abort); section->size = object_property_get_uint(obj, SGX_EPC_SIZE_PROP, @@ -237,7 +237,7 @@ SGXInfo *qmp_query_sgx(Error **errp) void hmp_info_sgx(Monitor *mon, const QDict *qdict) { Error *err = NULL; - SGXEPCSectionList *section_list, *section; + SgxEpcSectionList *section_list, *section; g_autoptr(SGXInfo) info = qmp_query_sgx(&err); uint64_t size = 0; diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 42e4a7417d..a1275d3873 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -319,7 +319,7 @@ 'if': 'TARGET_ARM' } ## -# @SGXEPCSection: +# @SgxEpcSection: # # Information about intel SGX EPC section info # @@ -329,7 +329,7 @@ # # Since: 7.0 ## -{ 'struct': 'SGXEPCSection', +{ 'struct': 'SgxEpcSection', 'data': { 'node': 'int', 'size': 'uint64'}} @@ -355,7 +355,7 @@ 'sgx1': 'bool', 'sgx2': 'bool', 'flc': 'bool', - 'sections': ['SGXEPCSection']}, + 'sections': ['SgxEpcSection']}, 'if': 'TARGET_I386' } ## From 88aea26d1880f105b00c352485d3bf1f21d55012 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Fri, 16 May 2025 17:11:30 +0800 Subject: [PATCH 1023/2760] qapi/misc-target: Rename SGXInfo to SgxInfo QAPI requires strict PascalCase naming style, i.e., only the first letter of a single word is allowed to be uppercase, which could help with readability. Rename SGXInfo to SgxInfo. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250516091130.2374221-3-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/sgx-stub.c | 4 ++-- hw/i386/sgx.c | 14 +++++++------- qapi/misc-target.json | 12 ++++++------ 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c index 38ff75e9f3..ccb21a975d 100644 --- a/hw/i386/sgx-stub.c +++ b/hw/i386/sgx-stub.c @@ -10,13 +10,13 @@ void sgx_epc_build_srat(GArray *table_data) { } -SGXInfo *qmp_query_sgx(Error **errp) +SgxInfo *qmp_query_sgx(Error **errp) { error_setg(errp, "SGX support is not compiled in"); return NULL; } -SGXInfo *qmp_query_sgx_capabilities(Error **errp) +SgxInfo *qmp_query_sgx_capabilities(Error **errp) { error_setg(errp, "SGX support is not compiled in"); return NULL; diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index 3c601689eb..c80203b438 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -153,9 +153,9 @@ static void sgx_epc_reset(void *opaque) } } -SGXInfo *qmp_query_sgx_capabilities(Error **errp) +SgxInfo *qmp_query_sgx_capabilities(Error **errp) { - SGXInfo *info = NULL; + SgxInfo *info = NULL; uint32_t eax, ebx, ecx, edx; Error *local_err = NULL; @@ -166,7 +166,7 @@ SGXInfo *qmp_query_sgx_capabilities(Error **errp) return NULL; } - info = g_new0(SGXInfo, 1); + info = g_new0(SgxInfo, 1); host_cpuid(0x7, 0, &eax, &ebx, &ecx, &edx); info->sgx = ebx & (1U << 2) ? true : false; @@ -205,9 +205,9 @@ static SgxEpcSectionList *sgx_get_epc_sections_list(void) return head; } -SGXInfo *qmp_query_sgx(Error **errp) +SgxInfo *qmp_query_sgx(Error **errp) { - SGXInfo *info = NULL; + SgxInfo *info = NULL; X86MachineState *x86ms; PCMachineState *pcms = (PCMachineState *)object_dynamic_cast(qdev_get_machine(), @@ -223,7 +223,7 @@ SGXInfo *qmp_query_sgx(Error **errp) return NULL; } - info = g_new0(SGXInfo, 1); + info = g_new0(SgxInfo, 1); info->sgx = true; info->sgx1 = true; @@ -238,7 +238,7 @@ void hmp_info_sgx(Monitor *mon, const QDict *qdict) { Error *err = NULL; SgxEpcSectionList *section_list, *section; - g_autoptr(SGXInfo) info = qmp_query_sgx(&err); + g_autoptr(SgxInfo) info = qmp_query_sgx(&err); uint64_t size = 0; if (err) { diff --git a/qapi/misc-target.json b/qapi/misc-target.json index a1275d3873..6b3c9d8bd5 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -334,7 +334,7 @@ 'size': 'uint64'}} ## -# @SGXInfo: +# @SgxInfo: # # Information about intel Safe Guard eXtension (SGX) support # @@ -350,7 +350,7 @@ # # Since: 6.2 ## -{ 'struct': 'SGXInfo', +{ 'struct': 'SgxInfo', 'data': { 'sgx': 'bool', 'sgx1': 'bool', 'sgx2': 'bool', @@ -363,7 +363,7 @@ # # Returns information about SGX # -# Returns: @SGXInfo +# Returns: @SgxInfo # # Since: 6.2 # @@ -375,14 +375,14 @@ # "sections": [{"node": 0, "size": 67108864}, # {"node": 1, "size": 29360128}]} } ## -{ 'command': 'query-sgx', 'returns': 'SGXInfo', 'if': 'TARGET_I386' } +{ 'command': 'query-sgx', 'returns': 'SgxInfo', 'if': 'TARGET_I386' } ## # @query-sgx-capabilities: # # Returns information from host SGX capabilities # -# Returns: @SGXInfo +# Returns: @SgxInfo # # Since: 6.2 # @@ -394,7 +394,7 @@ # "section" : [{"node": 0, "size": 67108864}, # {"node": 1, "size": 29360128}]} } ## -{ 'command': 'query-sgx-capabilities', 'returns': 'SGXInfo', 'if': 'TARGET_I386' } +{ 'command': 'query-sgx-capabilities', 'returns': 'SgxInfo', 'if': 'TARGET_I386' } ## From c6b8fb0fb1599cffdfe6603f93bba937c1ecb0b1 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 13 May 2025 22:31:30 +0800 Subject: [PATCH 1024/2760] qapi/misc-target: Fix the doc related SGXEPCSection The "sections" field of SGXInfo is used to gather EPC section information for both the guest and the host. Therefore, delete the "for guest" limitation. Additionally, avoid the abbreviation "info" and use "information" instead. And for SGXEPCSection, delete the redundant word "info". Reported-by: Markus Armbruster Signed-off-by: Zhao Liu Acked-by: Markus Armbruster Link: https://lore.kernel.org/r/20250513143131.2008078-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- qapi/misc-target.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 6b3c9d8bd5..6814708972 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -321,7 +321,7 @@ ## # @SgxEpcSection: # -# Information about intel SGX EPC section info +# Information about intel SGX EPC section # # @node: the numa node # @@ -346,7 +346,7 @@ # # @flc: true if FLC is supported # -# @sections: The EPC sections info for guest (Since: 7.0) +# @sections: The EPC sections information (Since: 7.0) # # Since: 6.2 ## From 7f2131c35c1781ca41c62dc26fd93282e1351323 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 13 May 2025 22:31:31 +0800 Subject: [PATCH 1025/2760] qapi/misc-target: Fix the doc to distinguish query-sgx and query-sgx-capabilities There're 2 QMP commands: query-sgx and query-sgx-capabilities, but their outputs are very similar and the documentation lacks clear differentiation. From the codes, query-sgx is used to gather guest's SGX capabilities (including SGX related CPUIDs and EPC sections' size, in SGXInfo), and if guest doesn't have SGX, then QEMU will report the error message. On the other hand, query-sgx-capabilities is used to gather host's SGX capabilities (descripted by SGXInfo as well). And if host doesn't support SGX, then QEMU will also report the error message. Considering that SGXInfo is already documented and both these 2 commands have enough error messages (for the exception case in their codes). Therefore the QAPI documentation for these two commands only needs to emphasize that one of them applies to the guest and the other to the host. Fix their documentation to reflect this difference. Reported-by: Markus Armbruster Suggested-by: Paolo Bonzini Signed-off-by: Zhao Liu Acked-by: Markus Armbruster Link: https://lore.kernel.org/r/20250513143131.2008078-3-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- qapi/misc-target.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qapi/misc-target.json b/qapi/misc-target.json index 6814708972..f7ec695caa 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -361,7 +361,7 @@ ## # @query-sgx: # -# Returns information about SGX +# Returns information about configured SGX capabilities of guest # # Returns: @SgxInfo # @@ -380,7 +380,7 @@ ## # @query-sgx-capabilities: # -# Returns information from host SGX capabilities +# Returns information about SGX capabilities of host # # Returns: @SgxInfo # From 82c81c07e83670befc61333e0bdf3d810e581219 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 12:00:14 +0100 Subject: [PATCH 1026/2760] hw/riscv: acpi: only create RHCT MMU entry for supported types Do not create the RHCT MMU type entry for RV32 CPUs, since it only has definitions for SV39/SV48/SV57. Likewise, check that satp_mode_max_from_map() will actually return a valid value, skipping the MMU type entry if all MMU types were disabled on the command line. Acked-by: Alistair Francis Signed-off-by: Paolo Bonzini --- hw/riscv/virt-acpi-build.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index 1eef2fb4eb..e693d529e1 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -288,6 +288,7 @@ static void build_rhct(GArray *table_data, RISCVCPU *cpu = &s->soc[0].harts[0]; uint32_t mmu_offset = 0; uint8_t satp_mode_max; + bool rv32 = riscv_cpu_is_32bit(cpu); g_autofree char *isa = NULL; AcpiTable table = { .sig = "RHCT", .rev = 1, .oem_id = s->oem_id, @@ -307,7 +308,8 @@ static void build_rhct(GArray *table_data, num_rhct_nodes++; } - if (cpu->cfg.satp_mode.supported != 0) { + if (!rv32 && cpu->cfg.satp_mode.supported != 0 && + (cpu->cfg.satp_mode.map & ~(1 << VM_1_10_MBARE))) { num_rhct_nodes++; } @@ -367,7 +369,8 @@ static void build_rhct(GArray *table_data, } /* MMU node structure */ - if (cpu->cfg.satp_mode.supported != 0) { + if (!rv32 && cpu->cfg.satp_mode.supported != 0 && + (cpu->cfg.satp_mode.map & ~(1 << VM_1_10_MBARE))) { satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); mmu_offset = table_data->len - table.table_offset; build_append_int_noprefix(table_data, 2, 2); /* Type */ @@ -382,7 +385,7 @@ static void build_rhct(GArray *table_data, } else if (satp_mode_max == VM_1_10_SV39) { build_append_int_noprefix(table_data, 0, 1); /* Sv39 */ } else { - assert(1); + g_assert_not_reached(); } } From b22cfa0f44e360d09595705cea8c97be692e2080 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 13:04:22 +0100 Subject: [PATCH 1027/2760] target/riscv: assert argument to set_satp_mode_max_supported is valid Check that the argument to set_satp_mode_max_supported is valid for the MXL value of the CPU. It would be a bug in the CPU definition if it weren't. In fact, there is such a bug in riscv_bare_cpu_init(): not just SV64 is not a valid VM mode for 32-bit CPUs, SV64 is not a valid VM mode at all, not yet at least. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d92874baa0..0f7ce5305b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -444,6 +444,8 @@ static void set_satp_mode_max_supported(RISCVCPU *cpu, cpu->cfg.satp_mode.supported |= (1 << i); } } + + assert(cpu->cfg.satp_mode.supported & (1 << satp_mode)); } /* Set the satp mode to the max supported */ @@ -1497,7 +1499,9 @@ static void riscv_bare_cpu_init(Object *obj) * satp_mode manually (see set_satp_mode_default()). */ #ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_SV64); + set_satp_mode_max_supported(RISCV_CPU(obj), + riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ? + VM_1_10_SV32 : VM_1_10_SV57); #endif } From 357ce8171a9c7581ba02475874c8c28ed5220d9e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 10:52:09 +0100 Subject: [PATCH 1028/2760] target/riscv: cpu: store max SATP mode as a single integer The maximum available SATP mode implies all the shorter virtual address sizes. Store it in RISCVCPUConfig and avoid recomputing it via satp_mode_max_from_map. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 11 +++++------ target/riscv/cpu_cfg.h | 1 + target/riscv/tcg/tcg-cpu.c | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0f7ce5305b..32c283a662 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -446,6 +446,7 @@ static void set_satp_mode_max_supported(RISCVCPU *cpu, } assert(cpu->cfg.satp_mode.supported & (1 << satp_mode)); + cpu->cfg.max_satp_mode = satp_mode; } /* Set the satp mode to the max supported */ @@ -1172,16 +1173,13 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) { bool rv32 = riscv_cpu_is_32bit(cpu); - uint8_t satp_mode_map_max, satp_mode_supported_max; + uint8_t satp_mode_map_max; /* The CPU wants the OS to decide which satp mode to use */ if (cpu->cfg.satp_mode.supported == 0) { return; } - satp_mode_supported_max = - satp_mode_max_from_map(cpu->cfg.satp_mode.supported); - if (cpu->cfg.satp_mode.map == 0) { if (cpu->cfg.satp_mode.init == 0) { /* If unset by the user, we fallback to the default satp mode. */ @@ -1210,10 +1208,10 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); /* Make sure the user asked for a supported configuration (HW and qemu) */ - if (satp_mode_map_max > satp_mode_supported_max) { + if (satp_mode_map_max > cpu->cfg.max_satp_mode) { error_setg(errp, "satp_mode %s is higher than hw max capability %s", satp_mode_str(satp_mode_map_max, rv32), - satp_mode_str(satp_mode_supported_max, rv32)); + satp_mode_str(cpu->cfg.max_satp_mode, rv32)); return; } @@ -1473,6 +1471,7 @@ static void riscv_cpu_init(Object *obj) cpu->cfg.cbop_blocksize = 64; cpu->cfg.cboz_blocksize = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; + cpu->cfg.max_satp_mode = -1; } static void riscv_bare_cpu_init(Object *obj) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index cfe371b829..c8ea5cdc87 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -196,6 +196,7 @@ struct RISCVCPUConfig { bool short_isa_string; + int8_t max_satp_mode; RISCVSATPMap satp_mode; }; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 55e00972b7..ab8659f304 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -816,8 +816,9 @@ static bool riscv_cpu_validate_profile_satp(RISCVCPU *cpu, RISCVCPUProfile *profile, bool send_warn) { - int satp_max = satp_mode_max_from_map(cpu->cfg.satp_mode.supported); + int satp_max = cpu->cfg.max_satp_mode; + assert(satp_max >= 0); if (profile->satp_mode > satp_max) { if (send_warn) { bool is_32bit = riscv_cpu_is_32bit(cpu); From 211c7f9bb817ca7bb7855535da4db5ca80a8aa1d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 11:09:15 +0100 Subject: [PATCH 1029/2760] target/riscv: update max_satp_mode based on QOM properties Almost all users of cpu->cfg.satp_mode care about the "max" value satp_mode_max_from_map(cpu->cfg.satp_mode.map). Convert the QOM properties back into it. For TCG, deduce the bitmap of supported modes from valid_vm[]. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- hw/riscv/virt-acpi-build.c | 14 +++++--------- hw/riscv/virt.c | 5 ++--- target/riscv/cpu.c | 27 ++++++++++----------------- target/riscv/cpu.h | 1 - target/riscv/csr.c | 9 +++++++-- 5 files changed, 24 insertions(+), 32 deletions(-) diff --git a/hw/riscv/virt-acpi-build.c b/hw/riscv/virt-acpi-build.c index e693d529e1..8b5683dbde 100644 --- a/hw/riscv/virt-acpi-build.c +++ b/hw/riscv/virt-acpi-build.c @@ -287,7 +287,6 @@ static void build_rhct(GArray *table_data, uint32_t isa_offset, num_rhct_nodes, cmo_offset = 0; RISCVCPU *cpu = &s->soc[0].harts[0]; uint32_t mmu_offset = 0; - uint8_t satp_mode_max; bool rv32 = riscv_cpu_is_32bit(cpu); g_autofree char *isa = NULL; @@ -308,8 +307,7 @@ static void build_rhct(GArray *table_data, num_rhct_nodes++; } - if (!rv32 && cpu->cfg.satp_mode.supported != 0 && - (cpu->cfg.satp_mode.map & ~(1 << VM_1_10_MBARE))) { + if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) { num_rhct_nodes++; } @@ -369,20 +367,18 @@ static void build_rhct(GArray *table_data, } /* MMU node structure */ - if (!rv32 && cpu->cfg.satp_mode.supported != 0 && - (cpu->cfg.satp_mode.map & ~(1 << VM_1_10_MBARE))) { - satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); + if (!rv32 && cpu->cfg.max_satp_mode >= VM_1_10_SV39) { mmu_offset = table_data->len - table.table_offset; build_append_int_noprefix(table_data, 2, 2); /* Type */ build_append_int_noprefix(table_data, 8, 2); /* Length */ build_append_int_noprefix(table_data, 0x1, 2); /* Revision */ build_append_int_noprefix(table_data, 0, 1); /* Reserved */ /* MMU Type */ - if (satp_mode_max == VM_1_10_SV57) { + if (cpu->cfg.max_satp_mode == VM_1_10_SV57) { build_append_int_noprefix(table_data, 2, 1); /* Sv57 */ - } else if (satp_mode_max == VM_1_10_SV48) { + } else if (cpu->cfg.max_satp_mode == VM_1_10_SV48) { build_append_int_noprefix(table_data, 1, 1); /* Sv48 */ - } else if (satp_mode_max == VM_1_10_SV39) { + } else if (cpu->cfg.max_satp_mode == VM_1_10_SV39) { build_append_int_noprefix(table_data, 0, 1); /* Sv39 */ } else { g_assert_not_reached(); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 0dcced1b49..cf280a92e5 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -237,10 +237,10 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, uint32_t cpu_phandle; MachineState *ms = MACHINE(s); bool is_32_bit = riscv_is_32bit(&s->soc[0]); - uint8_t satp_mode_max; for (cpu = s->soc[socket].num_harts - 1; cpu >= 0; cpu--) { RISCVCPU *cpu_ptr = &s->soc[socket].harts[cpu]; + int8_t satp_mode_max = cpu_ptr->cfg.max_satp_mode; g_autofree char *cpu_name = NULL; g_autofree char *core_name = NULL; g_autofree char *intc_name = NULL; @@ -252,8 +252,7 @@ static void create_fdt_socket_cpus(RISCVVirtState *s, int socket, s->soc[socket].hartid_base + cpu); qemu_fdt_add_subnode(ms->fdt, cpu_name); - if (cpu_ptr->cfg.satp_mode.supported != 0) { - satp_mode_max = satp_mode_max_from_map(cpu_ptr->cfg.satp_mode.map); + if (satp_mode_max != -1) { sv_name = g_strdup_printf("riscv,%s", satp_mode_str(satp_mode_max, is_32_bit)); qemu_fdt_setprop_string(ms->fdt, cpu_name, "mmu-type", sv_name); diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 32c283a662..48576bff92 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -389,7 +389,7 @@ static uint8_t satp_mode_from_str(const char *satp_mode_str) g_assert_not_reached(); } -uint8_t satp_mode_max_from_map(uint32_t map) +static uint8_t satp_mode_max_from_map(uint32_t map) { /* * 'map = 0' will make us return (31 - 32), which C will @@ -455,15 +455,13 @@ static void set_satp_mode_default_map(RISCVCPU *cpu) /* * Bare CPUs do not default to the max available. * Users must set a valid satp_mode in the command - * line. + * line. Otherwise, leave the existing max_satp_mode + * in place. */ if (object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_BARE_CPU) != NULL) { warn_report("No satp mode set. Defaulting to 'bare'"); - cpu->cfg.satp_mode.map = (1 << VM_1_10_MBARE); - return; + cpu->cfg.max_satp_mode = VM_1_10_MBARE; } - - cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported; } #endif @@ -1175,8 +1173,8 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) bool rv32 = riscv_cpu_is_32bit(cpu); uint8_t satp_mode_map_max; - /* The CPU wants the OS to decide which satp mode to use */ - if (cpu->cfg.satp_mode.supported == 0) { + if (cpu->cfg.max_satp_mode == -1) { + /* The CPU wants the hypervisor to decide which satp mode to allow */ return; } @@ -1195,14 +1193,14 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) (cpu->cfg.satp_mode.supported & (1 << i))) { for (int j = i - 1; j >= 0; --j) { if (cpu->cfg.satp_mode.supported & (1 << j)) { - cpu->cfg.satp_mode.map |= (1 << j); - break; + cpu->cfg.max_satp_mode = j; + return; } } - break; } } } + return; } satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); @@ -1232,12 +1230,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) } } - /* Finally expand the map so that all valid modes are set */ - for (int i = satp_mode_map_max - 1; i >= 0; --i) { - if (cpu->cfg.satp_mode.supported & (1 << i)) { - cpu->cfg.satp_mode.map |= (1 << i); - } - } + cpu->cfg.max_satp_mode = satp_mode_map_max; } #endif diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index b56d3afa69..3d89a4a83b 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -930,7 +930,6 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); target_ulong riscv_new_csr_seed(target_ulong new_value, target_ulong write_mask); -uint8_t satp_mode_max_from_map(uint32_t map); const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); /* Implemented in th_csr.c */ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 288edeedea..9843fd2191 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -1912,8 +1912,13 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno, static bool validate_vm(CPURISCVState *env, target_ulong vm) { - uint64_t mode_supported = riscv_cpu_cfg(env)->satp_mode.map; - return get_field(mode_supported, (1 << vm)); + bool rv32 = riscv_cpu_mxl(env) == MXL_RV32; + RISCVCPU *cpu = env_archcpu(env); + int satp_mode_supported_max = cpu->cfg.max_satp_mode; + const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; + + assert(satp_mode_supported_max >= 0); + return vm <= satp_mode_supported_max && valid_vm[vm]; } static target_ulong legalize_xatp(CPURISCVState *env, target_ulong old_xatp, From dabb54c160b84d648f375d8f7688fb1099ba32ab Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 11:09:15 +0100 Subject: [PATCH 1030/2760] target/riscv: remove supported from RISCVSATPMap "supported" can be computed on the fly based on the max_satp_mode. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 34 ++++++++++++++++++++++++---------- target/riscv/cpu_cfg.h | 4 +--- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 48576bff92..0326cd8e56 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -439,14 +439,27 @@ static void set_satp_mode_max_supported(RISCVCPU *cpu, bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; - for (int i = 0; i <= satp_mode; ++i) { - if (valid_vm[i]) { - cpu->cfg.satp_mode.supported |= (1 << i); - } + assert(valid_vm[satp_mode]); + cpu->cfg.max_satp_mode = satp_mode; +} + +static bool get_satp_mode_supported(RISCVCPU *cpu, uint16_t *supported) +{ + bool rv32 = riscv_cpu_is_32bit(cpu); + const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; + int satp_mode = cpu->cfg.max_satp_mode; + + if (satp_mode == -1) { + return false; } - assert(cpu->cfg.satp_mode.supported & (1 << satp_mode)); - cpu->cfg.max_satp_mode = satp_mode; + *supported = 0; + for (int i = 0; i <= satp_mode; ++i) { + if (valid_vm[i]) { + *supported |= (1 << i); + } + } + return true; } /* Set the satp mode to the max supported */ @@ -1171,9 +1184,10 @@ static void riscv_cpu_disas_set_info(CPUState *s, disassemble_info *info) static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) { bool rv32 = riscv_cpu_is_32bit(cpu); + uint16_t supported; uint8_t satp_mode_map_max; - if (cpu->cfg.max_satp_mode == -1) { + if (!get_satp_mode_supported(cpu, &supported)) { /* The CPU wants the hypervisor to decide which satp mode to allow */ return; } @@ -1190,9 +1204,9 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) */ for (int i = 1; i < 16; ++i) { if ((cpu->cfg.satp_mode.init & (1 << i)) && - (cpu->cfg.satp_mode.supported & (1 << i))) { + supported & (1 << i)) { for (int j = i - 1; j >= 0; --j) { - if (cpu->cfg.satp_mode.supported & (1 << j)) { + if (supported & (1 << j)) { cpu->cfg.max_satp_mode = j; return; } @@ -1221,7 +1235,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) for (int i = satp_mode_map_max - 1; i >= 0; --i) { if (!(cpu->cfg.satp_mode.map & (1 << i)) && (cpu->cfg.satp_mode.init & (1 << i)) && - (cpu->cfg.satp_mode.supported & (1 << i))) { + (supported & (1 << i))) { error_setg(errp, "cannot disable %s satp mode if %s " "is enabled", satp_mode_str(i, false), satp_mode_str(satp_mode_map_max, false)); diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index c8ea5cdc87..8b80e03c9a 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -29,11 +29,9 @@ * * init is a 16-bit bitmap used to make sure the user selected a correct * configuration as per the specification. - * - * supported is a 16-bit bitmap used to reflect the hw capabilities. */ typedef struct { - uint16_t map, init, supported; + uint16_t map, init; } RISCVSATPMap; struct RISCVCPUConfig { From 80b22be3820f1076d9de1b1f1646ae6b352d7675 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 11:27:12 +0100 Subject: [PATCH 1031/2760] target/riscv: move satp_mode.{map,init} out of CPUConfig They are used to provide the nice QOM properties for svNN, but the canonical source of the CPU configuration is now cpu->cfg.max_satp_mode. Store them in the ArchCPU struct. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 32 ++++++++++++++++---------------- target/riscv/cpu.h | 14 ++++++++++++++ target/riscv/cpu_cfg.h | 14 -------------- 3 files changed, 30 insertions(+), 30 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0326cd8e56..54a996c292 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1192,8 +1192,8 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) return; } - if (cpu->cfg.satp_mode.map == 0) { - if (cpu->cfg.satp_mode.init == 0) { + if (cpu->satp_modes.map == 0) { + if (cpu->satp_modes.init == 0) { /* If unset by the user, we fallback to the default satp mode. */ set_satp_mode_default_map(cpu); } else { @@ -1203,7 +1203,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) * valid_vm_1_10_32/64. */ for (int i = 1; i < 16; ++i) { - if ((cpu->cfg.satp_mode.init & (1 << i)) && + if ((cpu->satp_modes.init & (1 << i)) && supported & (1 << i)) { for (int j = i - 1; j >= 0; --j) { if (supported & (1 << j)) { @@ -1217,7 +1217,7 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) return; } - satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map); + satp_mode_map_max = satp_mode_max_from_map(cpu->satp_modes.map); /* Make sure the user asked for a supported configuration (HW and qemu) */ if (satp_mode_map_max > cpu->cfg.max_satp_mode) { @@ -1233,8 +1233,8 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp) */ if (!rv32) { for (int i = satp_mode_map_max - 1; i >= 0; --i) { - if (!(cpu->cfg.satp_mode.map & (1 << i)) && - (cpu->cfg.satp_mode.init & (1 << i)) && + if (!(cpu->satp_modes.map & (1 << i)) && + (cpu->satp_modes.init & (1 << i)) && (supported & (1 << i))) { error_setg(errp, "cannot disable %s satp mode if %s " "is enabled", satp_mode_str(i, false), @@ -1322,11 +1322,11 @@ bool riscv_cpu_accelerator_compatible(RISCVCPU *cpu) static void cpu_riscv_get_satp(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - RISCVSATPMap *satp_map = opaque; + RISCVSATPModes *satp_modes = opaque; uint8_t satp = satp_mode_from_str(name); bool value; - value = satp_map->map & (1 << satp); + value = satp_modes->map & (1 << satp); visit_type_bool(v, name, &value, errp); } @@ -1334,7 +1334,7 @@ static void cpu_riscv_get_satp(Object *obj, Visitor *v, const char *name, static void cpu_riscv_set_satp(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { - RISCVSATPMap *satp_map = opaque; + RISCVSATPModes *satp_modes = opaque; uint8_t satp = satp_mode_from_str(name); bool value; @@ -1342,8 +1342,8 @@ static void cpu_riscv_set_satp(Object *obj, Visitor *v, const char *name, return; } - satp_map->map = deposit32(satp_map->map, satp, 1, value); - satp_map->init |= 1 << satp; + satp_modes->map = deposit32(satp_modes->map, satp, 1, value); + satp_modes->init |= 1 << satp; } void riscv_add_satp_mode_properties(Object *obj) @@ -1352,16 +1352,16 @@ void riscv_add_satp_mode_properties(Object *obj) if (cpu->env.misa_mxl == MXL_RV32) { object_property_add(obj, "sv32", "bool", cpu_riscv_get_satp, - cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode); + cpu_riscv_set_satp, NULL, &cpu->satp_modes); } else { object_property_add(obj, "sv39", "bool", cpu_riscv_get_satp, - cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode); + cpu_riscv_set_satp, NULL, &cpu->satp_modes); object_property_add(obj, "sv48", "bool", cpu_riscv_get_satp, - cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode); + cpu_riscv_set_satp, NULL, &cpu->satp_modes); object_property_add(obj, "sv57", "bool", cpu_riscv_get_satp, - cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode); + cpu_riscv_set_satp, NULL, &cpu->satp_modes); object_property_add(obj, "sv64", "bool", cpu_riscv_get_satp, - cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode); + cpu_riscv_set_satp, NULL, &cpu->satp_modes); } } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 3d89a4a83b..731ea2540c 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -499,6 +499,19 @@ struct CPUArchState { uint64_t rnmi_excpvec; }; +/* + * map is a 16-bit bitmap: the most significant set bit in map is the maximum + * satp mode that is supported. It may be chosen by the user and must respect + * what qemu implements (valid_1_10_32/64) and what the hw is capable of + * (supported bitmap below). + * + * init is a 16-bit bitmap used to make sure the user selected a correct + * configuration as per the specification. + */ +typedef struct { + uint16_t map, init; +} RISCVSATPModes; + /* * RISCVCPU: * @env: #CPURISCVState @@ -515,6 +528,7 @@ struct ArchCPU { /* Configuration Settings */ RISCVCPUConfig cfg; + RISCVSATPModes satp_modes; QEMUTimer *pmu_timer; /* A bitmask of Available programmable counters */ diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 8b80e03c9a..8fa73c8a07 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -21,19 +21,6 @@ #ifndef RISCV_CPU_CFG_H #define RISCV_CPU_CFG_H -/* - * map is a 16-bit bitmap: the most significant set bit in map is the maximum - * satp mode that is supported. It may be chosen by the user and must respect - * what qemu implements (valid_1_10_32/64) and what the hw is capable of - * (supported bitmap below). - * - * init is a 16-bit bitmap used to make sure the user selected a correct - * configuration as per the specification. - */ -typedef struct { - uint16_t map, init; -} RISCVSATPMap; - struct RISCVCPUConfig { bool ext_zba; bool ext_zbb; @@ -195,7 +182,6 @@ struct RISCVCPUConfig { bool short_isa_string; int8_t max_satp_mode; - RISCVSATPMap satp_mode; }; typedef struct RISCVCPUConfig RISCVCPUConfig; From 71fb3aa5ebba5ba822371f864a12dbcded08147d Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 13:12:09 +0100 Subject: [PATCH 1032/2760] target/riscv: introduce RISCVCPUDef Start putting all the CPU definitions in a struct. Later this will replace instance_init functions with declarative code, for now just remove the ugly cast of class_data. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 27 ++++++++++++++++++--------- target/riscv/cpu.h | 4 ++++ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 54a996c292..6e92fbb992 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -3073,8 +3073,9 @@ static void riscv_cpu_common_class_init(ObjectClass *c, const void *data) static void riscv_cpu_class_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); + const RISCVCPUDef *def = data; - mcc->misa_mxl_max = (RISCVMXL)GPOINTER_TO_UINT(data); + mcc->misa_mxl_max = def->misa_mxl_max; riscv_cpu_validate_misa_mxl(mcc); } @@ -3170,40 +3171,48 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) } #endif -#define DEFINE_DYNAMIC_CPU(type_name, misa_mxl_max, initfn) \ +#define DEFINE_DYNAMIC_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ .parent = TYPE_RISCV_DYNAMIC_CPU, \ .instance_init = (initfn), \ .class_init = riscv_cpu_class_init, \ - .class_data = GUINT_TO_POINTER(misa_mxl_max) \ + .class_data = &(const RISCVCPUDef) { \ + .misa_mxl_max = (misa_mxl_max_), \ + }, \ } -#define DEFINE_VENDOR_CPU(type_name, misa_mxl_max, initfn) \ +#define DEFINE_VENDOR_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ .parent = TYPE_RISCV_VENDOR_CPU, \ .instance_init = (initfn), \ .class_init = riscv_cpu_class_init, \ - .class_data = GUINT_TO_POINTER(misa_mxl_max) \ + .class_data = &(const RISCVCPUDef) { \ + .misa_mxl_max = (misa_mxl_max_), \ + }, \ } -#define DEFINE_BARE_CPU(type_name, misa_mxl_max, initfn) \ +#define DEFINE_BARE_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ .parent = TYPE_RISCV_BARE_CPU, \ .instance_init = (initfn), \ .class_init = riscv_cpu_class_init, \ - .class_data = GUINT_TO_POINTER(misa_mxl_max) \ + .class_data = &(const RISCVCPUDef) { \ + .misa_mxl_max = (misa_mxl_max_), \ + }, \ } -#define DEFINE_PROFILE_CPU(type_name, misa_mxl_max, initfn) \ +#define DEFINE_PROFILE_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ .parent = TYPE_RISCV_BARE_CPU, \ .instance_init = (initfn), \ .class_init = riscv_cpu_class_init, \ - .class_data = GUINT_TO_POINTER(misa_mxl_max) \ + .class_data = &(const RISCVCPUDef) { \ + .misa_mxl_max = (misa_mxl_max_), \ + }, \ } static const TypeInfo riscv_cpu_type_infos[] = { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 731ea2540c..9de3f716ea 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -538,6 +538,10 @@ struct ArchCPU { const GPtrArray *decoders; }; +typedef struct RISCVCPUDef { + RISCVMXL misa_mxl_max; /* max mxl for this cpu */ +} RISCVCPUDef; + /** * RISCVCPUClass: * @parent_realize: The parent class' realize handler. From 5fd23f20e12a56e7ac2dabbe9570fb2f10d7c5b4 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 13:13:23 +0100 Subject: [PATCH 1033/2760] target/riscv: store RISCVCPUDef struct directly in the class Prepare for adding more fields to RISCVCPUDef and reading them in riscv_cpu_init: instead of storing the misa_mxl_max field in RISCVCPUClass, ensure that there's always a valid RISCVCPUDef struct and go through it. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- hw/riscv/boot.c | 2 +- target/riscv/cpu.c | 23 ++++++++++++++++++----- target/riscv/cpu.h | 2 +- target/riscv/gdbstub.c | 6 +++--- target/riscv/kvm/kvm-cpu.c | 21 +++++++++------------ target/riscv/machine.c | 2 +- target/riscv/tcg/tcg-cpu.c | 10 +++++----- target/riscv/translate.c | 2 +- 8 files changed, 39 insertions(+), 29 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 765b9e2b1a..828a867be3 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -37,7 +37,7 @@ bool riscv_is_32bit(RISCVHartArrayState *harts) { RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(&harts->harts[0]); - return mcc->misa_mxl_max == MXL_RV32; + return mcc->def->misa_mxl_max == MXL_RV32; } /* diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 6e92fbb992..22e3a2211e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -356,7 +356,7 @@ void riscv_cpu_set_misa_ext(CPURISCVState *env, uint32_t ext) int riscv_cpu_max_xlen(RISCVCPUClass *mcc) { - return 16 << mcc->misa_mxl_max; + return 16 << mcc->def->misa_mxl_max; } #ifndef CONFIG_USER_ONLY @@ -1047,7 +1047,7 @@ static void riscv_cpu_reset_hold(Object *obj, ResetType type) mcc->parent_phases.hold(obj, type); } #ifndef CONFIG_USER_ONLY - env->misa_mxl = mcc->misa_mxl_max; + env->misa_mxl = mcc->def->misa_mxl_max; env->priv = PRV_M; env->mstatus &= ~(MSTATUS_MIE | MSTATUS_MPRV); if (env->misa_mxl > MXL_RV32) { @@ -1449,7 +1449,7 @@ static void riscv_cpu_init(Object *obj) RISCVCPU *cpu = RISCV_CPU(obj); CPURISCVState *env = &cpu->env; - env->misa_mxl = mcc->misa_mxl_max; + env->misa_mxl = mcc->def->misa_mxl_max; #ifndef CONFIG_USER_ONLY qdev_init_gpio_in(DEVICE(obj), riscv_cpu_set_irq, @@ -1543,7 +1543,7 @@ static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc) CPUClass *cc = CPU_CLASS(mcc); /* Validate that MISA_MXL is set properly. */ - switch (mcc->misa_mxl_max) { + switch (mcc->def->misa_mxl_max) { #ifdef TARGET_RISCV64 case MXL_RV64: case MXL_RV128: @@ -3070,12 +3070,24 @@ static void riscv_cpu_common_class_init(ObjectClass *c, const void *data) device_class_set_props(dc, riscv_cpu_properties); } +static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) +{ + RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); + RISCVCPUClass *pcc = RISCV_CPU_CLASS(object_class_get_parent(c)); + + if (pcc->def) { + mcc->def = g_memdup2(pcc->def, sizeof(*pcc->def)); + } else { + mcc->def = g_new0(RISCVCPUDef, 1); + } +} + static void riscv_cpu_class_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); const RISCVCPUDef *def = data; - mcc->misa_mxl_max = def->misa_mxl_max; + mcc->def->misa_mxl_max = def->misa_mxl_max; riscv_cpu_validate_misa_mxl(mcc); } @@ -3226,6 +3238,7 @@ static const TypeInfo riscv_cpu_type_infos[] = { .abstract = true, .class_size = sizeof(RISCVCPUClass), .class_init = riscv_cpu_common_class_init, + .class_base_init = riscv_cpu_class_base_init, }, { .name = TYPE_RISCV_DYNAMIC_CPU, diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 9de3f716ea..d2d4db95c1 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -554,7 +554,7 @@ struct RISCVCPUClass { DeviceRealize parent_realize; ResettablePhases parent_phases; - RISCVMXL misa_mxl_max; /* max mxl for this cpu */ + RISCVCPUDef *def; }; static inline int riscv_has_ext(CPURISCVState *env, target_ulong ext) diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index 18e88f416a..1934f919c0 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -62,7 +62,7 @@ int riscv_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n) return 0; } - switch (mcc->misa_mxl_max) { + switch (mcc->def->misa_mxl_max) { case MXL_RV32: return gdb_get_reg32(mem_buf, tmp); case MXL_RV64: @@ -82,7 +82,7 @@ int riscv_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) int length = 0; target_ulong tmp; - switch (mcc->misa_mxl_max) { + switch (mcc->def->misa_mxl_max) { case MXL_RV32: tmp = (int32_t)ldl_p(mem_buf); length = 4; @@ -359,7 +359,7 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs), 0); } - switch (mcc->misa_mxl_max) { + switch (mcc->def->misa_mxl_max) { case MXL_RV32: gdb_register_coprocessor(cs, riscv_gdb_get_virtual, riscv_gdb_set_virtual, diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 82f9728636..e77f612af3 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -2086,22 +2086,19 @@ static void kvm_cpu_accel_register_types(void) } type_init(kvm_cpu_accel_register_types); -static void riscv_host_cpu_class_init(ObjectClass *c, const void *data) -{ - RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); - -#if defined(TARGET_RISCV32) - mcc->misa_mxl_max = MXL_RV32; -#elif defined(TARGET_RISCV64) - mcc->misa_mxl_max = MXL_RV64; -#endif -} - static const TypeInfo riscv_kvm_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU_HOST, .parent = TYPE_RISCV_CPU, - .class_init = riscv_host_cpu_class_init, +#if defined(TARGET_RISCV32) + .class_data = &(const RISCVCPUDef) { + .misa_mxl_max = MXL_RV32, + }, +#elif defined(TARGET_RISCV64) + .class_data = &(const RISCVCPUDef) { + .misa_mxl_max = MXL_RV64, + }, +#endif } }; diff --git a/target/riscv/machine.c b/target/riscv/machine.c index a1f70cc955..c97e9ce9df 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -170,7 +170,7 @@ static bool rv128_needed(void *opaque) { RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(opaque); - return mcc->misa_mxl_max == MXL_RV128; + return mcc->def->misa_mxl_max == MXL_RV128; } static const VMStateDescription vmstate_rv128 = { diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index ab8659f304..305912b8dd 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -691,7 +691,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } - if (mcc->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { + if (mcc->def->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) { error_setg(errp, "Zcf extension is only relevant to RV32"); return; } @@ -788,7 +788,7 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } - if (mcc->misa_mxl_max == MXL_RV32 && cpu->cfg.ext_svukte) { + if (mcc->def->misa_mxl_max == MXL_RV32 && cpu->cfg.ext_svukte) { error_setg(errp, "svukte is not supported for RV32"); return; } @@ -1026,7 +1026,7 @@ static void cpu_enable_zc_implied_rules(RISCVCPU *cpu) cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true); cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true); - if (riscv_has_ext(env, RVF) && mcc->misa_mxl_max == MXL_RV32) { + if (riscv_has_ext(env, RVF) && mcc->def->misa_mxl_max == MXL_RV32) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } } @@ -1035,7 +1035,7 @@ static void cpu_enable_zc_implied_rules(RISCVCPU *cpu) if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true); - if (riscv_has_ext(env, RVF) && mcc->misa_mxl_max == MXL_RV32) { + if (riscv_has_ext(env, RVF) && mcc->def->misa_mxl_max == MXL_RV32) { cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true); } @@ -1161,7 +1161,7 @@ static bool riscv_tcg_cpu_realize(CPUState *cs, Error **errp) #ifndef CONFIG_USER_ONLY RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); - if (mcc->misa_mxl_max >= MXL_RV128 && qemu_tcg_mttcg_enabled()) { + if (mcc->def->misa_mxl_max >= MXL_RV128 && qemu_tcg_mttcg_enabled()) { /* Missing 128-bit aligned atomics */ error_setg(errp, "128-bit RISC-V currently does not work with Multi " diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 0d4f7d601c..d7a6de02df 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -1276,7 +1276,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->cfg_vta_all_1s = cpu->cfg.rvv_ta_all_1s; ctx->vstart_eq_zero = FIELD_EX32(tb_flags, TB_FLAGS, VSTART_EQ_ZERO); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); - ctx->misa_mxl_max = mcc->misa_mxl_max; + ctx->misa_mxl_max = mcc->def->misa_mxl_max; ctx->xl = FIELD_EX32(tb_flags, TB_FLAGS, XL); ctx->address_xl = FIELD_EX32(tb_flags, TB_FLAGS, AXL); ctx->cs = cs; From 7f9e15d82d21714a2c82aff8869b8ef9aa191c98 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 13:41:49 +0100 Subject: [PATCH 1034/2760] target/riscv: merge riscv_cpu_class_init with the class_base function Since all TYPE_RISCV_CPU subclasses support a class_data of type RISCVCPUDef, process it even before calling the .class_init function for the subclasses. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 22e3a2211e..334791eebd 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -3080,15 +3080,18 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) } else { mcc->def = g_new0(RISCVCPUDef, 1); } -} -static void riscv_cpu_class_init(ObjectClass *c, const void *data) -{ - RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); - const RISCVCPUDef *def = data; + if (data) { + const RISCVCPUDef *def = data; + if (def->misa_mxl_max) { + assert(def->misa_mxl_max <= MXL_RV128); + mcc->def->misa_mxl_max = def->misa_mxl_max; + } + } - mcc->def->misa_mxl_max = def->misa_mxl_max; - riscv_cpu_validate_misa_mxl(mcc); + if (!object_class_is_abstract(c)) { + riscv_cpu_validate_misa_mxl(mcc); + } } static void riscv_isa_string_ext(RISCVCPU *cpu, char **isa_str, @@ -3188,7 +3191,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .name = (type_name), \ .parent = TYPE_RISCV_DYNAMIC_CPU, \ .instance_init = (initfn), \ - .class_init = riscv_cpu_class_init, \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ }, \ @@ -3199,7 +3201,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .name = (type_name), \ .parent = TYPE_RISCV_VENDOR_CPU, \ .instance_init = (initfn), \ - .class_init = riscv_cpu_class_init, \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ }, \ @@ -3210,7 +3211,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .name = (type_name), \ .parent = TYPE_RISCV_BARE_CPU, \ .instance_init = (initfn), \ - .class_init = riscv_cpu_class_init, \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ }, \ @@ -3221,7 +3221,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .name = (type_name), \ .parent = TYPE_RISCV_BARE_CPU, \ .instance_init = (initfn), \ - .class_init = riscv_cpu_class_init, \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ }, \ From 12877e739b3afff2b6ff7b80d6a6b22e451671c2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 11:28:23 +0100 Subject: [PATCH 1035/2760] target/riscv: move RISCVCPUConfig fields to a header file To support merging a subclass's RISCVCPUDef into the superclass, a list of all the CPU features is needed. Put them into a header file that can be included multiple times, expanding the macros BOOL_FIELD and TYPE_FIELD to different operations. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu_cfg.h | 163 +--------------------------- target/riscv/cpu_cfg_fields.h.inc | 170 ++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 160 deletions(-) create mode 100644 target/riscv/cpu_cfg_fields.h.inc diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index 8fa73c8a07..e9bf75730a 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -22,166 +22,9 @@ #define RISCV_CPU_CFG_H struct RISCVCPUConfig { - bool ext_zba; - bool ext_zbb; - bool ext_zbc; - bool ext_zbkb; - bool ext_zbkc; - bool ext_zbkx; - bool ext_zbs; - bool ext_zca; - bool ext_zcb; - bool ext_zcd; - bool ext_zce; - bool ext_zcf; - bool ext_zcmp; - bool ext_zcmt; - bool ext_zk; - bool ext_zkn; - bool ext_zknd; - bool ext_zkne; - bool ext_zknh; - bool ext_zkr; - bool ext_zks; - bool ext_zksed; - bool ext_zksh; - bool ext_zkt; - bool ext_zifencei; - bool ext_zicntr; - bool ext_zicsr; - bool ext_zicbom; - bool ext_zicbop; - bool ext_zicboz; - bool ext_zicfilp; - bool ext_zicfiss; - bool ext_zicond; - bool ext_zihintntl; - bool ext_zihintpause; - bool ext_zihpm; - bool ext_zimop; - bool ext_zcmop; - bool ext_ztso; - bool ext_smstateen; - bool ext_sstc; - bool ext_smcdeleg; - bool ext_ssccfg; - bool ext_smcntrpmf; - bool ext_smcsrind; - bool ext_sscsrind; - bool ext_ssdbltrp; - bool ext_smdbltrp; - bool ext_svadu; - bool ext_svinval; - bool ext_svnapot; - bool ext_svpbmt; - bool ext_svvptc; - bool ext_svukte; - bool ext_zdinx; - bool ext_zaamo; - bool ext_zacas; - bool ext_zama16b; - bool ext_zabha; - bool ext_zalrsc; - bool ext_zawrs; - bool ext_zfa; - bool ext_zfbfmin; - bool ext_zfh; - bool ext_zfhmin; - bool ext_zfinx; - bool ext_zhinx; - bool ext_zhinxmin; - bool ext_zve32f; - bool ext_zve32x; - bool ext_zve64f; - bool ext_zve64d; - bool ext_zve64x; - bool ext_zvbb; - bool ext_zvbc; - bool ext_zvkb; - bool ext_zvkg; - bool ext_zvkned; - bool ext_zvknha; - bool ext_zvknhb; - bool ext_zvksed; - bool ext_zvksh; - bool ext_zvkt; - bool ext_zvkn; - bool ext_zvknc; - bool ext_zvkng; - bool ext_zvks; - bool ext_zvksc; - bool ext_zvksg; - bool ext_zmmul; - bool ext_zvfbfmin; - bool ext_zvfbfwma; - bool ext_zvfh; - bool ext_zvfhmin; - bool ext_smaia; - bool ext_ssaia; - bool ext_smctr; - bool ext_ssctr; - bool ext_sscofpmf; - bool ext_smepmp; - bool ext_smrnmi; - bool ext_ssnpm; - bool ext_smnpm; - bool ext_smmpm; - bool ext_sspm; - bool ext_supm; - bool rvv_ta_all_1s; - bool rvv_ma_all_1s; - bool rvv_vl_half_avl; - - uint32_t mvendorid; - uint64_t marchid; - uint64_t mimpid; - - /* Named features */ - bool ext_svade; - bool ext_zic64b; - bool ext_ssstateen; - bool ext_sha; - - /* - * Always 'true' booleans for named features - * TCG always implement/can't be user disabled, - * based on spec version. - */ - bool has_priv_1_13; - bool has_priv_1_12; - bool has_priv_1_11; - - /* Always enabled for TCG if has_priv_1_11 */ - bool ext_ziccrse; - - /* Vendor-specific custom extensions */ - bool ext_xtheadba; - bool ext_xtheadbb; - bool ext_xtheadbs; - bool ext_xtheadcmo; - bool ext_xtheadcondmov; - bool ext_xtheadfmemidx; - bool ext_xtheadfmv; - bool ext_xtheadmac; - bool ext_xtheadmemidx; - bool ext_xtheadmempair; - bool ext_xtheadsync; - bool ext_XVentanaCondOps; - - uint32_t pmu_mask; - uint16_t vlenb; - uint16_t elen; - uint16_t cbom_blocksize; - uint16_t cbop_blocksize; - uint16_t cboz_blocksize; - bool mmu; - bool pmp; - bool debug; - bool misa_w; - - bool short_isa_string; - - int8_t max_satp_mode; +#define BOOL_FIELD(x) bool x; +#define TYPED_FIELD(type, x) type x; +#include "cpu_cfg_fields.h.inc" }; typedef struct RISCVCPUConfig RISCVCPUConfig; diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc new file mode 100644 index 0000000000..cb86bfc5dc --- /dev/null +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -0,0 +1,170 @@ +/* + * Required definitions before including this file: + * + * #define BOOL_FIELD(x) + * #define TYPED_FIELD(type, x) + */ + +BOOL_FIELD(ext_zba) +BOOL_FIELD(ext_zbb) +BOOL_FIELD(ext_zbc) +BOOL_FIELD(ext_zbkb) +BOOL_FIELD(ext_zbkc) +BOOL_FIELD(ext_zbkx) +BOOL_FIELD(ext_zbs) +BOOL_FIELD(ext_zca) +BOOL_FIELD(ext_zcb) +BOOL_FIELD(ext_zcd) +BOOL_FIELD(ext_zce) +BOOL_FIELD(ext_zcf) +BOOL_FIELD(ext_zcmp) +BOOL_FIELD(ext_zcmt) +BOOL_FIELD(ext_zk) +BOOL_FIELD(ext_zkn) +BOOL_FIELD(ext_zknd) +BOOL_FIELD(ext_zkne) +BOOL_FIELD(ext_zknh) +BOOL_FIELD(ext_zkr) +BOOL_FIELD(ext_zks) +BOOL_FIELD(ext_zksed) +BOOL_FIELD(ext_zksh) +BOOL_FIELD(ext_zkt) +BOOL_FIELD(ext_zifencei) +BOOL_FIELD(ext_zicntr) +BOOL_FIELD(ext_zicsr) +BOOL_FIELD(ext_zicbom) +BOOL_FIELD(ext_zicbop) +BOOL_FIELD(ext_zicboz) +BOOL_FIELD(ext_zicfilp) +BOOL_FIELD(ext_zicfiss) +BOOL_FIELD(ext_zicond) +BOOL_FIELD(ext_zihintntl) +BOOL_FIELD(ext_zihintpause) +BOOL_FIELD(ext_zihpm) +BOOL_FIELD(ext_zimop) +BOOL_FIELD(ext_zcmop) +BOOL_FIELD(ext_ztso) +BOOL_FIELD(ext_smstateen) +BOOL_FIELD(ext_sstc) +BOOL_FIELD(ext_smcdeleg) +BOOL_FIELD(ext_ssccfg) +BOOL_FIELD(ext_smcntrpmf) +BOOL_FIELD(ext_smcsrind) +BOOL_FIELD(ext_sscsrind) +BOOL_FIELD(ext_ssdbltrp) +BOOL_FIELD(ext_smdbltrp) +BOOL_FIELD(ext_svadu) +BOOL_FIELD(ext_svinval) +BOOL_FIELD(ext_svnapot) +BOOL_FIELD(ext_svpbmt) +BOOL_FIELD(ext_svvptc) +BOOL_FIELD(ext_svukte) +BOOL_FIELD(ext_zdinx) +BOOL_FIELD(ext_zaamo) +BOOL_FIELD(ext_zacas) +BOOL_FIELD(ext_zama16b) +BOOL_FIELD(ext_zabha) +BOOL_FIELD(ext_zalrsc) +BOOL_FIELD(ext_zawrs) +BOOL_FIELD(ext_zfa) +BOOL_FIELD(ext_zfbfmin) +BOOL_FIELD(ext_zfh) +BOOL_FIELD(ext_zfhmin) +BOOL_FIELD(ext_zfinx) +BOOL_FIELD(ext_zhinx) +BOOL_FIELD(ext_zhinxmin) +BOOL_FIELD(ext_zve32f) +BOOL_FIELD(ext_zve32x) +BOOL_FIELD(ext_zve64f) +BOOL_FIELD(ext_zve64d) +BOOL_FIELD(ext_zve64x) +BOOL_FIELD(ext_zvbb) +BOOL_FIELD(ext_zvbc) +BOOL_FIELD(ext_zvkb) +BOOL_FIELD(ext_zvkg) +BOOL_FIELD(ext_zvkned) +BOOL_FIELD(ext_zvknha) +BOOL_FIELD(ext_zvknhb) +BOOL_FIELD(ext_zvksed) +BOOL_FIELD(ext_zvksh) +BOOL_FIELD(ext_zvkt) +BOOL_FIELD(ext_zvkn) +BOOL_FIELD(ext_zvknc) +BOOL_FIELD(ext_zvkng) +BOOL_FIELD(ext_zvks) +BOOL_FIELD(ext_zvksc) +BOOL_FIELD(ext_zvksg) +BOOL_FIELD(ext_zmmul) +BOOL_FIELD(ext_zvfbfmin) +BOOL_FIELD(ext_zvfbfwma) +BOOL_FIELD(ext_zvfh) +BOOL_FIELD(ext_zvfhmin) +BOOL_FIELD(ext_smaia) +BOOL_FIELD(ext_ssaia) +BOOL_FIELD(ext_smctr) +BOOL_FIELD(ext_ssctr) +BOOL_FIELD(ext_sscofpmf) +BOOL_FIELD(ext_smepmp) +BOOL_FIELD(ext_smrnmi) +BOOL_FIELD(ext_ssnpm) +BOOL_FIELD(ext_smnpm) +BOOL_FIELD(ext_smmpm) +BOOL_FIELD(ext_sspm) +BOOL_FIELD(ext_supm) +BOOL_FIELD(rvv_ta_all_1s) +BOOL_FIELD(rvv_ma_all_1s) +BOOL_FIELD(rvv_vl_half_avl) +/* Named features */ +BOOL_FIELD(ext_svade) +BOOL_FIELD(ext_zic64b) +BOOL_FIELD(ext_ssstateen) +BOOL_FIELD(ext_sha) + +/* + * Always 'true' booleans for named features + * TCG always implement/can't be user disabled, + * based on spec version. + */ +BOOL_FIELD(has_priv_1_13) +BOOL_FIELD(has_priv_1_12) +BOOL_FIELD(has_priv_1_11) + +/* Always enabled for TCG if has_priv_1_11 */ +BOOL_FIELD(ext_ziccrse) + +/* Vendor-specific custom extensions */ +BOOL_FIELD(ext_xtheadba) +BOOL_FIELD(ext_xtheadbb) +BOOL_FIELD(ext_xtheadbs) +BOOL_FIELD(ext_xtheadcmo) +BOOL_FIELD(ext_xtheadcondmov) +BOOL_FIELD(ext_xtheadfmemidx) +BOOL_FIELD(ext_xtheadfmv) +BOOL_FIELD(ext_xtheadmac) +BOOL_FIELD(ext_xtheadmemidx) +BOOL_FIELD(ext_xtheadmempair) +BOOL_FIELD(ext_xtheadsync) +BOOL_FIELD(ext_XVentanaCondOps) + +BOOL_FIELD(mmu) +BOOL_FIELD(pmp) +BOOL_FIELD(debug) +BOOL_FIELD(misa_w) + +BOOL_FIELD(short_isa_string) + +TYPED_FIELD(uint32_t, mvendorid) +TYPED_FIELD(uint64_t, marchid) +TYPED_FIELD(uint64_t, mimpid) + +TYPED_FIELD(uint32_t, pmu_mask) +TYPED_FIELD(uint16_t, vlenb) +TYPED_FIELD(uint16_t, elen) +TYPED_FIELD(uint16_t, cbom_blocksize) +TYPED_FIELD(uint16_t, cbop_blocksize) +TYPED_FIELD(uint16_t, cboz_blocksize) + +TYPED_FIELD(int8_t, max_satp_mode) + +#undef BOOL_FIELD +#undef TYPED_FIELD From 407254031edd649e6acde736e3f7e95bb0fdf299 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Mar 2025 13:22:48 +0100 Subject: [PATCH 1036/2760] target/riscv: include default value in cpu_cfg_fields.h.inc In preparation for adding a function to merge two RISCVCPUConfigs (pulling values from the parent if they are not overridden) annotate cpu_cfg_fields.h.inc with the default value of the fields. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu_cfg.h | 2 +- target/riscv/cpu_cfg_fields.h.inc | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index e9bf75730a..aa28dc8d7e 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -23,7 +23,7 @@ struct RISCVCPUConfig { #define BOOL_FIELD(x) bool x; -#define TYPED_FIELD(type, x) type x; +#define TYPED_FIELD(type, x, default) type x; #include "cpu_cfg_fields.h.inc" }; diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc index cb86bfc5dc..59f134a419 100644 --- a/target/riscv/cpu_cfg_fields.h.inc +++ b/target/riscv/cpu_cfg_fields.h.inc @@ -2,7 +2,7 @@ * Required definitions before including this file: * * #define BOOL_FIELD(x) - * #define TYPED_FIELD(type, x) + * #define TYPED_FIELD(type, x, default) */ BOOL_FIELD(ext_zba) @@ -153,18 +153,18 @@ BOOL_FIELD(misa_w) BOOL_FIELD(short_isa_string) -TYPED_FIELD(uint32_t, mvendorid) -TYPED_FIELD(uint64_t, marchid) -TYPED_FIELD(uint64_t, mimpid) +TYPED_FIELD(uint32_t, mvendorid, 0) +TYPED_FIELD(uint64_t, marchid, 0) +TYPED_FIELD(uint64_t, mimpid, 0) -TYPED_FIELD(uint32_t, pmu_mask) -TYPED_FIELD(uint16_t, vlenb) -TYPED_FIELD(uint16_t, elen) -TYPED_FIELD(uint16_t, cbom_blocksize) -TYPED_FIELD(uint16_t, cbop_blocksize) -TYPED_FIELD(uint16_t, cboz_blocksize) +TYPED_FIELD(uint32_t, pmu_mask, 0) +TYPED_FIELD(uint16_t, vlenb, 0) +TYPED_FIELD(uint16_t, elen, 0) +TYPED_FIELD(uint16_t, cbom_blocksize, 0) +TYPED_FIELD(uint16_t, cbop_blocksize, 0) +TYPED_FIELD(uint16_t, cboz_blocksize, 0) -TYPED_FIELD(int8_t, max_satp_mode) +TYPED_FIELD(int8_t, max_satp_mode, -1) #undef BOOL_FIELD #undef TYPED_FIELD From a6ba81424a7e751fbcee40dc1f5826ba29fddd30 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 11:31:30 +0100 Subject: [PATCH 1037/2760] target/riscv: add more RISCVCPUDef fields Allow using RISCVCPUDef to replicate all the logic of custom .instance_init functions. To simulate inheritance, merge the child's RISCVCPUDef with the parent and then finally move it to the CPUState at the end of TYPE_RISCV_CPU's own instance_init function. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 42 +++++++++++++++++++++++++++++++++++++- target/riscv/cpu.h | 4 ++++ target/riscv/kvm/kvm-cpu.c | 6 ++++++ 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 334791eebd..634216870e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -73,6 +73,13 @@ bool riscv_cpu_option_set(const char *optname) return g_hash_table_contains(general_user_opts, optname); } +static void riscv_cpu_cfg_merge(RISCVCPUConfig *dest, const RISCVCPUConfig *src) +{ +#define BOOL_FIELD(x) dest->x |= src->x; +#define TYPED_FIELD(type, x, default_) if (src->x != default_) dest->x = src->x; +#include "cpu_cfg_fields.h.inc" +} + #define ISA_EXT_DATA_ENTRY(_name, _min_ver, _prop) \ {#_name, _min_ver, CPU_CFG_OFFSET(_prop)} @@ -434,7 +441,7 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) } static void set_satp_mode_max_supported(RISCVCPU *cpu, - uint8_t satp_mode) + int satp_mode) { bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; @@ -1479,6 +1486,16 @@ static void riscv_cpu_init(Object *obj) cpu->cfg.cboz_blocksize = 64; cpu->env.vext_ver = VEXT_VERSION_1_00_0; cpu->cfg.max_satp_mode = -1; + + env->misa_ext_mask = env->misa_ext = mcc->def->misa_ext; + riscv_cpu_cfg_merge(&cpu->cfg, &mcc->def->cfg); + + if (mcc->def->priv_spec != RISCV_PROFILE_ATTR_UNUSED) { + cpu->env.priv_ver = mcc->def->priv_spec; + } + if (mcc->def->vext_spec != RISCV_PROFILE_ATTR_UNUSED) { + cpu->env.vext_ver = mcc->def->vext_spec; + } } static void riscv_bare_cpu_init(Object *obj) @@ -3087,6 +3104,17 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) assert(def->misa_mxl_max <= MXL_RV128); mcc->def->misa_mxl_max = def->misa_mxl_max; } + if (def->priv_spec != RISCV_PROFILE_ATTR_UNUSED) { + assert(def->priv_spec <= PRIV_VERSION_LATEST); + mcc->def->priv_spec = def->priv_spec; + } + if (def->vext_spec != RISCV_PROFILE_ATTR_UNUSED) { + assert(def->vext_spec != 0); + mcc->def->vext_spec = def->vext_spec; + } + mcc->def->misa_ext |= def->misa_ext; + + riscv_cpu_cfg_merge(&mcc->def->cfg, &def->cfg); } if (!object_class_is_abstract(c)) { @@ -3193,6 +3221,9 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .instance_init = (initfn), \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .cfg.max_satp_mode = -1, \ }, \ } @@ -3203,6 +3234,9 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .instance_init = (initfn), \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .cfg.max_satp_mode = -1, \ }, \ } @@ -3213,6 +3247,9 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .instance_init = (initfn), \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .cfg.max_satp_mode = -1, \ }, \ } @@ -3223,6 +3260,9 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) .instance_init = (initfn), \ .class_data = &(const RISCVCPUDef) { \ .misa_mxl_max = (misa_mxl_max_), \ + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .cfg.max_satp_mode = -1, \ }, \ } diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index d2d4db95c1..29b01e9aa8 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -540,6 +540,10 @@ struct ArchCPU { typedef struct RISCVCPUDef { RISCVMXL misa_mxl_max; /* max mxl for this cpu */ + uint32_t misa_ext; + int priv_spec; + int32_t vext_spec; + RISCVCPUConfig cfg; } RISCVCPUDef; /** diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index e77f612af3..efb41fac53 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -2093,10 +2093,16 @@ static const TypeInfo riscv_kvm_cpu_type_infos[] = { #if defined(TARGET_RISCV32) .class_data = &(const RISCVCPUDef) { .misa_mxl_max = MXL_RV32, + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, + .cfg.max_satp_mode = -1, }, #elif defined(TARGET_RISCV64) .class_data = &(const RISCVCPUDef) { .misa_mxl_max = MXL_RV64, + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, + .cfg.max_satp_mode = -1, }, #endif } From 4e012d36c8654e7fa12762002150334bf591628a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 17:03:01 +0100 Subject: [PATCH 1038/2760] target/riscv: convert abstract CPU classes to RISCVCPUDef Start from the top of the hierarchy: dynamic and vendor CPUs are just markers, whereas bare CPUs can have their instance_init function replaced by RISCVCPUDef. The only difference is that the maximum supported SATP mode has to be specified separately for 32-bit and 64-bit modes. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 93 ++++++++++++++++++++++------------------------ target/riscv/cpu.h | 1 + 2 files changed, 46 insertions(+), 48 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 634216870e..7dcaf72fc1 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1474,8 +1474,8 @@ static void riscv_cpu_init(Object *obj) * for all CPUs. Each accelerator will decide what to do when * users disable them. */ - RISCV_CPU(obj)->cfg.ext_zicntr = true; - RISCV_CPU(obj)->cfg.ext_zihpm = true; + RISCV_CPU(obj)->cfg.ext_zicntr = !mcc->def->bare; + RISCV_CPU(obj)->cfg.ext_zihpm = !mcc->def->bare; /* Default values for non-bool cpu properties */ cpu->cfg.pmu_mask = MAKE_64BIT_MASK(3, 16); @@ -1498,36 +1498,6 @@ static void riscv_cpu_init(Object *obj) } } -static void riscv_bare_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - - /* - * Bare CPUs do not inherit the timer and performance - * counters from the parent class (see riscv_cpu_init() - * for info on why the parent enables them). - * - * Users have to explicitly enable these counters for - * bare CPUs. - */ - cpu->cfg.ext_zicntr = false; - cpu->cfg.ext_zihpm = false; - - /* Set to QEMU's first supported priv version */ - cpu->env.priv_ver = PRIV_VERSION_1_10_0; - - /* - * Support all available satp_mode settings. The default - * value will be set to MBARE if the user doesn't set - * satp_mode manually (see set_satp_mode_default()). - */ -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), - riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ? - VM_1_10_SV32 : VM_1_10_SV57); -#endif -} - typedef struct misa_ext_info { const char *name; const char *description; @@ -3100,6 +3070,7 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) if (data) { const RISCVCPUDef *def = data; + mcc->def->bare |= def->bare; if (def->misa_mxl_max) { assert(def->misa_mxl_max <= MXL_RV128); mcc->def->misa_mxl_max = def->misa_mxl_max; @@ -3253,6 +3224,19 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) }, \ } +#define DEFINE_ABSTRACT_RISCV_CPU(type_name, parent_type_name, ...) \ + { \ + .name = (type_name), \ + .parent = (parent_type_name), \ + .abstract = true, \ + .class_data = &(const RISCVCPUDef) { \ + .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ + .cfg.max_satp_mode = -1, \ + __VA_ARGS__ \ + }, \ + } + #define DEFINE_PROFILE_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ @@ -3279,22 +3263,35 @@ static const TypeInfo riscv_cpu_type_infos[] = { .class_init = riscv_cpu_common_class_init, .class_base_init = riscv_cpu_class_base_init, }, - { - .name = TYPE_RISCV_DYNAMIC_CPU, - .parent = TYPE_RISCV_CPU, - .abstract = true, - }, - { - .name = TYPE_RISCV_VENDOR_CPU, - .parent = TYPE_RISCV_CPU, - .abstract = true, - }, - { - .name = TYPE_RISCV_BARE_CPU, - .parent = TYPE_RISCV_CPU, - .instance_init = riscv_bare_cpu_init, - .abstract = true, - }, + + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_DYNAMIC_CPU, TYPE_RISCV_CPU), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_VENDOR_CPU, TYPE_RISCV_CPU), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_BARE_CPU, TYPE_RISCV_CPU, + /* + * Bare CPUs do not inherit the timer and performance + * counters from the parent class (see riscv_cpu_init() + * for info on why the parent enables them). + * + * Users have to explicitly enable these counters for + * bare CPUs. + */ + .bare = true, + + /* Set to QEMU's first supported priv version */ + .priv_spec = PRIV_VERSION_1_10_0, + + /* + * Support all available satp_mode settings. By default + * only MBARE will be available if the user doesn't enable + * a mode manually (see riscv_cpu_satp_mode_finalize()). + */ +#ifdef TARGET_RISCV32 + .cfg.max_satp_mode = VM_1_10_SV32, +#else + .cfg.max_satp_mode = VM_1_10_SV57, +#endif + ), + #if defined(TARGET_RISCV32) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV32, riscv_max_cpu_init), #elif defined(TARGET_RISCV64) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 29b01e9aa8..f3d70afb86 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -544,6 +544,7 @@ typedef struct RISCVCPUDef { int priv_spec; int32_t vext_spec; RISCVCPUConfig cfg; + bool bare; } RISCVCPUDef; /** From 198265df8a71e6743d42d5003c29a060fea7d019 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 27 Feb 2025 14:56:30 +0100 Subject: [PATCH 1039/2760] target/riscv: convert profile CPU models to RISCVCPUDef Profile CPUs reuse the instance_init function for bare CPUs; make them proper subclasses instead. Enabling a profile is now done based on the RISCVCPUDef struct: even though there is room for only one in RISCVCPUDef, subclasses check that the parent class's profile is enabled through the parent profile mechanism. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 85 +++++++++++++++++++++++++--------------------- target/riscv/cpu.h | 1 + 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 7dcaf72fc1..54fce76765 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1487,6 +1487,10 @@ static void riscv_cpu_init(Object *obj) cpu->env.vext_ver = VEXT_VERSION_1_00_0; cpu->cfg.max_satp_mode = -1; + if (mcc->def->profile) { + mcc->def->profile->enabled = true; + } + env->misa_ext_mask = env->misa_ext = mcc->def->misa_ext; riscv_cpu_cfg_merge(&cpu->cfg, &mcc->def->cfg); @@ -2959,36 +2963,6 @@ static const Property riscv_cpu_properties[] = { DEFINE_PROP_BOOL("x-misa-w", RISCVCPU, cfg.misa_w, false), }; -#if defined(TARGET_RISCV64) -static void rva22u64_profile_cpu_init(Object *obj) -{ - rv64i_bare_cpu_init(obj); - - RVA22U64.enabled = true; -} - -static void rva22s64_profile_cpu_init(Object *obj) -{ - rv64i_bare_cpu_init(obj); - - RVA22S64.enabled = true; -} - -static void rva23u64_profile_cpu_init(Object *obj) -{ - rv64i_bare_cpu_init(obj); - - RVA23U64.enabled = true; -} - -static void rva23s64_profile_cpu_init(Object *obj) -{ - rv64i_bare_cpu_init(obj); - - RVA23S64.enabled = true; -} -#endif - static const gchar *riscv_gdb_arch_name(CPUState *cs) { RISCVCPU *cpu = RISCV_CPU(cs); @@ -3057,6 +3031,32 @@ static void riscv_cpu_common_class_init(ObjectClass *c, const void *data) device_class_set_props(dc, riscv_cpu_properties); } +static bool profile_extends(RISCVCPUProfile *trial, RISCVCPUProfile *parent) +{ + RISCVCPUProfile *curr; + if (!parent) { + return true; + } + + curr = trial; + while (curr) { + if (curr == parent) { + return true; + } + curr = curr->u_parent; + } + + curr = trial; + while (curr) { + if (curr == parent) { + return true; + } + curr = curr->s_parent; + } + + return false; +} + static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) { RISCVCPUClass *mcc = RISCV_CPU_CLASS(c); @@ -3071,6 +3071,11 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) if (data) { const RISCVCPUDef *def = data; mcc->def->bare |= def->bare; + if (def->profile) { + assert(profile_extends(def->profile, mcc->def->profile)); + assert(mcc->def->bare); + mcc->def->profile = def->profile; + } if (def->misa_mxl_max) { assert(def->misa_mxl_max <= MXL_RV128); mcc->def->misa_mxl_max = def->misa_mxl_max; @@ -3237,19 +3242,22 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) }, \ } -#define DEFINE_PROFILE_CPU(type_name, misa_mxl_max_, initfn) \ +#define DEFINE_RISCV_CPU(type_name, parent_type_name, ...) \ { \ .name = (type_name), \ - .parent = TYPE_RISCV_BARE_CPU, \ - .instance_init = (initfn), \ + .parent = (parent_type_name), \ .class_data = &(const RISCVCPUDef) { \ - .misa_mxl_max = (misa_mxl_max_), \ .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ .cfg.max_satp_mode = -1, \ + __VA_ARGS__ \ }, \ } +#define DEFINE_PROFILE_CPU(type_name, parent_type_name, profile_) \ + DEFINE_RISCV_CPU(type_name, parent_type_name, \ + .profile = &(profile_)) + static const TypeInfo riscv_cpu_type_infos[] = { { .name = TYPE_RISCV_CPU, @@ -3328,10 +3336,11 @@ static const TypeInfo riscv_cpu_type_infos[] = { #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, MXL_RV64, rv64i_bare_cpu_init), DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64E, MXL_RV64, rv64e_bare_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, MXL_RV64, rva22u64_profile_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, MXL_RV64, rva22s64_profile_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23U64, MXL_RV64, rva23u64_profile_cpu_init), - DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23S64, MXL_RV64, rva23s64_profile_cpu_init), + + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, TYPE_RISCV_CPU_RV64I, RVA22U64), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, TYPE_RISCV_CPU_RV64I, RVA22S64), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23U64, TYPE_RISCV_CPU_RV64I, RVA23U64), + DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA23S64, TYPE_RISCV_CPU_RV64I, RVA23S64), #endif /* TARGET_RISCV64 */ }; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f3d70afb86..ed88adef45 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -540,6 +540,7 @@ struct ArchCPU { typedef struct RISCVCPUDef { RISCVMXL misa_mxl_max; /* max mxl for this cpu */ + RISCVCPUProfile *profile; uint32_t misa_ext; int priv_spec; int32_t vext_spec; From 37815d80be11f98636a4ed76fe6b1ecc7aefcaf3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 17:10:46 +0100 Subject: [PATCH 1040/2760] target/riscv: convert bare CPU models to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 58 ++++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 54fce76765..8b82a1b7b3 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -732,18 +732,6 @@ static void rv128_base_cpu_init(Object *obj) } #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ -static void rv64i_bare_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - riscv_cpu_set_misa_ext(env, RVI); -} - -static void rv64e_bare_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - riscv_cpu_set_misa_ext(env, RVE); -} - #endif /* !TARGET_RISCV64 */ #if defined(TARGET_RISCV32) || \ @@ -836,18 +824,6 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj) cpu->cfg.ext_zicsr = true; cpu->cfg.pmp = true; } - -static void rv32i_bare_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - riscv_cpu_set_misa_ext(env, RVI); -} - -static void rv32e_bare_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - riscv_cpu_set_misa_ext(env, RVE); -} #endif static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -3216,19 +3192,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) }, \ } -#define DEFINE_BARE_CPU(type_name, misa_mxl_max_, initfn) \ - { \ - .name = (type_name), \ - .parent = TYPE_RISCV_BARE_CPU, \ - .instance_init = (initfn), \ - .class_data = &(const RISCVCPUDef) { \ - .misa_mxl_max = (misa_mxl_max_), \ - .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .cfg.max_satp_mode = -1, \ - }, \ - } - #define DEFINE_ABSTRACT_RISCV_CPU(type_name, parent_type_name, ...) \ { \ .name = (type_name), \ @@ -3313,8 +3276,15 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, MXL_RV32, rv32_sifive_e_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, MXL_RV32, rv32_imafcu_nommu_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, MXL_RV32, rv32_sifive_u_cpu_init), - DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32I, MXL_RV32, rv32i_bare_cpu_init), - DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV32E, MXL_RV32, rv32e_bare_cpu_init), + + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV32I, TYPE_RISCV_BARE_CPU, + .misa_mxl_max = MXL_RV32, + .misa_ext = RVI + ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV32E, TYPE_RISCV_BARE_CPU, + .misa_mxl_max = MXL_RV32, + .misa_ext = RVE + ), #endif #if (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) @@ -3334,8 +3304,14 @@ static const TypeInfo riscv_cpu_type_infos[] = { #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, MXL_RV128, rv128_base_cpu_init), #endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ - DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64I, MXL_RV64, rv64i_bare_cpu_init), - DEFINE_BARE_CPU(TYPE_RISCV_CPU_RV64E, MXL_RV64, rv64e_bare_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV64I, TYPE_RISCV_BARE_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVI + ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV64E, TYPE_RISCV_BARE_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVE + ), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22U64, TYPE_RISCV_CPU_RV64I, RVA22U64), DEFINE_PROFILE_CPU(TYPE_RISCV_CPU_RVA22S64, TYPE_RISCV_CPU_RV64I, RVA22S64), From 0edc2465ba76c0d2bbeb475b6d2491c92dccd27b Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 14:59:05 +0100 Subject: [PATCH 1041/2760] target/riscv: convert dynamic CPU models to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 113 +++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 82 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 8b82a1b7b3..2b26f23bd0 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -485,38 +485,7 @@ static void set_satp_mode_default_map(RISCVCPU *cpu) } #endif -static void riscv_max_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; - - env->priv_ver = PRIV_VERSION_LATEST; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), - riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ? - VM_1_10_SV32 : VM_1_10_SV57); -#endif -} - #if defined(TARGET_RISCV64) -static void rv64_base_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; - - /* Set latest version of privileged specification */ - env->priv_ver = PRIV_VERSION_LATEST; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); -#endif -} - static void rv64_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); @@ -717,41 +686,11 @@ static void rv64_xiangshan_nanhu_cpu_init(Object *obj) #endif } -#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) -static void rv128_base_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; - - /* Set latest version of privileged specification */ - env->priv_ver = PRIV_VERSION_LATEST; - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57); -} -#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ - #endif /* !TARGET_RISCV64 */ #if defined(TARGET_RISCV32) || \ (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) -static void rv32_base_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; - - /* Set latest version of privileged specification */ - env->priv_ver = PRIV_VERSION_LATEST; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); -#endif -} - static void rv32_sifive_u_cpu_init(Object *obj) { RISCVCPU *cpu = RISCV_CPU(obj); @@ -3166,19 +3105,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) } #endif -#define DEFINE_DYNAMIC_CPU(type_name, misa_mxl_max_, initfn) \ - { \ - .name = (type_name), \ - .parent = TYPE_RISCV_DYNAMIC_CPU, \ - .instance_init = (initfn), \ - .class_data = &(const RISCVCPUDef) { \ - .misa_mxl_max = (misa_mxl_max_), \ - .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .cfg.max_satp_mode = -1, \ - }, \ - } - #define DEFINE_VENDOR_CPU(type_name, misa_mxl_max_, initfn) \ { \ .name = (type_name), \ @@ -3235,7 +3161,12 @@ static const TypeInfo riscv_cpu_type_infos[] = { .class_base_init = riscv_cpu_class_base_init, }, - DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_DYNAMIC_CPU, TYPE_RISCV_CPU), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_DYNAMIC_CPU, TYPE_RISCV_CPU, + .cfg.mmu = true, + .cfg.pmp = true, + .priv_spec = PRIV_VERSION_LATEST, + ), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_VENDOR_CPU, TYPE_RISCV_CPU), DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_BARE_CPU, TYPE_RISCV_CPU, /* @@ -3263,15 +3194,23 @@ static const TypeInfo riscv_cpu_type_infos[] = { #endif ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_MAX, TYPE_RISCV_DYNAMIC_CPU, #if defined(TARGET_RISCV32) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV32, riscv_max_cpu_init), + .misa_mxl_max = MXL_RV32, + .cfg.max_satp_mode = VM_1_10_SV32, #elif defined(TARGET_RISCV64) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX, MXL_RV64, riscv_max_cpu_init), + .misa_mxl_max = MXL_RV64, + .cfg.max_satp_mode = VM_1_10_SV57, #endif + ), #if defined(TARGET_RISCV32) || \ (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE32, MXL_RV32, rv32_base_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU, + .cfg.max_satp_mode = VM_1_10_SV32, + .misa_mxl_max = MXL_RV32, + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, MXL_RV32, rv32_ibex_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, MXL_RV32, rv32_sifive_e_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, MXL_RV32, rv32_imafcu_nommu_cpu_init), @@ -3288,11 +3227,18 @@ static const TypeInfo riscv_cpu_type_infos[] = { #endif #if (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_MAX32, MXL_RV32, riscv_max_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_MAX32, TYPE_RISCV_DYNAMIC_CPU, + .cfg.max_satp_mode = VM_1_10_SV32, + .misa_mxl_max = MXL_RV32, + ), #endif #if defined(TARGET_RISCV64) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE64, MXL_RV64, rv64_base_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE64, TYPE_RISCV_DYNAMIC_CPU, + .cfg.max_satp_mode = VM_1_10_SV57, + .misa_mxl_max = MXL_RV64, + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, MXL_RV64, rv64_sifive_e_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, MXL_RV64, rv64_sifive_u_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, MXL_RV64, rv64_sifive_u_cpu_init), @@ -3302,8 +3248,11 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, MXL_RV64, rv64_xiangshan_nanhu_cpu_init), #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) - DEFINE_DYNAMIC_CPU(TYPE_RISCV_CPU_BASE128, MXL_RV128, rv128_base_cpu_init), -#endif /* CONFIG_TCG && !CONFIG_USER_ONLY */ + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU, + .cfg.max_satp_mode = VM_1_10_SV57, + .misa_mxl_max = MXL_RV128, + ), +#endif /* CONFIG_TCG */ DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV64I, TYPE_RISCV_BARE_CPU, .misa_mxl_max = MXL_RV64, .misa_ext = RVI From e89d4931d0a15ff0481e9a6e7cbb9f7a28e91434 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 15:32:52 +0100 Subject: [PATCH 1042/2760] target/riscv: convert SiFive E CPU models to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 74 ++++++++++++------------------------------ 2 files changed, 21 insertions(+), 54 deletions(-) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 4cfdb74891..0f9be15e47 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -44,6 +44,7 @@ #define TYPE_RISCV_CPU_RVA23S64 RISCV_CPU_TYPE_NAME("rva23s64") #define TYPE_RISCV_CPU_IBEX RISCV_CPU_TYPE_NAME("lowrisc-ibex") #define TYPE_RISCV_CPU_SHAKTI_C RISCV_CPU_TYPE_NAME("shakti-c") +#define TYPE_RISCV_CPU_SIFIVE_E RISCV_CPU_TYPE_NAME("sifive-e") #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2b26f23bd0..17ad8b2ca1 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -503,23 +503,6 @@ static void rv64_sifive_u_cpu_init(Object *obj) cpu->cfg.pmp = true; } -static void rv64_sifive_e_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVC | RVU); - env->priv_ver = PRIV_VERSION_1_10_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_MBARE); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.pmp = true; -} - static void rv64_thead_c906_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -708,23 +691,6 @@ static void rv32_sifive_u_cpu_init(Object *obj) cpu->cfg.pmp = true; } -static void rv32_sifive_e_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVC | RVU); - env->priv_ver = PRIV_VERSION_1_10_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_MBARE); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.pmp = true; -} - static void rv32_ibex_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -746,23 +712,6 @@ static void rv32_ibex_cpu_init(Object *obj) cpu->cfg.ext_zbc = true; cpu->cfg.ext_zbs = true; } - -static void rv32_imafcu_nommu_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVC | RVU); - env->priv_ver = PRIV_VERSION_1_10_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_MBARE); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.pmp = true; -} #endif static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -3204,6 +3153,15 @@ static const TypeInfo riscv_cpu_type_infos[] = { #endif ), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E, TYPE_RISCV_VENDOR_CPU, + .misa_ext = RVI | RVM | RVA | RVC | RVU, + .priv_spec = PRIV_VERSION_1_10_0, + .cfg.max_satp_mode = VM_1_10_MBARE, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.pmp = true + ), + #if defined(TARGET_RISCV32) || \ (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU, @@ -3212,8 +3170,14 @@ static const TypeInfo riscv_cpu_type_infos[] = { ), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, MXL_RV32, rv32_ibex_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E31, MXL_RV32, rv32_sifive_e_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E34, MXL_RV32, rv32_imafcu_nommu_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E31, TYPE_RISCV_CPU_SIFIVE_E, + .misa_mxl_max = MXL_RV32 + ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E34, TYPE_RISCV_CPU_SIFIVE_E, + .misa_mxl_max = MXL_RV32, + .misa_ext = RVF, /* IMAFCU */ + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, MXL_RV32, rv32_sifive_u_cpu_init), DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV32I, TYPE_RISCV_BARE_CPU, @@ -3239,7 +3203,9 @@ static const TypeInfo riscv_cpu_type_infos[] = { .misa_mxl_max = MXL_RV64, ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_E51, MXL_RV64, rv64_sifive_e_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E51, TYPE_RISCV_CPU_SIFIVE_E, + .misa_mxl_max = MXL_RV64 + ), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, MXL_RV64, rv64_sifive_u_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, MXL_RV64, rv64_sifive_u_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, MXL_RV64, rv64_thead_c906_cpu_init), From 5106b8ee9ac78505f872a956c931c1f965ad073e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 17:27:16 +0100 Subject: [PATCH 1043/2760] target/riscv: convert ibex CPU models to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 17ad8b2ca1..689c33916e 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -690,28 +690,6 @@ static void rv32_sifive_u_cpu_init(Object *obj) cpu->cfg.mmu = true; cpu->cfg.pmp = true; } - -static void rv32_ibex_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVI | RVM | RVC | RVU); - env->priv_ver = PRIV_VERSION_1_12_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_MBARE); -#endif - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.pmp = true; - cpu->cfg.ext_smepmp = true; - - cpu->cfg.ext_zba = true; - cpu->cfg.ext_zbb = true; - cpu->cfg.ext_zbc = true; - cpu->cfg.ext_zbs = true; -} #endif static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) @@ -3169,7 +3147,22 @@ static const TypeInfo riscv_cpu_type_infos[] = { .misa_mxl_max = MXL_RV32, ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_IBEX, MXL_RV32, rv32_ibex_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_IBEX, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV32, + .misa_ext = RVI | RVM | RVC | RVU, + .priv_spec = PRIV_VERSION_1_12_0, + .cfg.max_satp_mode = VM_1_10_MBARE, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.pmp = true, + .cfg.ext_smepmp = true, + + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.ext_zbc = true, + .cfg.ext_zbs = true + ), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E31, TYPE_RISCV_CPU_SIFIVE_E, .misa_mxl_max = MXL_RV32 ), From 5a62948c91a910de4f9c7332cf8803152c099eac Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 18 Feb 2025 13:05:25 +0100 Subject: [PATCH 1044/2760] target/riscv: convert SiFive U models to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu-qom.h | 1 + target/riscv/cpu.c | 79 +++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h index 0f9be15e47..1ee05eb393 100644 --- a/target/riscv/cpu-qom.h +++ b/target/riscv/cpu-qom.h @@ -48,6 +48,7 @@ #define TYPE_RISCV_CPU_SIFIVE_E31 RISCV_CPU_TYPE_NAME("sifive-e31") #define TYPE_RISCV_CPU_SIFIVE_E34 RISCV_CPU_TYPE_NAME("sifive-e34") #define TYPE_RISCV_CPU_SIFIVE_E51 RISCV_CPU_TYPE_NAME("sifive-e51") +#define TYPE_RISCV_CPU_SIFIVE_U RISCV_CPU_TYPE_NAME("sifive-u") #define TYPE_RISCV_CPU_SIFIVE_U34 RISCV_CPU_TYPE_NAME("sifive-u34") #define TYPE_RISCV_CPU_SIFIVE_U54 RISCV_CPU_TYPE_NAME("sifive-u54") #define TYPE_RISCV_CPU_THEAD_C906 RISCV_CPU_TYPE_NAME("thead-c906") diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 689c33916e..01b028653a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -440,8 +440,8 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -static void set_satp_mode_max_supported(RISCVCPU *cpu, - int satp_mode) +static void __attribute__((unused)) +set_satp_mode_max_supported(RISCVCPU *cpu, int satp_mode) { bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; @@ -486,23 +486,6 @@ static void set_satp_mode_default_map(RISCVCPU *cpu) #endif #if defined(TARGET_RISCV64) -static void rv64_sifive_u_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - env->priv_ver = PRIV_VERSION_1_10_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; -} - static void rv64_thead_c906_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -671,27 +654,6 @@ static void rv64_xiangshan_nanhu_cpu_init(Object *obj) #endif /* !TARGET_RISCV64 */ -#if defined(TARGET_RISCV32) || \ - (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) - -static void rv32_sifive_u_cpu_init(Object *obj) -{ - RISCVCPU *cpu = RISCV_CPU(obj); - CPURISCVState *env = &cpu->env; - riscv_cpu_set_misa_ext(env, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); - env->priv_ver = PRIV_VERSION_1_10_0; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; -} -#endif - static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -2921,6 +2883,17 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) if (def->misa_mxl_max) { assert(def->misa_mxl_max <= MXL_RV128); mcc->def->misa_mxl_max = def->misa_mxl_max; + +#ifndef CONFIG_USER_ONLY + /* + * Hack to simplify CPU class hierarchies that include both 32- and + * 64-bit models: reduce SV39/48/57/64 to SV32 for 32-bit models. + */ + if (mcc->def->misa_mxl_max == MXL_RV32 && + !valid_vm_1_10_32[mcc->def->cfg.max_satp_mode]) { + mcc->def->cfg.max_satp_mode = VM_1_10_SV32; + } +#endif } if (def->priv_spec != RISCV_PROFILE_ATTR_UNUSED) { assert(def->priv_spec <= PRIV_VERSION_LATEST); @@ -3140,6 +3113,17 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.pmp = true ), + DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_U, TYPE_RISCV_VENDOR_CPU, + .misa_ext = RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU, + .priv_spec = PRIV_VERSION_1_10_0, + + .cfg.max_satp_mode = VM_1_10_SV39, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.mmu = true, + .cfg.pmp = true + ), + #if defined(TARGET_RISCV32) || \ (defined(TARGET_RISCV64) && !defined(CONFIG_USER_ONLY)) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE32, TYPE_RISCV_DYNAMIC_CPU, @@ -3171,7 +3155,9 @@ static const TypeInfo riscv_cpu_type_infos[] = { .misa_ext = RVF, /* IMAFCU */ ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U34, MXL_RV32, rv32_sifive_u_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_U34, TYPE_RISCV_CPU_SIFIVE_U, + .misa_mxl_max = MXL_RV32, + ), DEFINE_RISCV_CPU(TYPE_RISCV_CPU_RV32I, TYPE_RISCV_BARE_CPU, .misa_mxl_max = MXL_RV32, @@ -3199,8 +3185,15 @@ static const TypeInfo riscv_cpu_type_infos[] = { DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_E51, TYPE_RISCV_CPU_SIFIVE_E, .misa_mxl_max = MXL_RV64 ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SIFIVE_U54, MXL_RV64, rv64_sifive_u_cpu_init), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_SHAKTI_C, MXL_RV64, rv64_sifive_u_cpu_init), + + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_U54, TYPE_RISCV_CPU_SIFIVE_U, + .misa_mxl_max = MXL_RV64, + ), + + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_SHAKTI_C, TYPE_RISCV_CPU_SIFIVE_U, + .misa_mxl_max = MXL_RV64, + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, MXL_RV64, rv64_thead_c906_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_TT_ASCALON, MXL_RV64, rv64_tt_ascalon_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), From 1d84c2401c48617b8695d292602e2e777e0d1178 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 17:39:49 +0100 Subject: [PATCH 1045/2760] target/riscv: th: make CSR insertion test a bit more intuitive In preparation for generalizing the custom CSR functionality, make the test return bool instead of int. Make the insertion_test optional, too. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/th_csr.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c index 6c970d4e81..969a9fe3c8 100644 --- a/target/riscv/th_csr.c +++ b/target/riscv/th_csr.c @@ -29,7 +29,7 @@ typedef struct { int csrno; - int (*insertion_test)(RISCVCPU *cpu); + bool (*insertion_test)(RISCVCPU *cpu); riscv_csr_operations csr_ops; } riscv_csr; @@ -42,13 +42,9 @@ static RISCVException smode(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } -static int test_thead_mvendorid(RISCVCPU *cpu) +static bool test_thead_mvendorid(RISCVCPU *cpu) { - if (cpu->cfg.mvendorid != THEAD_VENDOR_ID) { - return -1; - } - - return 0; + return cpu->cfg.mvendorid == THEAD_VENDOR_ID; } static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno, @@ -66,13 +62,12 @@ static riscv_csr th_csr_list[] = { .csr_ops = { "th.sxstatus", smode, read_th_sxstatus } } }; - void th_register_custom_csrs(RISCVCPU *cpu) { for (size_t i = 0; i < ARRAY_SIZE(th_csr_list); i++) { int csrno = th_csr_list[i].csrno; riscv_csr_operations *csr_ops = &th_csr_list[i].csr_ops; - if (!th_csr_list[i].insertion_test(cpu)) { + if (!th_csr_list[i].insertion_test || th_csr_list[i].insertion_test(cpu)) { riscv_set_csr_ops(csrno, csr_ops); } } From 1016b0364f981e7aa9304866d7d756813e8dc6c2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 27 Feb 2025 15:09:49 +0100 Subject: [PATCH 1046/2760] target/riscv: generalize custom CSR functionality While at it, constify it so that the RISCVCSR array in RISCVCPUDef can also be const. Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 25 ++++++++++++++++++++++++- target/riscv/cpu.h | 15 ++++++++++++--- target/riscv/csr.c | 2 +- target/riscv/th_csr.c | 21 +++------------------ 4 files changed, 40 insertions(+), 23 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 01b028653a..12f4bc4151 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -485,6 +485,19 @@ static void set_satp_mode_default_map(RISCVCPU *cpu) } #endif +#ifndef CONFIG_USER_ONLY +static void riscv_register_custom_csrs(RISCVCPU *cpu, const RISCVCSR *csr_list) +{ + for (size_t i = 0; csr_list[i].csr_ops.name; i++) { + int csrno = csr_list[i].csrno; + const riscv_csr_operations *csr_ops = &csr_list[i].csr_ops; + if (!csr_list[i].insertion_test || csr_list[i].insertion_test(cpu)) { + riscv_set_csr_ops(csrno, csr_ops); + } + } +} +#endif + #if defined(TARGET_RISCV64) static void rv64_thead_c906_cpu_init(Object *obj) { @@ -511,7 +524,7 @@ static void rv64_thead_c906_cpu_init(Object *obj) cpu->cfg.mvendorid = THEAD_VENDOR_ID; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_SV39); - th_register_custom_csrs(cpu); + riscv_register_custom_csrs(cpu, th_csr_list); #endif /* inherited from parent obj via riscv_cpu_init() */ @@ -1304,6 +1317,11 @@ static void riscv_cpu_init(Object *obj) if (mcc->def->vext_spec != RISCV_PROFILE_ATTR_UNUSED) { cpu->env.vext_ver = mcc->def->vext_spec; } +#ifndef CONFIG_USER_ONLY + if (mcc->def->custom_csrs) { + riscv_register_custom_csrs(cpu, mcc->def->custom_csrs); + } +#endif } typedef struct misa_ext_info { @@ -2906,6 +2924,11 @@ static void riscv_cpu_class_base_init(ObjectClass *c, const void *data) mcc->def->misa_ext |= def->misa_ext; riscv_cpu_cfg_merge(&mcc->def->cfg, &def->cfg); + + if (def->custom_csrs) { + assert(!mcc->def->custom_csrs); + mcc->def->custom_csrs = def->custom_csrs; + } } if (!object_class_is_abstract(c)) { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index ed88adef45..229ade9ed9 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -538,6 +538,8 @@ struct ArchCPU { const GPtrArray *decoders; }; +typedef struct RISCVCSR RISCVCSR; + typedef struct RISCVCPUDef { RISCVMXL misa_mxl_max; /* max mxl for this cpu */ RISCVCPUProfile *profile; @@ -546,6 +548,7 @@ typedef struct RISCVCPUDef { int32_t vext_spec; RISCVCPUConfig cfg; bool bare; + const RISCVCSR *custom_csrs; } RISCVCPUDef; /** @@ -893,6 +896,12 @@ typedef struct { uint32_t min_priv_ver; } riscv_csr_operations; +struct RISCVCSR { + int csrno; + bool (*insertion_test)(RISCVCPU *cpu); + riscv_csr_operations csr_ops; +}; + /* CSR function table constants */ enum { CSR_TABLE_SIZE = 0x1000 @@ -947,7 +956,7 @@ extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE]; extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[]; void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops); -void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); +void riscv_set_csr_ops(int csrno, const riscv_csr_operations *ops); void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); @@ -956,8 +965,8 @@ target_ulong riscv_new_csr_seed(target_ulong new_value, const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); -/* Implemented in th_csr.c */ -void th_register_custom_csrs(RISCVCPU *cpu); +/* In th_csr.c */ +extern const RISCVCSR th_csr_list[]; const char *priv_spec_to_str(int priv_version); #endif /* RISCV_CPU_H */ diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 9843fd2191..fb14972169 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -40,7 +40,7 @@ void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops) *ops = csr_ops[csrno & (CSR_TABLE_SIZE - 1)]; } -void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops) +void riscv_set_csr_ops(int csrno, const riscv_csr_operations *ops) { csr_ops[csrno & (CSR_TABLE_SIZE - 1)] = *ops; } diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c index 969a9fe3c8..49eb7bbab5 100644 --- a/target/riscv/th_csr.c +++ b/target/riscv/th_csr.c @@ -27,12 +27,6 @@ #define TH_SXSTATUS_MAEE BIT(21) #define TH_SXSTATUS_THEADISAEE BIT(22) -typedef struct { - int csrno; - bool (*insertion_test)(RISCVCPU *cpu); - riscv_csr_operations csr_ops; -} riscv_csr; - static RISCVException smode(CPURISCVState *env, int csrno) { if (riscv_has_ext(env, RVS)) { @@ -55,20 +49,11 @@ static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static riscv_csr th_csr_list[] = { +const RISCVCSR th_csr_list[] = { { .csrno = CSR_TH_SXSTATUS, .insertion_test = test_thead_mvendorid, .csr_ops = { "th.sxstatus", smode, read_th_sxstatus } - } + }, + { } }; -void th_register_custom_csrs(RISCVCPU *cpu) -{ - for (size_t i = 0; i < ARRAY_SIZE(th_csr_list); i++) { - int csrno = th_csr_list[i].csrno; - riscv_csr_operations *csr_ops = &th_csr_list[i].csr_ops; - if (!th_csr_list[i].insertion_test || th_csr_list[i].insertion_test(cpu)) { - riscv_set_csr_ops(csrno, csr_ops); - } - } -} From 5f687d77ff93ae3dd2fb48600e4e6ae32eb7350e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 15:48:47 +0100 Subject: [PATCH 1047/2760] target/riscv: convert THead C906 to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 61 +++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 12f4bc4151..5d2ccf647d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -499,38 +499,6 @@ static void riscv_register_custom_csrs(RISCVCPU *cpu, const RISCVCSR *csr_list) #endif #if defined(TARGET_RISCV64) -static void rv64_thead_c906_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVG | RVC | RVS | RVU); - env->priv_ver = PRIV_VERSION_1_11_0; - - cpu->cfg.ext_zfa = true; - cpu->cfg.ext_zfh = true; - cpu->cfg.mmu = true; - cpu->cfg.ext_xtheadba = true; - cpu->cfg.ext_xtheadbb = true; - cpu->cfg.ext_xtheadbs = true; - cpu->cfg.ext_xtheadcmo = true; - cpu->cfg.ext_xtheadcondmov = true; - cpu->cfg.ext_xtheadfmemidx = true; - cpu->cfg.ext_xtheadmac = true; - cpu->cfg.ext_xtheadmemidx = true; - cpu->cfg.ext_xtheadmempair = true; - cpu->cfg.ext_xtheadsync = true; - - cpu->cfg.mvendorid = THEAD_VENDOR_ID; -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_SV39); - riscv_register_custom_csrs(cpu, th_csr_list); -#endif - - /* inherited from parent obj via riscv_cpu_init() */ - cpu->cfg.pmp = true; -} - static void rv64_veyron_v1_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -3217,7 +3185,34 @@ static const TypeInfo riscv_cpu_type_infos[] = { .misa_mxl_max = MXL_RV64, ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_THEAD_C906, MXL_RV64, rv64_thead_c906_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_THEAD_C906, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVG | RVC | RVS | RVU, + .priv_spec = PRIV_VERSION_1_11_0, + + .cfg.ext_zfa = true, + .cfg.ext_zfh = true, + .cfg.mmu = true, + .cfg.ext_xtheadba = true, + .cfg.ext_xtheadbb = true, + .cfg.ext_xtheadbs = true, + .cfg.ext_xtheadcmo = true, + .cfg.ext_xtheadcondmov = true, + .cfg.ext_xtheadfmemidx = true, + .cfg.ext_xtheadmac = true, + .cfg.ext_xtheadmemidx = true, + .cfg.ext_xtheadmempair = true, + .cfg.ext_xtheadsync = true, + .cfg.pmp = true, + + .cfg.mvendorid = THEAD_VENDOR_ID, + + .cfg.max_satp_mode = VM_1_10_SV39, +#ifndef CONFIG_USER_ONLY + .custom_csrs = th_csr_list, +#endif + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_TT_ASCALON, MXL_RV64, rv64_tt_ascalon_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, From 09ef7d97454a64e00d8dc9fd3a188d6c06003cc1 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 15:53:28 +0100 Subject: [PATCH 1048/2760] target/riscv: convert TT Ascalon to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 127 +++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 67 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 5d2ccf647d..48939adaaf 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -539,72 +539,6 @@ static void rv64_veyron_v1_cpu_init(Object *obj) #endif } -/* Tenstorrent Ascalon */ -static void rv64_tt_ascalon_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVG | RVC | RVS | RVU | RVH | RVV); - env->priv_ver = PRIV_VERSION_1_13_0; - - /* Enable ISA extensions */ - cpu->cfg.mmu = true; - cpu->cfg.vlenb = 256 >> 3; - cpu->cfg.elen = 64; - cpu->env.vext_ver = VEXT_VERSION_1_00_0; - cpu->cfg.rvv_ma_all_1s = true; - cpu->cfg.rvv_ta_all_1s = true; - cpu->cfg.misa_w = true; - cpu->cfg.pmp = true; - cpu->cfg.cbom_blocksize = 64; - cpu->cfg.cbop_blocksize = 64; - cpu->cfg.cboz_blocksize = 64; - cpu->cfg.ext_zic64b = true; - cpu->cfg.ext_zicbom = true; - cpu->cfg.ext_zicbop = true; - cpu->cfg.ext_zicboz = true; - cpu->cfg.ext_zicntr = true; - cpu->cfg.ext_zicond = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zihintntl = true; - cpu->cfg.ext_zihintpause = true; - cpu->cfg.ext_zihpm = true; - cpu->cfg.ext_zimop = true; - cpu->cfg.ext_zawrs = true; - cpu->cfg.ext_zfa = true; - cpu->cfg.ext_zfbfmin = true; - cpu->cfg.ext_zfh = true; - cpu->cfg.ext_zfhmin = true; - cpu->cfg.ext_zcb = true; - cpu->cfg.ext_zcmop = true; - cpu->cfg.ext_zba = true; - cpu->cfg.ext_zbb = true; - cpu->cfg.ext_zbs = true; - cpu->cfg.ext_zkt = true; - cpu->cfg.ext_zvbb = true; - cpu->cfg.ext_zvbc = true; - cpu->cfg.ext_zvfbfmin = true; - cpu->cfg.ext_zvfbfwma = true; - cpu->cfg.ext_zvfh = true; - cpu->cfg.ext_zvfhmin = true; - cpu->cfg.ext_zvkng = true; - cpu->cfg.ext_smaia = true; - cpu->cfg.ext_smstateen = true; - cpu->cfg.ext_ssaia = true; - cpu->cfg.ext_sscofpmf = true; - cpu->cfg.ext_sstc = true; - cpu->cfg.ext_svade = true; - cpu->cfg.ext_svinval = true; - cpu->cfg.ext_svnapot = true; - cpu->cfg.ext_svpbmt = true; - -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_SV57); -#endif -} - static void rv64_xiangshan_nanhu_cpu_init(Object *obj) { CPURISCVState *env = &RISCV_CPU(obj)->env; @@ -3213,7 +3147,66 @@ static const TypeInfo riscv_cpu_type_infos[] = { #endif ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_TT_ASCALON, MXL_RV64, rv64_tt_ascalon_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_TT_ASCALON, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVG | RVC | RVS | RVU | RVH | RVV, + .priv_spec = PRIV_VERSION_1_13_0, + .vext_spec = VEXT_VERSION_1_00_0, + + /* ISA extensions */ + .cfg.mmu = true, + .cfg.vlenb = 256 >> 3, + .cfg.elen = 64, + .cfg.rvv_ma_all_1s = true, + .cfg.rvv_ta_all_1s = true, + .cfg.misa_w = true, + .cfg.pmp = true, + .cfg.cbom_blocksize = 64, + .cfg.cbop_blocksize = 64, + .cfg.cboz_blocksize = 64, + .cfg.ext_zic64b = true, + .cfg.ext_zicbom = true, + .cfg.ext_zicbop = true, + .cfg.ext_zicboz = true, + .cfg.ext_zicntr = true, + .cfg.ext_zicond = true, + .cfg.ext_zicsr = true, + .cfg.ext_zifencei = true, + .cfg.ext_zihintntl = true, + .cfg.ext_zihintpause = true, + .cfg.ext_zihpm = true, + .cfg.ext_zimop = true, + .cfg.ext_zawrs = true, + .cfg.ext_zfa = true, + .cfg.ext_zfbfmin = true, + .cfg.ext_zfh = true, + .cfg.ext_zfhmin = true, + .cfg.ext_zcb = true, + .cfg.ext_zcmop = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.ext_zbs = true, + .cfg.ext_zkt = true, + .cfg.ext_zvbb = true, + .cfg.ext_zvbc = true, + .cfg.ext_zvfbfmin = true, + .cfg.ext_zvfbfwma = true, + .cfg.ext_zvfh = true, + .cfg.ext_zvfhmin = true, + .cfg.ext_zvkng = true, + .cfg.ext_smaia = true, + .cfg.ext_smstateen = true, + .cfg.ext_ssaia = true, + .cfg.ext_sscofpmf = true, + .cfg.ext_sstc = true, + .cfg.ext_svade = true, + .cfg.ext_svinval = true, + .cfg.ext_svnapot = true, + .cfg.ext_svpbmt = true, + + .cfg.max_satp_mode = VM_1_10_SV57, + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, MXL_RV64, rv64_xiangshan_nanhu_cpu_init), From 0927f7d55cd5a214eb2ef9671ddd271a3fb2a15c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 15:53:28 +0100 Subject: [PATCH 1049/2760] target/riscv: convert Ventana V1 to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 75 ++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 40 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 48939adaaf..000fcc6a1d 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -499,45 +499,6 @@ static void riscv_register_custom_csrs(RISCVCPU *cpu, const RISCVCSR *csr_list) #endif #if defined(TARGET_RISCV64) -static void rv64_veyron_v1_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVG | RVC | RVS | RVU | RVH); - env->priv_ver = PRIV_VERSION_1_12_0; - - /* Enable ISA extensions */ - cpu->cfg.mmu = true; - cpu->cfg.ext_zifencei = true; - cpu->cfg.ext_zicsr = true; - cpu->cfg.pmp = true; - cpu->cfg.ext_zicbom = true; - cpu->cfg.cbom_blocksize = 64; - cpu->cfg.cboz_blocksize = 64; - cpu->cfg.ext_zicboz = true; - cpu->cfg.ext_smaia = true; - cpu->cfg.ext_ssaia = true; - cpu->cfg.ext_sscofpmf = true; - cpu->cfg.ext_sstc = true; - cpu->cfg.ext_svinval = true; - cpu->cfg.ext_svnapot = true; - cpu->cfg.ext_svpbmt = true; - cpu->cfg.ext_smstateen = true; - cpu->cfg.ext_zba = true; - cpu->cfg.ext_zbb = true; - cpu->cfg.ext_zbc = true; - cpu->cfg.ext_zbs = true; - cpu->cfg.ext_XVentanaCondOps = true; - - cpu->cfg.mvendorid = VEYRON_V1_MVENDORID; - cpu->cfg.marchid = VEYRON_V1_MARCHID; - cpu->cfg.mimpid = VEYRON_V1_MIMPID; - -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_SV48); -#endif -} static void rv64_xiangshan_nanhu_cpu_init(Object *obj) { @@ -3207,7 +3168,41 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_SV57, ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_VEYRON_V1, MXL_RV64, rv64_veyron_v1_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_VEYRON_V1, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVG | RVC | RVS | RVU | RVH, + .priv_spec = PRIV_VERSION_1_12_0, + + /* ISA extensions */ + .cfg.mmu = true, + .cfg.ext_zifencei = true, + .cfg.ext_zicsr = true, + .cfg.pmp = true, + .cfg.ext_zicbom = true, + .cfg.cbom_blocksize = 64, + .cfg.cboz_blocksize = 64, + .cfg.ext_zicboz = true, + .cfg.ext_smaia = true, + .cfg.ext_ssaia = true, + .cfg.ext_sscofpmf = true, + .cfg.ext_sstc = true, + .cfg.ext_svinval = true, + .cfg.ext_svnapot = true, + .cfg.ext_svpbmt = true, + .cfg.ext_smstateen = true, + .cfg.ext_zba = true, + .cfg.ext_zbb = true, + .cfg.ext_zbc = true, + .cfg.ext_zbs = true, + .cfg.ext_XVentanaCondOps = true, + + .cfg.mvendorid = VEYRON_V1_MVENDORID, + .cfg.marchid = VEYRON_V1_MARCHID, + .cfg.mimpid = VEYRON_V1_MIMPID, + + .cfg.max_satp_mode = VM_1_10_SV48, + ), + DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, MXL_RV64, rv64_xiangshan_nanhu_cpu_init), #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) From 70f48d7fb19a88bca3cd4c388646d4cb9ee730f0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 17:36:06 +0100 Subject: [PATCH 1050/2760] target/riscv: convert Xiangshan Nanhu to RISCVCPUDef Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 80 +++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 57 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 000fcc6a1d..640aa958fd 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -440,16 +440,6 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit) g_assert_not_reached(); } -static void __attribute__((unused)) -set_satp_mode_max_supported(RISCVCPU *cpu, int satp_mode) -{ - bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32; - const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64; - - assert(valid_vm[satp_mode]); - cpu->cfg.max_satp_mode = satp_mode; -} - static bool get_satp_mode_supported(RISCVCPU *cpu, uint16_t *supported) { bool rv32 = riscv_cpu_is_32bit(cpu); @@ -498,38 +488,6 @@ static void riscv_register_custom_csrs(RISCVCPU *cpu, const RISCVCSR *csr_list) } #endif -#if defined(TARGET_RISCV64) - -static void rv64_xiangshan_nanhu_cpu_init(Object *obj) -{ - CPURISCVState *env = &RISCV_CPU(obj)->env; - RISCVCPU *cpu = RISCV_CPU(obj); - - riscv_cpu_set_misa_ext(env, RVG | RVC | RVB | RVS | RVU); - env->priv_ver = PRIV_VERSION_1_12_0; - - /* Enable ISA extensions */ - cpu->cfg.ext_zbc = true; - cpu->cfg.ext_zbkb = true; - cpu->cfg.ext_zbkc = true; - cpu->cfg.ext_zbkx = true; - cpu->cfg.ext_zknd = true; - cpu->cfg.ext_zkne = true; - cpu->cfg.ext_zknh = true; - cpu->cfg.ext_zksed = true; - cpu->cfg.ext_zksh = true; - cpu->cfg.ext_svinval = true; - - cpu->cfg.mmu = true; - cpu->cfg.pmp = true; - -#ifndef CONFIG_USER_ONLY - set_satp_mode_max_supported(cpu, VM_1_10_SV39); -#endif -} - -#endif /* !TARGET_RISCV64 */ - static ObjectClass *riscv_cpu_class_by_name(const char *cpu_model) { ObjectClass *oc; @@ -2891,19 +2849,6 @@ void riscv_isa_write_fdt(RISCVCPU *cpu, void *fdt, char *nodename) } #endif -#define DEFINE_VENDOR_CPU(type_name, misa_mxl_max_, initfn) \ - { \ - .name = (type_name), \ - .parent = TYPE_RISCV_VENDOR_CPU, \ - .instance_init = (initfn), \ - .class_data = &(const RISCVCPUDef) { \ - .misa_mxl_max = (misa_mxl_max_), \ - .priv_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .vext_spec = RISCV_PROFILE_ATTR_UNUSED, \ - .cfg.max_satp_mode = -1, \ - }, \ - } - #define DEFINE_ABSTRACT_RISCV_CPU(type_name, parent_type_name, ...) \ { \ .name = (type_name), \ @@ -3203,8 +3148,29 @@ static const TypeInfo riscv_cpu_type_infos[] = { .cfg.max_satp_mode = VM_1_10_SV48, ), - DEFINE_VENDOR_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, - MXL_RV64, rv64_xiangshan_nanhu_cpu_init), + DEFINE_RISCV_CPU(TYPE_RISCV_CPU_XIANGSHAN_NANHU, TYPE_RISCV_VENDOR_CPU, + .misa_mxl_max = MXL_RV64, + .misa_ext = RVG | RVC | RVB | RVS | RVU, + .priv_spec = PRIV_VERSION_1_12_0, + + /* ISA extensions */ + .cfg.ext_zbc = true, + .cfg.ext_zbkb = true, + .cfg.ext_zbkc = true, + .cfg.ext_zbkx = true, + .cfg.ext_zknd = true, + .cfg.ext_zkne = true, + .cfg.ext_zknh = true, + .cfg.ext_zksed = true, + .cfg.ext_zksh = true, + .cfg.ext_svinval = true, + + .cfg.mmu = true, + .cfg.pmp = true, + + .cfg.max_satp_mode = VM_1_10_SV39, + ), + #if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY) DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU, .cfg.max_satp_mode = VM_1_10_SV57, From 42bc8af14033b9eeeb535449f243767c015f027e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 6 Feb 2025 12:57:12 +0100 Subject: [PATCH 1051/2760] target/riscv: remove .instance_post_init Unlike other uses of .instance_post_init, accel_cpu_instance_init() *registers* properties, and therefore must be run before device_post_init() which sets them to their values from -global. In order to move all registration of properties to .instance_init, call accel_cpu_instance_init() at the end of riscv_cpu_init(). Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- target/riscv/cpu.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 640aa958fd..629ac37501 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1083,11 +1083,6 @@ static bool riscv_cpu_is_dynamic(Object *cpu_obj) return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL; } -static void riscv_cpu_post_init(Object *obj) -{ - accel_cpu_instance_init(CPU(obj)); -} - static void riscv_cpu_init(Object *obj) { RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(obj); @@ -1143,6 +1138,8 @@ static void riscv_cpu_init(Object *obj) riscv_register_custom_csrs(cpu, mcc->def->custom_csrs); } #endif + + accel_cpu_instance_init(CPU(obj)); } typedef struct misa_ext_info { @@ -2885,7 +2882,6 @@ static const TypeInfo riscv_cpu_type_infos[] = { .instance_size = sizeof(RISCVCPU), .instance_align = __alignof(RISCVCPU), .instance_init = riscv_cpu_init, - .instance_post_init = riscv_cpu_post_init, .abstract = true, .class_size = sizeof(RISCVCPUClass), .class_init = riscv_cpu_common_class_init, From 220c739903cec99df032219ac94c45b5269a0ab5 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 3 Feb 2025 12:35:39 +0100 Subject: [PATCH 1052/2760] qom: reverse order of instance_post_init calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the instance_post_init calls are performed from the leaf class and all the way up to Object. This is incorrect because the leaf class cannot observe property values applied by the superclasses; for example, a compat property will be set on a device *after* the class's post_init callback has run. In particular this makes it impossible for implementations of accel_cpu_instance_init() to operate based on the actual values of the properties, though it seems that cxl_dsp_instance_post_init and rp_instance_post_init might have similar issues. Follow instead the same order as instance_init, starting with Object and running the child class's instance_post_init after the parent. Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Alistair Francis Signed-off-by: Paolo Bonzini --- include/qom/object.h | 3 ++- qom/object.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/include/qom/object.h b/include/qom/object.h index 1d5b033724..26df6137b9 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -445,7 +445,8 @@ struct Object * class will have already been initialized so the type is only responsible * for initializing its own members. * @instance_post_init: This function is called to finish initialization of - * an object, after all @instance_init functions were called. + * an object, after all @instance_init functions were called, as well as + * @instance_post_init functions for the parent classes. * @instance_finalize: This function is called during object destruction. This * is called before the parent @instance_finalize function has been called. * An object should only free the members that are unique to its type in this diff --git a/qom/object.c b/qom/object.c index 7b013f40a0..1856bb36c7 100644 --- a/qom/object.c +++ b/qom/object.c @@ -431,13 +431,13 @@ static void object_init_with_type(Object *obj, TypeImpl *ti) static void object_post_init_with_type(Object *obj, TypeImpl *ti) { - if (ti->instance_post_init) { - ti->instance_post_init(obj); - } - if (type_has_parent(ti)) { object_post_init_with_type(obj, type_get_parent(ti)); } + + if (ti->instance_post_init) { + ti->instance_post_init(obj); + } } bool object_apply_global_props(Object *obj, const GPtrArray *props, From c4f88b7136aa5aa5670a16c2f173ffb45da401b2 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 1 May 2025 11:12:35 -0400 Subject: [PATCH 1053/2760] scripts/vmstate-static-checker.py: Add new hpet entry for num_timers The old "num_timers" got a rename. See commit 1433e38cc8 ("hpet: do not overwrite properties on post_load") for more details. Teach the script to accept the new name. Cc: Paolo Bonzini Cc: Thomas Huth Reviewed-by: Thomas Huth Link: https://lore.kernel.org/r/20250501151235.636709-1-peterx@redhat.com Signed-off-by: Peter Xu --- scripts/vmstate-static-checker.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py index 25aca839a0..2335e25f94 100755 --- a/scripts/vmstate-static-checker.py +++ b/scripts/vmstate-static-checker.py @@ -91,6 +91,7 @@ def check_fields_match(name, s_field, d_field): 'mem_win_size', 'mig_mem_win_size', 'io_win_addr', 'mig_io_win_addr', 'io_win_size', 'mig_io_win_size'], + 'hpet': ['num_timers', 'num_timers_save'], } if not name in changed_names: From 7b2e4f788d60a8ec25efbf1e6bb6552ee0cef17c Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Fri, 9 May 2025 09:42:10 +0800 Subject: [PATCH 1054/2760] qtest/migration/rdma: Enforce RLIMIT_MEMLOCK >= 128MB requirement Ensure successful migration over RDMA by verifying that RLIMIT_MEMLOCK is set to at least 128MB. This allocation is necessary due to the requirement to pin significant portions of guest memory, typically exceeding 100MB in this test, while the remainder is transmitted as compressed zero pages. Otherwise, it will fail with: stderr: qemu-system-x86_64: cannot get rkey qemu-system-x86_64: error while loading state section id 2(ram) qemu-system-x86_64: load of migration failed: Operation not permitted qemu-system-x86_64: rdma migration: recv polling control error! qemu-system-x86_64: RDMA is in an error state waiting migration to abort! qemu-system-x86_64: failed to save SaveStateEntry with id(name): 2(ram): -1 qemu-system-x86_64: Channel error: Operation not permitted Reported-by: Peter Xu Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20250509014211.1272640-1-lizhijian@fujitsu.com Signed-off-by: Peter Xu --- tests/qtest/migration/precopy-tests.c | 34 +++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index 87b0a7e8ef..5be1cd5742 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -101,6 +101,35 @@ static void test_precopy_unix_dirty_ring(void) #ifdef CONFIG_RDMA +#include + +/* + * During migration over RDMA, it will try to pin portions of guest memory, + * typically exceeding 100MB in this test, while the remainder will be + * transmitted as compressed zero pages. + * + * REQUIRED_MEMLOCK_SZ indicates the minimal mlock size in the current context. + */ +#define REQUIRED_MEMLOCK_SZ (128 << 20) /* 128MB */ + +/* check 'ulimit -l' */ +static bool mlock_check(void) +{ + uid_t uid; + struct rlimit rlim; + + uid = getuid(); + if (uid == 0) { + return true; + } + + if (getrlimit(RLIMIT_MEMLOCK, &rlim) != 0) { + return false; + } + + return rlim.rlim_cur >= REQUIRED_MEMLOCK_SZ; +} + #define RDMA_MIGRATION_HELPER "scripts/rdma-migration-helper.sh" static int new_rdma_link(char *buffer) { @@ -136,6 +165,11 @@ static void test_precopy_rdma_plain(void) { char buffer[128] = {}; + if (!mlock_check()) { + g_test_skip("'ulimit -l' is too small, require >=128M"); + return; + } + if (new_rdma_link(buffer)) { g_test_skip("No rdma link available\n" "# To enable the test:\n" From 6b84c46e8e0ef6f83f33657a29a8abb2b8362d02 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Tue, 13 May 2025 09:22:07 +0800 Subject: [PATCH 1055/2760] qtest/migration/rdma: Add test for rdma migration with ipv6 Recently, we removed ipv6 restriction[0] from RDMA migration, add a test for it. [0] https://lore.kernel.org/qemu-devel/20250326095224.9918-1-jinpu.wang@ionos.com/ Cc: Jack Wang Cc: Michael R. Galaxy Cc: Peter Xu Cc: Yu Zhang Reviewed-by: Jack Wang Signed-off-by: Li Zhijian Link: https://lore.kernel.org/r/20250513012207.2867069-1-lizhijian@fujitsu.com [peterx: Fix over long lines] Signed-off-by: Peter Xu --- scripts/rdma-migration-helper.sh | 57 ++++++++++++++++++++++----- tests/qtest/migration/precopy-tests.c | 21 ++++++++-- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/scripts/rdma-migration-helper.sh b/scripts/rdma-migration-helper.sh index a39f2fb0e5..d784d1566a 100755 --- a/scripts/rdma-migration-helper.sh +++ b/scripts/rdma-migration-helper.sh @@ -8,23 +8,44 @@ get_ipv4_addr() head -1 | tr -d '\n' } +get_ipv6_addr() { + ipv6=$(ip -6 -o addr show dev "$1" | + sed -n 's/.*[[:blank:]]inet6[[:blank:]]*\([^[:blank:]/]*\).*/\1/p' | + head -1 | tr -d '\n') + + [ $? -eq 0 ] || return + + if [[ "$ipv6" =~ ^fe80: ]]; then + echo -n "[$ipv6%$1]" + else + echo -n "[$ipv6]" + fi +} + # existing rdma interfaces rdma_interfaces() { - rdma link show | sed -nE 's/^link .* netdev ([^ ]+).*$/\1 /p' + rdma link show | sed -nE 's/^link .* netdev ([^ ]+).*$/\1 /p' | + grep -Ev '^(lo|tun|tap)' } # existing valid ipv4 interfaces ipv4_interfaces() { - ip -o addr show | awk '/inet / {print $2}' | grep -v -w lo + ip -o addr show | awk '/inet / {print $2}' | grep -Ev '^(lo|tun|tap)' +} + +ipv6_interfaces() +{ + ip -o addr show | awk '/inet6 / {print $2}' | grep -Ev '^(lo|tun|tap)' } rdma_rxe_detect() { + family=$1 for r in $(rdma_interfaces) do - ipv4_interfaces | grep -qw $r && get_ipv4_addr $r && return + "$family"_interfaces | grep -qw $r && get_"$family"_addr $r && return done return 1 @@ -32,16 +53,23 @@ rdma_rxe_detect() rdma_rxe_setup() { - for i in $(ipv4_interfaces) + family=$1 + for i in $("$family"_interfaces) do - rdma_interfaces | grep -qw $i && continue + if rdma_interfaces | grep -qw $i; then + echo "$family: Reuse the existing rdma/rxe ${i}_rxe" \ + "for $i with $(get_"$family"_addr $i)" + return + fi + rdma link add "${i}_rxe" type rxe netdev "$i" && { - echo "Setup new rdma/rxe ${i}_rxe for $i with $(get_ipv4_addr $i)" + echo "$family: Setup new rdma/rxe ${i}_rxe" \ + "for $i with $(get_"$family"_addr $i)" return } done - echo "Failed to setup any new rdma/rxe link" >&2 + echo "$family: Failed to setup any new rdma/rxe link" >&2 return 1 } @@ -50,6 +78,12 @@ rdma_rxe_clean() modprobe -r rdma_rxe } +IP_FAMILY=${IP_FAMILY:-ipv4} +if [ "$IP_FAMILY" != "ipv6" ] && [ "$IP_FAMILY" != "ipv4" ]; then + echo "Unknown ip family '$IP_FAMILY', only ipv4 or ipv6 is supported." >&2 + exit 1 +fi + operation=${1:-detect} command -v rdma >/dev/null || { @@ -62,9 +96,14 @@ if [ "$operation" == "setup" ] || [ "$operation" == "clean" ]; then echo "Root privilege is required to setup/clean a rdma/rxe link" >&2 exit 1 } - rdma_rxe_"$operation" + if [ "$operation" == "setup" ]; then + rdma_rxe_setup ipv4 + rdma_rxe_setup ipv6 + else + rdma_rxe_clean + fi elif [ "$operation" == "detect" ]; then - rdma_rxe_detect + rdma_rxe_detect "$IP_FAMILY" else echo "Usage: $0 [setup | detect | clean]" fi diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index 5be1cd5742..a62d3c5378 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -131,12 +131,13 @@ static bool mlock_check(void) } #define RDMA_MIGRATION_HELPER "scripts/rdma-migration-helper.sh" -static int new_rdma_link(char *buffer) +static int new_rdma_link(char *buffer, bool ipv6) { char cmd[256]; bool verbose = g_getenv("QTEST_LOG"); - snprintf(cmd, sizeof(cmd), "%s detect %s", RDMA_MIGRATION_HELPER, + snprintf(cmd, sizeof(cmd), "IP_FAMILY=%s %s detect %s", + ipv6 ? "ipv6" : "ipv4", RDMA_MIGRATION_HELPER, verbose ? "" : "2>/dev/null"); FILE *pipe = popen(cmd, "r"); @@ -161,7 +162,7 @@ static int new_rdma_link(char *buffer) return -1; } -static void test_precopy_rdma_plain(void) +static void __test_precopy_rdma_plain(bool ipv6) { char buffer[128] = {}; @@ -170,7 +171,7 @@ static void test_precopy_rdma_plain(void) return; } - if (new_rdma_link(buffer)) { + if (new_rdma_link(buffer, ipv6)) { g_test_skip("No rdma link available\n" "# To enable the test:\n" "# Run \'" RDMA_MIGRATION_HELPER " setup\' with root to " @@ -193,6 +194,16 @@ static void test_precopy_rdma_plain(void) test_precopy_common(&args); } + +static void test_precopy_rdma_plain(void) +{ + __test_precopy_rdma_plain(false); +} + +static void test_precopy_rdma_plain_ipv6(void) +{ + __test_precopy_rdma_plain(true); +} #endif static void test_precopy_tcp_plain(void) @@ -1226,6 +1237,8 @@ static void migration_test_add_precopy_smoke(MigrationTestEnv *env) #ifdef CONFIG_RDMA migration_test_add("/migration/precopy/rdma/plain", test_precopy_rdma_plain); + migration_test_add("/migration/precopy/rdma/plain/ipv6", + test_precopy_rdma_plain_ipv6); #endif } From e74598a981afe39d6f4951cd5d23101f537957bb Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 13 May 2025 10:33:51 -0300 Subject: [PATCH 1056/2760] ci: Re-enable python subtests in qtest migration suite The migration compatibility tests have been running with the PYTHON variable unset to avoid running a broken test. The faulty test has since been removed, so we can enable the python tests once again. Aside from the broken test, only one other test uses python and I have been running it locally ever since, so this commit should not expose any new bug. Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Link: https://lore.kernel.org/r/20250513133353.23022-2-farosas@suse.de Signed-off-by: Peter Xu --- .gitlab-ci.d/buildtest.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index 248aaed137..fbad34138c 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -227,14 +227,6 @@ build-previous-qemu: # testing an old QEMU against new features/tests that it is not # compatible with. - cd build-previous - # Don't allow python-based tests to run. The - # vmstate-checker-script test has a race that causes it to fail - # sometimes. It cannot be fixed it because this job runs the test - # from the old QEMU version. The test will be removed on master, - # but this job will only see the change in the next release. - # - # TODO: remove this line after 9.2 release - - unset PYTHON # old to new - QTEST_QEMU_BINARY_SRC=./qemu-system-${TARGET} QTEST_QEMU_BINARY=../build/qemu-system-${TARGET} ./tests/qtest/migration-test From d5845228b41dbf44f85744e64c3c1744f76a368d Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 13 May 2025 10:33:52 -0300 Subject: [PATCH 1057/2760] ci: Fix build-previous-qemu when the version tag is absent Stefan reports that during QEMU release, pushing a series with the VERSION bump commit, but not pushing the new git tag in the same command will cause a failure of the build-previous-qemu job at the git fetch step. Since the job is intended to produce a build of the previous QEMU version for consumption by the migration-compat-* jobs, there's no reason to produce a build of the release commit because the migration job would end up testing the release against itself. Skip the job when VERSION contains the newly release version number. I'm opting for 'exit 0' for both the build and the test jobs because allow_failure would mask any real error in the jobs. It also avoids having an orange ! on every release pipeline. Reported-by: Stefan Hajnoczi Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Link: https://lore.kernel.org/r/20250513133353.23022-3-farosas@suse.de Signed-off-by: Peter Xu --- .gitlab-ci.d/buildtest.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index fbad34138c..b4e39fd7c1 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -203,6 +203,11 @@ build-previous-qemu: GIT_FETCH_EXTRA_FLAGS: --prune --quiet before_script: - source scripts/ci/gitlab-ci-section + # Skip if this series contains the release bump commit. During the + # release process there might be a window of commits when the + # version tag is not yet present in the remote and git fetch would + # fail. + - if grep -q "\.0$" VERSION; then exit 0; fi - export QEMU_PREV_VERSION="$(sed 's/\([0-9.]*\)\.[0-9]*/v\1.0/' VERSION)" - git remote add upstream https://gitlab.com/qemu-project/qemu - git fetch upstream refs/tags/$QEMU_PREV_VERSION:refs/tags/$QEMU_PREV_VERSION @@ -223,6 +228,9 @@ build-previous-qemu: IMAGE: opensuse-leap MAKE_CHECK_ARGS: check-build script: + # Skip for round release numbers, this job is only relevant for + # testing a development tree. + - if grep -q "\.0$" VERSION; then exit 0; fi # Use the migration-tests from the older QEMU tree. This avoids # testing an old QEMU against new features/tests that it is not # compatible with. From 371650534d44c8b27249ca615d908a037f75b048 Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Tue, 13 May 2025 10:33:53 -0300 Subject: [PATCH 1058/2760] ci: Reduce the size of artifacts for build-previous-qemu The build-previous-qemu job is intented to produce a build of the previous QEMU release for consumption by the migration-compat-* jobs. Keep only the pieces of the build that are necessary. Reviewed-by: Peter Xu Signed-off-by: Fabiano Rosas Link: https://lore.kernel.org/r/20250513133353.23022-4-farosas@suse.de Signed-off-by: Peter Xu --- .gitlab-ci.d/buildtest.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml index b4e39fd7c1..ca1a9c6f70 100644 --- a/.gitlab-ci.d/buildtest.yml +++ b/.gitlab-ci.d/buildtest.yml @@ -188,12 +188,11 @@ build-previous-qemu: when: on_success expire_in: 2 days paths: - - build-previous - exclude: - - build-previous/**/*.p - - build-previous/**/*.a.p - - build-previous/**/*.c.o - - build-previous/**/*.c.o.d + - build-previous/qemu-bundle + - build-previous/qemu-system-aarch64 + - build-previous/qemu-system-x86_64 + - build-previous/tests/qtest/migration-test + - build-previous/scripts needs: job: amd64-opensuse-leap-container variables: From 249543d0c02d7645b8bcda552dad138769e96831 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Mon, 12 May 2025 18:21:22 +0530 Subject: [PATCH 1059/2760] migration: write zero pages when postcopy enabled During multifd migration, zero pages are written if they are migrated more than once. This may result in a migration thread hang issue when multifd and postcopy are enabled together. When postcopy is enabled, always write zero pages as and when they are migrated. Signed-off-by: Prasad Pandit Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/20250512125124.147064-2-ppandit@redhat.com Signed-off-by: Peter Xu --- migration/multifd-zero-page.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/migration/multifd-zero-page.c b/migration/multifd-zero-page.c index dbc1184921..4cde868159 100644 --- a/migration/multifd-zero-page.c +++ b/migration/multifd-zero-page.c @@ -85,9 +85,27 @@ void multifd_recv_zero_page_process(MultiFDRecvParams *p) { for (int i = 0; i < p->zero_num; i++) { void *page = p->host + p->zero[i]; - if (ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i])) { + bool received = + ramblock_recv_bitmap_test_byte_offset(p->block, p->zero[i]); + + /* + * During multifd migration zero page is written to the memory + * only if it is migrated more than once. + * + * It becomes a problem when both multifd & postcopy options are + * enabled. If the zero page which was skipped during multifd phase, + * is accessed during the postcopy phase of the migration, a page + * fault occurs. But this page fault is not served because the + * 'receivedmap' says the zero page is already received. Thus the + * thread accessing that page may hang. + * + * When postcopy is enabled, always write the zero page as and when + * it is migrated. + */ + if (migrate_postcopy_ram() || received) { memset(page, 0, multifd_ram_page_size()); - } else { + } + if (!received) { ramblock_recv_bitmap_set_offset(p->block, p->zero[i]); } } From e27418861288285d20352448fef4491a68223d39 Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Mon, 12 May 2025 18:21:23 +0530 Subject: [PATCH 1060/2760] migration: enable multifd and postcopy together Enable Multifd and Postcopy migration together. The migration_ioc_process_incoming() routine checks magic value sent on each channel and helps to properly setup multifd and postcopy channels. The Precopy and Multifd threads work during the initial guest RAM transfer. When migration moves to the Postcopy phase, the multifd threads cease to send data on multifd channels and Postcopy threads on the destination request/pull data from the source side. Reviewed-by: Fabiano Rosas Signed-off-by: Prasad Pandit Link: https://lore.kernel.org/r/20250512125124.147064-3-ppandit@redhat.com Signed-off-by: Peter Xu --- migration/multifd-nocomp.c | 3 ++- migration/multifd.c | 7 +++++++ migration/options.c | 5 ----- migration/ram.c | 5 ++--- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/migration/multifd-nocomp.c b/migration/multifd-nocomp.c index 88fe0f99f2..b48eae3d86 100644 --- a/migration/multifd-nocomp.c +++ b/migration/multifd-nocomp.c @@ -17,6 +17,7 @@ #include "migration-stats.h" #include "multifd.h" #include "options.h" +#include "migration.h" #include "qapi/error.h" #include "qemu/cutils.h" #include "qemu/error-report.h" @@ -398,7 +399,7 @@ int multifd_ram_flush_and_sync(QEMUFile *f) MultiFDSyncReq req; int ret; - if (!migrate_multifd()) { + if (!migrate_multifd() || migration_in_postcopy()) { return 0; } diff --git a/migration/multifd.c b/migration/multifd.c index ec108af624..f18b166bcf 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -1379,6 +1379,13 @@ static void *multifd_recv_thread(void *opaque) } if (has_data) { + /* + * multifd thread should not be active and receive data + * when migration is in the Postcopy phase. Two threads + * writing the same memory area could easily corrupt + * the guest state. + */ + assert(!migration_in_postcopy()); if (is_device_state) { assert(use_packets); ret = multifd_device_state_recv(p, &local_err); diff --git a/migration/options.c b/migration/options.c index b6ae95358d..3fcd577cd7 100644 --- a/migration/options.c +++ b/migration/options.c @@ -509,11 +509,6 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) error_setg(errp, "Postcopy is not compatible with ignore-shared"); return false; } - - if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) { - error_setg(errp, "Postcopy is not yet compatible with multifd"); - return false; - } } if (new_caps[MIGRATION_CAPABILITY_BACKGROUND_SNAPSHOT]) { diff --git a/migration/ram.c b/migration/ram.c index e12913b43e..d26dbd37c4 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -1993,9 +1993,8 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss) } } - if (migrate_multifd()) { - RAMBlock *block = pss->block; - return ram_save_multifd_page(block, offset); + if (migrate_multifd() && !migration_in_postcopy()) { + return ram_save_multifd_page(pss->block, offset); } return ram_save_page(rs, pss); From 766bbabac8f00bc5cf23ba90a8326678636280ed Mon Sep 17 00:00:00 2001 From: Prasad Pandit Date: Mon, 12 May 2025 18:21:24 +0530 Subject: [PATCH 1061/2760] tests/qtest/migration: add postcopy tests with multifd Add new qtests to run postcopy migration with multifd channels enabled. Signed-off-by: Prasad Pandit Link: https://lore.kernel.org/r/20250512125124.147064-4-ppandit@redhat.com [peterx: rename all new tests to be under /migration/multifd+postcopy/] Signed-off-by: Peter Xu --- tests/qtest/migration/compression-tests.c | 18 ++++++++ tests/qtest/migration/postcopy-tests.c | 27 ++++++++++++ tests/qtest/migration/precopy-tests.c | 28 ++++++++++++- tests/qtest/migration/tls-tests.c | 51 +++++++++++++++++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c index 41e79f031b..b827665b8e 100644 --- a/tests/qtest/migration/compression-tests.c +++ b/tests/qtest/migration/compression-tests.c @@ -42,6 +42,20 @@ static void test_multifd_tcp_zstd(void) }; test_precopy_common(&args); } + +static void test_multifd_postcopy_tcp_zstd(void) +{ + MigrateCommon args = { + .listen_uri = "defer", + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true, + }, + .start_hook = migrate_hook_start_precopy_tcp_multifd_zstd, + }; + + test_precopy_common(&args); +} #endif /* CONFIG_ZSTD */ #ifdef CONFIG_QATZIP @@ -184,6 +198,10 @@ void migration_test_add_compression(MigrationTestEnv *env) #ifdef CONFIG_ZSTD migration_test_add("/migration/multifd/tcp/plain/zstd", test_multifd_tcp_zstd); + if (env->has_uffd) { + migration_test_add("/migration/multifd+postcopy/tcp/plain/zstd", + test_multifd_postcopy_tcp_zstd); + } #endif #ifdef CONFIG_QATZIP diff --git a/tests/qtest/migration/postcopy-tests.c b/tests/qtest/migration/postcopy-tests.c index 483e3ff99f..3773525843 100644 --- a/tests/qtest/migration/postcopy-tests.c +++ b/tests/qtest/migration/postcopy-tests.c @@ -94,6 +94,29 @@ static void migration_test_add_postcopy_smoke(MigrationTestEnv *env) } } +static void test_multifd_postcopy(void) +{ + MigrateCommon args = { + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, + }; + + test_postcopy_common(&args); +} + +static void test_multifd_postcopy_preempt(void) +{ + MigrateCommon args = { + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, + }; + + test_postcopy_common(&args); +} + void migration_test_add_postcopy(MigrationTestEnv *env) { migration_test_add_postcopy_smoke(env); @@ -114,6 +137,10 @@ void migration_test_add_postcopy(MigrationTestEnv *env) "/migration/postcopy/recovery/double-failures/reconnect", test_postcopy_recovery_fail_reconnect); + migration_test_add("/migration/multifd+postcopy/plain", + test_multifd_postcopy); + migration_test_add("/migration/multifd+postcopy/preempt/plain", + test_multifd_postcopy_preempt); if (env->is_x86) { migration_test_add("/migration/postcopy/suspend", test_postcopy_suspend); diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index a62d3c5378..bb38292550 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -569,7 +569,7 @@ static void test_multifd_tcp_channels_none(void) * * And see that it works */ -static void test_multifd_tcp_cancel(void) +static void test_multifd_tcp_cancel(bool postcopy_ram) { MigrateStart args = { .hide_stderr = true, @@ -583,6 +583,11 @@ static void test_multifd_tcp_cancel(void) migrate_ensure_non_converge(from); migrate_prepare_for_dirty_mem(from); + if (postcopy_ram) { + migrate_set_capability(from, "postcopy-ram", true); + migrate_set_capability(to, "postcopy-ram", true); + } + migrate_set_parameter_int(from, "multifd-channels", 16); migrate_set_parameter_int(to, "multifd-channels", 16); @@ -624,6 +629,10 @@ static void test_multifd_tcp_cancel(void) return; } + if (postcopy_ram) { + migrate_set_capability(to2, "postcopy-ram", true); + } + migrate_set_parameter_int(to2, "multifd-channels", 16); migrate_set_capability(to2, "multifd", true); @@ -647,6 +656,16 @@ static void test_multifd_tcp_cancel(void) migrate_end(from, to2, true); } +static void test_multifd_precopy_tcp_cancel(void) +{ + test_multifd_tcp_cancel(false); +} + +static void test_multifd_postcopy_tcp_cancel(void) +{ + test_multifd_tcp_cancel(true); +} + static void test_cancel_src_after_failed(QTestState *from, QTestState *to, const char *uri, const char *phase) { @@ -1233,7 +1252,12 @@ static void migration_test_add_precopy_smoke(MigrationTestEnv *env) migration_test_add("/migration/multifd/tcp/uri/plain/none", test_multifd_tcp_uri_none); migration_test_add("/migration/multifd/tcp/plain/cancel", - test_multifd_tcp_cancel); + test_multifd_precopy_tcp_cancel); + if (env->has_uffd) { + migration_test_add("/migration/multifd+postcopy/tcp/plain/cancel", + test_multifd_postcopy_tcp_cancel); + } + #ifdef CONFIG_RDMA migration_test_add("/migration/precopy/rdma/plain", test_precopy_rdma_plain); diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index 72f44defbb..21e9fec87d 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -395,6 +395,19 @@ static void test_postcopy_recovery_tls_psk(void) test_postcopy_recovery_common(&args); } +static void test_multifd_postcopy_recovery_tls_psk(void) +{ + MigrateCommon args = { + .start_hook = migrate_hook_start_tls_psk_match, + .end_hook = migrate_hook_end_tls_psk, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + }, + }; + + test_postcopy_recovery_common(&args); +} + /* This contains preempt+recovery+tls test altogether */ static void test_postcopy_preempt_all(void) { @@ -409,6 +422,20 @@ static void test_postcopy_preempt_all(void) test_postcopy_recovery_common(&args); } +static void test_multifd_postcopy_preempt_recovery_tls_psk(void) +{ + MigrateCommon args = { + .start_hook = migrate_hook_start_tls_psk_match, + .end_hook = migrate_hook_end_tls_psk, + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_POSTCOPY_PREEMPT] = true, + }, + }; + + test_postcopy_recovery_common(&args); +} + static void test_precopy_unix_tls_psk(void) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); @@ -657,6 +684,21 @@ static void test_multifd_tcp_tls_psk_mismatch(void) test_precopy_common(&args); } +static void test_multifd_postcopy_tcp_tls_psk_match(void) +{ + MigrateCommon args = { + .start = { + .caps[MIGRATION_CAPABILITY_MULTIFD] = true, + .caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true, + }, + .listen_uri = "defer", + .start_hook = migrate_hook_start_multifd_tcp_tls_psk_match, + .end_hook = migrate_hook_end_tls_psk, + }; + + test_precopy_common(&args); +} + #ifdef CONFIG_TASN1 static void test_multifd_tcp_tls_x509_default_host(void) { @@ -774,6 +816,11 @@ void migration_test_add_tls(MigrationTestEnv *env) test_postcopy_preempt_tls_psk); migration_test_add("/migration/postcopy/preempt/recovery/tls/psk", test_postcopy_preempt_all); + migration_test_add("/migration/multifd+postcopy/recovery/tls/psk", + test_multifd_postcopy_recovery_tls_psk); + migration_test_add( + "/migration/multifd+postcopy/preempt/recovery/tls/psk", + test_multifd_postcopy_preempt_recovery_tls_psk); } #ifdef CONFIG_TASN1 migration_test_add("/migration/precopy/unix/tls/x509/default-host", @@ -805,6 +852,10 @@ void migration_test_add_tls(MigrationTestEnv *env) test_multifd_tcp_tls_psk_match); migration_test_add("/migration/multifd/tcp/tls/psk/mismatch", test_multifd_tcp_tls_psk_mismatch); + if (env->has_uffd) { + migration_test_add("/migration/multifd+postcopy/tcp/tls/psk/match", + test_multifd_postcopy_tcp_tls_psk_match); + } #ifdef CONFIG_TASN1 migration_test_add("/migration/multifd/tcp/tls/x509/default-host", test_multifd_tcp_tls_x509_default_host); From 6be7696129b302830a9cff7e30484e08c2d64b57 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Fri, 16 May 2025 15:53:03 +0200 Subject: [PATCH 1062/2760] migration/multifd: Don't send device state packets with zerocopy flag If zerocopy is enabled for multifd then QIO_CHANNEL_WRITE_FLAG_ZERO_COPY flag is forced into all multifd channel write calls via p->write_flags that was setup in multifd_nocomp_send_setup(). However, device state packets aren't compatible with zerocopy - the data buffer isn't getting kept pinned until multifd channel flush. Make sure to mask that QIO_CHANNEL_WRITE_FLAG_ZERO_COPY flag in a multifd send thread if the data being sent is device state. Fixes: 0525b91a0b99 ("migration/multifd: Device state transfer support - send side") Signed-off-by: Maciej S. Szmigiero Reviewed-by: Fabiano Rosas Link: https://lore.kernel.org/r/3bd5f48578e29f3a78f41b1e4fbea3d4b2d9b136.1747403393.git.maciej.szmigiero@oracle.com Signed-off-by: Peter Xu --- migration/multifd.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/migration/multifd.c b/migration/multifd.c index f18b166bcf..b255778855 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -690,6 +690,7 @@ static void *multifd_send_thread(void *opaque) if (qatomic_load_acquire(&p->pending_job)) { bool is_device_state = multifd_payload_device_state(p->data); size_t total_size; + int write_flags_masked = 0; p->flags = 0; p->iovs_num = 0; @@ -697,6 +698,9 @@ static void *multifd_send_thread(void *opaque) if (is_device_state) { multifd_device_state_send_prepare(p); + + /* Device state packets cannot be sent via zerocopy */ + write_flags_masked |= QIO_CHANNEL_WRITE_FLAG_ZERO_COPY; } else { ret = multifd_send_state->ops->send_prepare(p, &local_err); if (ret != 0) { @@ -718,7 +722,8 @@ static void *multifd_send_thread(void *opaque) &p->data->u.ram, &local_err); } else { ret = qio_channel_writev_full_all(p->c, p->iov, p->iovs_num, - NULL, 0, p->write_flags, + NULL, 0, + p->write_flags & ~write_flags_masked, &local_err); } From 17bec9235bb0775cf8dec4103c167757ee8898f3 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 13 May 2025 17:33:16 -0400 Subject: [PATCH 1063/2760] migration: Allow caps to be set when preempt or multifd cap enabled With commit 82137e6c8c ("migration: enforce multifd and postcopy preempt to be set before incoming"), and if postcopy preempt / multifd is enabled, one cannot setup any capability because these checks would always fail. (qemu) migrate_set_capability xbzrle off Error: Postcopy preempt must be set before incoming starts To fix it, check existing cap and only raise an error if the specific cap changed. Fixes: 82137e6c8c ("migration: enforce multifd and postcopy preempt to be set before incoming") Reviewed-by: Dr. David Alan Gilbert Reviewed-by: Juraj Marcin Signed-off-by: Peter Xu --- migration/options.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/options.c b/migration/options.c index 3fcd577cd7..162c72cda4 100644 --- a/migration/options.c +++ b/migration/options.c @@ -568,7 +568,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) return false; } - if (migrate_incoming_started()) { + if (!migrate_postcopy_preempt() && migrate_incoming_started()) { error_setg(errp, "Postcopy preempt must be set before incoming starts"); return false; @@ -576,7 +576,7 @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) } if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) { - if (migrate_incoming_started()) { + if (!migrate_multifd() && migrate_incoming_started()) { error_setg(errp, "Multifd must be set before incoming starts"); return false; } From e09c6d837593aa1e12d92d7031c65a881eb2eb27 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Tue, 13 May 2025 17:08:17 -0400 Subject: [PATCH 1064/2760] migration/hmp: Add "info migrate -a", reorg the dump A new parameter "-a" is added to "info migrate" to dump all info, while when not specified it only dumps the important ones. When at it, reorg everything to make it easier to read for human. The general rule is: - Put important things at the top - Reuse a single line when things are very relevant, hence reducing lines needed to show the results - Remove almost useless ones (e.g. "normal_bytes", while we also have both "page size" and "normal" pages) - Regroup things, so that related fields will show together - etc. Before this change, it looks like (one example of a completed case): globals: store-global-state: on only-migratable: off send-configuration: on send-section-footer: on send-switchover-start: on clear-bitmap-shift: 18 Migration status: completed total time: 122952 ms downtime: 76 ms setup: 15 ms transferred ram: 130825923 kbytes throughput: 8717.68 mbps remaining ram: 0 kbytes total ram: 16777992 kbytes duplicate: 997263 pages normal: 32622225 pages normal bytes: 130488900 kbytes dirty sync count: 10 page size: 4 kbytes multifd bytes: 117134260 kbytes pages-per-second: 169431 postcopy request count: 5835 precopy ram: 15 kbytes postcopy ram: 13691151 kbytes After this change, sample output (default, no "-a" specified): Status: postcopy-active Time (ms): total=40504, setup=14, down=145 RAM info: Bandwidth (mbps): 6102.65 Sizes (KB): psize=4, total=16777992, transferred=37673019, remain=2136404, precopy=3, multifd=26108780, postcopy=11563855 Pages: normal=9394288, zero=600672, rate_per_sec=185875 Others: dirty_syncs=3, dirty_pages_rate=278378, postcopy_req=4078 Sample output when "-a" specified: Status: active Time (ms): total=3040, setup=4, exp_down=300 RAM info: Throughput (mbps): 10.51 Sizes (KB): psize=4, total=4211528, transferred=3979, remain=4206452, precopy=3978, multifd=0, postcopy=0 Pages: normal=992, zero=277, rate_per_sec=320 Others: dirty_syncs=1 Globals: store-global-state: on only-migratable: off send-configuration: on send-section-footer: on send-switchover-start: on clear-bitmap-shift: 18 XBZRLE: size=67108864, transferred=0, pages=0, miss=188451 miss_rate=0.00, encode_rate=0.00, overflow=0 CPU Throttle (%): 0 Dirty-limit Throttle (us): 0 Dirty-limit Ring Full (us): 0 Postcopy Blocktime (ms): 0 Postcopy vCPU Blocktime: ... Reviewed-by: Dr. David Alan Gilbert Tested-by: Mario Casquero [peterx: print "," too in 1st line of RAM info] Signed-off-by: Peter Xu --- hmp-commands-info.hx | 6 +- migration/migration-hmp-cmds.c | 186 +++++++++++++++++---------------- 2 files changed, 99 insertions(+), 93 deletions(-) diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx index c59cd6637b..639a450ee5 100644 --- a/hmp-commands-info.hx +++ b/hmp-commands-info.hx @@ -475,9 +475,9 @@ ERST { .name = "migrate", - .args_type = "", - .params = "", - .help = "show migration status", + .args_type = "all:-a", + .params = "[-a]", + .help = "show migration status (-a: all, dump all status)", .cmd = hmp_info_migrate, }, diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index 49c26daed3..e8a563c7d8 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -37,29 +37,28 @@ static void migration_global_dump(Monitor *mon) { MigrationState *ms = migrate_get_current(); - monitor_printf(mon, "globals:\n"); - monitor_printf(mon, "store-global-state: %s\n", + monitor_printf(mon, "Globals:\n"); + monitor_printf(mon, " store-global-state: %s\n", ms->store_global_state ? "on" : "off"); - monitor_printf(mon, "only-migratable: %s\n", + monitor_printf(mon, " only-migratable: %s\n", only_migratable ? "on" : "off"); - monitor_printf(mon, "send-configuration: %s\n", + monitor_printf(mon, " send-configuration: %s\n", ms->send_configuration ? "on" : "off"); - monitor_printf(mon, "send-section-footer: %s\n", + monitor_printf(mon, " send-section-footer: %s\n", ms->send_section_footer ? "on" : "off"); - monitor_printf(mon, "send-switchover-start: %s\n", + monitor_printf(mon, " send-switchover-start: %s\n", ms->send_switchover_start ? "on" : "off"); - monitor_printf(mon, "clear-bitmap-shift: %u\n", + monitor_printf(mon, " clear-bitmap-shift: %u\n", ms->clear_bitmap_shift); } void hmp_info_migrate(Monitor *mon, const QDict *qdict) { + bool show_all = qdict_get_try_bool(qdict, "all", false); MigrationInfo *info; info = qmp_query_migrate(NULL); - migration_global_dump(mon); - if (info->blocked_reasons) { strList *reasons = info->blocked_reasons; monitor_printf(mon, "Outgoing migration blocked:\n"); @@ -70,7 +69,7 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) } if (info->has_status) { - monitor_printf(mon, "Migration status: %s", + monitor_printf(mon, "Status: %s", MigrationStatus_str(info->status)); if (info->status == MIGRATION_STATUS_FAILED && info->error_desc) { monitor_printf(mon, " (%s)\n", info->error_desc); @@ -78,107 +77,130 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) monitor_printf(mon, "\n"); } - monitor_printf(mon, "total time: %" PRIu64 " ms\n", - info->total_time); - if (info->has_expected_downtime) { - monitor_printf(mon, "expected downtime: %" PRIu64 " ms\n", - info->expected_downtime); + if (info->total_time) { + monitor_printf(mon, "Time (ms): total=%" PRIu64, + info->total_time); + if (info->has_setup_time) { + monitor_printf(mon, ", setup=%" PRIu64, + info->setup_time); + } + if (info->has_expected_downtime) { + monitor_printf(mon, ", exp_down=%" PRIu64, + info->expected_downtime); + } + if (info->has_downtime) { + monitor_printf(mon, ", down=%" PRIu64, + info->downtime); + } + monitor_printf(mon, "\n"); } - if (info->has_downtime) { - monitor_printf(mon, "downtime: %" PRIu64 " ms\n", - info->downtime); - } - if (info->has_setup_time) { - monitor_printf(mon, "setup: %" PRIu64 " ms\n", - info->setup_time); + } + + if (info->has_socket_address) { + SocketAddressList *addr; + + monitor_printf(mon, "Sockets: [\n"); + + for (addr = info->socket_address; addr; addr = addr->next) { + char *s = socket_uri(addr->value); + monitor_printf(mon, "\t%s\n", s); + g_free(s); } + monitor_printf(mon, "]\n"); } if (info->ram) { - monitor_printf(mon, "transferred ram: %" PRIu64 " kbytes\n", - info->ram->transferred >> 10); - monitor_printf(mon, "throughput: %0.2f mbps\n", + monitor_printf(mon, "RAM info:\n"); + monitor_printf(mon, " Throughput (Mbps): %0.2f\n", info->ram->mbps); - monitor_printf(mon, "remaining ram: %" PRIu64 " kbytes\n", - info->ram->remaining >> 10); - monitor_printf(mon, "total ram: %" PRIu64 " kbytes\n", + monitor_printf(mon, " Sizes (KiB): pagesize=%" PRIu64 + ", total=%" PRIu64 ",\n", + info->ram->page_size >> 10, info->ram->total >> 10); - monitor_printf(mon, "duplicate: %" PRIu64 " pages\n", - info->ram->duplicate); - monitor_printf(mon, "normal: %" PRIu64 " pages\n", - info->ram->normal); - monitor_printf(mon, "normal bytes: %" PRIu64 " kbytes\n", - info->ram->normal_bytes >> 10); - monitor_printf(mon, "dirty sync count: %" PRIu64 "\n", - info->ram->dirty_sync_count); - monitor_printf(mon, "page size: %" PRIu64 " kbytes\n", - info->ram->page_size >> 10); - monitor_printf(mon, "multifd bytes: %" PRIu64 " kbytes\n", - info->ram->multifd_bytes >> 10); - monitor_printf(mon, "pages-per-second: %" PRIu64 "\n", + monitor_printf(mon, " transferred=%" PRIu64 + ", remain=%" PRIu64 ",\n", + info->ram->transferred >> 10, + info->ram->remaining >> 10); + monitor_printf(mon, " precopy=%" PRIu64 + ", multifd=%" PRIu64 + ", postcopy=%" PRIu64, + info->ram->precopy_bytes >> 10, + info->ram->multifd_bytes >> 10, + info->ram->postcopy_bytes >> 10); + + if (info->vfio) { + monitor_printf(mon, ", vfio=%" PRIu64, + info->vfio->transferred >> 10); + } + monitor_printf(mon, "\n"); + + monitor_printf(mon, " Pages: normal=%" PRIu64 ", zero=%" PRIu64 + ", rate_per_sec=%" PRIu64 "\n", + info->ram->normal, + info->ram->duplicate, info->ram->pages_per_second); + monitor_printf(mon, " Others: dirty_syncs=%" PRIu64, + info->ram->dirty_sync_count); if (info->ram->dirty_pages_rate) { - monitor_printf(mon, "dirty pages rate: %" PRIu64 " pages\n", + monitor_printf(mon, ", dirty_pages_rate=%" PRIu64, info->ram->dirty_pages_rate); } if (info->ram->postcopy_requests) { - monitor_printf(mon, "postcopy request count: %" PRIu64 "\n", + monitor_printf(mon, ", postcopy_req=%" PRIu64, info->ram->postcopy_requests); } - if (info->ram->precopy_bytes) { - monitor_printf(mon, "precopy ram: %" PRIu64 " kbytes\n", - info->ram->precopy_bytes >> 10); - } if (info->ram->downtime_bytes) { - monitor_printf(mon, "downtime ram: %" PRIu64 " kbytes\n", - info->ram->downtime_bytes >> 10); - } - if (info->ram->postcopy_bytes) { - monitor_printf(mon, "postcopy ram: %" PRIu64 " kbytes\n", - info->ram->postcopy_bytes >> 10); + monitor_printf(mon, ", downtime_ram=%" PRIu64, + info->ram->downtime_bytes); } if (info->ram->dirty_sync_missed_zero_copy) { - monitor_printf(mon, - "Zero-copy-send fallbacks happened: %" PRIu64 " times\n", + monitor_printf(mon, ", zerocopy_fallbacks=%" PRIu64, info->ram->dirty_sync_missed_zero_copy); } + monitor_printf(mon, "\n"); } + if (!show_all) { + goto out; + } + + migration_global_dump(mon); + if (info->xbzrle_cache) { - monitor_printf(mon, "cache size: %" PRIu64 " bytes\n", - info->xbzrle_cache->cache_size); - monitor_printf(mon, "xbzrle transferred: %" PRIu64 " kbytes\n", - info->xbzrle_cache->bytes >> 10); - monitor_printf(mon, "xbzrle pages: %" PRIu64 " pages\n", - info->xbzrle_cache->pages); - monitor_printf(mon, "xbzrle cache miss: %" PRIu64 " pages\n", - info->xbzrle_cache->cache_miss); - monitor_printf(mon, "xbzrle cache miss rate: %0.2f\n", - info->xbzrle_cache->cache_miss_rate); - monitor_printf(mon, "xbzrle encoding rate: %0.2f\n", - info->xbzrle_cache->encoding_rate); - monitor_printf(mon, "xbzrle overflow: %" PRIu64 "\n", + monitor_printf(mon, "XBZRLE: size=%" PRIu64 + ", transferred=%" PRIu64 + ", pages=%" PRIu64 + ", miss=%" PRIu64 "\n" + " miss_rate=%0.2f" + ", encode_rate=%0.2f" + ", overflow=%" PRIu64 "\n", + info->xbzrle_cache->cache_size, + info->xbzrle_cache->bytes, + info->xbzrle_cache->pages, + info->xbzrle_cache->cache_miss, + info->xbzrle_cache->cache_miss_rate, + info->xbzrle_cache->encoding_rate, info->xbzrle_cache->overflow); } if (info->has_cpu_throttle_percentage) { - monitor_printf(mon, "cpu throttle percentage: %" PRIu64 "\n", + monitor_printf(mon, "CPU Throttle (%%): %" PRIu64 "\n", info->cpu_throttle_percentage); } if (info->has_dirty_limit_throttle_time_per_round) { - monitor_printf(mon, "dirty-limit throttle time: %" PRIu64 " us\n", + monitor_printf(mon, "Dirty-limit Throttle (us): %" PRIu64 "\n", info->dirty_limit_throttle_time_per_round); } if (info->has_dirty_limit_ring_full_time) { - monitor_printf(mon, "dirty-limit ring full time: %" PRIu64 " us\n", + monitor_printf(mon, "Dirty-limit Ring Full (us): %" PRIu64 "\n", info->dirty_limit_ring_full_time); } if (info->has_postcopy_blocktime) { - monitor_printf(mon, "postcopy blocktime: %u\n", + monitor_printf(mon, "Postcopy Blocktime (ms): %" PRIu32 "\n", info->postcopy_blocktime); } @@ -189,28 +211,12 @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) visit_type_uint32List(v, NULL, &info->postcopy_vcpu_blocktime, &error_abort); visit_complete(v, &str); - monitor_printf(mon, "postcopy vcpu blocktime: %s\n", str); + monitor_printf(mon, "Postcopy vCPU Blocktime: %s\n", str); g_free(str); visit_free(v); } - if (info->has_socket_address) { - SocketAddressList *addr; - - monitor_printf(mon, "socket address: [\n"); - - for (addr = info->socket_address; addr; addr = addr->next) { - char *s = socket_uri(addr->value); - monitor_printf(mon, "\t%s\n", s); - g_free(s); - } - monitor_printf(mon, "]\n"); - } - - if (info->vfio) { - monitor_printf(mon, "vfio device transferred: %" PRIu64 " kbytes\n", - info->vfio->transferred >> 10); - } +out: qapi_free_MigrationInfo(info); } From e460991883d7209d52d0fdb534d9cd8cce0f9cce Mon Sep 17 00:00:00 2001 From: Alberto Faria Date: Fri, 2 May 2025 13:11:14 +0100 Subject: [PATCH 1065/2760] scsi-disk: Add native FUA write support Simply propagate the FUA flag on write requests to the driver. The block layer will emulate it if necessary. Signed-off-by: Alberto Faria Message-ID: <20250502121115.3613717-2-afaria@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- hw/scsi/scsi-disk.c | 53 +++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index cb4af1b715..738d8df8ec 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -74,7 +74,7 @@ struct SCSIDiskClass { */ DMAIOFunc *dma_readv; DMAIOFunc *dma_writev; - bool (*need_fua_emulation)(SCSICommand *cmd); + bool (*need_fua)(SCSICommand *cmd); void (*update_sense)(SCSIRequest *r); }; @@ -85,7 +85,7 @@ typedef struct SCSIDiskReq { uint32_t sector_count; uint32_t buflen; bool started; - bool need_fua_emulation; + bool need_fua; struct iovec iov; QEMUIOVector qiov; BlockAcctCookie acct; @@ -389,24 +389,6 @@ static bool scsi_is_cmd_fua(SCSICommand *cmd) } } -static void scsi_write_do_fua(SCSIDiskReq *r) -{ - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - - assert(r->req.aiocb == NULL); - assert(!r->req.io_canceled); - - if (r->need_fua_emulation) { - block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, - BLOCK_ACCT_FLUSH); - r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_aio_complete, r); - return; - } - - scsi_req_complete(&r->req, GOOD); - scsi_req_unref(&r->req); -} - static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret) { assert(r->req.aiocb == NULL); @@ -416,12 +398,7 @@ static void scsi_dma_complete_noio(SCSIDiskReq *r, int ret) r->sector += r->sector_count; r->sector_count = 0; - if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { - scsi_write_do_fua(r); - return; - } else { - scsi_req_complete(&r->req, GOOD); - } + scsi_req_complete(&r->req, GOOD); done: scsi_req_unref(&r->req); @@ -564,7 +541,7 @@ static void scsi_read_data(SCSIRequest *req) first = !r->started; r->started = true; - if (first && r->need_fua_emulation) { + if (first && r->need_fua) { block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, BLOCK_ACCT_FLUSH); r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, scsi_do_read_cb, r); @@ -589,8 +566,7 @@ static void scsi_write_complete_noio(SCSIDiskReq *r, int ret) r->sector += n; r->sector_count -= n; if (r->sector_count == 0) { - scsi_write_do_fua(r); - return; + scsi_req_complete(&r->req, GOOD); } else { scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); trace_scsi_disk_write_complete_noio(r->req.tag, r->qiov.size); @@ -623,6 +599,7 @@ static void scsi_write_data(SCSIRequest *req) SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); SCSIDiskClass *sdc = (SCSIDiskClass *) object_get_class(OBJECT(s)); + BlockCompletionFunc *cb; /* No data transfer may already be in progress */ assert(r->req.aiocb == NULL); @@ -648,11 +625,10 @@ static void scsi_write_data(SCSIRequest *req) if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 || r->req.cmd.buf[0] == VERIFY_16) { - if (r->req.sg) { - scsi_dma_complete_noio(r, 0); - } else { - scsi_write_complete_noio(r, 0); - } + block_acct_start(blk_get_stats(s->qdev.conf.blk), &r->acct, 0, + BLOCK_ACCT_FLUSH); + cb = r->req.sg ? scsi_dma_complete : scsi_write_complete; + r->req.aiocb = blk_aio_flush(s->qdev.conf.blk, cb, r); return; } @@ -2391,7 +2367,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); return 0; } - r->need_fua_emulation = sdc->need_fua_emulation(&r->req.cmd); + r->need_fua = sdc->need_fua(&r->req.cmd); if (r->sector_count == 0) { scsi_req_complete(&r->req, GOOD); } @@ -3137,7 +3113,8 @@ BlockAIOCB *scsi_dma_writev(int64_t offset, QEMUIOVector *iov, { SCSIDiskReq *r = opaque; SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, 0, cb, cb_opaque); + int flags = r->need_fua ? BDRV_REQ_FUA : 0; + return blk_aio_pwritev(s->qdev.conf.blk, offset, iov, flags, cb, cb_opaque); } static char *scsi_property_get_loadparm(Object *obj, Error **errp) @@ -3186,7 +3163,7 @@ static void scsi_disk_base_class_initfn(ObjectClass *klass, const void *data) device_class_set_legacy_reset(dc, scsi_disk_reset); sdc->dma_readv = scsi_dma_readv; sdc->dma_writev = scsi_dma_writev; - sdc->need_fua_emulation = scsi_is_cmd_fua; + sdc->need_fua = scsi_is_cmd_fua; } static const TypeInfo scsi_disk_base_info = { @@ -3338,7 +3315,7 @@ static void scsi_block_class_initfn(ObjectClass *klass, const void *data) sdc->dma_readv = scsi_block_dma_readv; sdc->dma_writev = scsi_block_dma_writev; sdc->update_sense = scsi_block_update_sense; - sdc->need_fua_emulation = scsi_block_no_fua; + sdc->need_fua = scsi_block_no_fua; dc->desc = "SCSI block device passthrough"; device_class_set_props(dc, scsi_block_properties); dc->vmsd = &vmstate_scsi_disk_state; From 5562e214e82ae4bcb0b642cc52b304bdc78a58c3 Mon Sep 17 00:00:00 2001 From: Alberto Faria Date: Fri, 2 May 2025 13:11:15 +0100 Subject: [PATCH 1066/2760] scsi-disk: Advertise FUA support by default Allow the guest to submit FUA requests directly, instead of forcing it to emulate them using a regular flush. Signed-off-by: Alberto Faria Message-ID: <20250502121115.3613717-3-afaria@redhat.com> Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- hw/core/machine.c | 4 +++- hw/scsi/scsi-disk.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index b8ae155dfa..c3f3a5020d 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -37,7 +37,9 @@ #include "hw/virtio/virtio-iommu.h" #include "audio/audio.h" -GlobalProperty hw_compat_10_0[] = {}; +GlobalProperty hw_compat_10_0[] = { + { "scsi-hd", "dpofua", "off" }, +}; const size_t hw_compat_10_0_len = G_N_ELEMENTS(hw_compat_10_0); GlobalProperty hw_compat_9_2[] = { diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 738d8df8ec..b4782c6248 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -3192,7 +3192,7 @@ static const Property scsi_hd_properties[] = { DEFINE_PROP_BIT("removable", SCSIDiskState, features, SCSI_DISK_F_REMOVABLE, false), DEFINE_PROP_BIT("dpofua", SCSIDiskState, features, - SCSI_DISK_F_DPOFUA, false), + SCSI_DISK_F_DPOFUA, true), DEFINE_PROP_UINT64("wwn", SCSIDiskState, qdev.wwn, 0), DEFINE_PROP_UINT64("port_wwn", SCSIDiskState, qdev.port_wwn, 0), DEFINE_PROP_UINT16("port_index", SCSIDiskState, port_index, 0), From 7ed96710e82c385c6cfc3d064eec7dde20f0f3fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 27 Jan 2025 18:45:47 +0000 Subject: [PATCH 1067/2760] ui/vnc.c: replace big endian flag with byte order value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will make it easier to do certain comparisons in future if we store G_BIG_ENDIAN/G_LITTLE_ENDIAN directly, instead of a boolean flag, as we can then compare directly to the G_BYTE_ORDER constant. Reviewed-by: BALATON Zoltan Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé --- ui/vnc-enc-tight.c | 2 +- ui/vnc-enc-zrle.c | 2 +- ui/vnc-jobs.c | 2 +- ui/vnc.c | 6 +++--- ui/vnc.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index 41f559eb83..f8aaa8f346 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -150,7 +150,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h) * If client is big-endian, color samples begin from the second * byte (offset 1) of a 32-bit pixel value. */ - off = vs->client_be; + off = vs->client_endian == G_BIG_ENDIAN ? 1 : 0; memset(stats, 0, sizeof (stats)); diff --git a/ui/vnc-enc-zrle.c b/ui/vnc-enc-zrle.c index bd33b89063..97ec6c7119 100644 --- a/ui/vnc-enc-zrle.c +++ b/ui/vnc-enc-zrle.c @@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value) static int zrle_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) { - bool be = vs->client_be; + bool be = vs->client_endian == G_BIG_ENDIAN; size_t bytes; int zywrle_level; diff --git a/ui/vnc-jobs.c b/ui/vnc-jobs.c index fcca7ec632..d3486af9e2 100644 --- a/ui/vnc-jobs.c +++ b/ui/vnc-jobs.c @@ -188,7 +188,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local) local->lossy_rect = orig->lossy_rect; local->write_pixels = orig->write_pixels; local->client_pf = orig->client_pf; - local->client_be = orig->client_be; + local->client_endian = orig->client_endian; local->tight = orig->tight; local->zlib = orig->zlib; local->hextile = orig->hextile; diff --git a/ui/vnc.c b/ui/vnc.c index 9e097dc4b4..ab18172c4d 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -891,7 +891,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) buf[0] = v; break; case 2: - if (vs->client_be) { + if (vs->client_endian == G_BIG_ENDIAN) { buf[0] = v >> 8; buf[1] = v; } else { @@ -901,7 +901,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) break; default: case 4: - if (vs->client_be) { + if (vs->client_endian == G_BIG_ENDIAN) { buf[0] = v >> 24; buf[1] = v >> 16; buf[2] = v >> 8; @@ -2312,7 +2312,7 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel, vs->client_pf.bits_per_pixel = bits_per_pixel; vs->client_pf.bytes_per_pixel = bits_per_pixel / 8; vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel; - vs->client_be = big_endian_flag; + vs->client_endian = big_endian_flag ? G_BIG_ENDIAN : G_LITTLE_ENDIAN; if (!true_color_flag) { send_color_map(vs); diff --git a/ui/vnc.h b/ui/vnc.h index acc53a2cc1..02613aa63a 100644 --- a/ui/vnc.h +++ b/ui/vnc.h @@ -323,7 +323,7 @@ struct VncState VncWritePixels *write_pixels; PixelFormat client_pf; pixman_format_code_t client_format; - bool client_be; + int client_endian; /* G_LITTLE_ENDIAN or G_BIG_ENDIAN */ CaptureVoiceOut *audio_cap; struct audsettings as; From 70097442853c389a765c9f6502d861d182b092ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 27 Jan 2025 18:48:50 +0000 Subject: [PATCH 1068/2760] ui/vnc: take account of client byte order in pixman format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The set_pixel_conversion() method is responsible for determining whether the VNC client pixel format matches the server format, and thus whether we can use the fast path "copy" impl for sending pixels, or must use the generic impl with bit swizzling. The VNC server format is set at build time to VNC_SERVER_FB_FORMAT, which corresponds to PIXMAN_x8r8g8b8. The qemu_pixman_get_format() method is then responsible for converting the VNC pixel format into a pixman format. The VNC client pixel shifts are relative to the associated endianness. The pixman formats are always relative to the host native endianness. The qemu_pixman_get_format() method does not take into account the VNC client endianness, and is thus returning a pixman format that is only valid with the host endianness matches that of the VNC client. This has been broken since pixman was introduced to the VNC server: commit 9f64916da20eea67121d544698676295bbb105a7 Author: Gerd Hoffmann Date: Wed Oct 10 13:29:43 2012 +0200 pixman/vnc: use pixman images in vnc. The flaw can be demonstrated using the Tigervnc client by using vncviewer -AutoSelect=0 -PreferredEncoding=raw server:display connecting from a LE client to a QEMU on a BE server, or the reverse. The bug was masked, however, because almost all VNC clients will advertize support for the "tight" encoding and the QEMU VNC server will prefer "tight" if advertized. The tight_pack24 method is responsible for taking a set of pixels which have already been converted into client endianness and then repacking them into the TPIXEL format which the RFB spec defines as "TPIXEL is only 3 bytes long, where the first byte is the red component, the second byte is the green component, and the third byte is the blue component of the pixel color value" IOW, the TPIXEL format is fixed on the wire, regardless of what the VNC client declare as its endianness. Since the VNC pixel encoding code was failing to honour the endian flag of the client, the tight_pack24 method was always operating on data in native endianness. Its impl cancelled out the VNC pixel encoding bug. With the VNC pixel encoding code now fixed, the tight_pack24 method needs to take into account that it is operating on data in client endianness, not native endianness. It thus may need to invert the pixel shifts. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé --- include/ui/qemu-pixman.h | 4 ++-- ui/qemu-pixman.c | 15 ++++++++------- ui/vnc-enc-tight.c | 2 +- ui/vnc.c | 3 ++- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/include/ui/qemu-pixman.h b/include/ui/qemu-pixman.h index 193bc046d1..2ca0ed7029 100644 --- a/include/ui/qemu-pixman.h +++ b/include/ui/qemu-pixman.h @@ -75,12 +75,12 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format); pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian); pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format); uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman); -int qemu_pixman_get_type(int rshift, int gshift, int bshift); +int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian); bool qemu_pixman_check_format(DisplayChangeListener *dcl, pixman_format_code_t format); #ifdef CONFIG_PIXMAN -pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf); +pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian); pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format, int width); void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb, diff --git a/ui/qemu-pixman.c b/ui/qemu-pixman.c index 6ef4376f4e..ef4e71da11 100644 --- a/ui/qemu-pixman.c +++ b/ui/qemu-pixman.c @@ -126,33 +126,34 @@ uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format) return 0; } -int qemu_pixman_get_type(int rshift, int gshift, int bshift) +int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian) { int type = PIXMAN_TYPE_OTHER; + bool native_endian = (endian == G_BYTE_ORDER); if (rshift > gshift && gshift > bshift) { if (bshift == 0) { - type = PIXMAN_TYPE_ARGB; + type = native_endian ? PIXMAN_TYPE_ARGB : PIXMAN_TYPE_BGRA; } else { - type = PIXMAN_TYPE_RGBA; + type = native_endian ? PIXMAN_TYPE_RGBA : PIXMAN_TYPE_ABGR; } } else if (rshift < gshift && gshift < bshift) { if (rshift == 0) { - type = PIXMAN_TYPE_ABGR; + type = native_endian ? PIXMAN_TYPE_ABGR : PIXMAN_TYPE_RGBA; } else { - type = PIXMAN_TYPE_BGRA; + type = native_endian ? PIXMAN_TYPE_BGRA : PIXMAN_TYPE_ARGB; } } return type; } #ifdef CONFIG_PIXMAN -pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf) +pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian) { pixman_format_code_t format; int type; - type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift); + type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift, endian); format = PIXMAN_FORMAT(pf->bits_per_pixel, type, pf->abits, pf->rbits, pf->gbits, pf->bbits); if (!pixman_format_supported_source(format)) { diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index f8aaa8f346..a5bdc19ebb 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -891,7 +891,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret) buf8 = buf; - if (1 /* FIXME */) { + if (vs->client_endian == G_BYTE_ORDER) { rshift = vs->client_pf.rshift; gshift = vs->client_pf.gshift; bshift = vs->client_pf.bshift; diff --git a/ui/vnc.c b/ui/vnc.c index ab18172c4d..d095cd7da3 100644 --- a/ui/vnc.c +++ b/ui/vnc.c @@ -2240,7 +2240,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) static void set_pixel_conversion(VncState *vs) { - pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf); + pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf, + vs->client_endian); if (fmt == VNC_SERVER_FB_FORMAT) { vs->write_pixels = vnc_write_pixels_copy; From 63d320909220a90647c484263ae5e2f26eb54587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 28 Jan 2025 13:27:25 +0000 Subject: [PATCH 1069/2760] ui/vnc: fix tight palette pixel encoding for 8/16-bpp formats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When sending a tight rectangle with the palette filter, if the client format was 8/16bpp, the colours on big endian hosts are not set as we're sending the wrong bytes. We must first cast the 32-bit colour to a 16/8-bit value, and then send the result. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Daniel P. Berrangé --- ui/vnc-enc-tight.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c index a5bdc19ebb..25c7b2c788 100644 --- a/ui/vnc-enc-tight.c +++ b/ui/vnc-enc-tight.c @@ -1001,16 +1001,24 @@ static int send_mono_rect(VncState *vs, int x, int y, break; } case 2: - vnc_write(vs, &bg, 2); - vnc_write(vs, &fg, 2); + { + uint16_t bg16 = bg; + uint16_t fg16 = fg; + vnc_write(vs, &bg16, 2); + vnc_write(vs, &fg16, 2); tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg); break; + } default: - vnc_write_u8(vs, bg); - vnc_write_u8(vs, fg); + { + uint8_t bg8 = bg; + uint8_t fg8 = fg; + vnc_write_u8(vs, bg8); + vnc_write_u8(vs, fg8); tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg); break; } + } vs->tight->tight.offset = bytes; bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY); From 212c217f7d540fdbf1df4b65653ad5592073bb8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 7 May 2025 15:37:28 +0100 Subject: [PATCH 1070/2760] tests: skip encrypted secret tests if AES is not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids test breakage when we drop support for using the built-in AES impl as a fallback for missing crypto libraries. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-secret.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/tests/unit/test-crypto-secret.c b/tests/unit/test-crypto-secret.c index ffd13ff70e..fc32a01747 100644 --- a/tests/unit/test-crypto-secret.c +++ b/tests/unit/test-crypto-secret.c @@ -22,6 +22,7 @@ #include "crypto/init.h" #include "crypto/secret.h" +#include "crypto/cipher.h" #include "qapi/error.h" #include "qemu/module.h" #if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING) @@ -597,18 +598,21 @@ int main(int argc, char **argv) g_test_add_func("/crypto/secret/conv/utf8/base64", test_secret_conv_utf8_base64); - g_test_add_func("/crypto/secret/crypt/raw", - test_secret_crypt_raw); - g_test_add_func("/crypto/secret/crypt/base64", - test_secret_crypt_base64); - g_test_add_func("/crypto/secret/crypt/shortkey", - test_secret_crypt_short_key); - g_test_add_func("/crypto/secret/crypt/shortiv", - test_secret_crypt_short_iv); - g_test_add_func("/crypto/secret/crypt/missingiv", - test_secret_crypt_missing_iv); - g_test_add_func("/crypto/secret/crypt/badiv", - test_secret_crypt_bad_iv); + if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128, + QCRYPTO_CIPHER_MODE_CBC)) { + g_test_add_func("/crypto/secret/crypt/raw", + test_secret_crypt_raw); + g_test_add_func("/crypto/secret/crypt/base64", + test_secret_crypt_base64); + g_test_add_func("/crypto/secret/crypt/shortkey", + test_secret_crypt_short_key); + g_test_add_func("/crypto/secret/crypt/shortiv", + test_secret_crypt_short_iv); + g_test_add_func("/crypto/secret/crypt/missingiv", + test_secret_crypt_missing_iv); + g_test_add_func("/crypto/secret/crypt/badiv", + test_secret_crypt_bad_iv); + } return g_test_run(); } From 75134a32851e2d9f240097cc7a3bc3426667e147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 7 May 2025 15:47:18 +0100 Subject: [PATCH 1071/2760] tests: skip legacy qcow2 encryption test if AES is not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids test breakage when we drop support for using the built-in AES impl as a fallback for missing crypto libraries. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-block.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/unit/test-crypto-block.c b/tests/unit/test-crypto-block.c index 9217b9a2ef..3ac7f17b2a 100644 --- a/tests/unit/test-crypto-block.c +++ b/tests/unit/test-crypto-block.c @@ -574,6 +574,13 @@ int main(int argc, char **argv) for (i = 0; i < G_N_ELEMENTS(test_data); i++) { if (test_data[i].open_opts->format == QCRYPTO_BLOCK_FORMAT_LUKS && !qcrypto_hash_supports(test_data[i].hash_alg)) { + g_printerr("# skip unsupported %s\n", + QCryptoHashAlgo_str(test_data[i].hash_alg)); + continue; + } + if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128, + QCRYPTO_CIPHER_MODE_CBC)) { + g_printerr("# skip unsupported aes-128:cbc\n"); continue; } if (!test_data[i].slow || From 01ce649e5d260d4d1a466d10dfaeabeeb2b7478d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 7 May 2025 15:48:31 +0100 Subject: [PATCH 1072/2760] tests: fix skipping cipher tests when AES is not available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoid tests breakage when we drop support for using the built-in AES impl as a fallback for missing crypto libraries. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé --- tests/unit/test-crypto-cipher.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c index b328b482e1..1331d558cf 100644 --- a/tests/unit/test-crypto-cipher.c +++ b/tests/unit/test-crypto-cipher.c @@ -828,11 +828,16 @@ int main(int argc, char **argv) } } - g_test_add_func("/crypto/cipher/null-iv", - test_cipher_null_iv); + if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_256, + QCRYPTO_CIPHER_MODE_CBC)) { + g_test_add_func("/crypto/cipher/null-iv", + test_cipher_null_iv); - g_test_add_func("/crypto/cipher/short-plaintext", - test_cipher_short_plaintext); + g_test_add_func("/crypto/cipher/short-plaintext", + test_cipher_short_plaintext); + } else { + g_printerr("# skip unsupported aes-256:cbc\n"); + } return g_test_run(); } From 5a56f60d7c2e241bf972b8eca31286cf7f3cd7c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Tue, 6 May 2025 15:07:08 +0100 Subject: [PATCH 1073/2760] crypto: fully drop built-in cipher provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When originally creating the internal crypto cipher APIs, they were wired up to use the built-in D3DES and AES implementations, as a way to gracefully transition to the new APIs without introducing an immediate hard dep on any external crypto libraries for the VNC password auth (D3DES) or the qcow2 encryption (AES). In the 6.1.0 release we dropped the built-in D3DES impl, and also the XTS mode for the AES impl, leaving only AES with ECB/CBC modes. The rational was that with the system emulators, it is expected that 3rd party crypto libraries will be available. The qcow2 LUKS impl is preferred to the legacy raw AES impl, and by default that requires AES in XTS mode, limiting the usefulness of the built-in cipher provider. The built-in AES impl has known timing attacks and is only suitable for use cases where a security boundary is already not expected to be provided (TCG). Providing a built-in cipher impl thus potentially misleads users, should they configure a QEMU without any crypto library, and try to use it with the LUKS backend, even if that requires a non-default configuration choice. Complete what we started in 6.1.0 and purge the remaining AES support. Use of either gnutls, nettle, or libcrypt is now mandatory for any cipher support, except for TCG impls. Reviewed-by: Richard Henderson Reviewed-by: Alex Bennée Signed-off-by: Daniel P. Berrangé --- crypto/cipher-builtin.c.inc | 303 ------------------------------------ crypto/cipher-stub.c.inc | 30 ++++ crypto/cipher.c | 2 +- 3 files changed, 31 insertions(+), 304 deletions(-) delete mode 100644 crypto/cipher-builtin.c.inc create mode 100644 crypto/cipher-stub.c.inc diff --git a/crypto/cipher-builtin.c.inc b/crypto/cipher-builtin.c.inc deleted file mode 100644 index da5fcbd9a3..0000000000 --- a/crypto/cipher-builtin.c.inc +++ /dev/null @@ -1,303 +0,0 @@ -/* - * QEMU Crypto cipher built-in algorithms - * - * Copyright (c) 2015 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see . - * - */ - -#include "crypto/aes.h" - -typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; -struct QCryptoCipherBuiltinAESContext { - AES_KEY enc; - AES_KEY dec; -}; - -typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; -struct QCryptoCipherBuiltinAES { - QCryptoCipher base; - QCryptoCipherBuiltinAESContext key; - uint8_t iv[AES_BLOCK_SIZE]; -}; - - -static inline bool qcrypto_length_check(size_t len, size_t blocksize, - Error **errp) -{ - if (unlikely(len & (blocksize - 1))) { - error_setg(errp, "Length %zu must be a multiple of block size %zu", - len, blocksize); - return false; - } - return true; -} - -static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher) -{ - g_free(cipher); -} - -static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher, - const uint8_t *iv, size_t niv, - Error **errp) -{ - error_setg(errp, "Setting IV is not supported"); - return -1; -} - -static void do_aes_encrypt_ecb(const void *vctx, - size_t len, - uint8_t *out, - const uint8_t *in) -{ - const QCryptoCipherBuiltinAESContext *ctx = vctx; - - /* We have already verified that len % AES_BLOCK_SIZE == 0. */ - while (len) { - AES_encrypt(in, out, &ctx->enc); - in += AES_BLOCK_SIZE; - out += AES_BLOCK_SIZE; - len -= AES_BLOCK_SIZE; - } -} - -static void do_aes_decrypt_ecb(const void *vctx, - size_t len, - uint8_t *out, - const uint8_t *in) -{ - const QCryptoCipherBuiltinAESContext *ctx = vctx; - - /* We have already verified that len % AES_BLOCK_SIZE == 0. */ - while (len) { - AES_decrypt(in, out, &ctx->dec); - in += AES_BLOCK_SIZE; - out += AES_BLOCK_SIZE; - len -= AES_BLOCK_SIZE; - } -} - -static void do_aes_encrypt_cbc(const AES_KEY *key, - size_t len, - uint8_t *out, - const uint8_t *in, - uint8_t *ivec) -{ - uint8_t tmp[AES_BLOCK_SIZE]; - size_t n; - - /* We have already verified that len % AES_BLOCK_SIZE == 0. */ - while (len) { - for (n = 0; n < AES_BLOCK_SIZE; ++n) { - tmp[n] = in[n] ^ ivec[n]; - } - AES_encrypt(tmp, out, key); - memcpy(ivec, out, AES_BLOCK_SIZE); - len -= AES_BLOCK_SIZE; - in += AES_BLOCK_SIZE; - out += AES_BLOCK_SIZE; - } -} - -static void do_aes_decrypt_cbc(const AES_KEY *key, - size_t len, - uint8_t *out, - const uint8_t *in, - uint8_t *ivec) -{ - uint8_t tmp[AES_BLOCK_SIZE]; - size_t n; - - /* We have already verified that len % AES_BLOCK_SIZE == 0. */ - while (len) { - memcpy(tmp, in, AES_BLOCK_SIZE); - AES_decrypt(in, out, key); - for (n = 0; n < AES_BLOCK_SIZE; ++n) { - out[n] ^= ivec[n]; - } - memcpy(ivec, tmp, AES_BLOCK_SIZE); - len -= AES_BLOCK_SIZE; - in += AES_BLOCK_SIZE; - out += AES_BLOCK_SIZE; - } -} - -static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - do_aes_encrypt_ecb(&ctx->key, len, out, in); - return 0; -} - -static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - do_aes_decrypt_ecb(&ctx->key, len, out, in); - return 0; -} - -static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv); - return 0; -} - -static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher, - const void *in, void *out, - size_t len, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { - return -1; - } - do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv); - return 0; -} - -static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv, - size_t niv, Error **errp) -{ - QCryptoCipherBuiltinAES *ctx - = container_of(cipher, QCryptoCipherBuiltinAES, base); - - if (niv != AES_BLOCK_SIZE) { - error_setg(errp, "IV must be %d bytes not %zu", - AES_BLOCK_SIZE, niv); - return -1; - } - - memcpy(ctx->iv, iv, AES_BLOCK_SIZE); - return 0; -} - -static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = { - .cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb, - .cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb, - .cipher_setiv = qcrypto_cipher_no_setiv, - .cipher_free = qcrypto_cipher_ctx_free, -}; - -static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = { - .cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc, - .cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc, - .cipher_setiv = qcrypto_cipher_aes_setiv, - .cipher_free = qcrypto_cipher_ctx_free, -}; - -bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, - QCryptoCipherMode mode) -{ - switch (alg) { - case QCRYPTO_CIPHER_ALGO_AES_128: - case QCRYPTO_CIPHER_ALGO_AES_192: - case QCRYPTO_CIPHER_ALGO_AES_256: - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - case QCRYPTO_CIPHER_MODE_CBC: - return true; - default: - return false; - } - break; - default: - return false; - } -} - -static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, - QCryptoCipherMode mode, - const uint8_t *key, - size_t nkey, - Error **errp) -{ - if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { - return NULL; - } - - switch (alg) { - case QCRYPTO_CIPHER_ALGO_AES_128: - case QCRYPTO_CIPHER_ALGO_AES_192: - case QCRYPTO_CIPHER_ALGO_AES_256: - { - QCryptoCipherBuiltinAES *ctx; - const QCryptoCipherDriver *drv; - - switch (mode) { - case QCRYPTO_CIPHER_MODE_ECB: - drv = &qcrypto_cipher_aes_driver_ecb; - break; - case QCRYPTO_CIPHER_MODE_CBC: - drv = &qcrypto_cipher_aes_driver_cbc; - break; - default: - goto bad_mode; - } - - ctx = g_new0(QCryptoCipherBuiltinAES, 1); - ctx->base.driver = drv; - - if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) { - error_setg(errp, "Failed to set encryption key"); - goto error; - } - if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) { - error_setg(errp, "Failed to set decryption key"); - goto error; - } - - return &ctx->base; - - error: - g_free(ctx); - return NULL; - } - - default: - error_setg(errp, - "Unsupported cipher algorithm %s", - QCryptoCipherAlgo_str(alg)); - return NULL; - } - - bad_mode: - error_setg(errp, "Unsupported cipher mode %s", - QCryptoCipherMode_str(mode)); - return NULL; -} diff --git a/crypto/cipher-stub.c.inc b/crypto/cipher-stub.c.inc new file mode 100644 index 0000000000..1b7ea81eac --- /dev/null +++ b/crypto/cipher-stub.c.inc @@ -0,0 +1,30 @@ +/* + * SPDX-License-Identifier: GPL-2.0-or-later + * + * QEMU Crypto cipher impl stub + * + * Copyright (c) 2025 Red Hat, Inc. + * + */ + +bool qcrypto_cipher_supports(QCryptoCipherAlgo alg, + QCryptoCipherMode mode) +{ + return false; +} + +static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg, + QCryptoCipherMode mode, + const uint8_t *key, + size_t nkey, + Error **errp) +{ + if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { + return NULL; + } + + error_setg(errp, + "Unsupported cipher algorithm %s, no crypto library enabled in build", + QCryptoCipherAlgo_str(alg)); + return NULL; +} diff --git a/crypto/cipher.c b/crypto/cipher.c index c14a8b8a11..229710f76b 100644 --- a/crypto/cipher.c +++ b/crypto/cipher.c @@ -145,7 +145,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgo alg, #elif defined CONFIG_GNUTLS_CRYPTO #include "cipher-gnutls.c.inc" #else -#include "cipher-builtin.c.inc" +#include "cipher-stub.c.inc" #endif QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgo alg, From 66411ab48b3676894903148406db12a446445adc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 May 2025 17:40:33 +0100 Subject: [PATCH 1074/2760] Revert "scripts: mandate that new files have SPDX-License-Identifier" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fa4d79c64dae03ffa269e42e21822453856618b7. The logic in this commit was flawed in two critical ways * It always failed to report SPDX validation on the last newly added file. IOW, it only worked if at least 2 new files were added in a commit * If an existing file change, followed a new file change, in the commit and the existing file context/changed lines included SPDX-License-Identifier, it would incorrectly associate this with the previous newly added file. Simply reverting this commit will make it significantly easier to understand the improved logic in the following commit. Reported-by: Peter Maydell Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 365892de04..d355c0dad5 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1442,8 +1442,6 @@ sub process { my $in_imported_file = 0; my $in_no_imported_file = 0; my $non_utf8_charset = 0; - my $expect_spdx = 0; - my $expect_spdx_file; our @report = (); our $cnt_lines = 0; @@ -1681,34 +1679,6 @@ sub process { WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); } -# All new files should have a SPDX-License-Identifier tag - if ($line =~ /^new file mode\s*\d+\s*$/) { - if ($expect_spdx) { - if ($expect_spdx_file =~ - /\.(c|h|py|pl|sh|json|inc|Makefile)$/) { - # source code files MUST have SPDX license declared - ERROR("New file '$expect_spdx_file' requires " . - "'SPDX-License-Identifier'"); - } else { - # Other files MAY have SPDX license if appropriate - WARN("Does new file '$expect_spdx_file' need " . - "'SPDX-License-Identifier'?"); - } - } - $expect_spdx = 1; - $expect_spdx_file = undef; - } elsif ($expect_spdx) { - $expect_spdx_file = $realfile unless - defined $expect_spdx_file; - - # SPDX tags may occurr in comments which were - # stripped from '$line', so use '$rawline' - if ($rawline =~ /SPDX-License-Identifier/) { - $expect_spdx = 0; - $expect_spdx_file = undef; - } - } - # Check SPDX-License-Identifier references a permitted license if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) { &checkspdx($realfile, $1); From 619bf37594e362131f12b42888e6a35ddee488e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 12 May 2025 18:11:58 +0100 Subject: [PATCH 1075/2760] scripts/checkpatch.pl: fix various indentation mistakes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various checks in the code were under-indented relative to other surrounding code. Some places used 4-space indents instead of single tab, while other places simply used too few tabs. Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 103 ++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d355c0dad5..2c19f6f0f2 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1681,19 +1681,20 @@ sub process { # Check SPDX-License-Identifier references a permitted license if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) { - &checkspdx($realfile, $1); + &checkspdx($realfile, $1); } if ($rawline =~ m,(SPDX-[a-zA-Z0-9-_]+):,) { - my $tag = $1; - my @permitted = qw( - SPDX-License-Identifier - ); + my $tag = $1; + my @permitted = qw( + SPDX-License-Identifier + ); - unless (grep { /^$tag$/ } @permitted) { - ERROR("Tag $tag not permitted in QEMU code, valid " . - "choices are: " . join(", ", @permitted)); - } + unless (grep { /^$tag$/ } @permitted) { + ERROR("Tag $tag not permitted in QEMU code, " . + "valid choices are: " . + join(", ", @permitted)); + } } # Check for wrappage within a valid hunk of the file @@ -2274,7 +2275,7 @@ sub process { # missing space after union, struct or enum definition if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) { - ERROR("missing space after $1 definition\n" . $herecurr); + ERROR("missing space after $1 definition\n" . $herecurr); } # check for spacing round square brackets; allowed: @@ -2569,7 +2570,7 @@ sub process { if ($line =~ /^.\s*(Q(?:S?LIST|SIMPLEQ|TAILQ)_HEAD)\s*\(\s*[^,]/ && $line !~ /^.typedef/) { - ERROR("named $1 should be typedefed separately\n" . $herecurr); + ERROR("named $1 should be typedefed separately\n" . $herecurr); } # Need a space before open parenthesis after if, while etc @@ -3118,48 +3119,50 @@ sub process { # Qemu error function tests - # Find newlines in error messages - my $qemu_error_funcs = qr{error_setg| - error_setg_errno| - error_setg_win32| - error_setg_file_open| - error_set| - error_prepend| - warn_reportf_err| - error_reportf_err| - error_vreport| - warn_vreport| - info_vreport| - error_report| - warn_report| - info_report| - g_test_message}x; + # Find newlines in error messages + my $qemu_error_funcs = qr{error_setg| + error_setg_errno| + error_setg_win32| + error_setg_file_open| + error_set| + error_prepend| + warn_reportf_err| + error_reportf_err| + error_vreport| + warn_vreport| + info_vreport| + error_report| + warn_report| + info_report| + g_test_message}x; - if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(.*\".*\\n/) { - ERROR("Error messages should not contain newlines\n" . $herecurr); - } - - # Continue checking for error messages that contains newlines. This - # check handles cases where string literals are spread over multiple lines. - # Example: - # error_report("Error msg line #1" - # "Error msg line #2\n"); - my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"}; - my $continued_str_literal = qr{\+\s*\".*\"}; - - if ($rawline =~ /$quoted_newline_regex/) { - # Backtrack to first line that does not contain only a quoted literal - # and assume that it is the start of the statement. - my $i = $linenr - 2; - - while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) { - $i--; - } - - if ($rawlines[$i] =~ /\b(?:$qemu_error_funcs)\s*\(/) { + if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(.*\".*\\n/) { ERROR("Error messages should not contain newlines\n" . $herecurr); } - } + + # Continue checking for error messages that contains newlines. + # This check handles cases where string literals are spread + # over multiple lines. + # Example: + # error_report("Error msg line #1" + # "Error msg line #2\n"); + my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"}; + my $continued_str_literal = qr{\+\s*\".*\"}; + + if ($rawline =~ /$quoted_newline_regex/) { + # Backtrack to first line that does not contain only + # a quoted literal and assume that it is the start + # of the statement. + my $i = $linenr - 2; + + while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) { + $i--; + } + + if ($rawlines[$i] =~ /\b(?:$qemu_error_funcs)\s*\(/) { + ERROR("Error messages should not contain newlines\n" . $herecurr); + } + } # check for non-portable libc calls that have portable alternatives in QEMU if ($line =~ /\bffs\(/) { From 25374ba59bce2d8c714283c7bb18b1dc2cc89ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 12 May 2025 16:57:38 +0100 Subject: [PATCH 1076/2760] scripts/checkpatch: introduce tracking of file start/end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some checks want to be performed either at the start of a new file within a patch, or at the end. This is complicated by the fact that the information relevant to the check may be spread across multiple lines. It is further complicated by a need to support both git and non-git diffs, and special handling for renames where there might not be any patch hunks. To handle this more sanely, introduce explicit tracking of file start/end, taking account of git metadata, and calling a hook function at each transition. Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 110 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 2c19f6f0f2..bb3830d693 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1417,6 +1417,39 @@ sub checkspdx { } } +# All three of the methods below take a 'file info' record +# which is a hash ref containing +# +# 'isgit': 1 if an enhanced git diff or 0 for a plain diff +# 'githeader': 1 if still parsing git patch header, 0 otherwise +# 'linestart': line number of start of file diff +# 'lineend': line number of end of file diff +# 'filenew': the new filename +# 'fileold': the old filename (same as 'new filename' except +# for renames in git diffs) +# 'action': one of 'modified' (always) or 'new' or 'deleted' or +# 'renamed' (git diffs only) +# 'mode': file mode for new/deleted files (git diffs only) +# 'similarity': file similarity when renamed (git diffs only) +# 'facts': hash ref for storing any metadata related to checks +# + +# Called at the end of each patch, with the list of +# real filenames that were seen in the patch +sub process_file_list { + my @fileinfos = @_; +} + +# Called at the start of processing a diff hunk for a file +sub process_start_of_file { + my $fileinfo = shift; +} + +# Called at the end of processing a diff hunk for a file +sub process_end_of_file { + my $fileinfo = shift; +} + sub process { my $filename = shift; @@ -1453,7 +1486,10 @@ sub process { my $realfile = ''; my $realline = 0; my $realcnt = 0; + my $fileinfo; + my @fileinfolist; my $here = ''; + my $oldhere = ''; my $in_comment = 0; my $comment_edge = 0; my $first_line = 0; @@ -1591,17 +1627,56 @@ sub process { $prefix = "$filename:$realline: " if ($emacs && $file); $prefix = "$filename:$linenr: " if ($emacs && !$file); + $oldhere = $here; $here = "#$linenr: " if (!$file); $here = "#$realline: " if ($file); # extract the filename as it passes - if ($line =~ /^diff --git.*?(\S+)$/) { - $realfile = $1; - $realfile =~ s@^([^/]*)/@@ if (!$file); + if ($line =~ /^diff --git\s+(\S+)\s+(\S+)$/) { + my $fileold = $1; + my $filenew = $2; + + if (defined $fileinfo) { + $fileinfo->{lineend} = $oldhere; + process_end_of_file($fileinfo) + } + $fileold =~ s@^([^/]*)/@@ if (!$file); + $filenew =~ s@^([^/]*)/@@ if (!$file); + $realfile = $filenew; checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); + + $fileinfo = { + "isgit" => 1, + "githeader" => 1, + "linestart" => $here, + "lineend" => 0, + "fileold" => $fileold, + "filenew" => $filenew, + "action" => "modified", + "mode" => 0, + "similarity" => 0, + "facts" => {}, + }; + push @fileinfolist, $fileinfo; + } elsif (defined $fileinfo && $fileinfo->{githeader} && + $line =~ /^(new|deleted) (?:file )?mode\s+([0-7]+)$/) { + $fileinfo->{action} = $1; + $fileinfo->{mode} = oct($2); + } elsif (defined $fileinfo && $fileinfo->{githeader} && + $line =~ /^similarity index (\d+)%/) { + $fileinfo->{similarity} = int($1); + } elsif (defined $fileinfo && $fileinfo->{githeader} && + $line =~ /^rename (from|to) [\w\/\.\-]+\s*$/) { + $fileinfo->{action} = "renamed"; + # For a no-change rename, we'll never have any "+++..." + # lines, so trigger actions now + if ($1 eq "to" && $fileinfo->{similarity} == 100) { + process_start_of_file($fileinfo); + } } elsif ($line =~ /^\+\+\+\s+(\S+)/) { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); + checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); $p1_prefix = $1; @@ -1610,6 +1685,30 @@ sub process { WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n"); } + if (defined $fileinfo && !$fileinfo->{isgit}) { + $fileinfo->{lineend} = $oldhere; + process_end_of_file($fileinfo); + } + + if (!defined $fileinfo || !$fileinfo->{isgit}) { + $fileinfo = { + "isgit" => 0, + "githeader" => 0, + "linestart" => $here, + "lineend" => 0, + "fileold" => $realfile, + "filenew" => $realfile, + "action" => "modified", + "mode" => 0, + "similarity" => 0, + "facts" => {}, + }; + push @fileinfolist, $fileinfo; + } else { + $fileinfo->{githeader} = 0; + } + process_start_of_file($fileinfo); + next; } @@ -3216,6 +3315,11 @@ sub process { } } + if (defined $fileinfo) { + process_end_of_file($fileinfo); + } + process_file_list(@fileinfolist); + if ($is_patch && $chk_signoff && $signoff == 0) { ERROR("Missing Signed-off-by: line(s)\n"); } From 9bec5f93e794271b2dc643cdc1c43082af958fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 12 May 2025 17:48:20 +0100 Subject: [PATCH 1077/2760] scripts/checkpatch: use new hook for ACPI test data check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ACPI test data check needs to analyse a list of all files in a commit, so can use the new hook for processing the file list. Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 61 ++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index bb3830d693..817df98231 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1330,29 +1330,6 @@ sub WARN { } } -# According to tests/qtest/bios-tables-test.c: do not -# change expected file in the same commit with adding test -sub checkfilename { - my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_; - - # Note: shell script that rebuilds the expected files is in the same - # directory as files themselves. - # Note: allowed diff list can be changed both when changing expected - # files and when changing tests. - if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) { - $$acpi_testexpected = $name; - } elsif ($name !~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { - $$acpi_nontestexpected = $name; - } - if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) { - ERROR("Do not add expected files together with tests, " . - "follow instructions in " . - "tests/qtest/bios-tables-test.c: both " . - $$acpi_testexpected . " and " . - $$acpi_nontestexpected . " found\n"); - } -} - sub checkspdx { my ($file, $expr) = @_; @@ -1438,6 +1415,34 @@ sub checkspdx { # real filenames that were seen in the patch sub process_file_list { my @fileinfos = @_; + + # According to tests/qtest/bios-tables-test.c: do not + # change expected file in the same commit with adding test + my @acpi_testexpected; + my @acpi_nontestexpected; + + foreach my $fileinfo (@fileinfos) { + # Note: shell script that rebuilds the expected files is in + # the same directory as files themselves. + # Note: allowed diff list can be changed both when changing + # expected files and when changing tests. + if ($fileinfo->{filenew} =~ m#^tests/data/acpi/# && + $fileinfo->{filenew} !~ m#^\.sh$#) { + push @acpi_testexpected, $fileinfo->{filenew}; + } elsif ($fileinfo->{filenew} !~ + m#^tests/qtest/bios-tables-test-allowed-diff.h$#) { + push @acpi_nontestexpected, $fileinfo->{filenew}; + } + } + if (int(@acpi_testexpected) > 0 and int(@acpi_nontestexpected) > 0) { + ERROR("Do not add expected files together with tests, " . + "follow instructions in " . + "tests/qtest/bios-tables-test.c. Files\n\n " . + join("\n ", @acpi_testexpected) . + "\n\nand\n\n " . + join("\n ", @acpi_nontestexpected) . + "\n\nfound in the same patch\n"); + } } # Called at the start of processing a diff hunk for a file @@ -1502,9 +1507,6 @@ sub process { my %suppress_whiletrailers; my %suppress_export; - my $acpi_testexpected; - my $acpi_nontestexpected; - # Pre-scan the patch sanitizing the lines. sanitise_line_reset(); @@ -1643,7 +1645,6 @@ sub process { $fileold =~ s@^([^/]*)/@@ if (!$file); $filenew =~ s@^([^/]*)/@@ if (!$file); $realfile = $filenew; - checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); $fileinfo = { "isgit" => 1, @@ -1677,8 +1678,6 @@ sub process { $realfile = $1; $realfile =~ s@^([^/]*)/@@ if (!$file); - checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected); - $p1_prefix = $1; if (!$file && $tree && $p1_prefix ne '' && -e "$root/$p1_prefix") { @@ -1771,9 +1770,7 @@ sub process { $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && (defined($1) || defined($2)))) && - !(($realfile ne '') && - defined($acpi_testexpected) && - ($realfile eq $acpi_testexpected))) { + $realfile !~ m#^tests/data/acpi/#) { $reported_maintainer_file = 1; WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); } From f48f16ec3d8cee0a3d843915451c5649fe3a8aaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 12 May 2025 17:11:55 +0100 Subject: [PATCH 1078/2760] scripts/checkpatch: use new hook for file permissions check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The file permissions check is the kind of check intended to be performed in the new start of file hook. Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 817df98231..881dcac29b 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1448,6 +1448,17 @@ sub process_file_list { # Called at the start of processing a diff hunk for a file sub process_start_of_file { my $fileinfo = shift; + + # Check for incorrect file permissions + if ($fileinfo->{action} eq "new" && ($fileinfo->{mode} & 0111)) { + my $permhere = $fileinfo->{linestart} . "FILE: " . + $fileinfo->{filenew} . "\n"; + if ($fileinfo->{filenew} =~ + /(\bMakefile(?:\.objs)?|\.(c|cc|cpp|h|mak|s|S))$/) { + ERROR("do not set execute permissions for source " . + "files\n" . $permhere); + } + } } # Called at the end of processing a diff hunk for a file @@ -1719,14 +1730,6 @@ sub process { $cnt_lines++ if ($realcnt != 0); -# Check for incorrect file permissions - if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { - my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(\bMakefile(?:\.objs)?|\.c|\.cc|\.cpp|\.h|\.mak|\.[sS])$/) { - ERROR("do not set execute permissions for source files\n" . $permhere); - } - } - # Only allow Python 3 interpreter if ($realline == 1 && $line =~ /^\+#!\ *\/usr\/bin\/(?:env )?python$/) { From 45abbf209f007db90d0a596139f653783cd1cb0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 15 May 2025 13:57:45 +0100 Subject: [PATCH 1079/2760] scripts/checkpatch: expand pattern for matching makefiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current regex matches Makefile & Makefile.objs, but the latter is no longer used, anjd we're missing coverage of Makefile.include and Makefile.target. Expand the pattern to match any suffix. Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 881dcac29b..82ec71e05d 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1454,7 +1454,7 @@ sub process_start_of_file { my $permhere = $fileinfo->{linestart} . "FILE: " . $fileinfo->{filenew} . "\n"; if ($fileinfo->{filenew} =~ - /(\bMakefile(?:\.objs)?|\.(c|cc|cpp|h|mak|s|S))$/) { + /(\bMakefile.*|\.(c|cc|cpp|h|mak|s|S))$/) { ERROR("do not set execute permissions for source " . "files\n" . $permhere); } From 1d745e6d96353af20f116672b87ae28b0d07eca9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Mon, 12 May 2025 18:01:00 +0100 Subject: [PATCH 1080/2760] scripts/checkpatch: use new hook for MAINTAINERS update check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When seeing a new/deleted/renamed file we check to see if MAINTAINERS is updated, but we don't give the user a list of files affected, as we don't want to repeat the same warning many times over. Using the new file list hook, we can give a single warning at the end with a list of filenames included. Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 82ec71e05d..c05559a108 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1443,6 +1443,25 @@ sub process_file_list { join("\n ", @acpi_nontestexpected) . "\n\nfound in the same patch\n"); } + + my $sawmaintainers = 0; + my @maybemaintainers; + foreach my $fileinfo (@fileinfos) { + if ($fileinfo->{action} ne "modified" && + $fileinfo->{filenew} !~ m#^tests/data/acpi/#) { + push @maybemaintainers, $fileinfo->{filenew}; + } + if ($fileinfo->{filenew} eq "MAINTAINERS") { + $sawmaintainers = 1; + } + } + + # If we don't see a MAINTAINERS update, prod the user to check + if (int(@maybemaintainers) > 0 && !$sawmaintainers) { + WARN("added, moved or deleted file(s):\n\n " . + join("\n ", @maybemaintainers) . + "\n\nDoes MAINTAINERS need updating?\n"); + } } # Called at the start of processing a diff hunk for a file @@ -1486,7 +1505,6 @@ sub process { my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch - my $reported_maintainer_file = 0; my $reported_mixing_imported_file = 0; my $in_imported_file = 0; my $in_no_imported_file = 0; @@ -1761,23 +1779,6 @@ sub process { } } -# Check if MAINTAINERS is being updated. If so, there's probably no need to -# emit the "does MAINTAINERS need updating?" message on file add/move/delete - if ($line =~ /^\s*MAINTAINERS\s*\|/) { - $reported_maintainer_file = 1; - } - -# Check for added, moved or deleted files - if (!$reported_maintainer_file && !$in_commit_log && - ($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ || - $line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ || - ($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ && - (defined($1) || defined($2)))) && - $realfile !~ m#^tests/data/acpi/#) { - $reported_maintainer_file = 1; - WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); - } - # Check SPDX-License-Identifier references a permitted license if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) { &checkspdx($realfile, $1); From b36934063c5550a3fcb1b36027fd1a509142e4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 8 May 2025 17:43:40 +0100 Subject: [PATCH 1081/2760] scripts/checkpatch: reimplement mandate for SPDX-License-Identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Going forward we want all newly created source files to have an SPDX-License-Identifier tag present. Initially mandate this for C, Python, Perl, Shell source files, as well as JSON (QAPI) and Makefiles, while encouraging users to consider it for other file types. The new attempt at detecting missing SPDX-License-Identifier relies on the hooks for relying triggering logic at the end of scanning a new file in the diff. Tested-by: Cédric Le Goater Reviewed-by: Cédric Le Goater Reviewed-by: Peter Maydell Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index c05559a108..da13102eda 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1483,6 +1483,20 @@ sub process_start_of_file { # Called at the end of processing a diff hunk for a file sub process_end_of_file { my $fileinfo = shift; + + if ($fileinfo->{action} eq "new" && + !exists $fileinfo->{facts}->{sawspdx}) { + if ($fileinfo->{filenew} =~ + /(\.(c|h|py|pl|sh|json|inc)|Makefile.*)$/) { + # source code files MUST have SPDX license declared + ERROR("New file '" . $fileinfo->{filenew} . + "' requires 'SPDX-License-Identifier'"); + } else { + # Other files MAY have SPDX license if appropriate + WARN("Does new file '" . $fileinfo->{filenew} . + "' need 'SPDX-License-Identifier'?"); + } + } } sub process { @@ -1781,6 +1795,7 @@ sub process { # Check SPDX-License-Identifier references a permitted license if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) { + $fileinfo->{facts}->{sawspdx} = 1; &checkspdx($realfile, $1); } From 1f59381d6c0126cf0348977caa73ab8f7cfa1269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 15 May 2025 14:13:13 +0100 Subject: [PATCH 1082/2760] scripts/checkpatch: reject license boilerplate on new files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit mandates use of SPDX-License-Identifier on common source files, and encourages it on all other files. Some contributors are none the less still also including the license boilerplate text. This is redundant and will potentially cause trouble if inconsistent with the SPDX declaration. Match common boilerplate text blurbs and report them as invalid, for newly added files. Reviewed-by: Peter Maydell Reviewed-by: Cédric Le Goater Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index da13102eda..9291bc9209 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -365,6 +365,18 @@ our @typeList = ( qr{guintptr}, ); +# Match text found in common license boilerplate comments: +# for new files the SPDX-License-Identifier line is sufficient. +our @LICENSE_BOILERPLATE = ( + "licensed under the terms of the GNU GPL", + "under the terms of the GNU General Public License", + "under the terms of the GNU Lesser General Public", + "Permission is hereby granted, free of charge", + "GNU GPL, version 2 or later", + "See the COPYING file" +); +our $LICENSE_BOILERPLATE_RE = join("|", @LICENSE_BOILERPLATE); + # Load common spelling mistakes and build regular expression list. my $misspellings; my %spelling_fix; @@ -1497,6 +1509,13 @@ sub process_end_of_file { "' need 'SPDX-License-Identifier'?"); } } + if ($fileinfo->{action} eq "new" && + exists $fileinfo->{facts}->{sawboilerplate}) { + ERROR("New file '" . $fileinfo->{filenew} . "' must " . + "not have license boilerplate header text, only " . + "the SPDX-License-Identifier, unless this file was " . + "copied from existing code already having such text."); + } } sub process { @@ -1799,6 +1818,10 @@ sub process { &checkspdx($realfile, $1); } + if ($rawline =~ /$LICENSE_BOILERPLATE_RE/) { + $fileinfo->{facts}->{sawboilerplate} = 1; + } + if ($rawline =~ m,(SPDX-[a-zA-Z0-9-_]+):,) { my $tag = $1; my @permitted = qw( From 0dc051aa85e1bd68d5c5110fa8af69204e6dbd3d Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:30 +0200 Subject: [PATCH 1083/2760] io: Fix partial struct copy in qio_dns_resolver_lookup_sync_inet() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit aec21d3175 (qapi: Add InetSocketAddress member keep-alive) introduces the keep-alive flag, but this flag is not copied together with other options in qio_dns_resolver_lookup_sync_inet(). This patch fixes this issue and also prevents future ones by copying the entire structure first and only then overriding a few attributes that need to be different. Fixes: aec21d31756c (qapi: Add InetSocketAddress member keep-alive) Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- io/dns-resolver.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/io/dns-resolver.c b/io/dns-resolver.c index 53b0e8407a..3712438f82 100644 --- a/io/dns-resolver.c +++ b/io/dns-resolver.c @@ -111,22 +111,11 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver, uaddr, INET6_ADDRSTRLEN, uport, 32, NI_NUMERICHOST | NI_NUMERICSERV); - newaddr->u.inet = (InetSocketAddress){ - .host = g_strdup(uaddr), - .port = g_strdup(uport), - .has_numeric = true, - .numeric = true, - .has_to = iaddr->has_to, - .to = iaddr->to, - .has_ipv4 = iaddr->has_ipv4, - .ipv4 = iaddr->ipv4, - .has_ipv6 = iaddr->has_ipv6, - .ipv6 = iaddr->ipv6, -#ifdef HAVE_IPPROTO_MPTCP - .has_mptcp = iaddr->has_mptcp, - .mptcp = iaddr->mptcp, -#endif - }; + newaddr->u.inet = *iaddr; + newaddr->u.inet.host = g_strdup(uaddr), + newaddr->u.inet.port = g_strdup(uport), + newaddr->u.inet.has_numeric = true, + newaddr->u.inet.numeric = true, (*addrs)[i] = newaddr; } From b8b5278aca78be4a1c2e7cbb11c6be176f63706d Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:31 +0200 Subject: [PATCH 1084/2760] util/qemu-sockets: Refactor setting client sockopts into a separate function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is done in preparation for enabling the SO_KEEPALIVE support for server sockets and adding settings for more TCP keep-alive socket options. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- util/qemu-sockets.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 77477c1cd5..4a878e0527 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -205,6 +205,22 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e) #endif } +static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp) +{ + if (saddr->keep_alive) { + int keep_alive = 1; + int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + &keep_alive, sizeof(keep_alive)); + + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set keep-alive option on socket"); + return -1; + } + } + return 0; +} + static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, int num, @@ -475,16 +491,9 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp) return sock; } - if (saddr->keep_alive) { - int val = 1; - int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - &val, sizeof(val)); - - if (ret < 0) { - error_setg_errno(errp, errno, "Unable to set KEEPALIVE"); - close(sock); - return -1; - } + if (inet_set_sockopts(sock, saddr, errp) < 0) { + close(sock); + return -1; } return sock; From 911e0f2c6e2d00c985affa75ec188c8edcf480f2 Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:32 +0200 Subject: [PATCH 1085/2760] util/qemu-sockets: Refactor success and failure paths in inet_listen_saddr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get a listening socket, we need to first create a socket, try binding it to a certain port, and lastly starting listening to it. Each of these operations can fail due to various reasons, one of them being that the requested address/port is already in use. In such case, the function tries the same process with a new port number. This patch refactors the port number loop, so the success path is no longer buried inside the 'if' statements in the middle of the loop. Now, the success path is not nested and ends at the end of the iteration after successful socket creation, binding, and listening. In case any of the operations fails, it either continues to the next iteration (and the next port) or jumps out of the loop to handle the error and exits the function. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- util/qemu-sockets.c | 53 ++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 4a878e0527..329fdbfd97 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -303,11 +303,20 @@ static int inet_listen_saddr(InetSocketAddress *saddr, port_min = inet_getport(e); port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { + if (slisten >= 0) { + /* + * We have a socket we tried with the previous port. It cannot + * be rebound, we need to close it and create a new one. + */ + close(slisten); + slisten = -1; + } inet_setport(e, p); slisten = create_fast_reuse_socket(e); if (slisten < 0) { - /* First time we expect we might fail to create the socket + /* + * First time we expect we might fail to create the socket * eg if 'e' has AF_INET6 but ipv6 kmod is not loaded. * Later iterations should always succeed if first iteration * worked though, so treat that as fatal. @@ -317,40 +326,38 @@ static int inet_listen_saddr(InetSocketAddress *saddr, } else { error_setg_errno(errp, errno, "Failed to recreate failed listening socket"); - goto listen_failed; + goto fail; } } socket_created = true; rc = try_bind(slisten, saddr, e); if (rc < 0) { - if (errno != EADDRINUSE) { - error_setg_errno(errp, errno, "Failed to bind socket"); - goto listen_failed; - } - } else { - if (!listen(slisten, num)) { - goto listen_ok; - } - if (errno != EADDRINUSE) { - error_setg_errno(errp, errno, "Failed to listen on socket"); - goto listen_failed; + if (errno == EADDRINUSE) { + /* This port is already used, try the next one */ + continue; } + error_setg_errno(errp, errno, "Failed to bind socket"); + goto fail; } - /* Someone else managed to bind to the same port and beat us - * to listen on it! Socket semantics does not allow us to - * recover from this situation, so we need to recreate the - * socket to allow bind attempts for subsequent ports: - */ - close(slisten); - slisten = -1; + if (listen(slisten, num)) { + if (errno == EADDRINUSE) { + /* This port is already used, try the next one */ + continue; + } + error_setg_errno(errp, errno, "Failed to listen on socket"); + goto fail; + } + /* We have a listening socket */ + freeaddrinfo(res); + return slisten; } } error_setg_errno(errp, errno, socket_created ? "Failed to find an available port" : "Failed to create a socket"); -listen_failed: +fail: saved_errno = errno; if (slisten >= 0) { close(slisten); @@ -358,10 +365,6 @@ listen_failed: freeaddrinfo(res); errno = saved_errno; return -1; - -listen_ok: - freeaddrinfo(res); - return slisten; } #ifdef _WIN32 From 00064705ed1f3943d3634be25da434466c87e7d5 Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:33 +0200 Subject: [PATCH 1086/2760] util/qemu-sockets: Add support for keep-alive flag to passive sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit aec21d3175 (qapi: Add InetSocketAddress member keep-alive) introduces the keep-alive flag, which enables the SO_KEEPALIVE socket option, but only on client-side sockets. However, this option is also useful for server-side sockets, so they can check if a client is still reachable or drop the connection otherwise. This patch enables the SO_KEEPALIVE socket option on passive server-side sockets if the keep-alive flag is enabled. This socket option is then inherited by active server-side sockets communicating with connected clients. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- qapi/sockets.json | 4 ++-- util/qemu-sockets.c | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/qapi/sockets.json b/qapi/sockets.json index 6a95023315..62797cd027 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -56,8 +56,8 @@ # @ipv6: whether to accept IPv6 addresses, default try both IPv4 and # IPv6 # -# @keep-alive: enable keep-alive when connecting to this socket. Not -# supported for passive sockets. (Since 4.2) +# @keep-alive: enable keep-alive when connecting to/listening on this socket. +# (Since 4.2, not supported for listening sockets until 10.1) # # @mptcp: enable multi-path TCP. (Since 6.1) # diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 329fdbfd97..4fbf1ed5bf 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -236,12 +236,6 @@ static int inet_listen_saddr(InetSocketAddress *saddr, int saved_errno = 0; bool socket_created = false; - if (saddr->keep_alive) { - error_setg(errp, "keep-alive option is not supported for passive " - "sockets"); - return -1; - } - memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; if (saddr->has_numeric && saddr->numeric) { @@ -349,6 +343,9 @@ static int inet_listen_saddr(InetSocketAddress *saddr, goto fail; } /* We have a listening socket */ + if (inet_set_sockopts(slisten, saddr, errp) < 0) { + goto fail; + } freeaddrinfo(res); return slisten; } From 316e8ee8d614f049bfae697570a5e62af450491c Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:34 +0200 Subject: [PATCH 1087/2760] util/qemu-sockets: Refactor inet_parse() to use QemuOpts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the inet address parser cannot handle multiple options where one is prefixed with the name of the other. For example, with the 'keep-alive-idle' option added, the current parser cannot parse '127.0.0.1:5000,keep-alive-idle=60,keep-alive' correctly. Instead, it fails with "error parsing 'keep-alive' flag '-idle=60,keep-alive'". To resolve these issues, this patch rewrites the inet address parsing using the QemuOpts parser, which the inet_parse_flag() function tries to mimic. This new parser supports all previously supported options and on top of that the 'numeric' flag is now also supported. The only difference is, the new parser produces an error if an unknown option is passed, instead of silently ignoring it. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- tests/unit/test-util-sockets.c | 196 +++++++++++++++++++++++++++++++++ util/qemu-sockets.c | 170 ++++++++++++++-------------- 2 files changed, 276 insertions(+), 90 deletions(-) diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index 4c9dd0b271..9e39b92e7c 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -332,6 +332,177 @@ static void test_socket_unix_abstract(void) #endif /* CONFIG_LINUX */ +static void inet_parse_test_helper(const char *str, + InetSocketAddress *exp_addr, bool success) +{ + InetSocketAddress addr; + Error *error = NULL; + + int rc = inet_parse(&addr, str, &error); + + if (success) { + g_assert_cmpint(rc, ==, 0); + } else { + g_assert_cmpint(rc, <, 0); + } + if (exp_addr != NULL) { + g_assert_cmpstr(addr.host, ==, exp_addr->host); + g_assert_cmpstr(addr.port, ==, exp_addr->port); + /* Own members: */ + g_assert_cmpint(addr.has_numeric, ==, exp_addr->has_numeric); + g_assert_cmpint(addr.numeric, ==, exp_addr->numeric); + g_assert_cmpint(addr.has_to, ==, exp_addr->has_to); + g_assert_cmpint(addr.to, ==, exp_addr->to); + g_assert_cmpint(addr.has_ipv4, ==, exp_addr->has_ipv4); + g_assert_cmpint(addr.ipv4, ==, exp_addr->ipv4); + g_assert_cmpint(addr.has_ipv6, ==, exp_addr->has_ipv6); + g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6); + g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive); + g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive); +#ifdef HAVE_IPPROTO_MPTCP + g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp); + g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp); +#endif + } + + g_free(addr.host); + g_free(addr.port); +} + +static void test_inet_parse_nohost_good(void) +{ + char host[] = ""; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + }; + inet_parse_test_helper(":5000", &exp_addr, true); +} + +static void test_inet_parse_empty_bad(void) +{ + inet_parse_test_helper("", NULL, false); +} + +static void test_inet_parse_only_colon_bad(void) +{ + inet_parse_test_helper(":", NULL, false); +} + +static void test_inet_parse_ipv4_good(void) +{ + char host[] = "127.0.0.1"; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + }; + inet_parse_test_helper("127.0.0.1:5000", &exp_addr, true); +} + +static void test_inet_parse_ipv4_noport_bad(void) +{ + inet_parse_test_helper("127.0.0.1", NULL, false); +} + +static void test_inet_parse_ipv6_good(void) +{ + char host[] = "::1"; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + }; + inet_parse_test_helper("[::1]:5000", &exp_addr, true); +} + +static void test_inet_parse_ipv6_noend_bad(void) +{ + inet_parse_test_helper("[::1", NULL, false); +} + +static void test_inet_parse_ipv6_noport_bad(void) +{ + inet_parse_test_helper("[::1]:", NULL, false); +} + +static void test_inet_parse_ipv6_empty_bad(void) +{ + inet_parse_test_helper("[]:5000", NULL, false); +} + +static void test_inet_parse_hostname_good(void) +{ + char host[] = "localhost"; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + }; + inet_parse_test_helper("localhost:5000", &exp_addr, true); +} + +static void test_inet_parse_all_options_good(void) +{ + char host[] = "::1"; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + .has_numeric = true, + .numeric = true, + .has_to = true, + .to = 5006, + .has_ipv4 = true, + .ipv4 = false, + .has_ipv6 = true, + .ipv6 = true, + .has_keep_alive = true, + .keep_alive = true, +#ifdef HAVE_IPPROTO_MPTCP + .has_mptcp = true, + .mptcp = false, +#endif + }; + inet_parse_test_helper( + "[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on" +#ifdef HAVE_IPPROTO_MPTCP + ",mptcp=off" +#endif + , &exp_addr, true); +} + +static void test_inet_parse_all_implicit_bool_good(void) +{ + char host[] = "::1"; + char port[] = "5000"; + InetSocketAddress exp_addr = { + .host = host, + .port = port, + .has_numeric = true, + .numeric = true, + .has_to = true, + .to = 5006, + .has_ipv4 = true, + .ipv4 = true, + .has_ipv6 = true, + .ipv6 = true, + .has_keep_alive = true, + .keep_alive = true, +#ifdef HAVE_IPPROTO_MPTCP + .has_mptcp = true, + .mptcp = true, +#endif + }; + inet_parse_test_helper( + "[::1]:5000,numeric,to=5006,ipv4,ipv6,keep-alive" +#ifdef HAVE_IPPROTO_MPTCP + ",mptcp" +#endif + , &exp_addr, true); +} + int main(int argc, char **argv) { bool has_ipv4, has_ipv6; @@ -377,6 +548,31 @@ int main(int argc, char **argv) test_socket_unix_abstract); #endif + g_test_add_func("/util/socket/inet-parse/nohost-good", + test_inet_parse_nohost_good); + g_test_add_func("/util/socket/inet-parse/empty-bad", + test_inet_parse_empty_bad); + g_test_add_func("/util/socket/inet-parse/only-colon-bad", + test_inet_parse_only_colon_bad); + g_test_add_func("/util/socket/inet-parse/ipv4-good", + test_inet_parse_ipv4_good); + g_test_add_func("/util/socket/inet-parse/ipv4-noport-bad", + test_inet_parse_ipv4_noport_bad); + g_test_add_func("/util/socket/inet-parse/ipv6-good", + test_inet_parse_ipv6_good); + g_test_add_func("/util/socket/inet-parse/ipv6-noend-bad", + test_inet_parse_ipv6_noend_bad); + g_test_add_func("/util/socket/inet-parse/ipv6-noport-bad", + test_inet_parse_ipv6_noport_bad); + g_test_add_func("/util/socket/inet-parse/ipv6-empty-bad", + test_inet_parse_ipv6_empty_bad); + g_test_add_func("/util/socket/inet-parse/hostname-good", + test_inet_parse_hostname_good); + g_test_add_func("/util/socket/inet-parse/all-options-good", + test_inet_parse_all_options_good); + g_test_add_func("/util/socket/inet-parse/all-bare-bool-good", + test_inet_parse_all_implicit_bool_good); + end: return g_test_run(); } diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 4fbf1ed5bf..403dc26b36 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -30,6 +30,7 @@ #include "qapi/qobject-input-visitor.h" #include "qapi/qobject-output-visitor.h" #include "qemu/cutils.h" +#include "qemu/option.h" #include "trace.h" #ifndef AI_ADDRCONFIG @@ -600,115 +601,104 @@ err: return -1; } -/* compatibility wrapper */ -static int inet_parse_flag(const char *flagname, const char *optstr, bool *val, - Error **errp) -{ - char *end; - size_t len; - - end = strstr(optstr, ","); - if (end) { - if (end[1] == ',') { /* Reject 'ipv6=on,,foo' */ - error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); - return -1; - } - len = end - optstr; - } else { - len = strlen(optstr); - } - if (len == 0 || (len == 3 && strncmp(optstr, "=on", len) == 0)) { - *val = true; - } else if (len == 4 && strncmp(optstr, "=off", len) == 0) { - *val = false; - } else { - error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr); - return -1; - } - return 0; -} +static QemuOptsList inet_opts = { + .name = "InetSocketAddress", + .head = QTAILQ_HEAD_INITIALIZER(inet_opts.head), + .implied_opt_name = "addr", + .desc = { + { + .name = "addr", + .type = QEMU_OPT_STRING, + }, + { + .name = "numeric", + .type = QEMU_OPT_BOOL, + }, + { + .name = "to", + .type = QEMU_OPT_NUMBER, + }, + { + .name = "ipv4", + .type = QEMU_OPT_BOOL, + }, + { + .name = "ipv6", + .type = QEMU_OPT_BOOL, + }, + { + .name = "keep-alive", + .type = QEMU_OPT_BOOL, + }, +#ifdef HAVE_IPPROTO_MPTCP + { + .name = "mptcp", + .type = QEMU_OPT_BOOL, + }, +#endif + { /* end of list */ } + }, +}; int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) { - const char *optstr, *h; - char host[65]; - char port[33]; - int to; - int pos; - char *begin; - + QemuOpts *opts = qemu_opts_parse(&inet_opts, str, true, errp); + if (!opts) { + return -1; + } memset(addr, 0, sizeof(*addr)); /* parse address */ - if (str[0] == ':') { - /* no host given */ - host[0] = '\0'; - if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) { - error_setg(errp, "error parsing port in address '%s'", str); - return -1; - } - } else if (str[0] == '[') { - /* IPv6 addr */ - if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) { - error_setg(errp, "error parsing IPv6 address '%s'", str); - return -1; - } - } else { - /* hostname or IPv4 addr */ - if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) { - error_setg(errp, "error parsing address '%s'", str); - return -1; - } + const char *addr_str = qemu_opt_get(opts, "addr"); + if (!addr_str) { + error_setg(errp, "error parsing address ''"); + return -1; + } + if (str[0] == '[') { + /* IPv6 addr */ + const char *ip_end = strstr(addr_str, "]:"); + if (!ip_end || ip_end - addr_str < 2 || strlen(ip_end) < 3) { + error_setg(errp, "error parsing IPv6 address '%s'", addr_str); + return -1; + } + addr->host = g_strndup(addr_str + 1, ip_end - addr_str - 1); + addr->port = g_strdup(ip_end + 2); + } else { + /* no host, hostname or IPv4 addr */ + const char *port = strchr(addr_str, ':'); + if (!port || strlen(port) < 2) { + error_setg(errp, "error parsing address '%s'", addr_str); + return -1; + } + addr->host = g_strndup(addr_str, port - addr_str); + addr->port = g_strdup(port + 1); } - - addr->host = g_strdup(host); - addr->port = g_strdup(port); /* parse options */ - optstr = str + pos; - h = strstr(optstr, ",to="); - if (h) { - h += 4; - if (sscanf(h, "%d%n", &to, &pos) != 1 || - (h[pos] != '\0' && h[pos] != ',')) { - error_setg(errp, "error parsing to= argument"); - return -1; - } + if (qemu_opt_find(opts, "numeric")) { + addr->has_numeric = true, + addr->numeric = qemu_opt_get_bool(opts, "numeric", false); + } + if (qemu_opt_find(opts, "to")) { addr->has_to = true; - addr->to = to; + addr->to = qemu_opt_get_number(opts, "to", 0); } - begin = strstr(optstr, ",ipv4"); - if (begin) { - if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) { - return -1; - } + if (qemu_opt_find(opts, "ipv4")) { addr->has_ipv4 = true; + addr->ipv4 = qemu_opt_get_bool(opts, "ipv4", false); } - begin = strstr(optstr, ",ipv6"); - if (begin) { - if (inet_parse_flag("ipv6", begin + 5, &addr->ipv6, errp) < 0) { - return -1; - } + if (qemu_opt_find(opts, "ipv6")) { addr->has_ipv6 = true; + addr->ipv6 = qemu_opt_get_bool(opts, "ipv6", false); } - begin = strstr(optstr, ",keep-alive"); - if (begin) { - if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"), - &addr->keep_alive, errp) < 0) - { - return -1; - } + if (qemu_opt_find(opts, "keep-alive")) { addr->has_keep_alive = true; + addr->keep_alive = qemu_opt_get_bool(opts, "keep-alive", false); } #ifdef HAVE_IPPROTO_MPTCP - begin = strstr(optstr, ",mptcp"); - if (begin) { - if (inet_parse_flag("mptcp", begin + strlen(",mptcp"), - &addr->mptcp, errp) < 0) - { - return -1; - } + if (qemu_opt_find(opts, "mptcp")) { addr->has_mptcp = true; + addr->mptcp = qemu_opt_get_bool(opts, "mptcp", 0); } #endif return 0; From 1bd4237cb1095d71c16afad3ce93b4a1e453173e Mon Sep 17 00:00:00 2001 From: Juraj Marcin Date: Wed, 21 May 2025 15:52:35 +0200 Subject: [PATCH 1088/2760] util/qemu-sockets: Introduce inet socket options controlling TCP keep-alive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the default TCP stack configuration, it could be even 2 hours before the connection times out due to the other side not being reachable. However, in some cases, the application needs to be aware of a connection issue much sooner. This is the case, for example, for postcopy live migration. If there is no traffic from the migration destination guest (server-side) to the migration source guest (client-side), the destination keeps waiting for pages indefinitely and does not switch to the postcopy-paused state. This can happen, for example, if the destination QEMU instance is started with the '-S' command line option and the machine is not started yet, or if the machine is idle and produces no new page faults for not-yet-migrated pages. This patch introduces new inet socket parameters that control count, idle period, and interval of TCP keep-alive packets before the connection is considered broken. These parameters are available on systems where the respective TCP socket options are defined, that includes Linux, Windows, macOS, but not OpenBSD. Additionally, macOS defines TCP_KEEPIDLE as TCP_KEEPALIVE instead, so the patch supplies its own definition. The default value for all is 0, which means the system configuration is used. Signed-off-by: Juraj Marcin Reviewed-by: Daniel P. Berrangé Signed-off-by: Daniel P. Berrangé --- meson.build | 30 +++++++++++++ qapi/sockets.json | 19 ++++++++ tests/unit/test-util-sockets.c | 39 +++++++++++++++++ util/qemu-sockets.c | 80 ++++++++++++++++++++++++++++++++++ 4 files changed, 168 insertions(+) diff --git a/meson.build b/meson.build index ad2053f968..fdad3fb528 100644 --- a/meson.build +++ b/meson.build @@ -2760,6 +2760,36 @@ if linux_io_uring.found() config_host_data.set('HAVE_IO_URING_PREP_WRITEV2', cc.has_header_symbol('liburing.h', 'io_uring_prep_writev2')) endif +config_host_data.set('HAVE_TCP_KEEPCNT', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT') or + cc.compiles(''' + #include + #ifndef TCP_KEEPCNT + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPCNT')) +# On Darwin TCP_KEEPIDLE is available under different name, TCP_KEEPALIVE. +# https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172 +config_host_data.set('HAVE_TCP_KEEPIDLE', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE') or + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPALIVE') or + cc.compiles(''' + #include + #ifndef TCP_KEEPIDLE + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPIDLE')) +config_host_data.set('HAVE_TCP_KEEPINTVL', + cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL') or + cc.compiles(''' + #include + #ifndef TCP_KEEPINTVL + #error + #endif + int main(void) { return 0; }''', + name: 'Win32 TCP_KEEPINTVL')) # has_member config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID', diff --git a/qapi/sockets.json b/qapi/sockets.json index 62797cd027..f9f559daba 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -59,6 +59,22 @@ # @keep-alive: enable keep-alive when connecting to/listening on this socket. # (Since 4.2, not supported for listening sockets until 10.1) # +# @keep-alive-count: number of keep-alive packets sent before the connection is +# closed. Only supported for TCP sockets on systems where TCP_KEEPCNT +# socket option is defined (this includes Linux, Windows, macOS, FreeBSD, +# but not OpenBSD). When set to 0, system setting is used. (Since 10.1) +# +# @keep-alive-idle: time in seconds the connection needs to be idle before +# sending a keepalive packet. Only supported for TCP sockets on systems +# where TCP_KEEPIDLE socket option is defined (this includes Linux, +# Windows, macOS, FreeBSD, but not OpenBSD). When set to 0, system setting +# is used. (Since 10.1) +# +# @keep-alive-interval: time in seconds between keep-alive packets. Only +# supported for TCP sockets on systems where TCP_KEEPINTVL is defined (this +# includes Linux, Windows, macOS, FreeBSD, but not OpenBSD). When set to +# 0, system setting is used. (Since 10.1) +# # @mptcp: enable multi-path TCP. (Since 6.1) # # Since: 1.3 @@ -71,6 +87,9 @@ '*ipv4': 'bool', '*ipv6': 'bool', '*keep-alive': 'bool', + '*keep-alive-count': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPCNT' }, + '*keep-alive-idle': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPIDLE' }, + '*keep-alive-interval': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPINTVL' }, '*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } } ## diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index 9e39b92e7c..8492f4d68f 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -359,6 +359,24 @@ static void inet_parse_test_helper(const char *str, g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6); g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive); g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive); +#ifdef HAVE_TCP_KEEPCNT + g_assert_cmpint(addr.has_keep_alive_count, ==, + exp_addr->has_keep_alive_count); + g_assert_cmpint(addr.keep_alive_count, ==, + exp_addr->keep_alive_count); +#endif +#ifdef HAVE_TCP_KEEPIDLE + g_assert_cmpint(addr.has_keep_alive_idle, ==, + exp_addr->has_keep_alive_idle); + g_assert_cmpint(addr.keep_alive_idle, ==, + exp_addr->keep_alive_idle); +#endif +#ifdef HAVE_TCP_KEEPINTVL + g_assert_cmpint(addr.has_keep_alive_interval, ==, + exp_addr->has_keep_alive_interval); + g_assert_cmpint(addr.keep_alive_interval, ==, + exp_addr->keep_alive_interval); +#endif #ifdef HAVE_IPPROTO_MPTCP g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp); g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp); @@ -460,6 +478,18 @@ static void test_inet_parse_all_options_good(void) .ipv6 = true, .has_keep_alive = true, .keep_alive = true, +#ifdef HAVE_TCP_KEEPCNT + .has_keep_alive_count = true, + .keep_alive_count = 10, +#endif +#ifdef HAVE_TCP_KEEPIDLE + .has_keep_alive_idle = true, + .keep_alive_idle = 60, +#endif +#ifdef HAVE_TCP_KEEPINTVL + .has_keep_alive_interval = true, + .keep_alive_interval = 30, +#endif #ifdef HAVE_IPPROTO_MPTCP .has_mptcp = true, .mptcp = false, @@ -467,6 +497,15 @@ static void test_inet_parse_all_options_good(void) }; inet_parse_test_helper( "[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on" +#ifdef HAVE_TCP_KEEPCNT + ",keep-alive-count=10" +#endif +#ifdef HAVE_TCP_KEEPIDLE + ",keep-alive-idle=60" +#endif +#ifdef HAVE_TCP_KEEPINTVL + ",keep-alive-interval=30" +#endif #ifdef HAVE_IPPROTO_MPTCP ",mptcp=off" #endif diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 403dc26b36..4773755fd5 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -45,6 +45,14 @@ # define AI_NUMERICSERV 0 #endif +/* + * On macOS TCP_KEEPIDLE is available under a different name, TCP_KEEPALIVE. + * https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172 + */ +#if defined(TCP_KEEPALIVE) && !defined(TCP_KEEPIDLE) +# define TCP_KEEPIDLE TCP_KEEPALIVE +#endif + static int inet_getport(struct addrinfo *e) { @@ -218,6 +226,42 @@ static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp) "Unable to set keep-alive option on socket"); return -1; } +#ifdef HAVE_TCP_KEEPCNT + if (saddr->has_keep_alive_count && saddr->keep_alive_count) { + int keep_count = saddr->keep_alive_count; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_count, + sizeof(keep_count)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive count option on socket"); + return -1; + } + } +#endif +#ifdef HAVE_TCP_KEEPIDLE + if (saddr->has_keep_alive_idle && saddr->keep_alive_idle) { + int keep_idle = saddr->keep_alive_idle; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle, + sizeof(keep_idle)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive idle option on socket"); + return -1; + } + } +#endif +#ifdef HAVE_TCP_KEEPINTVL + if (saddr->has_keep_alive_interval && saddr->keep_alive_interval) { + int keep_interval = saddr->keep_alive_interval; + ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval, + sizeof(keep_interval)); + if (ret < 0) { + error_setg_errno(errp, errno, + "Unable to set TCP keep-alive interval option on socket"); + return -1; + } + } +#endif } return 0; } @@ -630,6 +674,24 @@ static QemuOptsList inet_opts = { .name = "keep-alive", .type = QEMU_OPT_BOOL, }, +#ifdef HAVE_TCP_KEEPCNT + { + .name = "keep-alive-count", + .type = QEMU_OPT_NUMBER, + }, +#endif +#ifdef HAVE_TCP_KEEPIDLE + { + .name = "keep-alive-idle", + .type = QEMU_OPT_NUMBER, + }, +#endif +#ifdef HAVE_TCP_KEEPINTVL + { + .name = "keep-alive-interval", + .type = QEMU_OPT_NUMBER, + }, +#endif #ifdef HAVE_IPPROTO_MPTCP { .name = "mptcp", @@ -695,6 +757,24 @@ int inet_parse(InetSocketAddress *addr, const char *str, Error **errp) addr->has_keep_alive = true; addr->keep_alive = qemu_opt_get_bool(opts, "keep-alive", false); } +#ifdef HAVE_TCP_KEEPCNT + if (qemu_opt_find(opts, "keep-alive-count")) { + addr->has_keep_alive_count = true; + addr->keep_alive_count = qemu_opt_get_number(opts, "keep-alive-count", 0); + } +#endif +#ifdef HAVE_TCP_KEEPIDLE + if (qemu_opt_find(opts, "keep-alive-idle")) { + addr->has_keep_alive_idle = true; + addr->keep_alive_idle = qemu_opt_get_number(opts, "keep-alive-idle", 0); + } +#endif +#ifdef HAVE_TCP_KEEPINTVL + if (qemu_opt_find(opts, "keep-alive-interval")) { + addr->has_keep_alive_interval = true; + addr->keep_alive_interval = qemu_opt_get_number(opts, "keep-alive-interval", 0); + } +#endif #ifdef HAVE_IPPROTO_MPTCP if (qemu_opt_find(opts, "mptcp")) { addr->has_mptcp = true; From 81941aa896b718c194f08cebb4303561b64c60b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Wed, 21 May 2025 09:47:00 +0100 Subject: [PATCH 1089/2760] scripts/checkpatch.pl: mandate SPDX tag for Rust src files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Manos Pitsidianakis Signed-off-by: Daniel P. Berrangé --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9291bc9209..833f20f555 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1499,7 +1499,7 @@ sub process_end_of_file { if ($fileinfo->{action} eq "new" && !exists $fileinfo->{facts}->{sawspdx}) { if ($fileinfo->{filenew} =~ - /(\.(c|h|py|pl|sh|json|inc)|Makefile.*)$/) { + /(\.(c|h|py|pl|sh|json|inc|rs)|Makefile.*)$/) { # source code files MUST have SPDX license declared ERROR("New file '" . $fileinfo->{filenew} . "' requires 'SPDX-License-Identifier'"); From ff2ab634e4bb3bddcf5f5ee29e0b46f71e3f4b54 Mon Sep 17 00:00:00 2001 From: Denis Rastyogin Date: Tue, 6 May 2025 17:13:37 +0300 Subject: [PATCH 1090/2760] qemu-img: fix offset calculation in bench This error was discovered by fuzzing qemu-img. The current offset calculation leads to an EIO error in block/block-backend.c: blk_check_byte_request(): if (offset > len || len - offset < bytes) { return -EIO; } This triggers the error message: "qemu-img: Failed request: Input/output error". Example of the issue: offset: 260076 len: 260096 bytes: 4096 This fix ensures that offset remains within a valid range. Signed-off-by: Denis Rastyogin Message-ID: <20250506141410.100119-1-gerben@altlinux.org> [kwolf: Fixed up integer overflow] Signed-off-by: Kevin Wolf --- qemu-img.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu-img.c b/qemu-img.c index 76ac5d3028..139eeb5039 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -4488,10 +4488,10 @@ static void bench_cb(void *opaque, int ret) */ b->in_flight++; b->offset += b->step; - if (b->image_size == 0) { + if (b->image_size <= b->bufsize) { b->offset = 0; } else { - b->offset %= b->image_size; + b->offset %= b->image_size - b->bufsize; } if (b->write) { acb = blk_aio_pwritev(b->blk, offset, b->qiov, 0, bench_cb, b); From 5634622bcb339f213469eceeff005640492fc902 Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Thu, 17 Apr 2025 17:10:53 -0400 Subject: [PATCH 1091/2760] file-posix: allow BLKZEROOUT with -t writeback The Linux BLKZEROOUT ioctl is only invoked when BDRV_O_NOCACHE is set because old kernels did not invalidate the page cache. In that case mixing BLKZEROOUT with buffered I/O could lead to corruption. However, Linux 4.9 commit 22dd6d356628 ("block: invalidate the page cache when issuing BLKZEROOUT") made BLKZEROOUT coherent with the page cache. I have checked that Linux 4.9+ kernels are shipped at least as far back as Debian 10 (buster), openSUSE Leap 15.2, and RHEL/CentOS 8. Use BLKZEROOUT with buffered I/O, mostly so `qemu-img ... -t writeback` can offload write zeroes. Cc: Paolo Bonzini Cc: Christoph Hellwig Signed-off-by: Stefan Hajnoczi Message-ID: <20250417211053.98700-1-stefanha@redhat.com> Reviewed-by: Eric Blake Reviewed-by: Kevin Wolf Signed-off-by: Kevin Wolf --- block/file-posix.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index ec95b74869..5a3532e40b 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -785,17 +785,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } #endif - if (S_ISBLK(st.st_mode)) { -#ifdef __linux__ - /* On Linux 3.10, BLKDISCARD leaves stale data in the page cache. Do - * not rely on the contents of discarded blocks unless using O_DIRECT. - * Same for BLKZEROOUT. - */ - if (!(bs->open_flags & BDRV_O_NOCACHE)) { - s->has_write_zeroes = false; - } -#endif - } #ifdef __FreeBSD__ if (S_ISCHR(st.st_mode)) { /* From bf627788ef17721955bfcfba84209a07ae5f54ea Mon Sep 17 00:00:00 2001 From: Kevin Wolf Date: Thu, 22 May 2025 15:08:03 +0200 Subject: [PATCH 1092/2760] file-posix: Probe paths and retry SG_IO on potential path errors When scsi-block is used on a host multipath device, it runs into the problem that the kernel dm-mpath doesn't know anything about SCSI or SG_IO and therefore can't decide if a SG_IO request returned an error and needs to be retried on a different path. Instead of getting working failover, an error is returned to scsi-block and handled according to the configured error policy. Obviously, this is not what users want, they want working failover. QEMU can parse the SG_IO result and determine whether this could have been a path error, but just retrying the same request could just send it to the same failing path again and result in the same error. With a kernel that supports the DM_MPATH_PROBE_PATHS ioctl on dm-mpath block devices (queued in the device mapper tree for Linux 6.16), we can tell the kernel to probe all paths and tell us if any usable paths remained. If so, we can now retry the SG_IO ioctl and expect it to be sent to a working path. Signed-off-by: Kevin Wolf Message-ID: <20250522130803.34738-1-kwolf@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Hanna Czenczek Signed-off-by: Kevin Wolf --- block/file-posix.c | 115 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/block/file-posix.c b/block/file-posix.c index 5a3532e40b..9b5f08ccb2 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -41,6 +41,7 @@ #include "scsi/pr-manager.h" #include "scsi/constants.h" +#include "scsi/utils.h" #if defined(__APPLE__) && (__MACH__) #include @@ -72,6 +73,7 @@ #include #endif #include +#include #include #include #include @@ -138,6 +140,22 @@ #define RAW_LOCK_PERM_BASE 100 #define RAW_LOCK_SHARED_BASE 200 +/* + * Multiple retries are mostly meant for two separate scenarios: + * + * - DM_MPATH_PROBE_PATHS returns success, but before SG_IO completes, another + * path goes down. + * + * - DM_MPATH_PROBE_PATHS failed all paths in the current path group, so we have + * to send another SG_IO to switch to another path group to probe the paths in + * it. + * + * Even if each path is in a separate path group (path_grouping_policy set to + * failover), it's rare to have more than eight path groups - and even then + * pretty unlikely that only bad path groups would be chosen in eight retries. + */ +#define SG_IO_MAX_RETRIES 8 + typedef struct BDRVRawState { int fd; bool use_lock; @@ -165,6 +183,7 @@ typedef struct BDRVRawState { bool use_linux_aio:1; bool has_laio_fdsync:1; bool use_linux_io_uring:1; + bool use_mpath:1; int page_cache_inconsistent; /* errno from fdatasync failure */ bool has_fallocate; bool needs_alignment; @@ -4253,15 +4272,105 @@ hdev_open_Mac_error: /* Since this does ioctl the device must be already opened */ bs->sg = hdev_is_sg(bs); + /* sg devices aren't even block devices and can't use dm-mpath */ + s->use_mpath = !bs->sg; + return ret; } #if defined(__linux__) +#if defined(DM_MPATH_PROBE_PATHS) +static bool coroutine_fn sgio_path_error(int ret, sg_io_hdr_t *io_hdr) +{ + if (ret < 0) { + switch (ret) { + case -ENODEV: + return true; + case -EAGAIN: + /* + * The device is probably suspended. This happens while the dm table + * is reloaded, e.g. because a path is added or removed. This is an + * operation that should complete within 1ms, so just wait a bit and + * retry. + * + * If the device was suspended for another reason, we'll wait and + * retry SG_IO_MAX_RETRIES times. This is a tolerable delay before + * we return an error and potentially stop the VM. + */ + qemu_co_sleep_ns(QEMU_CLOCK_REALTIME, 1000000); + return true; + default: + return false; + } + } + + if (io_hdr->host_status != SCSI_HOST_OK) { + return true; + } + + switch (io_hdr->status) { + case GOOD: + case CONDITION_GOOD: + case INTERMEDIATE_GOOD: + case INTERMEDIATE_C_GOOD: + case RESERVATION_CONFLICT: + case COMMAND_TERMINATED: + return false; + case CHECK_CONDITION: + return !scsi_sense_buf_is_guest_recoverable(io_hdr->sbp, + io_hdr->mx_sb_len); + default: + return true; + } +} + +static bool coroutine_fn hdev_co_ioctl_sgio_retry(RawPosixAIOData *acb, int ret) +{ + BDRVRawState *s = acb->bs->opaque; + RawPosixAIOData probe_acb; + + if (!s->use_mpath) { + return false; + } + + if (!sgio_path_error(ret, acb->ioctl.buf)) { + return false; + } + + probe_acb = (RawPosixAIOData) { + .bs = acb->bs, + .aio_type = QEMU_AIO_IOCTL, + .aio_fildes = s->fd, + .aio_offset = 0, + .ioctl = { + .buf = NULL, + .cmd = DM_MPATH_PROBE_PATHS, + }, + }; + + ret = raw_thread_pool_submit(handle_aiocb_ioctl, &probe_acb); + if (ret == -ENOTTY) { + s->use_mpath = false; + } else if (ret == -EAGAIN) { + /* The device might be suspended for a table reload, worth retrying */ + return true; + } + + return ret == 0; +} +#else +static bool coroutine_fn hdev_co_ioctl_sgio_retry(RawPosixAIOData *acb, int ret) +{ + return false; +} +#endif /* DM_MPATH_PROBE_PATHS */ + static int coroutine_fn hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) { BDRVRawState *s = bs->opaque; RawPosixAIOData acb; + int retries = SG_IO_MAX_RETRIES; int ret; ret = fd_open(bs); @@ -4289,7 +4398,11 @@ hdev_co_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) }, }; - return raw_thread_pool_submit(handle_aiocb_ioctl, &acb); + do { + ret = raw_thread_pool_submit(handle_aiocb_ioctl, &acb); + } while (req == SG_IO && retries-- && hdev_co_ioctl_sgio_retry(&acb, ret)); + + return ret; } #endif /* linux */ From bf53e2023271cfea80d7cae1d92143181fa547b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 17:51:10 +0400 Subject: [PATCH 1093/2760] ui/gtk: warn if setting the clipboard failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just in case. Reviewed-by: Daniel P. Berrangé Signed-off-by: Marc-André Lureau --- ui/gtk-clipboard.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/ui/gtk-clipboard.c b/ui/gtk-clipboard.c index 8d8a636fd1..65d89ec601 100644 --- a/ui/gtk-clipboard.c +++ b/ui/gtk-clipboard.c @@ -19,6 +19,7 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" #include "qemu/main-loop.h" #include "ui/gtk.h" @@ -95,11 +96,13 @@ static void gd_clipboard_update_info(GtkDisplayState *gd, gtk_clipboard_clear(gd->gtkcb[s]); if (targets) { gd->cbowner[s] = true; - gtk_clipboard_set_with_data(gd->gtkcb[s], - targets, n_targets, - gd_clipboard_get_data, - gd_clipboard_clear, - gd); + if (!gtk_clipboard_set_with_data(gd->gtkcb[s], + targets, n_targets, + gd_clipboard_get_data, + gd_clipboard_clear, + gd)) { + warn_report("Failed to set GTK clipboard"); + } gtk_target_table_free(targets, n_targets); } From acc6a94a812cd1337785413b27580f8a8f4ac170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 17:52:14 +0400 Subject: [PATCH 1094/2760] ui/clipboard: use int for selection field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to use a VMSTATE_INT32 field for migration purposes. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- include/ui/clipboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h index ab6acdbd8a..14b6099e73 100644 --- a/include/ui/clipboard.h +++ b/include/ui/clipboard.h @@ -112,7 +112,7 @@ struct QemuClipboardNotify { struct QemuClipboardInfo { uint32_t refcount; QemuClipboardPeer *owner; - QemuClipboardSelection selection; + int selection; /* QemuClipboardSelection */ bool has_serial; uint32_t serial; struct { From a3f59c70d6c943e3a4d9c44ed138fa15c5ded70b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 17:53:06 +0400 Subject: [PATCH 1095/2760] ui/clipboard: split out QemuClipboardContent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allows to use VMSTATE STRUCT in following migration support patch. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- include/ui/clipboard.h | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h index 14b6099e73..88cfff91ef 100644 --- a/include/ui/clipboard.h +++ b/include/ui/clipboard.h @@ -25,6 +25,7 @@ typedef enum QemuClipboardSelection QemuClipboardSelection; typedef struct QemuClipboardPeer QemuClipboardPeer; typedef struct QemuClipboardNotify QemuClipboardNotify; typedef struct QemuClipboardInfo QemuClipboardInfo; +typedef struct QemuClipboardContent QemuClipboardContent; /** * enum QemuClipboardType @@ -97,6 +98,24 @@ struct QemuClipboardNotify { }; }; + +/** + * struct QemuClipboardContent + * + * @available: whether the data is available + * @requested: whether the data was requested + * @size: the size of the @data + * @data: the clipboard data + * + * Clipboard content. + */ +struct QemuClipboardContent { + bool available; + bool requested; + uint32_t size; + void *data; +}; + /** * struct QemuClipboardInfo * @@ -115,12 +134,7 @@ struct QemuClipboardInfo { int selection; /* QemuClipboardSelection */ bool has_serial; uint32_t serial; - struct { - bool available; - bool requested; - size_t size; - void *data; - } types[QEMU_CLIPBOARD_TYPE__COUNT]; + QemuClipboardContent types[QEMU_CLIPBOARD_TYPE__COUNT]; }; /** From d0de94cbc053c4475fbf705cafa1ab488eae3a19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 17:55:21 +0400 Subject: [PATCH 1096/2760] ui/clipboard: add vmstate_cbinfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a VMStateDescriptor for QemuClipboardInfo. Each clipboard owner will have to save its QemuClipboardInfo and reregister its owned clipboard after loading. (the global cbinfo has only pointers to owners, so it can't restore the relation with its owner if it was to handle migration) Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- include/ui/clipboard.h | 3 +++ ui/clipboard.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/ui/clipboard.h b/include/ui/clipboard.h index 88cfff91ef..62a96ce9ff 100644 --- a/include/ui/clipboard.h +++ b/include/ui/clipboard.h @@ -2,6 +2,7 @@ #define QEMU_CLIPBOARD_H #include "qemu/notify.h" +#include "migration/vmstate.h" /** * DOC: Introduction @@ -27,6 +28,8 @@ typedef struct QemuClipboardNotify QemuClipboardNotify; typedef struct QemuClipboardInfo QemuClipboardInfo; typedef struct QemuClipboardContent QemuClipboardContent; +extern const VMStateDescription vmstate_cbinfo; + /** * enum QemuClipboardType * diff --git a/ui/clipboard.c b/ui/clipboard.c index 132086eb13..f5db60c63d 100644 --- a/ui/clipboard.c +++ b/ui/clipboard.c @@ -7,6 +7,32 @@ static NotifierList clipboard_notifiers = static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT]; +static const VMStateDescription vmstate_cbcontent = { + .name = "clipboard/content", + .version_id = 0, + .minimum_version_id = 0, + .fields = (const VMStateField[]) { + VMSTATE_BOOL(available, QemuClipboardContent), + VMSTATE_BOOL(requested, QemuClipboardContent), + VMSTATE_UINT32(size, QemuClipboardContent), + VMSTATE_VBUFFER_ALLOC_UINT32(data, QemuClipboardContent, 0, 0, size), + VMSTATE_END_OF_LIST() + } +}; + +const VMStateDescription vmstate_cbinfo = { + .name = "clipboard", + .version_id = 0, + .minimum_version_id = 0, + .fields = (const VMStateField[]) { + VMSTATE_INT32(selection, QemuClipboardInfo), + VMSTATE_BOOL(has_serial, QemuClipboardInfo), + VMSTATE_UINT32(serial, QemuClipboardInfo), + VMSTATE_STRUCT_ARRAY(types, QemuClipboardInfo, QEMU_CLIPBOARD_TYPE__COUNT, 0, vmstate_cbcontent, QemuClipboardContent), + VMSTATE_END_OF_LIST() + } +}; + void qemu_clipboard_peer_register(QemuClipboardPeer *peer) { notifier_list_add(&clipboard_notifiers, &peer->notifier); From c967ff606b99f5f4ecc16817b9d9604a9c943dd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 18:51:08 +0400 Subject: [PATCH 1097/2760] ui/clipboard: delay clipboard update when not running MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When VM is paused, we shouldn't notify of clipboard changes, similar to how input are being treated. On unsuspend, notify of the current state. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/clipboard.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/ui/clipboard.c b/ui/clipboard.c index f5db60c63d..ec00a0b8ec 100644 --- a/ui/clipboard.c +++ b/ui/clipboard.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "system/runstate.h" #include "ui/clipboard.h" #include "trace.h" @@ -7,6 +8,10 @@ static NotifierList clipboard_notifiers = static QemuClipboardInfo *cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT]; +static VMChangeStateEntry *cb_change_state_entry = NULL; + +static bool cb_reset_serial_on_resume = false; + static const VMStateDescription vmstate_cbcontent = { .name = "clipboard/content", .version_id = 0, @@ -33,8 +38,32 @@ const VMStateDescription vmstate_cbinfo = { } }; +static void qemu_clipboard_change_state(void *opaque, bool running, RunState state) +{ + int i; + + if (!running) { + return; + } + + if (cb_reset_serial_on_resume) { + qemu_clipboard_reset_serial(); + } + + for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) { + if (cbinfo[i]) { + qemu_clipboard_update(cbinfo[i]); + } + } + +} + void qemu_clipboard_peer_register(QemuClipboardPeer *peer) { + if (cb_change_state_entry == NULL) { + cb_change_state_entry = qemu_add_vm_change_state_handler(qemu_clipboard_change_state, NULL); + } + notifier_list_add(&clipboard_notifiers, &peer->notifier); } @@ -109,7 +138,9 @@ void qemu_clipboard_update(QemuClipboardInfo *info) } } - notifier_list_notify(&clipboard_notifiers, ¬ify); + if (runstate_is_running() || runstate_check(RUN_STATE_SUSPENDED)) { + notifier_list_notify(&clipboard_notifiers, ¬ify); + } if (cbinfo[info->selection] != info) { qemu_clipboard_info_unref(cbinfo[info->selection]); @@ -189,7 +220,12 @@ void qemu_clipboard_reset_serial(void) info->serial = 0; } } - notifier_list_notify(&clipboard_notifiers, ¬ify); + + if (runstate_is_running() || runstate_check(RUN_STATE_SUSPENDED)) { + notifier_list_notify(&clipboard_notifiers, ¬ify); + } else { + cb_reset_serial_on_resume = true; + } } void qemu_clipboard_set_data(QemuClipboardPeer *peer, From ac5e2bc910d350cd0653b8d049518d642ee14a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 10 Mar 2025 15:26:25 +0400 Subject: [PATCH 1098/2760] ui/vdagent: replace Buffer with GByteArray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Buffer is slightly more advanced than GByteArray, since it has a cursor/position. But vdagent code doesn't need it. This simplify a bit the code, and migration state. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/vdagent.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/ui/vdagent.c b/ui/vdagent.c index 04513ded29..4027126b7d 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -47,7 +47,7 @@ struct VDAgentChardev { uint32_t msgsize; uint8_t *xbuf; uint32_t xoff, xsize; - Buffer outbuf; + GByteArray *outbuf; /* mouse */ DeviceState mouse_dev; @@ -142,16 +142,16 @@ static void vdagent_send_buf(VDAgentChardev *vd) { uint32_t len; - while (!buffer_empty(&vd->outbuf)) { + while (vd->outbuf->len) { len = qemu_chr_be_can_write(CHARDEV(vd)); if (len == 0) { return; } - if (len > vd->outbuf.offset) { - len = vd->outbuf.offset; + if (len > vd->outbuf->len) { + len = vd->outbuf->len; } - qemu_chr_be_write(CHARDEV(vd), vd->outbuf.buffer, len); - buffer_advance(&vd->outbuf, len); + qemu_chr_be_write(CHARDEV(vd), vd->outbuf->data, len); + g_byte_array_remove_range(vd->outbuf, 0, len); } } @@ -166,7 +166,7 @@ static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg) msg->protocol = VD_AGENT_PROTOCOL; - if (vd->outbuf.offset + msgsize > VDAGENT_BUFFER_LIMIT) { + if (vd->outbuf->len + msgsize > VDAGENT_BUFFER_LIMIT) { error_report("buffer full, dropping message"); return; } @@ -177,9 +177,8 @@ static void vdagent_send_msg(VDAgentChardev *vd, VDAgentMessage *msg) if (chunk.size > 1024) { chunk.size = 1024; } - buffer_reserve(&vd->outbuf, sizeof(chunk) + chunk.size); - buffer_append(&vd->outbuf, &chunk, sizeof(chunk)); - buffer_append(&vd->outbuf, msgbuf + msgoff, chunk.size); + g_byte_array_append(vd->outbuf, (void *)&chunk, sizeof(chunk)); + g_byte_array_append(vd->outbuf, msgbuf + msgoff, chunk.size); msgoff += chunk.size; } vdagent_send_buf(vd); @@ -859,7 +858,7 @@ static void vdagent_disconnect(VDAgentChardev *vd) { trace_vdagent_disconnect(); - buffer_reset(&vd->outbuf); + g_byte_array_set_size(vd->outbuf, 0); vdagent_reset_bufs(vd); vd->caps = 0; if (vd->mouse_hs) { @@ -920,7 +919,7 @@ static void vdagent_chr_init(Object *obj) { VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); - buffer_init(&vd->outbuf, "vdagent-outbuf"); + vd->outbuf = g_byte_array_new(); error_setg(&vd->migration_blocker, "The vdagent chardev doesn't yet support migration"); } @@ -934,7 +933,7 @@ static void vdagent_chr_fini(Object *obj) if (vd->mouse_hs) { qemu_input_handler_unregister(vd->mouse_hs); } - buffer_free(&vd->outbuf); + g_clear_pointer(&vd->outbuf, g_byte_array_unref); } static const TypeInfo vdagent_chr_type_info = { From 688ff4cbdf4993c60ee250afc48e15c0880f28de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 18:00:14 +0400 Subject: [PATCH 1099/2760] ui/vdagent: keep "connected" state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During post-load of migration, virtio will notify of fe_open state. However vdagent code will handle this as a reconnection. This will trigger a connection reset/caps with the agent. Check if the state actually changed before resetting the connection. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/vdagent.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ui/vdagent.c b/ui/vdagent.c index 4027126b7d..210b8c14ca 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -40,6 +40,7 @@ struct VDAgentChardev { bool clipboard; /* guest vdagent */ + bool connected; uint32_t caps; VDIChunkHeader chunk; uint32_t chunksize; @@ -858,6 +859,7 @@ static void vdagent_disconnect(VDAgentChardev *vd) { trace_vdagent_disconnect(); + vd->connected = false; g_byte_array_set_size(vd->outbuf, 0); vdagent_reset_bufs(vd); vd->caps = 0; @@ -876,6 +878,10 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open) trace_vdagent_fe_open(fe_open); + if (vd->connected == fe_open) { + return; + } + if (!fe_open) { trace_vdagent_close(); vdagent_disconnect(vd); @@ -885,6 +891,7 @@ static void vdagent_chr_set_fe_open(struct Chardev *chr, int fe_open) return; } + vd->connected = true; vdagent_send_caps(vd, true); } From f626116f9897b95f68e5514a08098d590349c22e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 18:03:47 +0400 Subject: [PATCH 1100/2760] ui/vdagent: factor out clipboard peer registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows common code reuse during migration. Note that resetting the serial is now done regardless if the clipboard peer was registered or not. This should still be correct. Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/vdagent.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/ui/vdagent.c b/ui/vdagent.c index 210b8c14ca..fcbd7b167b 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -694,6 +694,18 @@ static void vdagent_chr_open(Chardev *chr, *be_opened = true; } +static void vdagent_clipboard_peer_register(VDAgentChardev *vd) +{ + if (vd->cbpeer.notifier.notify != NULL) { + return; + } + + vd->cbpeer.name = "vdagent"; + vd->cbpeer.notifier.notify = vdagent_clipboard_notify; + vd->cbpeer.request = vdagent_clipboard_request; + qemu_clipboard_peer_register(&vd->cbpeer); +} + static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg) { VDAgentAnnounceCapabilities *caps = (void *)msg->data; @@ -720,13 +732,9 @@ static void vdagent_chr_recv_caps(VDAgentChardev *vd, VDAgentMessage *msg) memset(vd->last_serial, 0, sizeof(vd->last_serial)); - if (have_clipboard(vd) && vd->cbpeer.notifier.notify == NULL) { + if (have_clipboard(vd)) { qemu_clipboard_reset_serial(); - - vd->cbpeer.name = "vdagent"; - vd->cbpeer.notifier.notify = vdagent_clipboard_notify; - vd->cbpeer.request = vdagent_clipboard_request; - qemu_clipboard_peer_register(&vd->cbpeer); + vdagent_clipboard_peer_register(vd); } } From 5d56bff11e3d7fdbbf7fda6c9a8ebd0d6b7a7bac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Tue, 11 Mar 2025 18:32:10 +0400 Subject: [PATCH 1101/2760] ui/vdagent: add migration support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/vdagent.c | 142 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/ui/vdagent.c b/ui/vdagent.c index fcbd7b167b..adc8755bd9 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -10,6 +10,7 @@ #include "ui/clipboard.h" #include "ui/console.h" #include "ui/input.h" +#include "migration/vmstate.h" #include "trace.h" #include "qapi/qapi-types-char.h" @@ -930,6 +931,146 @@ static void vdagent_chr_class_init(ObjectClass *oc, const void *data) cc->chr_accept_input = vdagent_chr_accept_input; } +static int post_load(void *opaque, int version_id) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(opaque); + + if (have_mouse(vd) && vd->mouse_hs) { + qemu_input_handler_activate(vd->mouse_hs); + } + + if (have_clipboard(vd)) { + vdagent_clipboard_peer_register(vd); + } + + return 0; +} + +static const VMStateDescription vmstate_chunk = { + .name = "vdagent/chunk", + .version_id = 0, + .minimum_version_id = 0, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(port, VDIChunkHeader), + VMSTATE_UINT32(size, VDIChunkHeader), + VMSTATE_END_OF_LIST() + } +}; + +static const VMStateDescription vmstate_vdba = { + .name = "vdagent/bytearray", + .version_id = 0, + .minimum_version_id = 0, + .fields = (const VMStateField[]) { + VMSTATE_UINT32(len, GByteArray), + VMSTATE_VBUFFER_ALLOC_UINT32(data, GByteArray, 0, 0, len), + VMSTATE_END_OF_LIST() + } +}; + +struct CBInfoArray { + uint32_t n; + QemuClipboardInfo cbinfo[QEMU_CLIPBOARD_SELECTION__COUNT]; +}; + +static const VMStateDescription vmstate_cbinfo_array = { + .name = "cbinfoarray", + .fields = (const VMStateField[]) { + VMSTATE_UINT32(n, struct CBInfoArray), + VMSTATE_STRUCT_VARRAY_UINT32(cbinfo, struct CBInfoArray, n, + 0, vmstate_cbinfo, QemuClipboardInfo), + VMSTATE_END_OF_LIST() + } +}; + +static int put_cbinfo(QEMUFile *f, void *pv, size_t size, + const VMStateField *field, JSONWriter *vmdesc) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv); + struct CBInfoArray cbinfo = {}; + int i; + + if (!have_clipboard(vd)) { + return 0; + } + + for (i = 0; i < QEMU_CLIPBOARD_SELECTION__COUNT; i++) { + if (qemu_clipboard_peer_owns(&vd->cbpeer, i)) { + cbinfo.cbinfo[cbinfo.n++] = *qemu_clipboard_info(i); + } + } + + return vmstate_save_state(f, &vmstate_cbinfo_array, &cbinfo, vmdesc); +} + +static int get_cbinfo(QEMUFile *f, void *pv, size_t size, + const VMStateField *field) +{ + VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(pv); + struct CBInfoArray cbinfo = {}; + int i, ret; + + if (!have_clipboard(vd)) { + return 0; + } + + vdagent_clipboard_peer_register(vd); + + ret = vmstate_load_state(f, &vmstate_cbinfo_array, &cbinfo, 0); + if (ret) { + return ret; + } + + for (i = 0; i < cbinfo.n; i++) { + g_autoptr(QemuClipboardInfo) info = + qemu_clipboard_info_new(&vd->cbpeer, cbinfo.cbinfo[i].selection); + /* this will steal clipboard data pointer from cbinfo.types */ + memcpy(info->types, cbinfo.cbinfo[i].types, sizeof(cbinfo.cbinfo[i].types)); + qemu_clipboard_update(info); + } + + return 0; +} + +static const VMStateInfo vmstate_cbinfos = { + .name = "vdagent/cbinfos", + .get = get_cbinfo, + .put = put_cbinfo, +}; + +static const VMStateDescription vmstate_vdagent = { + .name = "vdagent", + .version_id = 0, + .minimum_version_id = 0, + .post_load = post_load, + .fields = (const VMStateField[]) { + VMSTATE_BOOL(connected, VDAgentChardev), + VMSTATE_UINT32(caps, VDAgentChardev), + VMSTATE_STRUCT(chunk, VDAgentChardev, 0, vmstate_chunk, VDIChunkHeader), + VMSTATE_UINT32(chunksize, VDAgentChardev), + VMSTATE_UINT32(msgsize, VDAgentChardev), + VMSTATE_VBUFFER_ALLOC_UINT32(msgbuf, VDAgentChardev, 0, 0, msgsize), + VMSTATE_UINT32(xsize, VDAgentChardev), + VMSTATE_UINT32(xoff, VDAgentChardev), + VMSTATE_VBUFFER_ALLOC_UINT32(xbuf, VDAgentChardev, 0, 0, xsize), + VMSTATE_STRUCT_POINTER(outbuf, VDAgentChardev, vmstate_vdba, GByteArray), + VMSTATE_UINT32(mouse_x, VDAgentChardev), + VMSTATE_UINT32(mouse_y, VDAgentChardev), + VMSTATE_UINT32(mouse_btn, VDAgentChardev), + VMSTATE_UINT32(mouse_display, VDAgentChardev), + VMSTATE_UINT32_ARRAY(last_serial, VDAgentChardev, + QEMU_CLIPBOARD_SELECTION__COUNT), + VMSTATE_UINT32_ARRAY(cbpending, VDAgentChardev, + QEMU_CLIPBOARD_SELECTION__COUNT), + { + .name = "cbinfos", + .info = &vmstate_cbinfos, + .flags = VMS_SINGLE, + }, + VMSTATE_END_OF_LIST() + } +}; + static void vdagent_chr_init(Object *obj) { VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); @@ -937,6 +1078,7 @@ static void vdagent_chr_init(Object *obj) vd->outbuf = g_byte_array_new(); error_setg(&vd->migration_blocker, "The vdagent chardev doesn't yet support migration"); + vmstate_register_any(NULL, &vmstate_vdagent, vd); } static void vdagent_chr_fini(Object *obj) From 42000e0013709f21b54f71b63525c22cb6b92d5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Date: Mon, 10 Mar 2025 11:46:13 +0400 Subject: [PATCH 1102/2760] ui/vdagent: remove migration blocker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://issues.redhat.com/browse/RHEL-81894 Signed-off-by: Marc-André Lureau Reviewed-by: Daniel P. Berrangé --- ui/vdagent.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/ui/vdagent.c b/ui/vdagent.c index adc8755bd9..c0746fe5b1 100644 --- a/ui/vdagent.c +++ b/ui/vdagent.c @@ -6,7 +6,6 @@ #include "qemu/option.h" #include "qemu/units.h" #include "hw/qdev-core.h" -#include "migration/blocker.h" #include "ui/clipboard.h" #include "ui/console.h" #include "ui/input.h" @@ -33,9 +32,6 @@ struct VDAgentChardev { Chardev parent; - /* TODO: migration isn't yet supported */ - Error *migration_blocker; - /* config */ bool mouse; bool clipboard; @@ -673,10 +669,6 @@ static void vdagent_chr_open(Chardev *chr, return; #endif - if (migrate_add_blocker(&vd->migration_blocker, errp) != 0) { - return; - } - vd->mouse = VDAGENT_MOUSE_DEFAULT; if (cfg->has_mouse) { vd->mouse = cfg->mouse; @@ -1076,8 +1068,6 @@ static void vdagent_chr_init(Object *obj) VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); vd->outbuf = g_byte_array_new(); - error_setg(&vd->migration_blocker, - "The vdagent chardev doesn't yet support migration"); vmstate_register_any(NULL, &vmstate_vdagent, vd); } @@ -1085,7 +1075,6 @@ static void vdagent_chr_fini(Object *obj) { VDAgentChardev *vd = QEMU_VDAGENT_CHARDEV(obj); - migrate_del_blocker(&vd->migration_blocker); vdagent_disconnect(vd); if (vd->mouse_hs) { qemu_input_handler_unregister(vd->mouse_hs); From 9498e2f7e1a247557cfa0f830a86c398a23c6809 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:11 +0800 Subject: [PATCH 1103/2760] ui/gtk: Document scale and coordinate handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existence of multiple scaling factors forces us to deal with various coordinate systems and this would be confusing. It would be beneficial to define the concepts clearly and use consistent representation for variables in different coordinates. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-2-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/ui/gtk.c b/ui/gtk.c index 982037b2c0..9f3171abc5 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -800,6 +800,71 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget) #endif } +/** + * DOC: Coordinate handling. + * + * We are coping with sizes and positions in various coordinates and the + * handling of these coordinates is somewhat confusing. It would benefit us + * all if we define these coordinates explicitly and clearly. Besides, it's + * also helpful to follow the same naming convention for variables + * representing values in different coordinates. + * + * I. Definitions + * + * - (guest) buffer coordinate: this is the coordinates that the guest will + * see. The x/y offsets and width/height specified in commands sent by + * guest is basically in buffer coordinate. + * + * - (host) pixel coordinate: this is the coordinate in pixel level on the + * host destop. A window/widget of width 300 in pixel coordinate means it + * occupies 300 pixels horizontally. + * + * - (host) logical window coordinate: the existence of global scaling + * factor in desktop level makes this kind of coordinate play a role. It + * always holds that (logical window size) * (global scale factor) = + * (pixel size). + * + * - global scale factor: this is specified in desktop level and is + * typically invariant during the life cycle of the process. Users with + * high-DPI monitors might set this scale, for example, to 2, in order to + * make the UI look larger. + * + * - zooming scale: this can be freely controlled by the QEMU user to zoom + * in/out the guest content. + * + * II. Representation + * + * We'd like to use consistent representation for variables in different + * coordinates: + * - buffer coordinate: prefix fb + * - pixel coordinate: prefix p + * - logical window coordinate: prefix w + * + * For scales: + * - global scale factor: prefix gs + * - zooming scale: prefix scale/s + * + * Example: fbw, pw, ww for width in different coordinates + * + * III. Equation + * + * - fbw * gs * scale_x = pw + * - pw = gs * ww + * + * Consequently we have + * + * - fbw * scale_x = ww + * + * Example: assuming we are running QEMU on a 3840x2160 screen and have set + * global scaling factor to 2, if the guest buffer size is 1920x1080 and the + * zooming scale is 0.5, then we have: + * - fbw = 1920, fbh = 1080 + * - pw = 1920, ph = 1080 + * - ww = 960, wh = 540 + * A bonus of this configuration is that we can achieve pixel to pixel + * presentation of the guest content. + */ + static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { VirtualConsole *vc = opaque; From 3a6b314409b42fe7c46c2bd80cfc2a6744d414fe Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:12 +0800 Subject: [PATCH 1104/2760] ui/gtk: Use consistent naming for variables in different coordinates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we've documented definitions and presentation of various coordinates, let's enforce the rules. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-3-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk-egl.c | 12 +++-- ui/gtk-gl-area.c | 14 ++--- ui/gtk.c | 133 ++++++++++++++++++++++++----------------------- 3 files changed, 82 insertions(+), 77 deletions(-) diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index f7a428c86a..947c99334b 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -70,16 +70,18 @@ void gd_egl_draw(VirtualConsole *vc) QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; int fence_fd; #endif - int ww, wh, ws; + int ww, wh, pw, ph, gs; if (!vc->gfx.gls) { return; } window = gtk_widget_get_window(vc->gfx.drawing_area); - ws = gdk_window_get_scale_factor(window); - ww = gdk_window_get_width(window) * ws; - wh = gdk_window_get_height(window) * ws; + gs = gdk_window_get_scale_factor(window); + ww = gdk_window_get_width(window); + wh = gdk_window_get_height(window); + pw = ww * gs; + ph = wh * gs; if (vc->gfx.scanout_mode) { #ifdef CONFIG_GBM @@ -115,7 +117,7 @@ void gd_egl_draw(VirtualConsole *vc) eglMakeCurrent(qemu_egl_display, vc->gfx.esurface, vc->gfx.esurface, vc->gfx.ectx); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index 2c9a0db425..ba9fbec432 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -42,16 +42,16 @@ void gd_gl_area_draw(VirtualConsole *vc) #ifdef CONFIG_GBM QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; #endif - int ww, wh, ws, y1, y2; + int pw, ph, gs, y1, y2; if (!vc->gfx.gls) { return; } gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - ws = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); - ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * ws; - wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * ws; + gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); + pw = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * gs; + ph = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * gs; if (vc->gfx.scanout_mode) { if (!vc->gfx.guest_fb.framebuffer) { @@ -71,11 +71,11 @@ void gd_gl_area_draw(VirtualConsole *vc) glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer); /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ - glViewport(0, 0, ww, wh); + glViewport(0, 0, pw, ph); y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; y2 = vc->gfx.y0_top ? vc->gfx.h : 0; glBlitFramebuffer(0, y1, vc->gfx.w, y2, - 0, 0, ww, wh, + 0, 0, pw, ph, GL_COLOR_BUFFER_BIT, GL_NEAREST); #ifdef CONFIG_GBM if (dmabuf) { @@ -101,7 +101,7 @@ void gd_gl_area_draw(VirtualConsole *vc) } gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); - surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh); + surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, pw, ph); surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds); } } diff --git a/ui/gtk.c b/ui/gtk.c index 9f3171abc5..8f5bb4b62e 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -387,16 +387,16 @@ static void *gd_win32_get_hwnd(VirtualConsole *vc) /** DisplayState Callbacks **/ static void gd_update(DisplayChangeListener *dcl, - int x, int y, int w, int h) + int fbx, int fby, int fbw, int fbh) { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); GdkWindow *win; - int x1, x2, y1, y2; - int mx, my; - int fbw, fbh; - int ww, wh; + int wx1, wx2, wy1, wy2; + int wx_offset, wy_offset; + int ww_surface, wh_surface; + int ww_widget, wh_widget; - trace_gd_update(vc->label, x, y, w, h); + trace_gd_update(vc->label, fbx, fby, fbw, fbh); if (!gtk_widget_get_realized(vc->gfx.drawing_area)) { return; @@ -405,35 +405,36 @@ static void gd_update(DisplayChangeListener *dcl, if (vc->gfx.convert) { pixman_image_composite(PIXMAN_OP_SRC, vc->gfx.ds->image, NULL, vc->gfx.convert, - x, y, 0, 0, x, y, w, h); + fbx, fby, 0, 0, fbx, fby, fbw, fbh); } - x1 = floor(x * vc->gfx.scale_x); - y1 = floor(y * vc->gfx.scale_y); + wx1 = floor(fbx * vc->gfx.scale_x); + wy1 = floor(fby * vc->gfx.scale_y); - x2 = ceil(x * vc->gfx.scale_x + w * vc->gfx.scale_x); - y2 = ceil(y * vc->gfx.scale_y + h * vc->gfx.scale_y); + wx2 = ceil(fbx * vc->gfx.scale_x + fbw * vc->gfx.scale_x); + wy2 = ceil(fby * vc->gfx.scale_y + fbh * vc->gfx.scale_y); - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; + ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x; + wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y; win = gtk_widget_get_window(vc->gfx.drawing_area); if (!win) { return; } - ww = gdk_window_get_width(win); - wh = gdk_window_get_height(win); + ww_widget = gdk_window_get_width(win); + wh_widget = gdk_window_get_height(win); - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } gtk_widget_queue_draw_area(vc->gfx.drawing_area, - mx + x1, my + y1, (x2 - x1), (y2 - y1)); + wx_offset + wx1, wy_offset + wy1, + (wx2 - wx1), (wy2 - wy1)); } static void gd_refresh(DisplayChangeListener *dcl) @@ -869,8 +870,8 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; - int mx, my; - int ww, wh; + int wx_offset, wy_offset; + int ww_widget, wh_widget, ww_surface, wh_surface; int fbw, fbh; #if defined(CONFIG_OPENGL) @@ -904,46 +905,47 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) fbw = surface_width(vc->gfx.ds); fbh = surface_height(vc->gfx.ds); - ww = gdk_window_get_width(gtk_widget_get_window(widget)); - wh = gdk_window_get_height(gtk_widget_get_window(widget)); + ww_widget = gdk_window_get_width(gtk_widget_get_window(widget)); + wh_widget = gdk_window_get_height(gtk_widget_get_window(widget)); if (s->full_screen) { - vc->gfx.scale_x = (double)ww / fbw; - vc->gfx.scale_y = (double)wh / fbh; + vc->gfx.scale_x = (double)ww_widget / fbw; + vc->gfx.scale_y = (double)wh_widget / fbh; } else if (s->free_scale) { double sx, sy; - sx = (double)ww / fbw; - sy = (double)wh / fbh; + sx = (double)ww_widget / fbw; + sy = (double)wh_widget / fbh; vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); } - fbw *= vc->gfx.scale_x; - fbh *= vc->gfx.scale_y; + ww_surface = fbw * vc->gfx.scale_x; + wh_surface = fbh * vc->gfx.scale_y; - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } - cairo_rectangle(cr, 0, 0, ww, wh); + cairo_rectangle(cr, 0, 0, ww_widget, wh_widget); /* Optionally cut out the inner area where the pixmap will be drawn. This avoids 'flashing' since we're not double-buffering. Note we're using the undocumented behaviour of drawing the rectangle from right to left to cut out the whole */ - cairo_rectangle(cr, mx + fbw, my, - -1 * fbw, fbh); + cairo_rectangle(cr, wx_offset + ww_surface, wy_offset, + -1 * ww_surface, wh_surface); cairo_fill(cr); cairo_scale(cr, vc->gfx.scale_x, vc->gfx.scale_y); cairo_set_source_surface(cr, vc->gfx.surface, - mx / vc->gfx.scale_x, my / vc->gfx.scale_y); + wx_offset / vc->gfx.scale_x, + wy_offset / vc->gfx.scale_y); cairo_paint(cr); return TRUE; @@ -954,19 +956,19 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, { VirtualConsole *vc = opaque; GtkDisplayState *s = vc->s; - int x, y; - int mx, my; - int fbh, fbw; - int ww, wh; + int fbx, fby; + int wx_offset, wy_offset; + int wh_surface, ww_surface; + int ww_widget, wh_widget; if (!vc->gfx.ds) { return TRUE; } - fbw = surface_width(vc->gfx.ds) * vc->gfx.scale_x; - fbh = surface_height(vc->gfx.ds) * vc->gfx.scale_y; - ww = gtk_widget_get_allocated_width(widget); - wh = gtk_widget_get_allocated_height(widget); + ww_surface = surface_width(vc->gfx.ds) * vc->gfx.scale_x; + wh_surface = surface_height(vc->gfx.ds) * vc->gfx.scale_y; + ww_widget = gtk_widget_get_allocated_width(widget); + wh_widget = gtk_widget_get_allocated_height(widget); /* * `widget` may not have the same size with the frame buffer. @@ -974,41 +976,42 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion, * To achieve that, `vc` will be displayed at (mx, my) * so that it is displayed at the center of the widget. */ - mx = my = 0; - if (ww > fbw) { - mx = (ww - fbw) / 2; + wx_offset = wy_offset = 0; + if (ww_widget > ww_surface) { + wx_offset = (ww_widget - ww_surface) / 2; } - if (wh > fbh) { - my = (wh - fbh) / 2; + if (wh_widget > wh_surface) { + wy_offset = (wh_widget - wh_surface) / 2; } /* * `motion` is reported in `widget` coordinates * so translating it to the coordinates in `vc`. */ - x = (motion->x - mx) / vc->gfx.scale_x; - y = (motion->y - my) / vc->gfx.scale_y; + fbx = (motion->x - wx_offset) / vc->gfx.scale_x; + fby = (motion->y - wy_offset) / vc->gfx.scale_y; - trace_gd_motion_event(ww, wh, gtk_widget_get_scale_factor(widget), x, y); + trace_gd_motion_event(ww_widget, wh_widget, + gtk_widget_get_scale_factor(widget), fbx, fby); if (qemu_input_is_absolute(vc->gfx.dcl.con)) { - if (x < 0 || y < 0 || - x >= surface_width(vc->gfx.ds) || - y >= surface_height(vc->gfx.ds)) { + if (fbx < 0 || fby < 0 || + fbx >= surface_width(vc->gfx.ds) || + fby >= surface_height(vc->gfx.ds)) { return TRUE; } - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, x, + qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_X, fbx, 0, surface_width(vc->gfx.ds)); - qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, y, + qemu_input_queue_abs(vc->gfx.dcl.con, INPUT_AXIS_Y, fby, 0, surface_height(vc->gfx.ds)); qemu_input_event_sync(); } else if (s->last_set && s->ptr_owner == vc) { - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, x - s->last_x); - qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, y - s->last_y); + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_X, fbx - s->last_x); + qemu_input_queue_rel(vc->gfx.dcl.con, INPUT_AXIS_Y, fby - s->last_y); qemu_input_event_sync(); } - s->last_x = x; - s->last_y = y; + s->last_x = fbx; + s->last_y = fby; s->last_set = TRUE; if (!qemu_input_is_absolute(vc->gfx.dcl.con) && s->ptr_owner == vc) { From a19665448156f17b52b7f33e7960d57efcfca067 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:13 +0800 Subject: [PATCH 1105/2760] gtk/ui: Introduce helper gd_update_scale MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code snippet updating scale_x/scale_y is general and will be used in next patch. Make it a function. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-4-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- include/ui/gtk.h | 2 ++ ui/gtk.c | 30 +++++++++++++++++++----------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/ui/gtk.h b/include/ui/gtk.h index aa3d637029..d3944046db 100644 --- a/include/ui/gtk.h +++ b/include/ui/gtk.h @@ -224,4 +224,6 @@ int gd_gl_area_make_current(DisplayGLCtx *dgc, /* gtk-clipboard.c */ void gd_clipboard_init(GtkDisplayState *gd); +void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh); + #endif /* UI_GTK_H */ diff --git a/ui/gtk.c b/ui/gtk.c index 8f5bb4b62e..47af49e387 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -801,6 +801,24 @@ void gd_update_monitor_refresh_rate(VirtualConsole *vc, GtkWidget *widget) #endif } +void gd_update_scale(VirtualConsole *vc, int ww, int wh, int fbw, int fbh) +{ + if (!vc) { + return; + } + + if (vc->s->full_screen) { + vc->gfx.scale_x = (double)ww / fbw; + vc->gfx.scale_y = (double)wh / fbh; + } else if (vc->s->free_scale) { + double sx, sy; + + sx = (double)ww / fbw; + sy = (double)wh / fbh; + + vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); + } +} /** * DOC: Coordinate handling. * @@ -908,17 +926,7 @@ static gboolean gd_draw_event(GtkWidget *widget, cairo_t *cr, void *opaque) ww_widget = gdk_window_get_width(gtk_widget_get_window(widget)); wh_widget = gdk_window_get_height(gtk_widget_get_window(widget)); - if (s->full_screen) { - vc->gfx.scale_x = (double)ww_widget / fbw; - vc->gfx.scale_y = (double)wh_widget / fbh; - } else if (s->free_scale) { - double sx, sy; - - sx = (double)ww_widget / fbw; - sy = (double)wh_widget / fbh; - - vc->gfx.scale_x = vc->gfx.scale_y = MIN(sx, sy); - } + gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh); ww_surface = fbw * vc->gfx.scale_x; wh_surface = fbh * vc->gfx.scale_y; From 8fb072472c38cb1778c5b0bebf535a8b13533857 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:14 +0800 Subject: [PATCH 1106/2760] ui/gtk: Update scales in fixed-scale mode when rendering GL area MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When gl=on, scale_x and scale_y were set to 1 on startup that didn't reflect the real situation of the scan-out in free scale mode, resulting in incorrect cursor coordinates to be sent when moving the mouse pointer. Simply updating the scales before rendering the image fixes this issue. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-5-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk-gl-area.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index ba9fbec432..db93cd6204 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -43,6 +43,8 @@ void gd_gl_area_draw(VirtualConsole *vc) QemuDmaBuf *dmabuf = vc->gfx.guest_fb.dmabuf; #endif int pw, ph, gs, y1, y2; + int ww, wh; + int fbw, fbh; if (!vc->gfx.gls) { return; @@ -50,8 +52,14 @@ void gd_gl_area_draw(VirtualConsole *vc) gtk_gl_area_make_current(GTK_GL_AREA(vc->gfx.drawing_area)); gs = gdk_window_get_scale_factor(gtk_widget_get_window(vc->gfx.drawing_area)); - pw = gtk_widget_get_allocated_width(vc->gfx.drawing_area) * gs; - ph = gtk_widget_get_allocated_height(vc->gfx.drawing_area) * gs; + fbw = surface_width(vc->gfx.ds); + fbh = surface_height(vc->gfx.ds); + ww = gtk_widget_get_allocated_width(vc->gfx.drawing_area); + wh = gtk_widget_get_allocated_height(vc->gfx.drawing_area); + pw = ww * gs; + ph = wh * gs; + + gd_update_scale(vc, ww, wh, fbw, fbh); if (vc->gfx.scanout_mode) { if (!vc->gfx.guest_fb.framebuffer) { From 30aa105640b0a2a541744b6584d57c9a4b86debd Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:15 +0800 Subject: [PATCH 1107/2760] ui/sdl: Consider scaling in mouse event handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using sdl display backend, if the window is scaled, incorrect mouse positions will be reported since scaling is not properly handled. Fix it by transforming the positions from window coordinate to guest buffer coordinate. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-6-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/sdl2.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ui/sdl2.c b/ui/sdl2.c index cda4293a53..b00e421f7f 100644 --- a/ui/sdl2.c +++ b/ui/sdl2.c @@ -488,14 +488,14 @@ static void handle_mousemotion(SDL_Event *ev) { int max_x, max_y; struct sdl2_console *scon = get_scon_from_window(ev->motion.windowID); + int scr_w, scr_h, surf_w, surf_h, x, y, dx, dy; if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { return; } + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); if (qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { - int scr_w, scr_h; - SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); max_x = scr_w - 1; max_y = scr_h - 1; if (gui_grab && !gui_fullscreen @@ -509,9 +509,14 @@ static void handle_mousemotion(SDL_Event *ev) sdl_grab_start(scon); } } + surf_w = surface_width(scon->surface); + surf_h = surface_height(scon->surface); + x = (int64_t)ev->motion.x * surf_w / scr_w; + y = (int64_t)ev->motion.y * surf_h / scr_h; + dx = (int64_t)ev->motion.xrel * surf_w / scr_w; + dy = (int64_t)ev->motion.yrel * surf_h / scr_h; if (gui_grab || qemu_input_is_absolute(scon->dcl.con) || absolute_enabled) { - sdl_send_mouse_event(scon, ev->motion.xrel, ev->motion.yrel, - ev->motion.x, ev->motion.y, ev->motion.state); + sdl_send_mouse_event(scon, dx, dy, x, y, ev->motion.state); } } @@ -520,12 +525,17 @@ static void handle_mousebutton(SDL_Event *ev) int buttonstate = SDL_GetMouseState(NULL, NULL); SDL_MouseButtonEvent *bev; struct sdl2_console *scon = get_scon_from_window(ev->button.windowID); + int scr_w, scr_h, x, y; if (!scon || !qemu_console_is_graphic(scon->dcl.con)) { return; } bev = &ev->button; + SDL_GetWindowSize(scon->real_window, &scr_w, &scr_h); + x = (int64_t)bev->x * surface_width(scon->surface) / scr_w; + y = (int64_t)bev->y * surface_height(scon->surface) / scr_h; + if (!gui_grab && !qemu_input_is_absolute(scon->dcl.con)) { if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) { /* start grabbing all events */ @@ -537,7 +547,7 @@ static void handle_mousebutton(SDL_Event *ev) } else { buttonstate &= ~SDL_BUTTON(bev->button); } - sdl_send_mouse_event(scon, 0, 0, bev->x, bev->y, buttonstate); + sdl_send_mouse_event(scon, 0, 0, x, y, buttonstate); } } From 02f25490879096b679ab3d7cb7f0facfef7c6484 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:16 +0800 Subject: [PATCH 1108/2760] ui/gtk: Don't update scale in fixed scale mode in gtk-egl.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scale shouldn't be changed until user explicitly requests it in fixed scale mode (full-screen=false and free-scale=false). Use function gd_update_scale to complete scale updating instead. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-7-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk-egl.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index 947c99334b..f8e4f4bc70 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -95,8 +95,9 @@ void gd_egl_draw(VirtualConsole *vc) #endif gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h); - vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds); - vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds); + gd_update_scale(vc, ww, wh, + surface_width(vc->gfx.ds), + surface_height(vc->gfx.ds)); glFlush(); #ifdef CONFIG_GBM @@ -122,8 +123,9 @@ void gd_egl_draw(VirtualConsole *vc) eglSwapBuffers(qemu_egl_display, vc->gfx.esurface); - vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds); - vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds); + gd_update_scale(vc, ww, wh, + surface_width(vc->gfx.ds), + surface_height(vc->gfx.ds)); glFlush(); } From a1b28f71f7ff0fcafbe0672b788e8e57ee4fe8f6 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:17 +0800 Subject: [PATCH 1109/2760] ui/gtk: Consider scaling when propagating ui info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ui width and height sent to guest is supposed to be in buffer coordinate. Hence conversion is required. If scaling (global window scale and zooming scale) is not respected in non-free-scale mode, window size could keep changing because of the existence of the iteration of the following steps: 1. In resize event or configure event, a size larger (or smaller) than the currently used one might be calculated due to not considering scaling. 2. On reception of the display size change event in guest, the guest might decide to do a mode setting and use the larger (or smaller) mode. 3. When the new guest scan-out command arrives, QEMU would request the window size to change to fit the new buffer size. This will trigger a resize event or a configure event, making us go back to step 1. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-8-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ui/gtk.c b/ui/gtk.c index 47af49e387..8c4a94c8f6 100644 --- a/ui/gtk.c +++ b/ui/gtk.c @@ -772,8 +772,21 @@ static void gd_resize_event(GtkGLArea *area, gint width, gint height, gpointer *opaque) { VirtualConsole *vc = (void *)opaque; + double pw = width, ph = height; + double sx = vc->gfx.scale_x, sy = vc->gfx.scale_y; + GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(area)); + const int gs = gdk_window_get_scale_factor(window); - gd_set_ui_size(vc, width, height); + if (!vc->s->free_scale && !vc->s->full_screen) { + pw /= sx; + ph /= sy; + } + + /** + * width and height here are in pixel coordinate, so we must divide it + * by global window scale (gs) + */ + gd_set_ui_size(vc, pw / gs, ph / gs); } #endif @@ -1836,8 +1849,16 @@ static gboolean gd_configure(GtkWidget *widget, GdkEventConfigure *cfg, gpointer opaque) { VirtualConsole *vc = opaque; + const double sx = vc->gfx.scale_x, sy = vc->gfx.scale_y; + double width = cfg->width, height = cfg->height; + + if (!vc->s->free_scale && !vc->s->full_screen) { + width /= sx; + height /= sy; + } + + gd_set_ui_size(vc, width, height); - gd_set_ui_size(vc, cfg->width, cfg->height); return FALSE; } From fdc09b028fde9d2ec70418735f354b51c8295d0f Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:18 +0800 Subject: [PATCH 1110/2760] ui/gtk-gl-area: Render guest content with padding in fixed-scale mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In fixed-scale mode (zoom-to-fit=false), we expect that scale should not change, meaning that if window size is larger than guest surface, padding is supposed to be added to preserve the scale. However, in OpenGL mode (gl=on), guest surface is always painted to the whole canvas without any padding. This change tries to fix this bug by adding appropriate padding when drawing surfaces. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-9-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- ui/gtk-gl-area.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/ui/gtk-gl-area.c b/ui/gtk-gl-area.c index db93cd6204..8151cc413c 100644 --- a/ui/gtk-gl-area.c +++ b/ui/gtk-gl-area.c @@ -44,7 +44,9 @@ void gd_gl_area_draw(VirtualConsole *vc) #endif int pw, ph, gs, y1, y2; int ww, wh; + int ww_surface, wh_surface; int fbw, fbh; + int wx_offset, wy_offset; if (!vc->gfx.gls) { return; @@ -61,6 +63,17 @@ void gd_gl_area_draw(VirtualConsole *vc) gd_update_scale(vc, ww, wh, fbw, fbh); + ww_surface = fbw * vc->gfx.scale_x; + wh_surface = fbh * vc->gfx.scale_y; + + wx_offset = wy_offset = 0; + if (ww > ww_surface) { + wx_offset = (ww - ww_surface) / 2; + } + if (wh > wh_surface) { + wy_offset = (wh - wh_surface) / 2; + } + if (vc->gfx.scanout_mode) { if (!vc->gfx.guest_fb.framebuffer) { return; @@ -79,11 +92,29 @@ void gd_gl_area_draw(VirtualConsole *vc) glBindFramebuffer(GL_READ_FRAMEBUFFER, vc->gfx.guest_fb.framebuffer); /* GtkGLArea sets GL_DRAW_FRAMEBUFFER for us */ + if (wx_offset > 0) { + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, wx_offset * gs, wh * gs); + glClear(GL_COLOR_BUFFER_BIT); + glScissor((ww - wx_offset) * gs, 0, wx_offset * gs, wh * gs); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + } + if (wy_offset > 0) { + glEnable(GL_SCISSOR_TEST); + glScissor(0, 0, ww * gs, wy_offset * gs); + glClear(GL_COLOR_BUFFER_BIT); + glScissor(0, (wh - wy_offset) * gs, ww * gs, wy_offset * gs); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + } + glViewport(0, 0, pw, ph); y1 = vc->gfx.y0_top ? 0 : vc->gfx.h; y2 = vc->gfx.y0_top ? vc->gfx.h : 0; glBlitFramebuffer(0, y1, vc->gfx.w, y2, - 0, 0, pw, ph, + wx_offset * gs, wy_offset * gs, + (ww - wx_offset) * gs, (wh - wy_offset) * gs, GL_COLOR_BUFFER_BIT, GL_NEAREST); #ifdef CONFIG_GBM if (dmabuf) { From f05e1a93f48729b568fdf86a12d56ee142cee5e1 Mon Sep 17 00:00:00 2001 From: Weifeng Liu Date: Sun, 11 May 2025 15:33:19 +0800 Subject: [PATCH 1111/2760] ui/gtk-egl: Render guest content with padding in fixed-scale mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scaling was not respected when rendering frames in gtk-egl.c (used if gl=on and X11 mode). To fix this, add fields x and y to struct egl_fb for x offset and y offset so we can add padding to window. Signed-off-by: Weifeng Liu Message-ID: <20250511073337.876650-10-weifeng.liu.z@gmail.com> Acked-by: Gerd Hoffmann Acked-by: Marc-André Lureau --- include/ui/egl-helpers.h | 4 +++- ui/egl-helpers.c | 10 ++++++++-- ui/gtk-egl.c | 36 +++++++++++++++++++++++++++++++----- ui/sdl2-gl.c | 2 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h index fb80e15142..acf993fcf5 100644 --- a/include/ui/egl-helpers.h +++ b/include/ui/egl-helpers.h @@ -17,6 +17,8 @@ extern bool qemu_egl_angle_d3d; typedef struct egl_fb { int width; int height; + int x; + int y; GLuint texture; GLuint framebuffer; bool delete_texture; @@ -26,7 +28,7 @@ typedef struct egl_fb { #define EGL_FB_INIT { 0, } void egl_fb_destroy(egl_fb *fb); -void egl_fb_setup_default(egl_fb *fb, int width, int height); +void egl_fb_setup_default(egl_fb *fb, int width, int height, int x, int y); void egl_fb_setup_for_tex(egl_fb *fb, int width, int height, GLuint texture, bool delete); void egl_fb_setup_new_tex(egl_fb *fb, int width, int height); diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c index 9cda2bbbee..5503a795e4 100644 --- a/ui/egl-helpers.c +++ b/ui/egl-helpers.c @@ -93,14 +93,18 @@ void egl_fb_destroy(egl_fb *fb) fb->width = 0; fb->height = 0; + fb->x = 0; + fb->y = 0; fb->texture = 0; fb->framebuffer = 0; } -void egl_fb_setup_default(egl_fb *fb, int width, int height) +void egl_fb_setup_default(egl_fb *fb, int width, int height, int x, int y) { fb->width = width; fb->height = height; + fb->x = x; + fb->y = y; fb->framebuffer = 0; /* default framebuffer */ } @@ -145,6 +149,7 @@ void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) glBindFramebuffer(GL_READ_FRAMEBUFFER, src->framebuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->framebuffer); glViewport(0, 0, dst->width, dst->height); + glClear(GL_COLOR_BUFFER_BIT); if (src->dmabuf) { x1 = qemu_dmabuf_get_x(src->dmabuf); @@ -161,7 +166,8 @@ void egl_fb_blit(egl_fb *dst, egl_fb *src, bool flip) x2 = x1 + w; glBlitFramebuffer(x1, y1, x2, y2, - 0, 0, dst->width, dst->height, + dst->x, dst->y, + dst->x + dst->width, dst->y + dst->height, GL_COLOR_BUFFER_BIT, GL_LINEAR); } diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c index f8e4f4bc70..0b787bea25 100644 --- a/ui/gtk-egl.c +++ b/ui/gtk-egl.c @@ -340,7 +340,11 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl, { VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl); GdkWindow *window; - int ww, wh, ws; + int px_offset, py_offset; + int gs; + int pw_widget, ph_widget, pw_surface, ph_surface; + int ww_widget, wh_widget, ww_surface, wh_surface; + int fbw, fbh; if (!vc->gfx.scanout_mode) { return; @@ -353,10 +357,32 @@ void gd_egl_scanout_flush(DisplayChangeListener *dcl, vc->gfx.esurface, vc->gfx.ectx); window = gtk_widget_get_window(vc->gfx.drawing_area); - ws = gdk_window_get_scale_factor(window); - ww = gdk_window_get_width(window) * ws; - wh = gdk_window_get_height(window) * ws; - egl_fb_setup_default(&vc->gfx.win_fb, ww, wh); + gs = gdk_window_get_scale_factor(window); + ww_widget = gdk_window_get_width(window); + wh_widget = gdk_window_get_height(window); + fbw = surface_width(vc->gfx.ds); + fbh = surface_height(vc->gfx.ds); + + gd_update_scale(vc, ww_widget, wh_widget, fbw, fbh); + + ww_surface = fbw * vc->gfx.scale_x; + wh_surface = fbh * vc->gfx.scale_y; + pw_widget = ww_widget * gs; + ph_widget = wh_widget * gs; + pw_surface = ww_surface * gs; + ph_surface = wh_surface * gs; + + px_offset = 0; + py_offset = 0; + if (pw_widget > pw_surface) { + px_offset = (pw_widget - pw_surface) / 2; + } + if (ph_widget > ph_surface) { + py_offset = (ph_widget - ph_surface) / 2; + } + + egl_fb_setup_default(&vc->gfx.win_fb, pw_surface, ph_surface, + px_offset, py_offset); if (vc->gfx.cursor_fb.texture) { egl_texture_blit(vc->gfx.gls, &vc->gfx.win_fb, &vc->gfx.guest_fb, vc->gfx.y0_top); diff --git a/ui/sdl2-gl.c b/ui/sdl2-gl.c index e01d9ab0c7..3be17d1079 100644 --- a/ui/sdl2-gl.c +++ b/ui/sdl2-gl.c @@ -241,7 +241,7 @@ void sdl2_gl_scanout_flush(DisplayChangeListener *dcl, SDL_GL_MakeCurrent(scon->real_window, scon->winctx); SDL_GetWindowSize(scon->real_window, &ww, &wh); - egl_fb_setup_default(&scon->win_fb, ww, wh); + egl_fb_setup_default(&scon->win_fb, ww, wh, 0, 0); egl_fb_blit(&scon->win_fb, &scon->guest_fb, !scon->y0_top); SDL_GL_SwapWindow(scon->real_window); From 9e9542a1771f5b44d198fbfa31b4b3fb947e46ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:23 +0200 Subject: [PATCH 1112/2760] tests/functional: use 'none' audio driver for q800 tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ac13a6b3fd ("audio: add Apple Sound Chip (ASC) emulation") the Quadra 800 machine has an audio device. It is not guaranteed that the default audio driver of the audio subsystem will work correctly on all host systems. Therefore, the 'none' audio driver should be used in all q800 tests. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2812 Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-1-vr_qemu@t-online.de> --- tests/functional/test_m68k_q800.py | 3 ++- tests/functional/test_m68k_replay.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/functional/test_m68k_q800.py b/tests/functional/test_m68k_q800.py index 400b7aeb5d..b3e655346c 100755 --- a/tests/functional/test_m68k_q800.py +++ b/tests/functional/test_m68k_q800.py @@ -25,7 +25,8 @@ class Q800MachineTest(LinuxKernelTest): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0 vga=off') self.vm.add_args('-kernel', kernel_path, - '-append', kernel_command_line) + '-append', kernel_command_line, + '-audio', 'none') self.vm.launch() console_pattern = 'Kernel command line: %s' % kernel_command_line self.wait_for_console_pattern(console_pattern) diff --git a/tests/functional/test_m68k_replay.py b/tests/functional/test_m68k_replay.py index 18c1db539c..213d6ae07e 100755 --- a/tests/functional/test_m68k_replay.py +++ b/tests/functional/test_m68k_replay.py @@ -24,7 +24,8 @@ class M68kReplay(ReplayKernelBase): kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0 vga=off') console_pattern = 'No filesystem could mount root' - self.run_rr(kernel_path, kernel_command_line, console_pattern) + self.run_rr(kernel_path, kernel_command_line, console_pattern, + args=('-audio', 'none')) ASSET_MCF5208 = Asset( 'https://qemu-advcal.gitlab.io/qac-best-of-multiarch/download/day07.tar.xz', From 5ddd6c8dc849b4af44bd06840c9133d64e62c27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:24 +0200 Subject: [PATCH 1113/2760] audio: fix SIGSEGV in AUD_get_buffer_size_out() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As far as the emulated audio devices are concerned the pointer returned by AUD_open_out() is an opaque handle. This includes the NULL pointer. In this case, AUD_get_buffer_size_out() should return a sensible buffer size instead of triggering a segmentation fault. All other public AUD_*_out() and audio_*_out() functions handle this case. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-2-vr_qemu@t-online.de> --- audio/audio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 41ee11aaad..70ef22b1a4 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -905,6 +905,10 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size) int AUD_get_buffer_size_out(SWVoiceOut *sw) { + if (!sw) { + return 0; + } + return sw->hw->samples * sw->hw->info.bytes_per_frame; } From ccb4fec0e5f233cb61a83b3af59ae11716ea06c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:25 +0200 Subject: [PATCH 1114/2760] audio: fix size calculation in AUD_get_buffer_size_out() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The buffer size calculated by AUD_get_buffer_size_out() is often incorrect. sw->hw->samples * sw->hw->info.bytes_per_frame is the size of the mixing engine buffer in audio frames multiplied by the size of one frame of the audio backend. Due to resampling or format conversion, the size of the frontend buffer can differ significantly. Return the correct buffer size when the mixing engine is used. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-3-vr_qemu@t-online.de> --- audio/audio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 70ef22b1a4..3f5baf0cc6 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -909,6 +909,10 @@ int AUD_get_buffer_size_out(SWVoiceOut *sw) return 0; } + if (audio_get_pdo_out(sw->s->dev)->mixing_engine) { + return sw->resample_buf.size * sw->info.bytes_per_frame; + } + return sw->hw->samples * sw->hw->info.bytes_per_frame; } From d009f26a54f573468be721590a19350c224bc730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:26 +0200 Subject: [PATCH 1115/2760] hw/audio/asc: fix SIGSEGV in asc_realize() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUD_open_out() may fail and return NULL. This may then lead to a segmentation fault in memset() below. The memset() behaviour is undefined if the pointer to the destination object is a null pointer. Add the missing error handling code. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Reviewed-by: Mark Cave-Ayland Message-Id: <20250515054429.7385-4-vr_qemu@t-online.de> --- hw/audio/asc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/audio/asc.c b/hw/audio/asc.c index 18382ccf6a..6721c0d9fb 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "qemu/timer.h" +#include "qapi/error.h" #include "hw/sysbus.h" #include "hw/irq.h" #include "audio/audio.h" @@ -653,6 +654,12 @@ static void asc_realize(DeviceState *dev, Error **errp) s->voice = AUD_open_out(&s->card, s->voice, "asc.out", s, asc_out_cb, &as); + if (!s->voice) { + AUD_remove_card(&s->card); + error_setg(errp, "Initializing audio stream failed"); + return; + } + s->shift = 1; s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; s->mixbuf = g_malloc0(s->samples << s->shift); From f4b1c3db11317c4bce18fa3bbb025df7c22ea54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:27 +0200 Subject: [PATCH 1116/2760] hw/audio/asc: replace g_malloc0() with g_malloc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to allocate initialized memory with g_malloc0() if it's directly followed by a memset() function call. g_malloc() is sufficient. Reviewed-by: Marc-André Lureau Reviewed-by: Mark Cave-Ayland Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-5-vr_qemu@t-online.de> --- hw/audio/asc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/audio/asc.c b/hw/audio/asc.c index 6721c0d9fb..edd42d6d91 100644 --- a/hw/audio/asc.c +++ b/hw/audio/asc.c @@ -664,7 +664,7 @@ static void asc_realize(DeviceState *dev, Error **errp) s->samples = AUD_get_buffer_size_out(s->voice) >> s->shift; s->mixbuf = g_malloc0(s->samples << s->shift); - s->silentbuf = g_malloc0(s->samples << s->shift); + s->silentbuf = g_malloc(s->samples << s->shift); memset(s->silentbuf, 0x80, s->samples << s->shift); /* Add easc registers if required */ From 9ddb7c85c965636f7abf91382dc40175ce121aa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:28 +0200 Subject: [PATCH 1117/2760] audio/mixeng: remove unnecessary pointer type casts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A simple assignment automatically converts a void pointer type to any other pointer type. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-6-vr_qemu@t-online.de> --- audio/mixeng.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/audio/mixeng.c b/audio/mixeng.c index 69f6549224..13e1ff9b08 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -286,7 +286,7 @@ static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1); static void conv_natural_float_to_mono(struct st_sample *dst, const void *src, int samples) { - float *in = (float *)src; + const float *in = src; while (samples--) { dst->r = dst->l = CONV_NATURAL_FLOAT(*in++); @@ -297,7 +297,7 @@ static void conv_natural_float_to_mono(struct st_sample *dst, const void *src, static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src, int samples) { - float *in = (float *)src; + const float *in = src; while (samples--) { dst->l = CONV_NATURAL_FLOAT(*in++); @@ -314,7 +314,7 @@ t_sample *mixeng_conv_float[2] = { static void clip_natural_float_from_mono(void *dst, const struct st_sample *src, int samples) { - float *out = (float *)dst; + float *out = dst; while (samples--) { *out++ = CLIP_NATURAL_FLOAT(src->l + src->r); @@ -325,7 +325,7 @@ static void clip_natural_float_from_mono(void *dst, const struct st_sample *src, static void clip_natural_float_from_stereo( void *dst, const struct st_sample *src, int samples) { - float *out = (float *)dst; + float *out = dst; while (samples--) { *out++ = CLIP_NATURAL_FLOAT(src->l); From 5d978c5da7f7d85d3a74b7d4dbe9ba5c5584d560 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volker=20R=C3=BCmelin?= Date: Thu, 15 May 2025 07:44:29 +0200 Subject: [PATCH 1118/2760] audio: add float sample endianness converters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit ed2a4a7941 ("audio: proper support for float samples in mixeng") added support for float audio samples. As there were no audio frontend devices with float support at that time, the code was limited to native endian float samples. When nobody was paying attention, an audio device that supports floating point samples crept in with commit eb9ad377bb ("virtio-sound: handle control messages and streams"). Add code for the audio subsystem to convert float samples to the correct endianness. The type punning code was taken from the PipeWire project. Reviewed-by: Marc-André Lureau Signed-off-by: Volker Rümelin Message-Id: <20250515054429.7385-7-vr_qemu@t-online.de> --- audio/audio.c | 3 +- audio/audio_template.h | 12 ++++--- audio/mixeng.c | 75 ++++++++++++++++++++++++++++++++++++++---- audio/mixeng.h | 6 ++-- 4 files changed, 82 insertions(+), 14 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 3f5baf0cc6..b58ad74433 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1892,7 +1892,8 @@ CaptureVoiceOut *AUD_add_capture( cap->buf = g_malloc0_n(hw->mix_buf.size, hw->info.bytes_per_frame); if (hw->info.is_float) { - hw->clip = mixeng_clip_float[hw->info.nchannels == 2]; + hw->clip = mixeng_clip_float[hw->info.nchannels == 2] + [hw->info.swap_endianness]; } else { hw->clip = mixeng_clip [hw->info.nchannels == 2] diff --git a/audio/audio_template.h b/audio/audio_template.h index 7ccfec0116..c29d79c443 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -174,9 +174,11 @@ static int glue (audio_pcm_sw_init_, TYPE) ( if (sw->info.is_float) { #ifdef DAC - sw->conv = mixeng_conv_float[sw->info.nchannels == 2]; + sw->conv = mixeng_conv_float[sw->info.nchannels == 2] + [sw->info.swap_endianness]; #else - sw->clip = mixeng_clip_float[sw->info.nchannels == 2]; + sw->clip = mixeng_clip_float[sw->info.nchannels == 2] + [sw->info.swap_endianness]; #endif } else { #ifdef DAC @@ -303,9 +305,11 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s, if (hw->info.is_float) { #ifdef DAC - hw->clip = mixeng_clip_float[hw->info.nchannels == 2]; + hw->clip = mixeng_clip_float[hw->info.nchannels == 2] + [hw->info.swap_endianness]; #else - hw->conv = mixeng_conv_float[hw->info.nchannels == 2]; + hw->conv = mixeng_conv_float[hw->info.nchannels == 2] + [hw->info.swap_endianness]; #endif } else { #ifdef DAC diff --git a/audio/mixeng.c b/audio/mixeng.c index 13e1ff9b08..703ee5448f 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -283,6 +283,11 @@ static const float float_scale_reciprocal = 1.f / ((int64_t)INT32_MAX + 1); #endif #endif +#define F32_TO_F32S(v) \ + bswap32((union { uint32_t i; float f; }){ .f = (v) }.i) +#define F32S_TO_F32(v) \ + ((union { uint32_t i; float f; }){ .i = bswap32(v) }.f) + static void conv_natural_float_to_mono(struct st_sample *dst, const void *src, int samples) { @@ -294,6 +299,17 @@ static void conv_natural_float_to_mono(struct st_sample *dst, const void *src, } } +static void conv_swap_float_to_mono(struct st_sample *dst, const void *src, + int samples) +{ + const uint32_t *in_f32s = src; + + while (samples--) { + dst->r = dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++)); + dst++; + } +} + static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src, int samples) { @@ -306,9 +322,27 @@ static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src, } } -t_sample *mixeng_conv_float[2] = { - conv_natural_float_to_mono, - conv_natural_float_to_stereo, +static void conv_swap_float_to_stereo(struct st_sample *dst, const void *src, + int samples) +{ + const uint32_t *in_f32s = src; + + while (samples--) { + dst->l = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++)); + dst->r = CONV_NATURAL_FLOAT(F32S_TO_F32(*in_f32s++)); + dst++; + } +} + +t_sample *mixeng_conv_float[2][2] = { + { + conv_natural_float_to_mono, + conv_swap_float_to_mono, + }, + { + conv_natural_float_to_stereo, + conv_swap_float_to_stereo, + } }; static void clip_natural_float_from_mono(void *dst, const struct st_sample *src, @@ -322,6 +356,17 @@ static void clip_natural_float_from_mono(void *dst, const struct st_sample *src, } } +static void clip_swap_float_from_mono(void *dst, const struct st_sample *src, + int samples) +{ + uint32_t *out_f32s = dst; + + while (samples--) { + *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l + src->r)); + src++; + } +} + static void clip_natural_float_from_stereo( void *dst, const struct st_sample *src, int samples) { @@ -334,9 +379,27 @@ static void clip_natural_float_from_stereo( } } -f_sample *mixeng_clip_float[2] = { - clip_natural_float_from_mono, - clip_natural_float_from_stereo, +static void clip_swap_float_from_stereo( + void *dst, const struct st_sample *src, int samples) +{ + uint32_t *out_f32s = dst; + + while (samples--) { + *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->l)); + *out_f32s++ = F32_TO_F32S(CLIP_NATURAL_FLOAT(src->r)); + src++; + } +} + +f_sample *mixeng_clip_float[2][2] = { + { + clip_natural_float_from_mono, + clip_swap_float_from_mono, + }, + { + clip_natural_float_from_stereo, + clip_swap_float_from_stereo, + } }; void audio_sample_to_uint64(const void *samples, int pos, diff --git a/audio/mixeng.h b/audio/mixeng.h index a5f56d2c26..ead93ac2f7 100644 --- a/audio/mixeng.h +++ b/audio/mixeng.h @@ -42,9 +42,9 @@ typedef void (f_sample) (void *dst, const struct st_sample *src, int samples); extern t_sample *mixeng_conv[2][2][2][3]; extern f_sample *mixeng_clip[2][2][2][3]; -/* indices: [stereo] */ -extern t_sample *mixeng_conv_float[2]; -extern f_sample *mixeng_clip_float[2]; +/* indices: [stereo][swap endianness] */ +extern t_sample *mixeng_conv_float[2][2]; +extern f_sample *mixeng_clip_float[2][2]; void *st_rate_start (int inrate, int outrate); void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf, From f6ccfd5d166acf495f5d6d320da503fae8dc14a4 Mon Sep 17 00:00:00 2001 From: BALATON Zoltan Date: Sun, 16 Mar 2025 01:20:46 +0100 Subject: [PATCH 1119/2760] alsaaudio: Set try-poll to false by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quoting Volker Rümelin: "try-poll=on tells the ALSA backend to try to use an event loop instead of the audio timer. This works most of the time. But the poll event handler in the ALSA backend has a bug. For example, if the guest can't provide enough audio frames in time, the ALSA buffer is only partly full and the event handler will be called again and again on every iteration of the main loop. This increases the processor load and the guest has less processor time to provide new audio frames in time. I have two examples where a guest can't recover from this situation and the guest seems to hang." One reproducer I've found is booting MorphOS demo iso on qemu-system-ppc -machine pegasos2 -audio alsa which should play a startup sound but instead it freezes. Even when it does not hang it plays choppy sound. Volker suggested using command line to set try-poll=off saying: "The try-poll=off arguments are typically necessary, because the alsa backend has a design issue with try-poll=on. If the guest can't provide enough audio frames, it's really unhelpful to ask for new audio frames on every main loop iteration until the guest can provide enough audio frames. Timer based playback doesn't have that problem." But users cannot easily find this option and having a non-working default is really unhelpful so to make life easier just set it to false by default which works until the issue with the alsa backend can be fixed. Signed-off-by: BALATON Zoltan Acked-by: Marc-André Lureau [ Marc-André - Updated QAPI and CLI doc ] Signed-off-by: Marc-André Lureau Message-Id: <20250316002046.D066A4E6004@zero.eik.bme.hu> --- audio/alsaaudio.c | 2 +- qapi/audio.json | 2 +- qemu-options.hx | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c index cacae1ea59..9b6c01c0ef 100644 --- a/audio/alsaaudio.c +++ b/audio/alsaaudio.c @@ -899,7 +899,7 @@ static void alsa_enable_in(HWVoiceIn *hw, bool enable) static void alsa_init_per_direction(AudiodevAlsaPerDirectionOptions *apdo) { if (!apdo->has_try_poll) { - apdo->try_poll = true; + apdo->try_poll = false; apdo->has_try_poll = true; } } diff --git a/qapi/audio.json b/qapi/audio.json index dd5a58d13e..49633cf317 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -96,7 +96,7 @@ # @period-length: the period length in microseconds # # @try-poll: attempt to use poll mode, falling back to non-polling -# access on failure (default true) +# access on failure (default false) # # Since: 4.0 ## diff --git a/qemu-options.hx b/qemu-options.hx index aab53bcfe8..7eb8e02b4b 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -965,7 +965,7 @@ SRST Sets the period length in microseconds. ``in|out.try-poll=on|off`` - Attempt to use poll mode with the device. Default is on. + Attempt to use poll mode with the device. Default is off. ``threshold=threshold`` Threshold (in microseconds) when playback starts. Default is 0. @@ -1002,7 +1002,7 @@ SRST ``in|out.buffer-count=count`` Sets the count of the buffers. - ``in|out.try-poll=on|of`` + ``in|out.try-poll=on|off`` Attempt to use poll mode with the device. Default is on. ``try-mmap=on|off`` From 2bccabe6df5e91145c1313bb79b98200aa13b5ff Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 17 Mar 2025 17:05:29 +0900 Subject: [PATCH 1120/2760] audio: Reset rate control when adding bytes Commit 90320051ea99 ("spiceaudio: add a pcm_ops buffer_get_free function") caused to emit messages saying "Resetting rate control" frequently when the guest generates no frames. audio_rate_peek_bytes() resets the rate control when frames < 0 || frames > 65536 where frames is the rate-limited number of frames. Resetting when frames < 0 is sensible as the number simply doesn't make sense. There is a problem when frames > 65536. It implies the guest stopped generating frames for a while so it makes sense to reset the rate control when the guest resumed generating frames. However, the commit mentioned earlier broke this assumption by letting spiceaudio call audio_rate_peek_bytes() whether the guest is generating frames or not. Reset the rate control in audio_rate_add_bytes(), which is called only when actually adding frames, according to the previous call to audio_rate_peek_bytes() to avoid frequent rate control resets even when the guest generates no frame. Signed-off-by: Akihiko Odaki Message-Id: <20250317-rate-v1-1-da9df062747c@daynix.com> --- audio/audio.c | 14 ++++++++------ audio/audio_int.h | 1 + 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index b58ad74433..89f091bc88 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2283,17 +2283,19 @@ size_t audio_rate_peek_bytes(RateCtl *rate, struct audio_pcm_info *info) ticks = now - rate->start_ticks; bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); frames = (bytes - rate->bytes_sent) / info->bytes_per_frame; - if (frames < 0 || frames > 65536) { - AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", frames); - audio_rate_start(rate); - frames = 0; - } + rate->peeked_frames = frames; - return frames * info->bytes_per_frame; + return frames < 0 ? 0 : frames * info->bytes_per_frame; } void audio_rate_add_bytes(RateCtl *rate, size_t bytes_used) { + if (rate->peeked_frames < 0 || rate->peeked_frames > 65536) { + AUD_log(NULL, "Resetting rate control (%" PRId64 " frames)\n", + rate->peeked_frames); + audio_rate_start(rate); + } + rate->bytes_sent += bytes_used; } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2d079d00a2..f78ca05f92 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -255,6 +255,7 @@ const char *audio_application_name(void); typedef struct RateCtl { int64_t start_ticks; int64_t bytes_sent; + int64_t peeked_frames; } RateCtl; void audio_rate_start(RateCtl *rate); From d75cdf6883fac728540798e42a8104d016ec762c Mon Sep 17 00:00:00 2001 From: Fabiano Rosas Date: Fri, 9 May 2025 14:50:47 -0300 Subject: [PATCH 1121/2760] tests/qtest/ast2700-smc-test: Fix leak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ASAN spotted a leak of the memory used to hold the tmp_path: Direct leak of 35 byte(s) in 1 object(s) allocated from: #0 0x55e29aa96da9 in malloc ../projects/compiler-rt/lib/asan/asan_malloc_linux.cpp:69:3 #1 0x7fe0cfb26518 in g_malloc ../glib/gmem.c:106 #2 0x7fe0cfb4146e in g_strconcat ../glib/gstrfuncs.c:629 #3 0x7fe0cfb0a78f in g_get_tmp_name ../glib/gfileutils.c:1742 #4 0x7fe0cfb0b00b in g_file_open_tmp ../glib/gfileutils.c:1802 #5 0x55e29ab53961 in test_ast2700_evb ../tests/qtest/ast2700-smc-test.c:20:10 #6 0x55e29ab53803 in main ../tests/qtest/ast2700-smc-test.c:65:5 #7 0x7fe0cf7bd24c in __libc_start_main ../csu/libc-start.c:308 #8 0x55e29a9f7759 in _start ../sysdeps/x86_64/start.S:120 Signed-off-by: Fabiano Rosas Reviewed-by: Jamin Lin Message-ID: <20250509175047.26066-1-farosas@suse.de> Signed-off-by: Cédric Le Goater --- tests/qtest/ast2700-smc-test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/qtest/ast2700-smc-test.c b/tests/qtest/ast2700-smc-test.c index d1c4856307..62d538d8a3 100644 --- a/tests/qtest/ast2700-smc-test.c +++ b/tests/qtest/ast2700-smc-test.c @@ -67,5 +67,6 @@ int main(int argc, char **argv) qtest_quit(ast2700_evb_data.s); unlink(ast2700_evb_data.tmp_path); + g_free(ast2700_evb_data.tmp_path); return ret; } From d09c0939c97061fca0faa842184171f2f94b3339 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Tue, 13 May 2025 16:08:06 +0800 Subject: [PATCH 1122/2760] tests/qtest/aspeed_smc-test: Fix memory leaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Link: https://patchwork.kernel.org/project/qemu-devel/patch/20250509175047.26066-1-farosas@suse.de/ Signed-off-by: Jamin Lin Reviewed-by: Laurent Vivier Link: https://lore.kernel.org/qemu-devel/20250513080806.1005996-1-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed_smc-test.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/qtest/aspeed_smc-test.c b/tests/qtest/aspeed_smc-test.c index 4e1389385d..52a00e6f0a 100644 --- a/tests/qtest/aspeed_smc-test.c +++ b/tests/qtest/aspeed_smc-test.c @@ -228,5 +228,10 @@ int main(int argc, char **argv) unlink(ast2500_evb_data.tmp_path); unlink(ast2600_evb_data.tmp_path); unlink(ast1030_evb_data.tmp_path); + g_free(palmetto_data.tmp_path); + g_free(ast2500_evb_data.tmp_path); + g_free(ast2600_evb_data.tmp_path); + g_free(ast1030_evb_data.tmp_path); + return ret; } From f05cc69c6ce0242e2eeae3cd1513454006b8f040 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:33 +0800 Subject: [PATCH 1123/2760] hw/misc/aspeed_hace: Remove unused code for better readability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the previous design of the hash framework, accumulative hashing was not supported. To work around this limitation, commit 5cd7d85 introduced an iov_cache array to store all the hash data from firmware. Once the ASPEED HACE model collected all the data, it passed the iov_cache to the hash API to calculate the final digest. However, with commit e3c0752, the hash framework now supports accumulative hashing. This allows us to refactor the ASPEED HACE model, removing redundant logic and simplifying the implementation for better readability and maintainability. As a result, the iov_count variable is no longer needed—it was previously used to track how many cached entries were used for hashing. To maintain VMSTATE compatibility after removing this field, the VMSTATE_VERSION is bumped to 2 This cleanup follows significant changes in commit 4c1d0af4a28d, making the model more readable. - Deleted "iov_cache" and "iov_count" from "AspeedHACEState". - Removed "reconstruct_iov" function and related logic. - Simplified "do_hash_operation" by eliminating redundant checks. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 39 ++--------------------------------- include/hw/misc/aspeed_hace.h | 2 -- 2 files changed, 2 insertions(+), 39 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index f4bff32a00..9263739ea6 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -142,25 +142,6 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov, return false; } -static int reconstruct_iov(AspeedHACEState *s, struct iovec *iov, int id, - uint32_t *pad_offset) -{ - int i, iov_count; - if (*pad_offset != 0) { - s->iov_cache[s->iov_count].iov_base = iov[id].iov_base; - s->iov_cache[s->iov_count].iov_len = *pad_offset; - ++s->iov_count; - } - for (i = 0; i < s->iov_count; i++) { - iov[i].iov_base = s->iov_cache[i].iov_base; - iov[i].iov_len = s->iov_cache[i].iov_len; - } - iov_count = s->iov_count; - s->iov_count = 0; - s->total_req_len = 0; - return iov_count; -} - static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { @@ -242,19 +223,6 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, iov[0].iov_base = haddr; iov[0].iov_len = len; i = 1; - - if (s->iov_count) { - /* - * In aspeed sdk kernel driver, sg_mode is disabled in hash_final(). - * Thus if we received a request with sg_mode disabled, it is - * required to check whether cache is empty. If no, we should - * combine cached iov and the current iov. - */ - s->total_req_len += len; - if (has_padding(s, iov, len, &total_msg_len, &pad_offset)) { - i = reconstruct_iov(s, iov, 0, &pad_offset); - } - } } if (acc_mode) { @@ -278,7 +246,6 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, qcrypto_hash_free(s->hash_ctx); s->hash_ctx = NULL; - s->iov_count = 0; s->total_req_len = 0; } } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, @@ -437,7 +404,6 @@ static void aspeed_hace_reset(DeviceState *dev) } memset(s->regs, 0, sizeof(s->regs)); - s->iov_count = 0; s->total_req_len = 0; } @@ -469,12 +435,11 @@ static const Property aspeed_hace_properties[] = { static const VMStateDescription vmstate_aspeed_hace = { .name = TYPE_ASPEED_HACE, - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), VMSTATE_UINT32(total_req_len, AspeedHACEState), - VMSTATE_UINT32(iov_count, AspeedHACEState), VMSTATE_END_OF_LIST(), } }; diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index 5d4aa19cfe..b69a038d35 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -31,10 +31,8 @@ struct AspeedHACEState { MemoryRegion iomem; qemu_irq irq; - struct iovec iov_cache[ASPEED_HACE_MAX_SG]; uint32_t regs[ASPEED_HACE_NR_REGS]; uint32_t total_req_len; - uint32_t iov_count; MemoryRegion *dram_mr; AddressSpace dram_as; From c869da4edd7ad91975fd9887ec924ba621b3c7f8 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:34 +0800 Subject: [PATCH 1124/2760] hw/misc/aspeed_hace: Improve readability and consistency in variable naming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, users define multiple local variables within different if-statements. To improve readability and maintain consistency in variable naming, rename the variables accordingly. Introduced "sg_addr" to clearly indicate the scatter-gather mode buffer address. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 71 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 9263739ea6..6be94963bc 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -145,15 +145,19 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov, static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { - struct iovec iov[ASPEED_HACE_MAX_SG]; - uint32_t total_msg_len; - uint32_t pad_offset; g_autofree uint8_t *digest_buf = NULL; - size_t digest_len = 0; - bool sg_acc_mode_final_request = false; - int i; - void *haddr; + struct iovec iov[ASPEED_HACE_MAX_SG]; + bool acc_final_request = false; Error *local_err = NULL; + uint32_t total_msg_len; + size_t digest_len = 0; + uint32_t sg_addr = 0; + uint32_t pad_offset; + int iov_idx = 0; + uint32_t len = 0; + uint32_t src = 0; + void *haddr; + hwaddr plen; if (acc_mode && s->hash_ctx == NULL) { s->hash_ctx = qcrypto_hash_new(algo, &local_err); @@ -166,74 +170,69 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } if (sg_mode) { - uint32_t len = 0; - - for (i = 0; !(len & SG_LIST_LEN_LAST); i++) { - uint32_t addr, src; - hwaddr plen; - - if (i == ASPEED_HACE_MAX_SG) { + for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) { + if (iov_idx == ASPEED_HACE_MAX_SG) { qemu_log_mask(LOG_GUEST_ERROR, "aspeed_hace: guest failed to set end of sg list marker\n"); break; } - src = s->regs[R_HASH_SRC] + (i * SG_LIST_ENTRY_SIZE); + src = s->regs[R_HASH_SRC] + (iov_idx * SG_LIST_ENTRY_SIZE); len = address_space_ldl_le(&s->dram_as, src, MEMTXATTRS_UNSPECIFIED, NULL); - addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, - MEMTXATTRS_UNSPECIFIED, NULL); - addr &= SG_LIST_ADDR_MASK; + sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, + MEMTXATTRS_UNSPECIFIED, NULL); + sg_addr &= SG_LIST_ADDR_MASK; plen = len & SG_LIST_LEN_MASK; - haddr = address_space_map(&s->dram_as, addr, &plen, false, + haddr = address_space_map(&s->dram_as, sg_addr, &plen, false, MEMTXATTRS_UNSPECIFIED); if (haddr == NULL) { qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); return; } - iov[i].iov_base = haddr; + iov[iov_idx].iov_base = haddr; if (acc_mode) { s->total_req_len += plen; - if (has_padding(s, &iov[i], plen, &total_msg_len, + if (has_padding(s, &iov[iov_idx], plen, &total_msg_len, &pad_offset)) { /* Padding being present indicates the final request */ - sg_acc_mode_final_request = true; - iov[i].iov_len = pad_offset; + acc_final_request = true; + iov[iov_idx].iov_len = pad_offset; } else { - iov[i].iov_len = plen; + iov[iov_idx].iov_len = plen; } } else { - iov[i].iov_len = plen; + iov[iov_idx].iov_len = plen; } } } else { - hwaddr len = s->regs[R_HASH_SRC_LEN]; + plen = s->regs[R_HASH_SRC_LEN]; haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], - &len, false, MEMTXATTRS_UNSPECIFIED); + &plen, false, MEMTXATTRS_UNSPECIFIED); if (haddr == NULL) { qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); return; } iov[0].iov_base = haddr; - iov[0].iov_len = len; - i = 1; + iov[0].iov_len = plen; + iov_idx = 1; } if (acc_mode) { - if (qcrypto_hash_updatev(s->hash_ctx, iov, i, &local_err) < 0) { + if (qcrypto_hash_updatev(s->hash_ctx, iov, iov_idx, &local_err) < 0) { qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s", error_get_pretty(local_err)); error_free(local_err); return; } - if (sg_acc_mode_final_request) { + if (acc_final_request) { if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf, &digest_len, &local_err)) { qemu_log_mask(LOG_GUEST_ERROR, @@ -248,7 +247,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, s->hash_ctx = NULL; s->total_req_len = 0; } - } else if (qcrypto_hash_bytesv(algo, iov, i, &digest_buf, + } else if (qcrypto_hash_bytesv(algo, iov, iov_idx, &digest_buf, &digest_len, &local_err) < 0) { qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s", error_get_pretty(local_err)); @@ -263,10 +262,10 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, "aspeed_hace: address space write failed\n"); } - for (; i > 0; i--) { - address_space_unmap(&s->dram_as, iov[i - 1].iov_base, - iov[i - 1].iov_len, false, - iov[i - 1].iov_len); + for (; iov_idx > 0; iov_idx--) { + address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base, + iov[iov_idx - 1].iov_len, false, + iov[iov_idx - 1].iov_len); } /* From fb8e59abbe46957cd599bb9aa9221fad1e4e989e Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:35 +0800 Subject: [PATCH 1125/2760] hw/misc/aspeed_hace: Ensure HASH_IRQ is always set to prevent firmware hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, if the program encounters an unsupported algorithm, it does not set the HASH_IRQ bit in the status register and send an interrupt to indicate command completion. As a result, the FW gets stuck waiting for a completion signal from the HACE module. Additionally, in do_hash_operation, if an error occurs within the conditional statement, the HASH_IRQ bit is not set in the status register. This causes the firmware to continuously send HASH commands, as it is unaware that the HACE model has completed processing the command. To fix this, the HASH_IRQ bit in the status register must always be set to ensure that the firmware receives an interrupt from the HACE module, preventing it from getting stuck or repeatedly sending HASH commands. Signed-off-by: Jamin Lin Fixes: c5475b3 ("hw: Model ASPEED's Hash and Crypto Engine") Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 6be94963bc..1256926d22 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -267,12 +267,6 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, iov[iov_idx - 1].iov_len, false, iov[iov_idx - 1].iov_len); } - - /* - * Set status bits to indicate completion. Testing shows hardware sets - * these irrespective of HASH_IRQ_EN. - */ - s->regs[R_STATUS] |= HASH_IRQ; } static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) @@ -356,10 +350,16 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid hash algorithm selection 0x%"PRIx64"\n", __func__, data & ahc->hash_mask); - break; + } else { + do_hash_operation(s, algo, data & HASH_SG_EN, + ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); } - do_hash_operation(s, algo, data & HASH_SG_EN, - ((data & HASH_HMAC_MASK) == HASH_DIGEST_ACCUM)); + + /* + * Set status bits to indicate completion. Testing shows hardware sets + * these irrespective of HASH_IRQ_EN. + */ + s->regs[R_STATUS] |= HASH_IRQ; if (data & HASH_IRQ_EN) { qemu_irq_raise(s->irq); From 7328c48b57c97e13863fdc3a76d6d9c8fe07d6ae Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:36 +0800 Subject: [PATCH 1126/2760] hw/misc/aspeed_hace: Extract direct mode hash buffer setup into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To improve code readability and maintainability of do_hash_operation(), this commit introduces a new helper function: hash_prepare_direct_iov(). This function encapsulates the logic for setting up the I/O vector (iov) in direct mode (non-scatter-gather). No functional changes are introduced. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-5-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 1256926d22..42c6f29f82 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -142,6 +142,31 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov, return false; } +static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov) +{ + uint32_t src; + void *haddr; + hwaddr plen; + int iov_idx; + + plen = s->regs[R_HASH_SRC_LEN]; + src = s->regs[R_HASH_SRC]; + haddr = address_space_map(&s->dram_as, src, &plen, false, + MEMTXATTRS_UNSPECIFIED); + if (haddr == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Unable to map address, addr=0x%x, " + "plen=0x%" HWADDR_PRIx "\n", + __func__, src, plen); + return -1; + } + + iov[0].iov_base = haddr; + iov[0].iov_len = plen; + iov_idx = 1; + + return iov_idx; +} static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { @@ -169,6 +194,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } } + /* Prepares the iov for hashing operations based on the selected mode */ if (sg_mode) { for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) { if (iov_idx == ASPEED_HACE_MAX_SG) { @@ -211,17 +237,13 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, } } } else { - plen = s->regs[R_HASH_SRC_LEN]; + iov_idx = hash_prepare_direct_iov(s, iov); + } - haddr = address_space_map(&s->dram_as, s->regs[R_HASH_SRC], - &plen, false, MEMTXATTRS_UNSPECIFIED); - if (haddr == NULL) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto failed\n", __func__); - return; - } - iov[0].iov_base = haddr; - iov[0].iov_len = plen; - iov_idx = 1; + if (iov_idx <= 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to prepare iov\n", __func__); + return; } if (acc_mode) { From 0b7dd5f9910c41d9a3faa51001b018a06f0c3ac7 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:37 +0800 Subject: [PATCH 1127/2760] hw/misc/aspeed_hace: Extract SG-mode hash buffer setup into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To improve code readability and maintainability of do_hash_operation(), this commit introduces a new helper function: hash_prepare_sg_iov(). This function handles scatter-gather (SG) mode setup, including SG list parsing, address mapping, and optional accumulation mode support with padding detection. No functional changes are introduced. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-6-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 111 ++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 48 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 42c6f29f82..22eea62693 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -167,6 +167,67 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov) return iov_idx; } + +static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, + bool acc_mode, bool *acc_final_request) +{ + uint32_t total_msg_len; + uint32_t pad_offset; + uint32_t len = 0; + uint32_t sg_addr; + uint32_t src; + int iov_idx; + hwaddr plen; + void *haddr; + + for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) { + if (iov_idx == ASPEED_HACE_MAX_SG) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to set end of sg list marker\n", + __func__); + return -1; + } + + src = s->regs[R_HASH_SRC] + (iov_idx * SG_LIST_ENTRY_SIZE); + + len = address_space_ldl_le(&s->dram_as, src, + MEMTXATTRS_UNSPECIFIED, NULL); + sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, + MEMTXATTRS_UNSPECIFIED, NULL); + sg_addr &= SG_LIST_ADDR_MASK; + + plen = len & SG_LIST_LEN_MASK; + haddr = address_space_map(&s->dram_as, sg_addr, &plen, false, + MEMTXATTRS_UNSPECIFIED); + + if (haddr == NULL) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Unable to map address, sg_addr=0x%x, " + "plen=0x%" HWADDR_PRIx "\n", + __func__, sg_addr, plen); + return -1; + } + + iov[iov_idx].iov_base = haddr; + if (acc_mode) { + s->total_req_len += plen; + + if (has_padding(s, &iov[iov_idx], plen, &total_msg_len, + &pad_offset)) { + /* Padding being present indicates the final request */ + *acc_final_request = true; + iov[iov_idx].iov_len = pad_offset; + } else { + iov[iov_idx].iov_len = plen; + } + } else { + iov[iov_idx].iov_len = plen; + } + } + + return iov_idx; +} + static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { @@ -174,15 +235,8 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, struct iovec iov[ASPEED_HACE_MAX_SG]; bool acc_final_request = false; Error *local_err = NULL; - uint32_t total_msg_len; size_t digest_len = 0; - uint32_t sg_addr = 0; - uint32_t pad_offset; - int iov_idx = 0; - uint32_t len = 0; - uint32_t src = 0; - void *haddr; - hwaddr plen; + int iov_idx = -1; if (acc_mode && s->hash_ctx == NULL) { s->hash_ctx = qcrypto_hash_new(algo, &local_err); @@ -196,46 +250,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, /* Prepares the iov for hashing operations based on the selected mode */ if (sg_mode) { - for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) { - if (iov_idx == ASPEED_HACE_MAX_SG) { - qemu_log_mask(LOG_GUEST_ERROR, - "aspeed_hace: guest failed to set end of sg list marker\n"); - break; - } - - src = s->regs[R_HASH_SRC] + (iov_idx * SG_LIST_ENTRY_SIZE); - - len = address_space_ldl_le(&s->dram_as, src, - MEMTXATTRS_UNSPECIFIED, NULL); - - sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, - MEMTXATTRS_UNSPECIFIED, NULL); - sg_addr &= SG_LIST_ADDR_MASK; - - plen = len & SG_LIST_LEN_MASK; - haddr = address_space_map(&s->dram_as, sg_addr, &plen, false, - MEMTXATTRS_UNSPECIFIED); - if (haddr == NULL) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: qcrypto failed\n", __func__); - return; - } - iov[iov_idx].iov_base = haddr; - if (acc_mode) { - s->total_req_len += plen; - - if (has_padding(s, &iov[iov_idx], plen, &total_msg_len, - &pad_offset)) { - /* Padding being present indicates the final request */ - acc_final_request = true; - iov[iov_idx].iov_len = pad_offset; - } else { - iov[iov_idx].iov_len = plen; - } - } else { - iov[iov_idx].iov_len = plen; - } - } + iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request); } else { iov_idx = hash_prepare_direct_iov(s, iov); } From 047941978508e68215d01cc0e3e5408c430e9e9f Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:38 +0800 Subject: [PATCH 1128/2760] hw/misc/aspeed_hace: Extract digest write and iov unmap into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To improve code readability and maintainability of do_hash_operation(), this commit introduces a new helper function: hash_write_digest_and_unmap_iov(). The helper consolidates the final digest writeback and subsequent unmapping of the I/O vectors into a single routine. No functional changes are introduced. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-7-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 22eea62693..7da781f864 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -228,6 +228,26 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, return iov_idx; } +static void hash_write_digest_and_unmap_iov(AspeedHACEState *s, + struct iovec *iov, + int iov_idx, + uint8_t *digest_buf, + size_t digest_len) +{ + if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], + MEMTXATTRS_UNSPECIFIED, digest_buf, digest_len)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Failed to write digest to 0x%x\n", + __func__, s->regs[R_HASH_DEST]); + } + + for (; iov_idx > 0; iov_idx--) { + address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base, + iov[iov_idx - 1].iov_len, false, + iov[iov_idx - 1].iov_len); + } +} + static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { @@ -292,18 +312,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, return; } - if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], - MEMTXATTRS_UNSPECIFIED, - digest_buf, digest_len)) { - qemu_log_mask(LOG_GUEST_ERROR, - "aspeed_hace: address space write failed\n"); - } - - for (; iov_idx > 0; iov_idx--) { - address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base, - iov[iov_idx - 1].iov_len, false, - iov[iov_idx - 1].iov_len); - } + hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len); } static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) From 02c4c448460e1370f767c56749a1756a5c4dcc3a Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:39 +0800 Subject: [PATCH 1129/2760] hw/misc/aspeed_hace: Extract non-accumulation hash execution into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To improve code readability and maintainability of do_hash_operation(), this commit introduces a new helper function: hash_execute_non_acc_mode(). The helper encapsulate the hashing logic for non-accumulation mode. No functional changes are introduced. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-8-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 7da781f864..c50e228cdf 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -248,6 +248,25 @@ static void hash_write_digest_and_unmap_iov(AspeedHACEState *s, } } +static void hash_execute_non_acc_mode(AspeedHACEState *s, int algo, + struct iovec *iov, int iov_idx) +{ + g_autofree uint8_t *digest_buf = NULL; + Error *local_err = NULL; + size_t digest_len = 0; + + if (qcrypto_hash_bytesv(algo, iov, iov_idx, &digest_buf, + &digest_len, &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: qcrypto hash bytesv failed : %s", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + + hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len); +} + static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { @@ -304,15 +323,12 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, s->hash_ctx = NULL; s->total_req_len = 0; } - } else if (qcrypto_hash_bytesv(algo, iov, iov_idx, &digest_buf, - &digest_len, &local_err) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash bytesv failed : %s", - error_get_pretty(local_err)); - error_free(local_err); - return; - } - hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len); + hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, + digest_len); + } else { + hash_execute_non_acc_mode(s, algo, iov, iov_idx); + } } static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) From b9ccbe212e2443294dd636cb17b4e436db8774a7 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:40 +0800 Subject: [PATCH 1130/2760] hw/misc/aspeed_hace: Extract accumulation-mode hash execution into helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To improve code readability and maintainability of do_hash_operation(), this commit introduces a new helper function: hash_execute_acc_mode(). This function encapsulates the full flow for accumulation mode, including context initialization, update, conditional finalization, and digest writeback with I/O vector unmapping. No functional changes are introduced. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-9-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 74 ++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index c50e228cdf..33e13974fe 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -267,26 +267,57 @@ static void hash_execute_non_acc_mode(AspeedHACEState *s, int algo, hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len); } -static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, - bool acc_mode) +static void hash_execute_acc_mode(AspeedHACEState *s, int algo, + struct iovec *iov, int iov_idx, + bool final_request) { g_autofree uint8_t *digest_buf = NULL; - struct iovec iov[ASPEED_HACE_MAX_SG]; - bool acc_final_request = false; Error *local_err = NULL; size_t digest_len = 0; - int iov_idx = -1; - if (acc_mode && s->hash_ctx == NULL) { + if (s->hash_ctx == NULL) { s->hash_ctx = qcrypto_hash_new(algo, &local_err); if (s->hash_ctx == NULL) { - qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash failed : %s", - error_get_pretty(local_err)); + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash new failed : %s", + __func__, error_get_pretty(local_err)); error_free(local_err); return; } } + if (qcrypto_hash_updatev(s->hash_ctx, iov, iov_idx, &local_err) < 0) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: qcrypto hash updatev failed : %s", + __func__, error_get_pretty(local_err)); + error_free(local_err); + return; + } + + if (final_request) { + if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf, + &digest_len, &local_err)) { + qemu_log_mask(LOG_GUEST_ERROR, + "%s: qcrypto hash finalize bytes failed : %s", + __func__, error_get_pretty(local_err)); + error_free(local_err); + local_err = NULL; + } + + qcrypto_hash_free(s->hash_ctx); + + s->hash_ctx = NULL; + s->total_req_len = 0; + } + + hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, digest_len); +} + +static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, + bool acc_mode) +{ + struct iovec iov[ASPEED_HACE_MAX_SG]; + bool acc_final_request = false; + int iov_idx = -1; + /* Prepares the iov for hashing operations based on the selected mode */ if (sg_mode) { iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request); @@ -300,32 +331,9 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, return; } + /* Executes the hash operation */ if (acc_mode) { - if (qcrypto_hash_updatev(s->hash_ctx, iov, iov_idx, &local_err) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, "qcrypto hash update failed : %s", - error_get_pretty(local_err)); - error_free(local_err); - return; - } - - if (acc_final_request) { - if (qcrypto_hash_finalize_bytes(s->hash_ctx, &digest_buf, - &digest_len, &local_err)) { - qemu_log_mask(LOG_GUEST_ERROR, - "qcrypto hash finalize failed : %s", - error_get_pretty(local_err)); - error_free(local_err); - local_err = NULL; - } - - qcrypto_hash_free(s->hash_ctx); - - s->hash_ctx = NULL; - s->total_req_len = 0; - } - - hash_write_digest_and_unmap_iov(s, iov, iov_idx, digest_buf, - digest_len); + hash_execute_acc_mode(s, algo, iov, iov_idx, acc_final_request); } else { hash_execute_non_acc_mode(s, algo, iov, iov_idx); } From c6c5fc5ab04533a22be11f377aa67d46e47056bf Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:41 +0800 Subject: [PATCH 1131/2760] hw/misc/aspeed_hace: Introduce 64-bit hash source address helper function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2700 CPU, based on the Cortex-A35, is a 64-bit processor, and its DRAM address space is also 64-bit. To support future AST2700 updates, the source hash buffer address data type is being updated to 64-bit. Introduces the "hash_get_source_addr()" helper function to extract the source hash buffer address. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-10-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 33e13974fe..b3c3af51fa 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -142,21 +142,30 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov, return false; } +static uint64_t hash_get_source_addr(AspeedHACEState *s) +{ + uint64_t src_addr = 0; + + src_addr = deposit64(src_addr, 0, 32, s->regs[R_HASH_SRC]); + + return src_addr; +} + static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov) { - uint32_t src; + uint64_t src; void *haddr; hwaddr plen; int iov_idx; plen = s->regs[R_HASH_SRC_LEN]; - src = s->regs[R_HASH_SRC]; + src = hash_get_source_addr(s); haddr = address_space_map(&s->dram_as, src, &plen, false, MEMTXATTRS_UNSPECIFIED); if (haddr == NULL) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: Unable to map address, addr=0x%x, " - "plen=0x%" HWADDR_PRIx "\n", + "%s: Unable to map address, addr=0x%" HWADDR_PRIx + " ,plen=0x%" HWADDR_PRIx "\n", __func__, src, plen); return -1; } @@ -175,11 +184,12 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, uint32_t pad_offset; uint32_t len = 0; uint32_t sg_addr; - uint32_t src; + uint64_t src; int iov_idx; hwaddr plen; void *haddr; + src = hash_get_source_addr(s); for (iov_idx = 0; !(len & SG_LIST_LEN_LAST); iov_idx++) { if (iov_idx == ASPEED_HACE_MAX_SG) { qemu_log_mask(LOG_GUEST_ERROR, @@ -188,8 +198,6 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, return -1; } - src = s->regs[R_HASH_SRC] + (iov_idx * SG_LIST_ENTRY_SIZE); - len = address_space_ldl_le(&s->dram_as, src, MEMTXATTRS_UNSPECIFIED, NULL); sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, @@ -208,6 +216,8 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, return -1; } + src += SG_LIST_ENTRY_SIZE; + iov[iov_idx].iov_base = haddr; if (acc_mode) { s->total_req_len += plen; From 973fab3b3099aa5f6a4510c4da03056d6baf09a7 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:42 +0800 Subject: [PATCH 1132/2760] hw/misc/aspeed_hace: Rename R_HASH_DEST to R_HASH_DIGEST and introduce 64-bit hash digest address helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Renaming R_HASH_DEST to R_HASH_DIGEST for better semantic clarity. The AST2700 CPU, based on the Cortex-A35, features a 64-bit DRAM address space. To prepare for future AST2700 support, this change introduces a new helper function hash_get_digest_addr() to encapsulate digest address extraction logic and improve code readability. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-11-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index b3c3af51fa..62649b5b27 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -27,7 +27,7 @@ #define TAG_IRQ BIT(15) #define R_HASH_SRC (0x20 / 4) -#define R_HASH_DEST (0x24 / 4) +#define R_HASH_DIGEST (0x24 / 4) #define R_HASH_KEY_BUFF (0x28 / 4) #define R_HASH_SRC_LEN (0x2c / 4) @@ -238,17 +238,30 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, return iov_idx; } +static uint64_t hash_get_digest_addr(AspeedHACEState *s) +{ + uint64_t digest_addr = 0; + + digest_addr = deposit64(digest_addr, 0, 32, s->regs[R_HASH_DIGEST]); + + return digest_addr; +} + static void hash_write_digest_and_unmap_iov(AspeedHACEState *s, struct iovec *iov, int iov_idx, uint8_t *digest_buf, size_t digest_len) { - if (address_space_write(&s->dram_as, s->regs[R_HASH_DEST], - MEMTXATTRS_UNSPECIFIED, digest_buf, digest_len)) { + uint64_t digest_addr = 0; + + digest_addr = hash_get_digest_addr(s); + if (address_space_write(&s->dram_as, digest_addr, + MEMTXATTRS_UNSPECIFIED, + digest_buf, digest_len)) { qemu_log_mask(LOG_GUEST_ERROR, - "%s: Failed to write digest to 0x%x\n", - __func__, s->regs[R_HASH_DEST]); + "%s: Failed to write digest to 0x%" HWADDR_PRIx "\n", + __func__, digest_addr); } for (; iov_idx > 0; iov_idx--) { @@ -402,7 +415,7 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, case R_HASH_SRC: data &= ahc->src_mask; break; - case R_HASH_DEST: + case R_HASH_DIGEST: data &= ahc->dest_mask; break; case R_HASH_KEY_BUFF: From 7b4e588000699701f5906746d1b5b845391705e6 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:43 +0800 Subject: [PATCH 1133/2760] hw/misc/aspeed_hace: Support accumulative mode for direct access mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enable accumulative mode for direct access mode operations. In direct access mode, only a single source buffer is used, so the "iovec" count is set to 1. If "acc_mode" is enabled: 1. Accumulate "total_req_len" with the current request length ("plen"). 2. Check for padding and determine whether this is the final request. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-12-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 62649b5b27..049f732f99 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -151,8 +151,11 @@ static uint64_t hash_get_source_addr(AspeedHACEState *s) return src_addr; } -static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov) +static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov, + bool acc_mode, bool *acc_final_request) { + uint32_t total_msg_len; + uint32_t pad_offset; uint64_t src; void *haddr; hwaddr plen; @@ -171,9 +174,23 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov) } iov[0].iov_base = haddr; - iov[0].iov_len = plen; iov_idx = 1; + if (acc_mode) { + s->total_req_len += plen; + + if (has_padding(s, &iov[0], plen, &total_msg_len, + &pad_offset)) { + /* Padding being present indicates the final request */ + *acc_final_request = true; + iov[0].iov_len = pad_offset; + } else { + iov[0].iov_len = plen; + } + } else { + iov[0].iov_len = plen; + } + return iov_idx; } @@ -345,7 +362,8 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, if (sg_mode) { iov_idx = hash_prepare_sg_iov(s, iov, acc_mode, &acc_final_request); } else { - iov_idx = hash_prepare_direct_iov(s, iov); + iov_idx = hash_prepare_direct_iov(s, iov, acc_mode, + &acc_final_request); } if (iov_idx <= 0) { From 89d2a9f3f7564c9421d61153bbf7e24af95d34ee Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:44 +0800 Subject: [PATCH 1134/2760] hw/misc/aspeed_hace: Move register size to instance class and dynamically allocate regs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dynamically allocate the register array by removing the hardcoded ASPEED_HACE_NR_REGS macro. To support different register sizes across SoC variants, introduce a new "nr_regs" class attribute and replace the static "regs" array with dynamically allocated memory. Add a new "aspeed_hace_unrealize" function to properly free the allocated "regs" memory during device cleanup. Remove the bounds checking in the MMIO read/write handlers since the MemoryRegion size now matches the (register array size << 2). This commit updates the VMState fields accordingly. The VMState version was already bumped in a previous patch of this series, so no further version change is needed. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-13-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 36 ++++++++++++++++++----------------- include/hw/misc/aspeed_hace.h | 5 +++-- 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 049f732f99..fef63eb488 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -386,13 +386,6 @@ static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) addr >>= 2; - if (addr >= ASPEED_HACE_NR_REGS) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n", - __func__, addr << 2); - return 0; - } - return s->regs[addr]; } @@ -404,13 +397,6 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, addr >>= 2; - if (addr >= ASPEED_HACE_NR_REGS) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n", - __func__, addr << 2); - return; - } - switch (addr) { case R_STATUS: if (data & HASH_IRQ) { @@ -507,13 +493,14 @@ static const MemoryRegionOps aspeed_hace_ops = { static void aspeed_hace_reset(DeviceState *dev) { struct AspeedHACEState *s = ASPEED_HACE(dev); + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); if (s->hash_ctx != NULL) { qcrypto_hash_free(s->hash_ctx); s->hash_ctx = NULL; } - memset(s->regs, 0, sizeof(s->regs)); + memset(s->regs, 0, ahc->nr_regs << 2); s->total_req_len = 0; } @@ -521,11 +508,13 @@ static void aspeed_hace_realize(DeviceState *dev, Error **errp) { AspeedHACEState *s = ASPEED_HACE(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); sysbus_init_irq(sbd, &s->irq); + s->regs = g_new(uint32_t, ahc->nr_regs); memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_hace_ops, s, - TYPE_ASPEED_HACE, 0x1000); + TYPE_ASPEED_HACE, ahc->nr_regs << 2); if (!s->dram_mr) { error_setg(errp, TYPE_ASPEED_HACE ": 'dram' link not set"); @@ -548,17 +537,25 @@ static const VMStateDescription vmstate_aspeed_hace = { .version_id = 2, .minimum_version_id = 2, .fields = (const VMStateField[]) { - VMSTATE_UINT32_ARRAY(regs, AspeedHACEState, ASPEED_HACE_NR_REGS), VMSTATE_UINT32(total_req_len, AspeedHACEState), VMSTATE_END_OF_LIST(), } }; +static void aspeed_hace_unrealize(DeviceState *dev) +{ + AspeedHACEState *s = ASPEED_HACE(dev); + + g_free(s->regs); + s->regs = NULL; +} + static void aspeed_hace_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->realize = aspeed_hace_realize; + dc->unrealize = aspeed_hace_unrealize; device_class_set_legacy_reset(dc, aspeed_hace_reset); device_class_set_props(dc, aspeed_hace_properties); dc->vmsd = &vmstate_aspeed_hace; @@ -579,6 +576,7 @@ static void aspeed_ast2400_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST2400 Hash and Crypto Engine"; + ahc->nr_regs = 0x64 >> 2; ahc->src_mask = 0x0FFFFFFF; ahc->dest_mask = 0x0FFFFFF8; ahc->key_mask = 0x0FFFFFC0; @@ -598,6 +596,7 @@ static void aspeed_ast2500_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST2500 Hash and Crypto Engine"; + ahc->nr_regs = 0x64 >> 2; ahc->src_mask = 0x3fffffff; ahc->dest_mask = 0x3ffffff8; ahc->key_mask = 0x3FFFFFC0; @@ -617,6 +616,7 @@ static void aspeed_ast2600_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST2600 Hash and Crypto Engine"; + ahc->nr_regs = 0x64 >> 2; ahc->src_mask = 0x7FFFFFFF; ahc->dest_mask = 0x7FFFFFF8; ahc->key_mask = 0x7FFFFFF8; @@ -636,6 +636,7 @@ static void aspeed_ast1030_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST1030 Hash and Crypto Engine"; + ahc->nr_regs = 0x64 >> 2; ahc->src_mask = 0x7FFFFFFF; ahc->dest_mask = 0x7FFFFFF8; ahc->key_mask = 0x7FFFFFF8; @@ -655,6 +656,7 @@ static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST2700 Hash and Crypto Engine"; + ahc->nr_regs = 0x64 >> 2; ahc->src_mask = 0x7FFFFFFF; ahc->dest_mask = 0x7FFFFFF8; ahc->key_mask = 0x7FFFFFF8; diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index b69a038d35..f30d606559 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -22,7 +22,6 @@ OBJECT_DECLARE_TYPE(AspeedHACEState, AspeedHACEClass, ASPEED_HACE) -#define ASPEED_HACE_NR_REGS (0x64 >> 2) #define ASPEED_HACE_MAX_SG 256 /* max number of entries */ struct AspeedHACEState { @@ -31,7 +30,7 @@ struct AspeedHACEState { MemoryRegion iomem; qemu_irq irq; - uint32_t regs[ASPEED_HACE_NR_REGS]; + uint32_t *regs; uint32_t total_req_len; MemoryRegion *dram_mr; @@ -44,10 +43,12 @@ struct AspeedHACEState { struct AspeedHACEClass { SysBusDeviceClass parent_class; + const MemoryRegionOps *reg_ops; uint32_t src_mask; uint32_t dest_mask; uint32_t key_mask; uint32_t hash_mask; + uint64_t nr_regs; bool raise_crypt_interrupt_workaround; }; From 6262c8addc8ed586dfa5f11606f1598fca45b3eb Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:45 +0800 Subject: [PATCH 1135/2760] hw/misc/aspeed_hace: Add support for source, digest, key buffer 64 bit addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the AST2700 design, the data source address is 64-bit, with R_HASH_SRC_HI storing bits [63:32] and R_HASH_SRC storing bits [31:0]. Similarly, the digest address is 64-bit, with R_HASH_DIGEST_HI storing bits [63:32] and R_HASH_DIGEST storing bits [31:0]. The HMAC key buffer address is also 64-bit, with R_HASH_KEY_BUFF_HI storing bits [63:32] and R_HASH_KEY_BUFF storing bits [31:0]. The AST2700 supports a maximum DRAM size of 8 GB, with a DRAM addressable range from 0x0_0000_0000 to 0x1_FFFF_FFFF. Since this range fits within 34 bits, only bits [33:0] are needed to store the DRAM offset. To optimize address storage, the high physical address bits [1:0] of the source, digest and key buffer addresses are stored as dram_offset bits [33:32]. To achieve this, a src_hi_mask with a mask value of 0x3 is introduced, ensuring that src_addr_hi consists of bits [1:0]. The final src_addr is computed as (src_addr_hi[1:0] << 32) | src_addr[31:0], representing the DRAM offset within bits [33:0]. Similarly, a dest_hi_mask with a mask value of 0x3 is introduced to ensure that dest_addr_hi consists of bits [1:0]. The final dest_addr is calculated as (dest_addr_hi[1:0] << 32) | dest_addr[31:0], representing the DRAM offset within bits [33:0]. Additionally, a key_hi_mask with a mask value of 0x3 is introduced to ensure that key_buf_addr_hi consists of bits [1:0]. The final key_buf_addr is determined as (key_buf_addr_hi[1:0] << 32) | key_buf_addr[31:0], representing the DRAM offset within bits [33:0]. This approach eliminates the need to reduce the high part of the DRAM physical address for DMA operations. Previously, this was calculated as (high physical address bits [7:0] - 4), since the DRAM start address is 0x4_00000000, making the high part address [7:0] - 4. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-14-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 31 ++++++++++++++++++++++++++++++- include/hw/misc/aspeed_hace.h | 3 +++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index fef63eb488..d58645cabd 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -30,6 +30,9 @@ #define R_HASH_DIGEST (0x24 / 4) #define R_HASH_KEY_BUFF (0x28 / 4) #define R_HASH_SRC_LEN (0x2c / 4) +#define R_HASH_SRC_HI (0x90 / 4) +#define R_HASH_DIGEST_HI (0x94 / 4) +#define R_HASH_KEY_BUFF_HI (0x98 / 4) #define R_HASH_CMD (0x30 / 4) /* Hash algorithm selection */ @@ -473,6 +476,15 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, } } break; + case R_HASH_SRC_HI: + data &= ahc->src_hi_mask; + break; + case R_HASH_DIGEST_HI: + data &= ahc->dest_hi_mask; + break; + case R_HASH_KEY_BUFF_HI: + data &= ahc->key_hi_mask; + break; default: break; } @@ -656,12 +668,29 @@ static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data) dc->desc = "AST2700 Hash and Crypto Engine"; - ahc->nr_regs = 0x64 >> 2; + ahc->nr_regs = 0x9C >> 2; ahc->src_mask = 0x7FFFFFFF; ahc->dest_mask = 0x7FFFFFF8; ahc->key_mask = 0x7FFFFFF8; ahc->hash_mask = 0x00147FFF; + /* + * The AST2700 supports a maximum DRAM size of 8 GB, with a DRAM + * addressable range from 0x0_0000_0000 to 0x1_FFFF_FFFF. Since this range + * fits within 34 bits, only bits [33:0] are needed to store the DRAM + * offset. To optimize address storage, the high physical address bits + * [1:0] of the source, digest and key buffer addresses are stored as + * dram_offset bits [33:32]. + * + * This approach eliminates the need to reduce the high part of the DRAM + * physical address for DMA operations. Previously, this was calculated as + * (high physical address bits [7:0] - 4), since the DRAM start address is + * 0x4_00000000, making the high part address [7:0] - 4. + */ + ahc->src_hi_mask = 0x00000003; + ahc->dest_hi_mask = 0x00000003; + ahc->key_hi_mask = 0x00000003; + /* * Currently, it does not support the CRYPT command. Instead, it only * sends an interrupt to notify the firmware that the crypt command diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index f30d606559..9945b61863 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -50,6 +50,9 @@ struct AspeedHACEClass { uint32_t hash_mask; uint64_t nr_regs; bool raise_crypt_interrupt_workaround; + uint32_t src_hi_mask; + uint32_t dest_hi_mask; + uint32_t key_hi_mask; }; #endif /* ASPEED_HACE_H */ From 7e65aa39b37cb189c4d0bc923d4d778bdd626f4b Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:46 +0800 Subject: [PATCH 1136/2760] hw/misc/aspeed_hace: Support DMA 64 bits dram address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the AST2700 design, the data source address is 64-bit, with R_HASH_SRC_HI storing bits [63:32] and R_HASH_SRC storing bits [31:0]. Similarly, the digest address is 64-bit, with R_HASH_DEST_HI storing bits [63:32] and R_HASH_DEST storing bits [31:0]. To maintain compatibility with older SoCs such as the AST2600, the AST2700 HW automatically set bit 34 of the 64-bit sg_addr. As a result, the firmware only needs to provide a 32-bit sg_addr containing bits [31:0]. This is sufficient for the AST2700, as it uses a DRAM offset rather than a DRAM address. Introduce a has_dma64 class attribute and set it to true for the AST2700. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-15-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 17 ++++++++++++++++- include/hw/misc/aspeed_hace.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index d58645cabd..764408716e 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -147,9 +147,13 @@ static bool has_padding(AspeedHACEState *s, struct iovec *iov, static uint64_t hash_get_source_addr(AspeedHACEState *s) { + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); uint64_t src_addr = 0; src_addr = deposit64(src_addr, 0, 32, s->regs[R_HASH_SRC]); + if (ahc->has_dma64) { + src_addr = deposit64(src_addr, 32, 32, s->regs[R_HASH_SRC_HI]); + } return src_addr; } @@ -223,7 +227,13 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, MEMTXATTRS_UNSPECIFIED, NULL); sg_addr &= SG_LIST_ADDR_MASK; - + /* + * To maintain compatibility with older SoCs such as the AST2600, + * the AST2700 HW automatically set bit 34 of the 64-bit sg_addr. + * As a result, the firmware only needs to provide a 32-bit sg_addr + * containing bits [31:0]. This is sufficient for the AST2700, as + * it uses a DRAM offset rather than a DRAM address. + */ plen = len & SG_LIST_LEN_MASK; haddr = address_space_map(&s->dram_as, sg_addr, &plen, false, MEMTXATTRS_UNSPECIFIED); @@ -260,9 +270,13 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, static uint64_t hash_get_digest_addr(AspeedHACEState *s) { + AspeedHACEClass *ahc = ASPEED_HACE_GET_CLASS(s); uint64_t digest_addr = 0; digest_addr = deposit64(digest_addr, 0, 32, s->regs[R_HASH_DIGEST]); + if (ahc->has_dma64) { + digest_addr = deposit64(digest_addr, 32, 32, s->regs[R_HASH_DIGEST_HI]); + } return digest_addr; } @@ -697,6 +711,7 @@ static void aspeed_ast2700_hace_class_init(ObjectClass *klass, const void *data) * has completed. It is a temporary workaround. */ ahc->raise_crypt_interrupt_workaround = true; + ahc->has_dma64 = true; } static const TypeInfo aspeed_ast2700_hace_info = { diff --git a/include/hw/misc/aspeed_hace.h b/include/hw/misc/aspeed_hace.h index 9945b61863..d5d07c6c02 100644 --- a/include/hw/misc/aspeed_hace.h +++ b/include/hw/misc/aspeed_hace.h @@ -53,6 +53,7 @@ struct AspeedHACEClass { uint32_t src_hi_mask; uint32_t dest_hi_mask; uint32_t key_hi_mask; + bool has_dma64; }; #endif /* ASPEED_HACE_H */ From 555167a8fde2bf6c27d0df035324743ed5bfbb0d Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:47 +0800 Subject: [PATCH 1137/2760] hw/misc/aspeed_hace: Add trace-events for better debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced "trace_aspeed_hace_hash_addr", "trace_aspeed_hace_hash_sg", "trace_aspeed_hace_read", "trace_aspeed_hace_hash_execute_acc_mode", and "trace_aspeed_hace_write" trace events. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-16-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 10 ++++++++++ hw/misc/trace-events | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 764408716e..ee1d9ab58f 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -18,6 +18,7 @@ #include "crypto/hash.h" #include "hw/qdev-properties.h" #include "hw/irq.h" +#include "trace.h" #define R_CRYPT_CMD (0x10 / 4) @@ -170,6 +171,7 @@ static int hash_prepare_direct_iov(AspeedHACEState *s, struct iovec *iov, plen = s->regs[R_HASH_SRC_LEN]; src = hash_get_source_addr(s); + trace_aspeed_hace_hash_addr("src", src); haddr = address_space_map(&s->dram_as, src, &plen, false, MEMTXATTRS_UNSPECIFIED); if (haddr == NULL) { @@ -227,6 +229,7 @@ static int hash_prepare_sg_iov(AspeedHACEState *s, struct iovec *iov, sg_addr = address_space_ldl_le(&s->dram_as, src + SG_LIST_LEN_SIZE, MEMTXATTRS_UNSPECIFIED, NULL); sg_addr &= SG_LIST_ADDR_MASK; + trace_aspeed_hace_hash_sg(iov_idx, src, sg_addr, len); /* * To maintain compatibility with older SoCs such as the AST2600, * the AST2700 HW automatically set bit 34 of the 64-bit sg_addr. @@ -290,6 +293,7 @@ static void hash_write_digest_and_unmap_iov(AspeedHACEState *s, uint64_t digest_addr = 0; digest_addr = hash_get_digest_addr(s); + trace_aspeed_hace_hash_addr("digest", digest_addr); if (address_space_write(&s->dram_as, digest_addr, MEMTXATTRS_UNSPECIFIED, digest_buf, digest_len)) { @@ -332,6 +336,8 @@ static void hash_execute_acc_mode(AspeedHACEState *s, int algo, Error *local_err = NULL; size_t digest_len = 0; + trace_aspeed_hace_hash_execute_acc_mode(final_request); + if (s->hash_ctx == NULL) { s->hash_ctx = qcrypto_hash_new(algo, &local_err); if (s->hash_ctx == NULL) { @@ -403,6 +409,8 @@ static uint64_t aspeed_hace_read(void *opaque, hwaddr addr, unsigned int size) addr >>= 2; + trace_aspeed_hace_read(addr << 2, s->regs[addr]); + return s->regs[addr]; } @@ -414,6 +422,8 @@ static void aspeed_hace_write(void *opaque, hwaddr addr, uint64_t data, addr >>= 2; + trace_aspeed_hace_write(addr << 2, data); + switch (addr) { case R_STATUS: if (data & HASH_IRQ) { diff --git a/hw/misc/trace-events b/hw/misc/trace-events index 4383808d7a..b980d7fdd3 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -302,6 +302,13 @@ aspeed_peci_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" aspeed_peci_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 aspeed_peci_raise_interrupt(uint32_t ctrl, uint32_t status) "ctrl 0x%" PRIx32 " status 0x%" PRIx32 +# aspeed_hace.c +aspeed_hace_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 +aspeed_hace_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 +aspeed_hace_hash_sg(int index, uint64_t list_addr, uint64_t buf_addr, uint32_t len) "%d: list_addr 0x%" PRIx64 " buf_addr 0x%" PRIx64 " len 0x%" PRIx32 +aspeed_hace_hash_addr(const char *s, uint64_t addr) "%s: 0x%" PRIx64 +aspeed_hace_hash_execute_acc_mode(bool final_request) "final request: %d" + # bcm2835_property.c bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu" From 22370d29e83753e4072457541ab59189edcd3947 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:48 +0800 Subject: [PATCH 1138/2760] hw/misc/aspeed_hace: Support to dump plaintext and digest for better debugging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Added "hace_hexdump()" to dump a contiguous buffer using qemu_hexdump. 2. Added "hace_iov_hexdump()" to flatten and dump scatter-gather source vectors. 3. Introduced a new trace event: "aspeed_hace_hexdump". Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-17-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/misc/aspeed_hace.c | 46 +++++++++++++++++++++++++++++++++++++++++++ hw/misc/trace-events | 1 + 2 files changed, 47 insertions(+) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index ee1d9ab58f..8924a30eff 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -10,8 +10,10 @@ */ #include "qemu/osdep.h" +#include "qemu/cutils.h" #include "qemu/log.h" #include "qemu/error-report.h" +#include "qemu/iov.h" #include "hw/misc/aspeed_hace.h" #include "qapi/error.h" #include "migration/vmstate.h" @@ -88,6 +90,42 @@ static const struct { QCRYPTO_HASH_ALGO_SHA256 }, }; +static void hace_hexdump(const char *desc, const char *buf, size_t size) +{ + g_autoptr(GString) str = g_string_sized_new(64); + size_t len; + size_t i; + + for (i = 0; i < size; i += len) { + len = MIN(16, size - i); + g_string_truncate(str, 0); + qemu_hexdump_line(str, buf + i, len, 1, 4); + trace_aspeed_hace_hexdump(desc, i, str->str); + } +} + +static void hace_iov_hexdump(const char *desc, const struct iovec *iov, + const unsigned int iov_cnt) +{ + size_t size = 0; + char *buf; + int i; + + for (i = 0; i < iov_cnt; i++) { + size += iov[i].iov_len; + } + + buf = g_malloc(size); + + if (!buf) { + return; + } + + iov_to_buf(iov, iov_cnt, 0, buf, size); + hace_hexdump(desc, buf, size); + g_free(buf); +} + static int hash_algo_lookup(uint32_t reg) { int i; @@ -302,6 +340,10 @@ static void hash_write_digest_and_unmap_iov(AspeedHACEState *s, __func__, digest_addr); } + if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) { + hace_hexdump("digest", (char *)digest_buf, digest_len); + } + for (; iov_idx > 0; iov_idx--) { address_space_unmap(&s->dram_as, iov[iov_idx - 1].iov_base, iov[iov_idx - 1].iov_len, false, @@ -395,6 +437,10 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, return; } + if (trace_event_get_state_backends(TRACE_ASPEED_HACE_HEXDUMP)) { + hace_iov_hexdump("plaintext", iov, iov_idx); + } + /* Executes the hash operation */ if (acc_mode) { hash_execute_acc_mode(s, algo, iov, iov_idx, acc_final_request); diff --git a/hw/misc/trace-events b/hw/misc/trace-events index b980d7fdd3..e3f64c0ff6 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -308,6 +308,7 @@ aspeed_hace_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x% aspeed_hace_hash_sg(int index, uint64_t list_addr, uint64_t buf_addr, uint32_t len) "%d: list_addr 0x%" PRIx64 " buf_addr 0x%" PRIx64 " len 0x%" PRIx32 aspeed_hace_hash_addr(const char *s, uint64_t addr) "%s: 0x%" PRIx64 aspeed_hace_hash_execute_acc_mode(bool final_request) "final request: %d" +aspeed_hace_hexdump(const char *desc, uint32_t offset, char *s) "%s: 0x%08x: %s" # bcm2835_property.c bcm2835_mbox_property(uint32_t tag, uint32_t bufsize, size_t resplen) "mbox property tag:0x%08x in_sz:%u out_sz:%zu" From 408326af1f05776eae0f4fc91dcf643b54f9240c Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:49 +0800 Subject: [PATCH 1139/2760] tests/qtest: Reorder aspeed test list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reordered the aspeed test list to keep the alphabetical order. No functional changes in test behavior. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-18-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/meson.build | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 7daf619845..c3a24a3eb4 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -212,9 +212,9 @@ qtests_npcm7xx = \ 'npcm_gmac-test'] + \ (slirp.found() ? ['npcm7xx_emc-test'] : []) qtests_aspeed = \ - ['aspeed_hace-test', - 'aspeed_smc-test', - 'aspeed_gpio-test'] + ['aspeed_gpio-test', + 'aspeed_hace-test', + 'aspeed_smc-test'] qtests_aspeed64 = \ ['ast2700-gpio-test', 'ast2700-smc-test'] @@ -361,6 +361,8 @@ if gnutls.found() endif qtests = { + 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), + 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'cdrom-test': files('boot-sector.c'), 'dbus-vmstate-test': files('migration/migration-qmp.c', @@ -382,8 +384,6 @@ qtests = { 'virtio-net-failover': migration_files, 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), - 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), - 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), } if vnc.found() From 70985b0ea776e0cd7d7ab2a173d9d35d31e8c21f Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:50 +0800 Subject: [PATCH 1140/2760] test/qtest: Introduce a new aspeed-hace-utils.c to place common testcases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test cases for the ASPEED HACE model were originally placed in aspeed_hace-test.c. However, this test file only supports ARM32. To enable compatibility with all ASPEED SoCs, including the AST2700, which uses the AArch64 architecture, this update introduces a new source file, aspeed-hace-utils.c. All common APIs and test cases have been moved from aspeed_hace-test.c to aspeed-hace-utils.c to facilitate reuse across different ASPEED SoCs. As a result, these test cases can now be reused for AST2700 and future ASPEED SoC testing. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-19-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 455 ++++++++++++++++++++++++++++ tests/qtest/aspeed-hace-utils.h | 71 +++++ tests/qtest/aspeed_hace-test.c | 515 ++------------------------------ tests/qtest/meson.build | 1 + 4 files changed, 547 insertions(+), 495 deletions(-) create mode 100644 tests/qtest/aspeed-hace-utils.c create mode 100644 tests/qtest/aspeed-hace-utils.h diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c new file mode 100644 index 0000000000..8582847945 --- /dev/null +++ b/tests/qtest/aspeed-hace-utils.c @@ -0,0 +1,455 @@ +/* + * QTest testcase for the ASPEED Hash and Crypto Engine + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 IBM Corp. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" +#include "aspeed-hace-utils.h" + +/* + * Test vector is the ascii "abc" + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abc' | dd of=/tmp/test + * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done + * + */ +static const uint8_t test_vector[] = {0x61, 0x62, 0x63}; + +static const uint8_t test_result_sha512[] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, + 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, + 0xa5, 0x4c, 0xa4, 0x9f}; + +static const uint8_t test_result_sha256[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + +static const uint8_t test_result_md5[] = { + 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, + 0x28, 0xe1, 0x7f, 0x72}; + +/* + * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken + * into blocks of 3 characters as shown + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abcdefghijkl' | dd of=/tmp/test + * for hash in sha512sum sha256sum; do $hash /tmp/test; done + * + */ +static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; +static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69}; +static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c}; + +static const uint8_t test_result_sg_sha512[] = { + 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8, + 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3, + 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63, + 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8, + 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40, + 0xf8, 0x6d, 0xda, 0x2e}; + +static const uint8_t test_result_sg_sha256[] = { + 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1, + 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, + 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4}; + +/* + * The accumulative mode requires firmware to provide internal initial state + * and message padding (including length L at the end of padding). + * + * This test vector is a ascii text "abc" with padding message. + * + * Expected results were generated using command line utitiles: + * + * echo -n -e 'abc' | dd of=/tmp/test + * for hash in sha512sum sha256sum; do $hash /tmp/test; done + */ +static const uint8_t test_vector_accum_512[] = { + 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; + +static const uint8_t test_vector_accum_256[] = { + 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; + +static const uint8_t test_result_accum_sha512[] = { + 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, + 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, + 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, + 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, + 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, + 0xa5, 0x4c, 0xa4, 0x9f}; + +static const uint8_t test_result_accum_sha256[] = { + 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, + 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, + 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; + +static void write_regs(QTestState *s, uint32_t base, uint32_t src, + uint32_t length, uint32_t out, uint32_t method) +{ + qtest_writel(s, base + HACE_HASH_SRC, src); + qtest_writel(s, base + HACE_HASH_DIGEST, out); + qtest_writel(s, base + HACE_HASH_DATA_LEN, length); + qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method); +} + +void aspeed_test_md5(const char *machine, const uint32_t base, + const uint32_t src_addr) + +{ + QTestState *s = qtest_init(machine); + + uint32_t digest_addr = src_addr + 0x01000000; + uint8_t digest[16] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), + digest_addr, HACE_ALGO_MD5); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_md5, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha256(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t digest_addr = src_addr + 0x1000000; + uint8_t digest[32] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, + HACE_ALGO_SHA256); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sha256, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha512(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t digest_addr = src_addr + 0x1000000; + uint8_t digest[64] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, + HACE_ALGO_SHA512); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sha512, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha256_sg(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t src_addr_1 = src_addr + 0x1000000; + const uint32_t src_addr_2 = src_addr + 0x2000000; + const uint32_t src_addr_3 = src_addr + 0x3000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[32] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_sg1)), + cpu_to_le32(src_addr_1) }, + { cpu_to_le32(sizeof(test_vector_sg2)), + cpu_to_le32(src_addr_2) }, + { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), + cpu_to_le32(src_addr_3) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); + qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); + qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, + (sizeof(test_vector_sg1) + + sizeof(test_vector_sg2) + + sizeof(test_vector_sg3)), + digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sg_sha256, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha512_sg(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t src_addr_1 = src_addr + 0x1000000; + const uint32_t src_addr_2 = src_addr + 0x2000000; + const uint32_t src_addr_3 = src_addr + 0x3000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[64] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_sg1)), + cpu_to_le32(src_addr_1) }, + { cpu_to_le32(sizeof(test_vector_sg2)), + cpu_to_le32(src_addr_2) }, + { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), + cpu_to_le32(src_addr_3) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); + qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); + qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, + (sizeof(test_vector_sg1) + + sizeof(test_vector_sg2) + + sizeof(test_vector_sg3)), + digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sg_sha512, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha256_accum(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t buffer_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[32] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST), + cpu_to_le32(buffer_addr) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, buffer_addr, test_vector_accum_256, + sizeof(test_vector_accum_256)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, sizeof(test_vector_accum_256), + digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN | HACE_ACCUM_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_accum_sha256, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_sha512_accum(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t buffer_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x4000000; + uint8_t digest[64] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST), + cpu_to_le32(buffer_addr) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, buffer_addr, test_vector_accum_512, + sizeof(test_vector_accum_512)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, sizeof(test_vector_accum_512), + digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN | HACE_ACCUM_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_accum_sha512, sizeof(digest)); + + qtest_quit(s); +} + +void aspeed_test_addresses(const char *machine, const uint32_t base, + const struct AspeedMasks *expected) +{ + QTestState *s = qtest_init(machine); + + /* + * Check command mode is zero, meaning engine is in direct access mode, + * as this affects the masking behavior of the HASH_SRC register. + */ + g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); + + + /* Check that the address masking is correct */ + qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src); + + qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, + expected->dest); + + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, + expected->len); + + /* Reset to zero */ + qtest_writel(s, base + HACE_HASH_SRC, 0); + qtest_writel(s, base + HACE_HASH_DIGEST, 0); + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0); + + /* Check that all bits are now zero */ + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); + + qtest_quit(s); +} + diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h new file mode 100644 index 0000000000..598577c69b --- /dev/null +++ b/tests/qtest/aspeed-hace-utils.h @@ -0,0 +1,71 @@ +/* + * QTest testcase for the ASPEED Hash and Crypto Engine + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2021 IBM Corp. + */ + +#ifndef TESTS_ASPEED_HACE_UTILS_H +#define TESTS_ASPEED_HACE_UTILS_H + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" + +#define HACE_CMD 0x10 +#define HACE_SHA_BE_EN BIT(3) +#define HACE_MD5_LE_EN BIT(2) +#define HACE_ALGO_MD5 0 +#define HACE_ALGO_SHA1 BIT(5) +#define HACE_ALGO_SHA224 BIT(6) +#define HACE_ALGO_SHA256 (BIT(4) | BIT(6)) +#define HACE_ALGO_SHA512 (BIT(5) | BIT(6)) +#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10)) +#define HACE_SG_EN BIT(18) +#define HACE_ACCUM_EN BIT(8) + +#define HACE_STS 0x1c +#define HACE_RSA_ISR BIT(13) +#define HACE_CRYPTO_ISR BIT(12) +#define HACE_HASH_ISR BIT(9) +#define HACE_RSA_BUSY BIT(2) +#define HACE_CRYPTO_BUSY BIT(1) +#define HACE_HASH_BUSY BIT(0) +#define HACE_HASH_SRC 0x20 +#define HACE_HASH_DIGEST 0x24 +#define HACE_HASH_KEY_BUFF 0x28 +#define HACE_HASH_DATA_LEN 0x2c +#define HACE_HASH_CMD 0x30 + +/* Scatter-Gather Hash */ +#define SG_LIST_LEN_LAST BIT(31) +struct AspeedSgList { + uint32_t len; + uint32_t addr; +} __attribute__ ((__packed__)); + +struct AspeedMasks { + uint32_t src; + uint32_t dest; + uint32_t len; +}; + +void aspeed_test_md5(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha256(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha512(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha256_sg(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha512_sg(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha256_accum(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_sha512_accum(const char *machine, const uint32_t base, + const uint32_t src_addr); +void aspeed_test_addresses(const char *machine, const uint32_t base, + const struct AspeedMasks *expected); + +#endif /* TESTS_ASPEED_HACE_UTILS_H */ + diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index ce86a44672..42a306af2a 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -6,584 +6,109 @@ */ #include "qemu/osdep.h" - #include "libqtest.h" #include "qemu/bitops.h" +#include "aspeed-hace-utils.h" -#define HACE_CMD 0x10 -#define HACE_SHA_BE_EN BIT(3) -#define HACE_MD5_LE_EN BIT(2) -#define HACE_ALGO_MD5 0 -#define HACE_ALGO_SHA1 BIT(5) -#define HACE_ALGO_SHA224 BIT(6) -#define HACE_ALGO_SHA256 (BIT(4) | BIT(6)) -#define HACE_ALGO_SHA512 (BIT(5) | BIT(6)) -#define HACE_ALGO_SHA384 (BIT(5) | BIT(6) | BIT(10)) -#define HACE_SG_EN BIT(18) -#define HACE_ACCUM_EN BIT(8) - -#define HACE_STS 0x1c -#define HACE_RSA_ISR BIT(13) -#define HACE_CRYPTO_ISR BIT(12) -#define HACE_HASH_ISR BIT(9) -#define HACE_RSA_BUSY BIT(2) -#define HACE_CRYPTO_BUSY BIT(1) -#define HACE_HASH_BUSY BIT(0) -#define HACE_HASH_SRC 0x20 -#define HACE_HASH_DIGEST 0x24 -#define HACE_HASH_KEY_BUFF 0x28 -#define HACE_HASH_DATA_LEN 0x2c -#define HACE_HASH_CMD 0x30 -/* Scatter-Gather Hash */ -#define SG_LIST_LEN_LAST BIT(31) -struct AspeedSgList { - uint32_t len; - uint32_t addr; -} __attribute__ ((__packed__)); - -/* - * Test vector is the ascii "abc" - * - * Expected results were generated using command line utitiles: - * - * echo -n -e 'abc' | dd of=/tmp/test - * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done - * - */ -static const uint8_t test_vector[] = {0x61, 0x62, 0x63}; - -static const uint8_t test_result_sha512[] = { - 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, - 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, - 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, - 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, - 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, - 0xa5, 0x4c, 0xa4, 0x9f}; - -static const uint8_t test_result_sha256[] = { - 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, - 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, - 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; - -static const uint8_t test_result_md5[] = { - 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, - 0x28, 0xe1, 0x7f, 0x72}; - -/* - * The Scatter-Gather Test vector is the ascii "abc" "def" "ghi", broken - * into blocks of 3 characters as shown - * - * Expected results were generated using command line utitiles: - * - * echo -n -e 'abcdefghijkl' | dd of=/tmp/test - * for hash in sha512sum sha256sum; do $hash /tmp/test; done - * - */ -static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; -static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69}; -static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c}; - -static const uint8_t test_result_sg_sha512[] = { - 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8, - 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3, - 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63, - 0xd5, 0xb7, 0x3f, 0xc3, 0x96, 0xc1, 0x2b, 0xe3, 0x8b, 0x2b, 0xd5, 0xd8, - 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40, - 0xf8, 0x6d, 0xda, 0x2e}; - -static const uint8_t test_result_sg_sha256[] = { - 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1, - 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, - 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4}; - -/* - * The accumulative mode requires firmware to provide internal initial state - * and message padding (including length L at the end of padding). - * - * This test vector is a ascii text "abc" with padding message. - * - * Expected results were generated using command line utitiles: - * - * echo -n -e 'abc' | dd of=/tmp/test - * for hash in sha512sum sha256sum; do $hash /tmp/test; done - */ -static const uint8_t test_vector_accum_512[] = { - 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; - -static const uint8_t test_vector_accum_256[] = { - 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; - -static const uint8_t test_result_accum_sha512[] = { - 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, - 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, - 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, - 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, - 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, - 0xa5, 0x4c, 0xa4, 0x9f}; - -static const uint8_t test_result_accum_sha256[] = { - 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, - 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, - 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; - -static void write_regs(QTestState *s, uint32_t base, uint32_t src, - uint32_t length, uint32_t out, uint32_t method) -{ - qtest_writel(s, base + HACE_HASH_SRC, src); - qtest_writel(s, base + HACE_HASH_DIGEST, out); - qtest_writel(s, base + HACE_HASH_DATA_LEN, length); - qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method); -} - -static void test_md5(const char *machine, const uint32_t base, - const uint32_t src_addr) - -{ - QTestState *s = qtest_init(machine); - - uint32_t digest_addr = src_addr + 0x01000000; - uint8_t digest[16] = {0}; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); - - write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_MD5); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_md5, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha256(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t digest_addr = src_addr + 0x1000000; - uint8_t digest[32] = {0}; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); - - write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA256); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_sha256, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha512(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t digest_addr = src_addr + 0x1000000; - uint8_t digest[64] = {0}; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); - - write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, HACE_ALGO_SHA512); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_sha512, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha256_sg(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t src_addr_1 = src_addr + 0x1000000; - const uint32_t src_addr_2 = src_addr + 0x2000000; - const uint32_t src_addr_3 = src_addr + 0x3000000; - const uint32_t digest_addr = src_addr + 0x4000000; - uint8_t digest[32] = {0}; - struct AspeedSgList array[] = { - { cpu_to_le32(sizeof(test_vector_sg1)), - cpu_to_le32(src_addr_1) }, - { cpu_to_le32(sizeof(test_vector_sg2)), - cpu_to_le32(src_addr_2) }, - { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), - cpu_to_le32(src_addr_3) }, - }; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); - qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); - qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); - qtest_memwrite(s, src_addr, array, sizeof(array)); - - write_regs(s, base, src_addr, - (sizeof(test_vector_sg1) - + sizeof(test_vector_sg2) - + sizeof(test_vector_sg3)), - digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_sg_sha256, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha512_sg(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t src_addr_1 = src_addr + 0x1000000; - const uint32_t src_addr_2 = src_addr + 0x2000000; - const uint32_t src_addr_3 = src_addr + 0x3000000; - const uint32_t digest_addr = src_addr + 0x4000000; - uint8_t digest[64] = {0}; - struct AspeedSgList array[] = { - { cpu_to_le32(sizeof(test_vector_sg1)), - cpu_to_le32(src_addr_1) }, - { cpu_to_le32(sizeof(test_vector_sg2)), - cpu_to_le32(src_addr_2) }, - { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), - cpu_to_le32(src_addr_3) }, - }; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); - qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); - qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); - qtest_memwrite(s, src_addr, array, sizeof(array)); - - write_regs(s, base, src_addr, - (sizeof(test_vector_sg1) - + sizeof(test_vector_sg2) - + sizeof(test_vector_sg3)), - digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_sg_sha512, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha256_accum(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t buffer_addr = src_addr + 0x1000000; - const uint32_t digest_addr = src_addr + 0x4000000; - uint8_t digest[32] = {0}; - struct AspeedSgList array[] = { - { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST), - cpu_to_le32(buffer_addr) }, - }; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, buffer_addr, test_vector_accum_256, - sizeof(test_vector_accum_256)); - qtest_memwrite(s, src_addr, array, sizeof(array)); - - write_regs(s, base, src_addr, sizeof(test_vector_accum_256), - digest_addr, HACE_ALGO_SHA256 | HACE_SG_EN | HACE_ACCUM_EN); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_accum_sha256, sizeof(digest)); - - qtest_quit(s); -} - -static void test_sha512_accum(const char *machine, const uint32_t base, - const uint32_t src_addr) -{ - QTestState *s = qtest_init(machine); - - const uint32_t buffer_addr = src_addr + 0x1000000; - const uint32_t digest_addr = src_addr + 0x4000000; - uint8_t digest[64] = {0}; - struct AspeedSgList array[] = { - { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST), - cpu_to_le32(buffer_addr) }, - }; - - /* Check engine is idle, no busy or irq bits set */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Write test vector into memory */ - qtest_memwrite(s, buffer_addr, test_vector_accum_512, - sizeof(test_vector_accum_512)); - qtest_memwrite(s, src_addr, array, sizeof(array)); - - write_regs(s, base, src_addr, sizeof(test_vector_accum_512), - digest_addr, HACE_ALGO_SHA512 | HACE_SG_EN | HACE_ACCUM_EN); - - /* Check hash IRQ status is asserted */ - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); - - /* Clear IRQ status and check status is deasserted */ - qtest_writel(s, base + HACE_STS, 0x00000200); - g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); - - /* Read computed digest from memory */ - qtest_memread(s, digest_addr, digest, sizeof(digest)); - - /* Check result of computation */ - g_assert_cmpmem(digest, sizeof(digest), - test_result_accum_sha512, sizeof(digest)); - - qtest_quit(s); -} - -struct masks { - uint32_t src; - uint32_t dest; - uint32_t len; -}; - -static const struct masks ast2600_masks = { +static const struct AspeedMasks ast2600_masks = { .src = 0x7fffffff, .dest = 0x7ffffff8, .len = 0x0fffffff, }; -static const struct masks ast2500_masks = { +static const struct AspeedMasks ast2500_masks = { .src = 0x3fffffff, .dest = 0x3ffffff8, .len = 0x0fffffff, }; -static const struct masks ast2400_masks = { +static const struct AspeedMasks ast2400_masks = { .src = 0x0fffffff, .dest = 0x0ffffff8, .len = 0x0fffffff, }; -static void test_addresses(const char *machine, const uint32_t base, - const struct masks *expected) -{ - QTestState *s = qtest_init(machine); - - /* - * Check command mode is zero, meaning engine is in direct access mode, - * as this affects the masking behavior of the HASH_SRC register. - */ - g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); - - - /* Check that the address masking is correct */ - qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src); - - qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, expected->dest); - - qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len); - - /* Reset to zero */ - qtest_writel(s, base + HACE_HASH_SRC, 0); - qtest_writel(s, base + HACE_HASH_DIGEST, 0); - qtest_writel(s, base + HACE_HASH_DATA_LEN, 0); - - /* Check that all bits are now zero */ - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); - g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); - - qtest_quit(s); -} - /* ast2600 */ static void test_md5_ast2600(void) { - test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_md5("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha256_ast2600(void) { - test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha256("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha256_sg_ast2600(void) { - test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha512_ast2600(void) { - test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha512_sg_ast2600(void) { - test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha512_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha256_accum_ast2600(void) { - test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_sha512_accum_ast2600(void) { - test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); + aspeed_test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } static void test_addresses_ast2600(void) { - test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks); + aspeed_test_addresses("-machine ast2600-evb", 0x1e6d0000, &ast2600_masks); } /* ast2500 */ static void test_md5_ast2500(void) { - test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000); + aspeed_test_md5("-machine ast2500-evb", 0x1e6e3000, 0x80000000); } static void test_sha256_ast2500(void) { - test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000); + aspeed_test_sha256("-machine ast2500-evb", 0x1e6e3000, 0x80000000); } static void test_sha512_ast2500(void) { - test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000); + aspeed_test_sha512("-machine ast2500-evb", 0x1e6e3000, 0x80000000); } static void test_addresses_ast2500(void) { - test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks); + aspeed_test_addresses("-machine ast2500-evb", 0x1e6e3000, &ast2500_masks); } /* ast2400 */ static void test_md5_ast2400(void) { - test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); + aspeed_test_md5("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); } static void test_sha256_ast2400(void) { - test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); + aspeed_test_sha256("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); } static void test_sha512_ast2400(void) { - test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); + aspeed_test_sha512("-machine palmetto-bmc", 0x1e6e3000, 0x40000000); } static void test_addresses_ast2400(void) { - test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks); + aspeed_test_addresses("-machine palmetto-bmc", 0x1e6e3000, &ast2400_masks); } int main(int argc, char **argv) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c3a24a3eb4..26d83cd9dd 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -361,6 +361,7 @@ if gnutls.found() endif qtests = { + 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], From 33627ab237168fa624435eb8ae87f82a2ba9d7f5 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:51 +0800 Subject: [PATCH 1141/2760] test/qtest/hace: Specify explicit array sizes for test vectors and hash results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To enhance code readability and prevent potential buffer overflows or unintended size assumptions, this commit updates all fixed-size array declarations to use explicit array sizes. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-20-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 8582847945..777fa5b986 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -19,9 +19,9 @@ * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done * */ -static const uint8_t test_vector[] = {0x61, 0x62, 0x63}; +static const uint8_t test_vector[3] = {0x61, 0x62, 0x63}; -static const uint8_t test_result_sha512[] = { +static const uint8_t test_result_sha512[64] = { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, @@ -29,12 +29,12 @@ static const uint8_t test_result_sha512[] = { 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; -static const uint8_t test_result_sha256[] = { +static const uint8_t test_result_sha256[32] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; -static const uint8_t test_result_md5[] = { +static const uint8_t test_result_md5[16] = { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72}; @@ -48,11 +48,11 @@ static const uint8_t test_result_md5[] = { * for hash in sha512sum sha256sum; do $hash /tmp/test; done * */ -static const uint8_t test_vector_sg1[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; -static const uint8_t test_vector_sg2[] = {0x67, 0x68, 0x69}; -static const uint8_t test_vector_sg3[] = {0x6a, 0x6b, 0x6c}; +static const uint8_t test_vector_sg1[6] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; +static const uint8_t test_vector_sg2[3] = {0x67, 0x68, 0x69}; +static const uint8_t test_vector_sg3[3] = {0x6a, 0x6b, 0x6c}; -static const uint8_t test_result_sg_sha512[] = { +static const uint8_t test_result_sg_sha512[64] = { 0x17, 0x80, 0x7c, 0x72, 0x8e, 0xe3, 0xba, 0x35, 0xe7, 0xcf, 0x7a, 0xf8, 0x23, 0x11, 0x6d, 0x26, 0xe4, 0x1e, 0x5d, 0x4d, 0x6c, 0x2f, 0xf1, 0xf3, 0x72, 0x0d, 0x3d, 0x96, 0xaa, 0xcb, 0x6f, 0x69, 0xde, 0x64, 0x2e, 0x63, @@ -60,7 +60,7 @@ static const uint8_t test_result_sg_sha512[] = { 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40, 0xf8, 0x6d, 0xda, 0x2e}; -static const uint8_t test_result_sg_sha256[] = { +static const uint8_t test_result_sg_sha256[32] = { 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1, 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, 0xd3, 0x5e, 0x6e, 0x4a, 0x71, 0x7f, 0xbd, 0xe4}; @@ -76,7 +76,7 @@ static const uint8_t test_result_sg_sha256[] = { * echo -n -e 'abc' | dd of=/tmp/test * for hash in sha512sum sha256sum; do $hash /tmp/test; done */ -static const uint8_t test_vector_accum_512[] = { +static const uint8_t test_vector_accum_512[128] = { 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -94,7 +94,7 @@ static const uint8_t test_vector_accum_512[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; -static const uint8_t test_vector_accum_256[] = { +static const uint8_t test_vector_accum_256[64] = { 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -104,7 +104,7 @@ static const uint8_t test_vector_accum_256[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; -static const uint8_t test_result_accum_sha512[] = { +static const uint8_t test_result_accum_sha512[64] = { 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, @@ -112,7 +112,7 @@ static const uint8_t test_result_accum_sha512[] = { 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; -static const uint8_t test_result_accum_sha256[] = { +static const uint8_t test_result_accum_sha256[32] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; From a3e7f6d05d8bf38b0337fabc438d32c46948ccff Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:52 +0800 Subject: [PATCH 1142/2760] test/qtest/hace: Adjust test address range for AST1030 due to SRAM limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The digest_addr is set to "src_addr + 0x1000000", where src_addr is the DRAM base address. However, the value 0x1000000 (16MB) is too large because the AST1030 does not support DRAM, and its SRAM size is only 768KB. A range size of 0x10000 (64KB) is sufficient for HACE test cases, as the test vector size does not exceed 64KB. Updates: 1. Direct Access Mode Update digest_addr to "src_addr + 0x10000" in the following functions: aspeed_test_md5 aspeed_test_sha256 aspeed_test_sha512 2. Scatter-Gather (SG) Mode Update source address for different SG buffer addresses in the following functions: src_addr1 = src_addr + 0x10000 src_addr2 = src_addr + 0x20000 src_addr3 = src_addr + 0x30000 digest_addr = src_addr + 0x40000 aspeed_test_sha256_sg aspeed_test_sha512_sg 3. ACC Mode Update Update the SG List start address: src_addr + 0x10000 Update the SG List buffer size to 0x30000 (192KB). buffer_addr = src_addr + 0x10000 digest_addr = src_addr + 0x40000 Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-21-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 777fa5b986..539d06e4f8 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -132,7 +132,7 @@ void aspeed_test_md5(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - uint32_t digest_addr = src_addr + 0x01000000; + uint32_t digest_addr = src_addr + 0x010000; uint8_t digest[16] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -166,7 +166,7 @@ void aspeed_test_sha256(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t digest_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x10000; uint8_t digest[32] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -200,7 +200,7 @@ void aspeed_test_sha512(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t digest_addr = src_addr + 0x1000000; + const uint32_t digest_addr = src_addr + 0x10000; uint8_t digest[64] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -234,10 +234,10 @@ void aspeed_test_sha256_sg(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t src_addr_1 = src_addr + 0x1000000; - const uint32_t src_addr_2 = src_addr + 0x2000000; - const uint32_t src_addr_3 = src_addr + 0x3000000; - const uint32_t digest_addr = src_addr + 0x4000000; + const uint32_t src_addr_1 = src_addr + 0x10000; + const uint32_t src_addr_2 = src_addr + 0x20000; + const uint32_t src_addr_3 = src_addr + 0x30000; + const uint32_t digest_addr = src_addr + 0x40000; uint8_t digest[32] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_sg1)), @@ -285,10 +285,10 @@ void aspeed_test_sha512_sg(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t src_addr_1 = src_addr + 0x1000000; - const uint32_t src_addr_2 = src_addr + 0x2000000; - const uint32_t src_addr_3 = src_addr + 0x3000000; - const uint32_t digest_addr = src_addr + 0x4000000; + const uint32_t src_addr_1 = src_addr + 0x10000; + const uint32_t src_addr_2 = src_addr + 0x20000; + const uint32_t src_addr_3 = src_addr + 0x30000; + const uint32_t digest_addr = src_addr + 0x40000; uint8_t digest[64] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_sg1)), @@ -336,8 +336,8 @@ void aspeed_test_sha256_accum(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t buffer_addr = src_addr + 0x1000000; - const uint32_t digest_addr = src_addr + 0x4000000; + const uint32_t buffer_addr = src_addr + 0x10000; + const uint32_t digest_addr = src_addr + 0x40000; uint8_t digest[32] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST), @@ -377,8 +377,8 @@ void aspeed_test_sha512_accum(const char *machine, const uint32_t base, { QTestState *s = qtest_init(machine); - const uint32_t buffer_addr = src_addr + 0x1000000; - const uint32_t digest_addr = src_addr + 0x4000000; + const uint32_t buffer_addr = src_addr + 0x10000; + const uint32_t digest_addr = src_addr + 0x40000; uint8_t digest[64] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST), From 3c13be86ba181faea21a1b4f66f54df5328574f7 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:53 +0800 Subject: [PATCH 1143/2760] test/qtest/hace: Add SHA-384 test cases for ASPEED HACE model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced SHA-384 test functions to verify hashing operations. Extended support for scatter-gather ("_sg") and accumulation ("_accum") tests. Updated test result vectors for SHA-384 validation. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-22-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 168 +++++++++++++++++++++++++++++++- tests/qtest/aspeed-hace-utils.h | 6 ++ 2 files changed, 171 insertions(+), 3 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 539d06e4f8..dad90ee81c 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -16,7 +16,7 @@ * Expected results were generated using command line utitiles: * * echo -n -e 'abc' | dd of=/tmp/test - * for hash in sha512sum sha256sum md5sum; do $hash /tmp/test; done + * for hash in sha512sum sha384sum sha256sum md5sum; do $hash /tmp/test; done * */ static const uint8_t test_vector[3] = {0x61, 0x62, 0x63}; @@ -29,6 +29,12 @@ static const uint8_t test_result_sha512[64] = { 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; +static const uint8_t test_result_sha384[48] = { + 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69, + 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b, + 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7}; + static const uint8_t test_result_sha256[32] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, @@ -45,7 +51,7 @@ static const uint8_t test_result_md5[16] = { * Expected results were generated using command line utitiles: * * echo -n -e 'abcdefghijkl' | dd of=/tmp/test - * for hash in sha512sum sha256sum; do $hash /tmp/test; done + * for hash in sha512sum sha384sum sha256sum; do $hash /tmp/test; done * */ static const uint8_t test_vector_sg1[6] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}; @@ -60,6 +66,12 @@ static const uint8_t test_result_sg_sha512[64] = { 0x84, 0x25, 0x7c, 0x32, 0xc8, 0xf6, 0xd0, 0x85, 0x4a, 0xe6, 0xb5, 0x40, 0xf8, 0x6d, 0xda, 0x2e}; +static const uint8_t test_result_sg_sha384[48] = { + 0x10, 0x3c, 0xa9, 0x6c, 0x06, 0xa1, 0xce, 0x79, 0x8f, 0x08, 0xf8, 0xef, + 0xf0, 0xdf, 0xb0, 0xcc, 0xdb, 0x56, 0x7d, 0x48, 0xb2, 0x85, 0xb2, 0x3d, + 0x0c, 0xd7, 0x73, 0x45, 0x46, 0x67, 0xa3, 0xc2, 0xfa, 0x5f, 0x1b, 0x58, + 0xd9, 0xcd, 0xf2, 0x32, 0x9b, 0xd9, 0x97, 0x97, 0x30, 0xbf, 0xaa, 0xff}; + static const uint8_t test_result_sg_sha256[32] = { 0xd6, 0x82, 0xed, 0x4c, 0xa4, 0xd9, 0x89, 0xc1, 0x34, 0xec, 0x94, 0xf1, 0x55, 0x1e, 0x1e, 0xc5, 0x80, 0xdd, 0x6d, 0x5a, 0x6e, 0xcd, 0xe9, 0xf3, @@ -74,7 +86,7 @@ static const uint8_t test_result_sg_sha256[32] = { * Expected results were generated using command line utitiles: * * echo -n -e 'abc' | dd of=/tmp/test - * for hash in sha512sum sha256sum; do $hash /tmp/test; done + * for hash in sha512sum sha384sum sha256sum; do $hash /tmp/test; done */ static const uint8_t test_vector_accum_512[128] = { 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, @@ -94,6 +106,24 @@ static const uint8_t test_vector_accum_512[128] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; +static const uint8_t test_vector_accum_384[128] = { + 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18}; + static const uint8_t test_vector_accum_256[64] = { 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -112,6 +142,12 @@ static const uint8_t test_result_accum_sha512[64] = { 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f}; +static const uint8_t test_result_accum_sha384[48] = { + 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69, + 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, + 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b, + 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7}; + static const uint8_t test_result_accum_sha256[32] = { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, @@ -195,6 +231,40 @@ void aspeed_test_sha256(const char *machine, const uint32_t base, qtest_quit(s); } +void aspeed_test_sha384(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t digest_addr = src_addr + 0x10000; + uint8_t digest[48] = {0}; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr, test_vector, sizeof(test_vector)); + + write_regs(s, base, src_addr, sizeof(test_vector), digest_addr, + HACE_ALGO_SHA384); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sha384, sizeof(digest)); + + qtest_quit(s); +} + void aspeed_test_sha512(const char *machine, const uint32_t base, const uint32_t src_addr) { @@ -280,6 +350,57 @@ void aspeed_test_sha256_sg(const char *machine, const uint32_t base, qtest_quit(s); } +void aspeed_test_sha384_sg(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t src_addr_1 = src_addr + 0x10000; + const uint32_t src_addr_2 = src_addr + 0x20000; + const uint32_t src_addr_3 = src_addr + 0x30000; + const uint32_t digest_addr = src_addr + 0x40000; + uint8_t digest[48] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_sg1)), + cpu_to_le32(src_addr_1) }, + { cpu_to_le32(sizeof(test_vector_sg2)), + cpu_to_le32(src_addr_2) }, + { cpu_to_le32(sizeof(test_vector_sg3) | SG_LIST_LEN_LAST), + cpu_to_le32(src_addr_3) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, src_addr_1, test_vector_sg1, sizeof(test_vector_sg1)); + qtest_memwrite(s, src_addr_2, test_vector_sg2, sizeof(test_vector_sg2)); + qtest_memwrite(s, src_addr_3, test_vector_sg3, sizeof(test_vector_sg3)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, + (sizeof(test_vector_sg1) + + sizeof(test_vector_sg2) + + sizeof(test_vector_sg3)), + digest_addr, HACE_ALGO_SHA384 | HACE_SG_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_sg_sha384, sizeof(digest)); + + qtest_quit(s); +} + void aspeed_test_sha512_sg(const char *machine, const uint32_t base, const uint32_t src_addr) { @@ -372,6 +493,47 @@ void aspeed_test_sha256_accum(const char *machine, const uint32_t base, qtest_quit(s); } +void aspeed_test_sha384_accum(const char *machine, const uint32_t base, + const uint32_t src_addr) +{ + QTestState *s = qtest_init(machine); + + const uint32_t buffer_addr = src_addr + 0x10000; + const uint32_t digest_addr = src_addr + 0x40000; + uint8_t digest[48] = {0}; + struct AspeedSgList array[] = { + { cpu_to_le32(sizeof(test_vector_accum_384) | SG_LIST_LEN_LAST), + cpu_to_le32(buffer_addr) }, + }; + + /* Check engine is idle, no busy or irq bits set */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Write test vector into memory */ + qtest_memwrite(s, buffer_addr, test_vector_accum_384, + sizeof(test_vector_accum_384)); + qtest_memwrite(s, src_addr, array, sizeof(array)); + + write_regs(s, base, src_addr, sizeof(test_vector_accum_384), + digest_addr, HACE_ALGO_SHA384 | HACE_SG_EN | HACE_ACCUM_EN); + + /* Check hash IRQ status is asserted */ + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0x00000200); + + /* Clear IRQ status and check status is deasserted */ + qtest_writel(s, base + HACE_STS, 0x00000200); + g_assert_cmphex(qtest_readl(s, base + HACE_STS), ==, 0); + + /* Read computed digest from memory */ + qtest_memread(s, digest_addr, digest, sizeof(digest)); + + /* Check result of computation */ + g_assert_cmpmem(digest, sizeof(digest), + test_result_accum_sha384, sizeof(digest)); + + qtest_quit(s); +} + void aspeed_test_sha512_accum(const char *machine, const uint32_t base, const uint32_t src_addr) { diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index 598577c69b..f4440561de 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -54,14 +54,20 @@ void aspeed_test_md5(const char *machine, const uint32_t base, const uint32_t src_addr); void aspeed_test_sha256(const char *machine, const uint32_t base, const uint32_t src_addr); +void aspeed_test_sha384(const char *machine, const uint32_t base, + const uint32_t src_addr); void aspeed_test_sha512(const char *machine, const uint32_t base, const uint32_t src_addr); void aspeed_test_sha256_sg(const char *machine, const uint32_t base, const uint32_t src_addr); +void aspeed_test_sha384_sg(const char *machine, const uint32_t base, + const uint32_t src_addr); void aspeed_test_sha512_sg(const char *machine, const uint32_t base, const uint32_t src_addr); void aspeed_test_sha256_accum(const char *machine, const uint32_t base, const uint32_t src_addr); +void aspeed_test_sha384_accum(const char *machine, const uint32_t base, + const uint32_t src_addr); void aspeed_test_sha512_accum(const char *machine, const uint32_t base, const uint32_t src_addr); void aspeed_test_addresses(const char *machine, const uint32_t base, From adf2fb3951625dfba7ff95433c82a449e464a578 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:54 +0800 Subject: [PATCH 1144/2760] test/qtest/hace: Add SHA-384 tests for AST2600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced "test_sha384_ast2600" to validate SHA-384 hashing. Added "test_sha384_sg_ast2600" for scatter-gather SHA-384 verification. Implemented "test_sha384_accum_ast2600" to test SHA-384 accumulation. Registered new test cases in "main" to ensure execution. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-23-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed_hace-test.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 42a306af2a..ab0c98330e 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -44,6 +44,16 @@ static void test_sha256_sg_ast2600(void) aspeed_test_sha256_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } +static void test_sha384_ast2600(void) +{ + aspeed_test_sha384("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + +static void test_sha384_sg_ast2600(void) +{ + aspeed_test_sha384_sg("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + static void test_sha512_ast2600(void) { aspeed_test_sha512("-machine ast2600-evb", 0x1e6d0000, 0x80000000); @@ -59,6 +69,11 @@ static void test_sha256_accum_ast2600(void) aspeed_test_sha256_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); } +static void test_sha384_accum_ast2600(void) +{ + aspeed_test_sha384_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); +} + static void test_sha512_accum_ast2600(void) { aspeed_test_sha512_accum("-machine ast2600-evb", 0x1e6d0000, 0x80000000); @@ -117,13 +132,16 @@ int main(int argc, char **argv) qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600); qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600); + qtest_add_func("ast2600/hace/sha384", test_sha384_ast2600); qtest_add_func("ast2600/hace/sha256", test_sha256_ast2600); qtest_add_func("ast2600/hace/md5", test_md5_ast2600); qtest_add_func("ast2600/hace/sha512_sg", test_sha512_sg_ast2600); + qtest_add_func("ast2600/hace/sha384_sg", test_sha384_sg_ast2600); qtest_add_func("ast2600/hace/sha256_sg", test_sha256_sg_ast2600); qtest_add_func("ast2600/hace/sha512_accum", test_sha512_accum_ast2600); + qtest_add_func("ast2600/hace/sha384_accum", test_sha384_accum_ast2600); qtest_add_func("ast2600/hace/sha256_accum", test_sha256_accum_ast2600); qtest_add_func("ast2500/hace/addresses", test_addresses_ast2500); From 4f4e25507de719605936c955df3a5a5c560c9986 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:55 +0800 Subject: [PATCH 1145/2760] test/qtest/hace: Add tests for AST1030 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HACE model in AST2600 and AST1030 is identical. Referencing the AST2600 test cases, new tests have been created for AST1030. Implemented test functions for SHA-256, SHA-384, SHA-512, and MD5. Added scatter-gather and accumulation test variants. For AST1030, the HACE controller base address starts at "0x7e6d0000", and the SDRAM start address is "0x0". Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-24-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed_hace-test.c | 76 ++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index ab0c98330e..31890d574e 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -10,6 +10,12 @@ #include "qemu/bitops.h" #include "aspeed-hace-utils.h" +static const struct AspeedMasks ast1030_masks = { + .src = 0x7fffffff, + .dest = 0x7ffffff8, + .len = 0x0fffffff, +}; + static const struct AspeedMasks ast2600_masks = { .src = 0x7fffffff, .dest = 0x7ffffff8, @@ -28,6 +34,62 @@ static const struct AspeedMasks ast2400_masks = { .len = 0x0fffffff, }; +/* ast1030 */ +static void test_md5_ast1030(void) +{ + aspeed_test_md5("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha256_ast1030(void) +{ + aspeed_test_sha256("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha256_sg_ast1030(void) +{ + aspeed_test_sha256_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha384_ast1030(void) +{ + aspeed_test_sha384("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha384_sg_ast1030(void) +{ + aspeed_test_sha384_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha512_ast1030(void) +{ + aspeed_test_sha512("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha512_sg_ast1030(void) +{ + aspeed_test_sha512_sg("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha256_accum_ast1030(void) +{ + aspeed_test_sha256_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha384_accum_ast1030(void) +{ + aspeed_test_sha384_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_sha512_accum_ast1030(void) +{ + aspeed_test_sha512_accum("-machine ast1030-evb", 0x7e6d0000, 0x00000000); +} + +static void test_addresses_ast1030(void) +{ + aspeed_test_addresses("-machine ast1030-evb", 0x7e6d0000, &ast1030_masks); +} + /* ast2600 */ static void test_md5_ast2600(void) { @@ -130,6 +192,20 @@ int main(int argc, char **argv) { g_test_init(&argc, &argv, NULL); + qtest_add_func("ast1030/hace/addresses", test_addresses_ast1030); + qtest_add_func("ast1030/hace/sha512", test_sha512_ast1030); + qtest_add_func("ast1030/hace/sha384", test_sha384_ast1030); + qtest_add_func("ast1030/hace/sha256", test_sha256_ast1030); + qtest_add_func("ast1030/hace/md5", test_md5_ast1030); + + qtest_add_func("ast1030/hace/sha512_sg", test_sha512_sg_ast1030); + qtest_add_func("ast1030/hace/sha384_sg", test_sha384_sg_ast1030); + qtest_add_func("ast1030/hace/sha256_sg", test_sha256_sg_ast1030); + + qtest_add_func("ast1030/hace/sha512_accum", test_sha512_accum_ast1030); + qtest_add_func("ast1030/hace/sha384_accum", test_sha384_accum_ast1030); + qtest_add_func("ast1030/hace/sha256_accum", test_sha256_accum_ast1030); + qtest_add_func("ast2600/hace/addresses", test_addresses_ast2600); qtest_add_func("ast2600/hace/sha512", test_sha512_ast2600); qtest_add_func("ast2600/hace/sha384", test_sha384_ast2600); From dcdbbd45a86ad47327282aa3301622cbe65e9fdb Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:56 +0800 Subject: [PATCH 1146/2760] test/qtest/hace: Update source data and digest data type to 64-bit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, the hash data source and digest result buffer addresses are set to 32-bit. However, the AST2700 CPU is a 64-bit Cortex-A35 architecture, and its DRAM base address is also 64-bit. To support AST2700, update the hash data source address and digest result buffer address to use 64-bit addressing. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-25-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 72 ++++++++++++++++----------------- tests/qtest/aspeed-hace-utils.h | 20 ++++----- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index dad90ee81c..1b54870dd4 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -153,22 +153,22 @@ static const uint8_t test_result_accum_sha256[32] = { 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}; -static void write_regs(QTestState *s, uint32_t base, uint32_t src, - uint32_t length, uint32_t out, uint32_t method) +static void write_regs(QTestState *s, uint32_t base, uint64_t src, + uint32_t length, uint64_t out, uint32_t method) { - qtest_writel(s, base + HACE_HASH_SRC, src); - qtest_writel(s, base + HACE_HASH_DIGEST, out); + qtest_writel(s, base + HACE_HASH_SRC, extract64(src, 0, 32)); + qtest_writel(s, base + HACE_HASH_DIGEST, extract64(out, 0, 32)); qtest_writel(s, base + HACE_HASH_DATA_LEN, length); qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method); } void aspeed_test_md5(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - uint32_t digest_addr = src_addr + 0x010000; + uint64_t digest_addr = src_addr + 0x010000; uint8_t digest[16] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -198,11 +198,11 @@ void aspeed_test_md5(const char *machine, const uint32_t base, } void aspeed_test_sha256(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t digest_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x10000; uint8_t digest[32] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -232,11 +232,11 @@ void aspeed_test_sha256(const char *machine, const uint32_t base, } void aspeed_test_sha384(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t digest_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x10000; uint8_t digest[48] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -266,11 +266,11 @@ void aspeed_test_sha384(const char *machine, const uint32_t base, } void aspeed_test_sha512(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t digest_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x10000; uint8_t digest[64] = {0}; /* Check engine is idle, no busy or irq bits set */ @@ -300,14 +300,14 @@ void aspeed_test_sha512(const char *machine, const uint32_t base, } void aspeed_test_sha256_sg(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t src_addr_1 = src_addr + 0x10000; - const uint32_t src_addr_2 = src_addr + 0x20000; - const uint32_t src_addr_3 = src_addr + 0x30000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t src_addr_1 = src_addr + 0x10000; + const uint64_t src_addr_2 = src_addr + 0x20000; + const uint64_t src_addr_3 = src_addr + 0x30000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[32] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_sg1)), @@ -351,14 +351,14 @@ void aspeed_test_sha256_sg(const char *machine, const uint32_t base, } void aspeed_test_sha384_sg(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t src_addr_1 = src_addr + 0x10000; - const uint32_t src_addr_2 = src_addr + 0x20000; - const uint32_t src_addr_3 = src_addr + 0x30000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t src_addr_1 = src_addr + 0x10000; + const uint64_t src_addr_2 = src_addr + 0x20000; + const uint64_t src_addr_3 = src_addr + 0x30000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[48] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_sg1)), @@ -402,14 +402,14 @@ void aspeed_test_sha384_sg(const char *machine, const uint32_t base, } void aspeed_test_sha512_sg(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t src_addr_1 = src_addr + 0x10000; - const uint32_t src_addr_2 = src_addr + 0x20000; - const uint32_t src_addr_3 = src_addr + 0x30000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t src_addr_1 = src_addr + 0x10000; + const uint64_t src_addr_2 = src_addr + 0x20000; + const uint64_t src_addr_3 = src_addr + 0x30000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[64] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_sg1)), @@ -453,12 +453,12 @@ void aspeed_test_sha512_sg(const char *machine, const uint32_t base, } void aspeed_test_sha256_accum(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t buffer_addr = src_addr + 0x10000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t buffer_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[32] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_accum_256) | SG_LIST_LEN_LAST), @@ -494,12 +494,12 @@ void aspeed_test_sha256_accum(const char *machine, const uint32_t base, } void aspeed_test_sha384_accum(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t buffer_addr = src_addr + 0x10000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t buffer_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[48] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_accum_384) | SG_LIST_LEN_LAST), @@ -535,12 +535,12 @@ void aspeed_test_sha384_accum(const char *machine, const uint32_t base, } void aspeed_test_sha512_accum(const char *machine, const uint32_t base, - const uint32_t src_addr) + const uint64_t src_addr) { QTestState *s = qtest_init(machine); - const uint32_t buffer_addr = src_addr + 0x10000; - const uint32_t digest_addr = src_addr + 0x40000; + const uint64_t buffer_addr = src_addr + 0x10000; + const uint64_t digest_addr = src_addr + 0x40000; uint8_t digest[64] = {0}; struct AspeedSgList array[] = { { cpu_to_le32(sizeof(test_vector_accum_512) | SG_LIST_LEN_LAST), diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index f4440561de..0382570fa2 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -51,25 +51,25 @@ struct AspeedMasks { }; void aspeed_test_md5(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha256(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha384(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha512(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha256_sg(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha384_sg(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha512_sg(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha256_accum(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha384_accum(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_sha512_accum(const char *machine, const uint32_t base, - const uint32_t src_addr); + const uint64_t src_addr); void aspeed_test_addresses(const char *machine, const uint32_t base, const struct AspeedMasks *expected); From 5ced818e42ddb9516137e68556eb03c16a486758 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:57 +0800 Subject: [PATCH 1147/2760] test/qtest/hace: Support 64-bit source and digest addresses for AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added "HACE_HASH_SRC_HI" and "HACE_HASH_DIGEST_HI", "HACE_HASH_KEY_BUFF_HI" registers to store upper 32 bits. Updated "write_regs" to handle 64-bit source and digest addresses. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-26-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 2 ++ tests/qtest/aspeed-hace-utils.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 1b54870dd4..842bf5630d 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -157,7 +157,9 @@ static void write_regs(QTestState *s, uint32_t base, uint64_t src, uint32_t length, uint64_t out, uint32_t method) { qtest_writel(s, base + HACE_HASH_SRC, extract64(src, 0, 32)); + qtest_writel(s, base + HACE_HASH_SRC_HI, extract64(src, 32, 32)); qtest_writel(s, base + HACE_HASH_DIGEST, extract64(out, 0, 32)); + qtest_writel(s, base + HACE_HASH_DIGEST_HI, extract64(out, 32, 32)); qtest_writel(s, base + HACE_HASH_DATA_LEN, length); qtest_writel(s, base + HACE_HASH_CMD, HACE_SHA_BE_EN | method); } diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index 0382570fa2..d8684d3f83 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -36,6 +36,9 @@ #define HACE_HASH_KEY_BUFF 0x28 #define HACE_HASH_DATA_LEN 0x2c #define HACE_HASH_CMD 0x30 +#define HACE_HASH_SRC_HI 0x90 +#define HACE_HASH_DIGEST_HI 0x94 +#define HACE_HASH_KEY_BUFF_HI 0x98 /* Scatter-Gather Hash */ #define SG_LIST_LEN_LAST BIT(31) From 88d8515fb76ca7b3de8a4cc89264e8494655567e Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:58 +0800 Subject: [PATCH 1148/2760] test/qtest/hace: Support to test upper 32 bits of digest and source addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added "src_hi" and "dest_hi" fields to "AspeedMasks" for 64-bit addresses test. Updated "aspeed_test_addresses" to validate "HACE_HASH_SRC_HI" and "HACE_HASH_DIGEST_HI". Ensured correct masking of 64-bit addresses by checking both lower and upper 32-bit registers. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-27-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 15 ++++++++++++++- tests/qtest/aspeed-hace-utils.h | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index 842bf5630d..cb78f18117 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -588,30 +588,43 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, */ g_assert_cmphex(qtest_readl(s, base + HACE_CMD), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); - /* Check that the address masking is correct */ qtest_writel(s, base + HACE_HASH_SRC, 0xffffffff); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, expected->src); + qtest_writel(s, base + HACE_HASH_SRC_HI, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), + ==, expected->src_hi); + qtest_writel(s, base + HACE_HASH_DIGEST, 0xffffffff); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, expected->dest); + qtest_writel(s, base + HACE_HASH_DIGEST_HI, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, + expected->dest_hi); + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len); /* Reset to zero */ qtest_writel(s, base + HACE_HASH_SRC, 0); + qtest_writel(s, base + HACE_HASH_SRC_HI, 0); qtest_writel(s, base + HACE_HASH_DIGEST, 0); + qtest_writel(s, base + HACE_HASH_DIGEST_HI, 0); qtest_writel(s, base + HACE_HASH_DATA_LEN, 0); /* Check that all bits are now zero */ g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); qtest_quit(s); diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index d8684d3f83..de8055a1db 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -51,6 +51,8 @@ struct AspeedMasks { uint32_t src; uint32_t dest; uint32_t len; + uint32_t src_hi; + uint32_t dest_hi; }; void aspeed_test_md5(const char *machine, const uint32_t base, From 823288fc136f8d4b165d2eb573306893e43bcdff Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:09:59 +0800 Subject: [PATCH 1149/2760] test/qtest/hace: Support to validate 64-bit hmac key buffer addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added "key" and "key_hi" fields to "AspeedMasks" for 64-bit addresses test. Updated "aspeed_test_addresses" to validate "HACE_HASH_KEY_BUFF" and "HACE_HASH_KEY_BUFF_HI". Ensured correct masking of 64-bit addresses by checking both lower and upper 32-bit registers. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-28-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/aspeed-hace-utils.c | 14 ++++++++++++++ tests/qtest/aspeed-hace-utils.h | 2 ++ tests/qtest/aspeed_hace-test.c | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/tests/qtest/aspeed-hace-utils.c b/tests/qtest/aspeed-hace-utils.c index cb78f18117..0f7f911e5e 100644 --- a/tests/qtest/aspeed-hace-utils.c +++ b/tests/qtest/aspeed-hace-utils.c @@ -591,6 +591,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); /* Check that the address masking is correct */ @@ -609,6 +611,14 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, expected->dest_hi); + qtest_writel(s, base + HACE_HASH_KEY_BUFF, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==, + expected->key); + + qtest_writel(s, base + HACE_HASH_KEY_BUFF_HI, 0xffffffff); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==, + expected->key_hi); + qtest_writel(s, base + HACE_HASH_DATA_LEN, 0xffffffff); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, expected->len); @@ -618,6 +628,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, qtest_writel(s, base + HACE_HASH_SRC_HI, 0); qtest_writel(s, base + HACE_HASH_DIGEST, 0); qtest_writel(s, base + HACE_HASH_DIGEST_HI, 0); + qtest_writel(s, base + HACE_HASH_KEY_BUFF, 0); + qtest_writel(s, base + HACE_HASH_KEY_BUFF_HI, 0); qtest_writel(s, base + HACE_HASH_DATA_LEN, 0); /* Check that all bits are now zero */ @@ -625,6 +637,8 @@ void aspeed_test_addresses(const char *machine, const uint32_t base, g_assert_cmphex(qtest_readl(s, base + HACE_HASH_SRC_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DIGEST_HI), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF), ==, 0); + g_assert_cmphex(qtest_readl(s, base + HACE_HASH_KEY_BUFF_HI), ==, 0); g_assert_cmphex(qtest_readl(s, base + HACE_HASH_DATA_LEN), ==, 0); qtest_quit(s); diff --git a/tests/qtest/aspeed-hace-utils.h b/tests/qtest/aspeed-hace-utils.h index de8055a1db..c8b2ec45af 100644 --- a/tests/qtest/aspeed-hace-utils.h +++ b/tests/qtest/aspeed-hace-utils.h @@ -50,9 +50,11 @@ struct AspeedSgList { struct AspeedMasks { uint32_t src; uint32_t dest; + uint32_t key; uint32_t len; uint32_t src_hi; uint32_t dest_hi; + uint32_t key_hi; }; void aspeed_test_md5(const char *machine, const uint32_t base, diff --git a/tests/qtest/aspeed_hace-test.c b/tests/qtest/aspeed_hace-test.c index 31890d574e..38777020ca 100644 --- a/tests/qtest/aspeed_hace-test.c +++ b/tests/qtest/aspeed_hace-test.c @@ -13,24 +13,28 @@ static const struct AspeedMasks ast1030_masks = { .src = 0x7fffffff, .dest = 0x7ffffff8, + .key = 0x7ffffff8, .len = 0x0fffffff, }; static const struct AspeedMasks ast2600_masks = { .src = 0x7fffffff, .dest = 0x7ffffff8, + .key = 0x7ffffff8, .len = 0x0fffffff, }; static const struct AspeedMasks ast2500_masks = { .src = 0x3fffffff, .dest = 0x3ffffff8, + .key = 0x3fffffc0, .len = 0x0fffffff, }; static const struct AspeedMasks ast2400_masks = { .src = 0x0fffffff, .dest = 0x0ffffff8, + .key = 0x0fffffc0, .len = 0x0fffffff, }; From 5071c229106dc6fc46fd1b7667ffa12e0bc47b1d Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 15 May 2025 16:10:00 +0800 Subject: [PATCH 1150/2760] test/qtest/hace: Add tests for AST2700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HACE models in AST2600 and AST2700 are nearly identical. Based on the AST2600 test cases, new tests have been added for AST2700. Implemented test functions for SHA-256, SHA-384, SHA-512, and MD5. Added scatter-gather and accumulation test variants. For AST2700, the HACE controller base address starts at "0x12070000", and the DRAM start address is "0x4_00000000". Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Acked-by: Fabiano Rosas Link: https://lore.kernel.org/qemu-devel/20250515081008.583578-29-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- tests/qtest/ast2700-hace-test.c | 98 +++++++++++++++++++++++++++++++++ tests/qtest/meson.build | 2 + 2 files changed, 100 insertions(+) create mode 100644 tests/qtest/ast2700-hace-test.c diff --git a/tests/qtest/ast2700-hace-test.c b/tests/qtest/ast2700-hace-test.c new file mode 100644 index 0000000000..a400e2962b --- /dev/null +++ b/tests/qtest/ast2700-hace-test.c @@ -0,0 +1,98 @@ +/* + * QTest testcase for the ASPEED Hash and Crypto Engine + * + * SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (C) 2025 ASPEED Technology Inc. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/bitops.h" +#include "aspeed-hace-utils.h" + +static const struct AspeedMasks as2700_masks = { + .src = 0x7fffffff, + .dest = 0x7ffffff8, + .key = 0x7ffffff8, + .len = 0x0fffffff, + .src_hi = 0x00000003, + .dest_hi = 0x00000003, + .key_hi = 0x00000003, +}; + +/* ast2700 */ +static void test_md5_ast2700(void) +{ + aspeed_test_md5("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha256_ast2700(void) +{ + aspeed_test_sha256("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha256_sg_ast2700(void) +{ + aspeed_test_sha256_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha384_ast2700(void) +{ + aspeed_test_sha384("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha384_sg_ast2700(void) +{ + aspeed_test_sha384_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha512_ast2700(void) +{ + aspeed_test_sha512("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha512_sg_ast2700(void) +{ + aspeed_test_sha512_sg("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha256_accum_ast2700(void) +{ + aspeed_test_sha256_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha384_accum_ast2700(void) +{ + aspeed_test_sha384_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_sha512_accum_ast2700(void) +{ + aspeed_test_sha512_accum("-machine ast2700a1-evb", 0x12070000, 0x400000000); +} + +static void test_addresses_ast2700(void) +{ + aspeed_test_addresses("-machine ast2700a1-evb", 0x12070000, &as2700_masks); +} + +int main(int argc, char **argv) +{ + g_test_init(&argc, &argv, NULL); + + qtest_add_func("ast2700/hace/addresses", test_addresses_ast2700); + qtest_add_func("ast2700/hace/sha512", test_sha512_ast2700); + qtest_add_func("ast2700/hace/sha384", test_sha384_ast2700); + qtest_add_func("ast2700/hace/sha256", test_sha256_ast2700); + qtest_add_func("ast2700/hace/md5", test_md5_ast2700); + + qtest_add_func("ast2700/hace/sha512_sg", test_sha512_sg_ast2700); + qtest_add_func("ast2700/hace/sha384_sg", test_sha384_sg_ast2700); + qtest_add_func("ast2700/hace/sha256_sg", test_sha256_sg_ast2700); + + qtest_add_func("ast2700/hace/sha512_accum", test_sha512_accum_ast2700); + qtest_add_func("ast2700/hace/sha384_accum", test_sha384_accum_ast2700); + qtest_add_func("ast2700/hace/sha256_accum", test_sha256_accum_ast2700); + + return g_test_run(); +} diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 26d83cd9dd..43e5a86699 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -217,6 +217,7 @@ qtests_aspeed = \ 'aspeed_smc-test'] qtests_aspeed64 = \ ['ast2700-gpio-test', + 'ast2700-hace-test', 'ast2700-smc-test'] qtests_stm32l4x5 = \ @@ -363,6 +364,7 @@ endif qtests = { 'aspeed_hace-test': files('aspeed-hace-utils.c', 'aspeed_hace-test.c'), 'aspeed_smc-test': files('aspeed-smc-utils.c', 'aspeed_smc-test.c'), + 'ast2700-hace-test': files('aspeed-hace-utils.c', 'ast2700-hace-test.c'), 'ast2700-smc-test': files('aspeed-smc-utils.c', 'ast2700-smc-test.c'), 'bios-tables-test': [io, 'boot-sector.c', 'acpi-utils.c', 'tpm-emu.c'], 'cdrom-test': files('boot-sector.c'), From 5c14d7cbd42326bf35d18cb765015edfc9883272 Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 22 May 2025 10:33:02 +0800 Subject: [PATCH 1151/2760] hw/intc/aspeed: Set impl.min_access_size to 4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch explicitly sets ".impl.min_access_size = 4" to match the declared ".valid.min_access_size = 4", enforcing stricter access size checking and preventing inconsistent partial accesses to the interrupt controller registers. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250522023305.2486536-2-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/intc/aspeed_intc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index 33fcbe729c..19f88853d8 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -737,6 +737,7 @@ static const MemoryRegionOps aspeed_intc_ops = { .read = aspeed_intc_read, .write = aspeed_intc_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -747,6 +748,7 @@ static const MemoryRegionOps aspeed_intcio_ops = { .read = aspeed_intcio_read, .write = aspeed_intcio_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -757,6 +759,7 @@ static const MemoryRegionOps aspeed_ssp_intc_ops = { .read = aspeed_intc_read, .write = aspeed_ssp_intc_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -767,6 +770,7 @@ static const MemoryRegionOps aspeed_ssp_intcio_ops = { .read = aspeed_intcio_read, .write = aspeed_ssp_intcio_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -777,6 +781,7 @@ static const MemoryRegionOps aspeed_tsp_intc_ops = { .read = aspeed_intc_read, .write = aspeed_tsp_intc_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, @@ -787,6 +792,7 @@ static const MemoryRegionOps aspeed_tsp_intcio_ops = { .read = aspeed_intcio_read, .write = aspeed_tsp_intcio_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { .min_access_size = 4, .max_access_size = 4, From 567accba673326a37b7c9210f613c86afe2965ff Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 22 May 2025 10:33:03 +0800 Subject: [PATCH 1152/2760] hw/intc/aspeed Fix coding style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix coding style issues from checkpatch.pl. Signed-off-by: Jamin Lin Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250522023305.2486536-3-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/intc/aspeed_intc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c index 19f88853d8..5cd786dee6 100644 --- a/hw/intc/aspeed_intc.c +++ b/hw/intc/aspeed_intc.c @@ -1001,7 +1001,8 @@ static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = { {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS}, }; -static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass, const void *data) +static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); @@ -1069,7 +1070,8 @@ static AspeedINTCIRQ aspeed_2700tsp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = { {5, 5, 1, R_TSPINT165_EN, R_TSPINT165_STATUS}, }; -static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass, const void *data) +static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass, + const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass); From e6941ac106190490d8b455eedc5b368e6d94d4cc Mon Sep 17 00:00:00 2001 From: Jamin Lin Date: Thu, 22 May 2025 10:33:04 +0800 Subject: [PATCH 1153/2760] hw/arm/aspeed_ast27x0: Fix RAM size detection failure on BE hosts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On big-endian hosts, the aspeed_ram_capacity_write() function previously passed the address of a 64-bit "data" variable directly to address_space_write(), assuming host and guest endianness matched. However, the data is expected to be written in little-endian format to DRAM. On big-endian hosts, this led to incorrect data being written into DRAM, which caused the guest firmware to misdetect the DRAM size. As a result, U-Boot fails to boot and hangs. - Replaces the "address_space_write()" call with "address_space_stl_le()", which performs an explicit 32-bit little-endian write. - Updating the MemoryRegionOps to restrict access to exactly 4 bytes using .valid.{min,max}_access_size = 4 and .impl.min_access_size = 4. Signed-off-by: Jamin Lin Fixes: 7436db1 ("aspeed/soc: fix incorrect dram size for AST2700") Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250522023305.2486536-4-jamin_lin@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 1974a25766..82a5ecff04 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -346,8 +346,9 @@ static void aspeed_ram_capacity_write(void *opaque, hwaddr addr, uint64_t data, * If writes the data to the address which is beyond the ram size, * it would write the data to the "address % ram_size". */ - result = address_space_write(&s->dram_as, addr % ram_size, - MEMTXATTRS_UNSPECIFIED, &data, 4); + address_space_stl_le(&s->dram_as, addr % ram_size, data, + MEMTXATTRS_UNSPECIFIED, &result); + if (result != MEMTX_OK) { qemu_log_mask(LOG_GUEST_ERROR, "%s: DRAM write failed, addr:0x%" HWADDR_PRIx @@ -360,9 +361,10 @@ static const MemoryRegionOps aspeed_ram_capacity_ops = { .read = aspeed_ram_capacity_read, .write = aspeed_ram_capacity_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, .valid = { - .min_access_size = 1, - .max_access_size = 8, + .min_access_size = 4, + .max_access_size = 4, }, }; From 453b928ab93415ebf5519d946a77e905a2f1ec12 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:38 +0800 Subject: [PATCH 1154/2760] hw/arm/aspeed_ast2700-fc: Add network support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds network support to the ast2700fc machine by initializing the NIC device in the ca35. Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-2-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 125a3ade40..7bf4f2a52d 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -86,6 +86,13 @@ static void ast2700fc_ca35_init(MachineState *machine) AST2700FC_BMC_RAM_SIZE, &error_abort)) { return; } + + for (int i = 0; i < sc->macs_num; i++) { + if (!qemu_configure_nic_device(DEVICE(&soc->ftgmac100[i]), + true, NULL)) { + break; + } + } if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1", AST2700FC_HW_STRAP1, &error_abort)) { return; From 61162c6f89d1e07788c5bd8a9b7f778102f8a1eb Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:39 +0800 Subject: [PATCH 1155/2760] hw/arm/aspeed_ast2700-fc: Reduce ca35 ram size to align with ast2700a1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce ca35 ram size from 2GiB to 1GiB to align with ast2700a1-evb, where the ram-container is defined as 1GiB in its class. Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-3-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index 7bf4f2a52d..f8cb632bca 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -48,7 +48,7 @@ struct Ast2700FCState { bool mmio_exec; }; -#define AST2700FC_BMC_RAM_SIZE (2 * GiB) +#define AST2700FC_BMC_RAM_SIZE (1 * GiB) #define AST2700FC_CM4_DRAM_SIZE (32 * MiB) #define AST2700FC_HW_STRAP1 0x000000C0 From 221d22d830eb1a96f780eec28e6a45286b85fe85 Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:40 +0800 Subject: [PATCH 1156/2760] hw/arm/aspeed_ast27x0: Fix unimplemented region overlap with vbootrom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unimplemented memory region overlaps with the VBootROM address range, causing incorrect memory layout. This patch adjusts the size and start address of the unimplemented region to avoid collision. The IO memory region (ASPEED_DEV_IOMEM) is now moved to 0x20000 to reserve space for VBootROM at 0x0. Although the memory range 0x20000 - 0x10000000 is undefined in the datasheet and should not be required, further testing shows OP-TEE or U-Boot may access 0x400000 during early boot. Removing the unimplemented region causes firmware hangs. To prevent unexpected accesses, retain the region as a safeguard. Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-4-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/aspeed_ast27x0.c b/hw/arm/aspeed_ast27x0.c index 82a5ecff04..6aa3841b69 100644 --- a/hw/arm/aspeed_ast27x0.c +++ b/hw/arm/aspeed_ast27x0.c @@ -23,14 +23,14 @@ #include "qobject/qlist.h" #include "qemu/log.h" -#define AST2700_SOC_IO_SIZE 0x01000000 +#define AST2700_SOC_IO_SIZE 0x00FE0000 #define AST2700_SOC_IOMEM_SIZE 0x01000000 #define AST2700_SOC_DPMCU_SIZE 0x00040000 #define AST2700_SOC_LTPI_SIZE 0x01000000 static const hwaddr aspeed_soc_ast2700_memmap[] = { - [ASPEED_DEV_IOMEM] = 0x00000000, [ASPEED_DEV_VBOOTROM] = 0x00000000, + [ASPEED_DEV_IOMEM] = 0x00020000, [ASPEED_DEV_SRAM] = 0x10000000, [ASPEED_DEV_DPMCU] = 0x11000000, [ASPEED_DEV_IOMEM0] = 0x12000000, From bb1747a39b162bdfbf33d53846ed4e7a99f2e75f Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:41 +0800 Subject: [PATCH 1157/2760] hw/arm/aspeed_ast27x0-fc: Map ca35 memory into system memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Map the CA35 memory region as a subregion of system_memory to ensure a valid FlatView. This prevents failures in APIs that rely on the global memory view, such as rom_check_and_register_reset(). Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-5-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/aspeed_ast27x0-fc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/aspeed_ast27x0-fc.c b/hw/arm/aspeed_ast27x0-fc.c index f8cb632bca..7087be4288 100644 --- a/hw/arm/aspeed_ast27x0-fc.c +++ b/hw/arm/aspeed_ast27x0-fc.c @@ -68,6 +68,7 @@ static void ast2700fc_ca35_init(MachineState *machine) memory_region_init(&s->ca35_memory, OBJECT(&s->ca35), "ca35-memory", UINT64_MAX); + memory_region_add_subregion(get_system_memory(), 0, &s->ca35_memory); if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram", AST2700FC_BMC_RAM_SIZE, &error_abort)) { From b21d68c34ec25391f6c1a588bdb5c88bd24bb87f Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:42 +0800 Subject: [PATCH 1158/2760] hw/arm/fby35: Map BMC memory into system memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the BMC memory region as a subregion of system_memory so that modules relying on system memory can operate correctly. Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-6-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- hw/arm/fby35.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/fby35.c b/hw/arm/fby35.c index e123fa69e1..c14fc2efe9 100644 --- a/hw/arm/fby35.c +++ b/hw/arm/fby35.c @@ -77,6 +77,7 @@ static void fby35_bmc_init(Fby35State *s) memory_region_init(&s->bmc_memory, OBJECT(&s->bmc), "bmc-memory", UINT64_MAX); + memory_region_add_subregion(get_system_memory(), 0, &s->bmc_memory); memory_region_init_ram(&s->bmc_dram, OBJECT(&s->bmc), "bmc-dram", FBY35_BMC_RAM_SIZE, &error_abort); From 8eaea4012c215a610b2bd6dcc7812e805e14dd0c Mon Sep 17 00:00:00 2001 From: Steven Lee Date: Fri, 23 May 2025 17:31:43 +0800 Subject: [PATCH 1159/2760] docs: Remove ast2700fc from Aspeed family boards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ast2700fc machine is now covered in the dedicated ast2700-evb section. Listing it in the general Aspeed board family list is redundant. Signed-off-by: Steven Lee Reviewed-by: Cédric Le Goater Link: https://lore.kernel.org/qemu-devel/20250523093144.991408-7-steven_lee@aspeedtech.com Signed-off-by: Cédric Le Goater --- docs/system/arm/aspeed.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/system/arm/aspeed.rst b/docs/system/arm/aspeed.rst index 58a8020eec..43d27d83cb 100644 --- a/docs/system/arm/aspeed.rst +++ b/docs/system/arm/aspeed.rst @@ -1,4 +1,4 @@ -Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``ast2700fc``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) +Aspeed family boards (``ast2500-evb``, ``ast2600-evb``, ``ast2700-evb``, ``bletchley-bmc``, ``fuji-bmc``, ``fby35-bmc``, ``fp5280g2-bmc``, ``g220a-bmc``, ``palmetto-bmc``, ``qcom-dc-scm-v1-bmc``, ``qcom-firework-bmc``, ``quanta-q71l-bmc``, ``rainier-bmc``, ``romulus-bmc``, ``sonorapass-bmc``, ``supermicrox11-bmc``, ``supermicrox11spi-bmc``, ``tiogapass-bmc``, ``witherspoon-bmc``, ``yosemitev2-bmc``) ================================================================================================================================================================================================================================================================================================================================================================================================================================= The QEMU Aspeed machines model BMCs of various OpenPOWER systems and From 4fb54de823e9d5b88b7f708516a2a9bf997d15c2 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:08 -0700 Subject: [PATCH 1160/2760] meson: build target libraries with common dependencies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As mentioned in [1], dependencies were missing when compiling per target libraries, thus breaking compilation on certain host systems. We now explicitly add common dependencies to those libraries, so it solves the problem. [1] https://lore.kernel.org/qemu-devel/20250513115637.184940-1-thuth@redhat.com/ Tested-by: Thomas Huth Fixes: 6f4e8a92bbd ("hw/arm: make most of the compilation units common") Signed-off-by: Pierrick Bouvier Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-2-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- meson.build | 75 ++++++++++++++++++++++++++++------------------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/meson.build b/meson.build index ad2053f968..cbb22f60d1 100644 --- a/meson.build +++ b/meson.build @@ -3242,6 +3242,7 @@ config_devices_mak_list = [] config_devices_h = {} config_target_h = {} config_target_mak = {} +config_base_arch_mak = {} disassemblers = { 'alpha' : ['CONFIG_ALPHA_DIS'], @@ -3433,6 +3434,11 @@ foreach target : target_dirs config_all_devices += config_devices endif config_target_mak += {target: config_target} + + # build a merged config for all targets with the same TARGET_BASE_ARCH + target_base_arch = config_target['TARGET_BASE_ARCH'] + config_base_arch = config_base_arch_mak.get(target_base_arch, {}) + config_target + config_base_arch_mak += {target_base_arch: config_base_arch} endforeach target_dirs = actual_target_dirs @@ -4111,57 +4117,56 @@ common_all = static_library('common', hw_common_arch_libs = {} target_common_arch_libs = {} target_common_system_arch_libs = {} -foreach target : target_dirs +foreach target_base_arch, config_base_arch : config_base_arch_mak config_target = config_target_mak[target] - target_base_arch = config_target['TARGET_BASE_ARCH'] target_inc = [include_directories('target' / target_base_arch)] inc = [common_user_inc + target_inc] + target_common = common_ss.apply(config_target, strict: false) + common_deps = [] + foreach dep: target_common.dependencies() + common_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach + # prevent common code to access cpu compile time definition, # but still allow access to cpu.h target_c_args = ['-DCPU_DEFS_H'] target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'] if target_base_arch in hw_common_arch - if target_base_arch not in hw_common_arch_libs - src = hw_common_arch[target_base_arch] - lib = static_library( - 'hw_' + target_base_arch, - build_by_default: false, - sources: src.all_sources() + genh, - include_directories: inc, - c_args: target_system_c_args, - dependencies: src.all_dependencies()) - hw_common_arch_libs += {target_base_arch: lib} - endif + src = hw_common_arch[target_base_arch] + lib = static_library( + 'hw_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_system_c_args, + dependencies: src.all_dependencies() + common_deps) + hw_common_arch_libs += {target_base_arch: lib} endif if target_base_arch in target_common_arch - if target_base_arch not in target_common_arch_libs - src = target_common_arch[target_base_arch] - lib = static_library( - 'target_' + target_base_arch, - build_by_default: false, - sources: src.all_sources() + genh, - include_directories: inc, - c_args: target_c_args, - dependencies: src.all_dependencies()) - target_common_arch_libs += {target_base_arch: lib} - endif + src = target_common_arch[target_base_arch] + lib = static_library( + 'target_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_c_args, + dependencies: src.all_dependencies() + common_deps) + target_common_arch_libs += {target_base_arch: lib} endif if target_base_arch in target_common_system_arch - if target_base_arch not in target_common_system_arch_libs - src = target_common_system_arch[target_base_arch] - lib = static_library( - 'target_system_' + target_base_arch, - build_by_default: false, - sources: src.all_sources() + genh, - include_directories: inc, - c_args: target_system_c_args, - dependencies: src.all_dependencies()) - target_common_system_arch_libs += {target_base_arch: lib} - endif + src = target_common_system_arch[target_base_arch] + lib = static_library( + 'target_system_' + target_base_arch, + build_by_default: false, + sources: src.all_sources() + genh, + include_directories: inc, + c_args: target_system_c_args, + dependencies: src.all_dependencies() + common_deps) + target_common_system_arch_libs += {target_base_arch: lib} endif endforeach From 0ca26a51791f2601238129c6c2724cc4c604392c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:09 -0700 Subject: [PATCH 1161/2760] hw/arm: remove explicit dependencies listed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pierrick Bouvier Reviewed-by: Thomas Huth Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-3-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- hw/arm/meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/arm/meson.build b/hw/arm/meson.build index 5098795f61..d90be8f4c9 100644 --- a/hw/arm/meson.build +++ b/hw/arm/meson.build @@ -8,7 +8,7 @@ arm_common_ss.add(when: 'CONFIG_HIGHBANK', if_true: files('highbank.c')) arm_common_ss.add(when: 'CONFIG_INTEGRATOR', if_true: files('integratorcp.c')) arm_common_ss.add(when: 'CONFIG_MICROBIT', if_true: files('microbit.c')) arm_common_ss.add(when: 'CONFIG_MPS3R', if_true: files('mps3r.c')) -arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [pixman, files('musicpal.c')]) +arm_common_ss.add(when: 'CONFIG_MUSICPAL', if_true: [files('musicpal.c')]) arm_common_ss.add(when: 'CONFIG_NETDUINOPLUS2', if_true: files('netduinoplus2.c')) arm_common_ss.add(when: 'CONFIG_OLIMEX_STM32_H405', if_true: files('olimex-stm32-h405.c')) arm_common_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx.c', 'npcm7xx_boards.c')) @@ -79,7 +79,7 @@ arm_common_ss.add(when: 'CONFIG_SX1', if_true: files('omap_sx1.c')) arm_common_ss.add(when: 'CONFIG_VERSATILE', if_true: files('versatilepb.c')) arm_common_ss.add(when: 'CONFIG_VEXPRESS', if_true: files('vexpress.c')) -arm_common_ss.add(fdt, files('boot.c')) +arm_common_ss.add(files('boot.c')) hw_arch += {'arm': arm_ss} hw_common_arch += {'arm': arm_common_ss} From 598a0ba8e6df8c113c77e69ee18c3872fda7b6e9 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:10 -0700 Subject: [PATCH 1162/2760] target/arm: remove explicit dependencies listed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pierrick Bouvier Reviewed-by: Thomas Huth Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-4-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index b404fa5486..2ff7ed6e98 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -28,7 +28,7 @@ arm_user_ss.add(files( 'vfp_fpscr.c', )) -arm_common_system_ss.add(files('cpu.c'), capstone) +arm_common_system_ss.add(files('cpu.c')) arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) From b17b51d325130bc9d0f1189461a9a681fbd554e5 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:11 -0700 Subject: [PATCH 1163/2760] meson: apply target config for picking files from lib{system, user} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit semihosting code needs to be included only if CONFIG_SEMIHOSTING is set. However, this is a target configuration, so we need to apply it to the lib{system, user}_ss. As well, this prepares merging lib{system, user}_ss with {system, user}_ss. Acked-by: Richard Henderson Signed-off-by: Pierrick Bouvier Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-5-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- meson.build | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/meson.build b/meson.build index cbb22f60d1..79d123c50e 100644 --- a/meson.build +++ b/meson.build @@ -4081,27 +4081,19 @@ common_ss.add(qom, qemuutil) common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss]) common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) -libuser_ss = libuser_ss.apply({}) libuser = static_library('user', - libuser_ss.sources() + genh, + libuser_ss.all_sources() + genh, c_args: ['-DCONFIG_USER_ONLY', '-DCOMPILING_SYSTEM_VS_USER'], - dependencies: libuser_ss.dependencies(), + dependencies: libuser_ss.all_dependencies(), build_by_default: false) -libuser = declare_dependency(objects: libuser.extract_all_objects(recursive: false), - dependencies: libuser_ss.dependencies()) -common_ss.add(when: 'CONFIG_USER_ONLY', if_true: libuser) -libsystem_ss = libsystem_ss.apply({}) libsystem = static_library('system', - libsystem_ss.sources() + genh, + libsystem_ss.all_sources() + genh, c_args: ['-DCONFIG_SOFTMMU', '-DCOMPILING_SYSTEM_VS_USER'], - dependencies: libsystem_ss.dependencies(), + dependencies: libsystem_ss.all_dependencies(), build_by_default: false) -libsystem = declare_dependency(objects: libsystem.extract_all_objects(recursive: false), - dependencies: libsystem_ss.dependencies()) -common_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: libsystem) # Note that this library is never used directly (only through extract_objects) # and is not built by default; therefore, source files not used by the build @@ -4343,6 +4335,16 @@ foreach target : target_dirs objects += lib.extract_objects(src.sources()) arch_deps += src.dependencies() endif + if target_type == 'system' + src = libsystem_ss.apply(config_target, strict: false) + objects += libsystem.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif + if target_type == 'user' + src = libuser_ss.apply(config_target, strict: false) + objects += libuser.extract_objects(src.sources()) + arch_deps += src.dependencies() + endif if target_type == 'system' and target_base_arch in hw_common_arch_libs src = hw_common_arch[target_base_arch].apply(config_target, strict: false) lib = hw_common_arch_libs[target_base_arch] From 7ca433244c6dde497bb36184f70b442b399fda3e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:12 -0700 Subject: [PATCH 1164/2760] meson: merge lib{system, user}_ss with {system, user}_ss MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that target configuration can be applied to lib{system, user}_ss, there is no reason to keep that separate from the existing {system, user}_ss. The only difference is that we'll now compile those files with -DCOMPILING_SYSTEM_VS_USER, which removes poison for CONFIG_USER_ONLY and CONFIG_SOFTMMU, without any other side effect. We extract existing system/user code common common libraries to lib{system, user}. To not break existing meson files, we alias libsystem_ss to system_ss and libuser_ss to user_ss, so we can do the cleanup in next commit. Signed-off-by: Pierrick Bouvier Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-6-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- meson.build | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/meson.build b/meson.build index 79d123c50e..ea54d15f4a 100644 --- a/meson.build +++ b/meson.build @@ -3694,14 +3694,14 @@ io_ss = ss.source_set() qmp_ss = ss.source_set() qom_ss = ss.source_set() system_ss = ss.source_set() -libsystem_ss = ss.source_set() +libsystem_ss = system_ss specific_fuzz_ss = ss.source_set() specific_ss = ss.source_set() rust_devices_ss = ss.source_set() stub_ss = ss.source_set() trace_ss = ss.source_set() user_ss = ss.source_set() -libuser_ss = ss.source_set() +libuser_ss = user_ss util_ss = ss.source_set() # accel modules @@ -4078,21 +4078,19 @@ common_ss.add(hwcore) system_ss.add(authz, blockdev, chardev, crypto, io, qmp) common_ss.add(qom, qemuutil) -common_ss.add_all(when: 'CONFIG_SYSTEM_ONLY', if_true: [system_ss]) -common_ss.add_all(when: 'CONFIG_USER_ONLY', if_true: user_ss) - libuser = static_library('user', - libuser_ss.all_sources() + genh, + user_ss.all_sources() + genh, c_args: ['-DCONFIG_USER_ONLY', '-DCOMPILING_SYSTEM_VS_USER'], - dependencies: libuser_ss.all_dependencies(), + include_directories: common_user_inc, + dependencies: user_ss.all_dependencies(), build_by_default: false) libsystem = static_library('system', - libsystem_ss.all_sources() + genh, + system_ss.all_sources() + genh, c_args: ['-DCONFIG_SOFTMMU', '-DCOMPILING_SYSTEM_VS_USER'], - dependencies: libsystem_ss.all_dependencies(), + dependencies: system_ss.all_dependencies(), build_by_default: false) # Note that this library is never used directly (only through extract_objects) @@ -4101,7 +4099,6 @@ libsystem = static_library('system', common_all = static_library('common', build_by_default: false, sources: common_ss.all_sources() + genh, - include_directories: common_user_inc, implicit_include_directories: false, dependencies: common_ss.all_dependencies()) @@ -4115,10 +4112,20 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak inc = [common_user_inc + target_inc] target_common = common_ss.apply(config_target, strict: false) + target_system = system_ss.apply(config_target, strict: false) + target_user = user_ss.apply(config_target, strict: false) common_deps = [] + system_deps = [] + user_deps = [] foreach dep: target_common.dependencies() common_deps += dep.partial_dependency(compile_args: true, includes: true) endforeach + foreach dep: target_system.dependencies() + system_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach + foreach dep: target_user.dependencies() + user_deps += dep.partial_dependency(compile_args: true, includes: true) + endforeach # prevent common code to access cpu compile time definition, # but still allow access to cpu.h @@ -4133,7 +4140,7 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak sources: src.all_sources() + genh, include_directories: inc, c_args: target_system_c_args, - dependencies: src.all_dependencies() + common_deps) + dependencies: src.all_dependencies() + common_deps + system_deps) hw_common_arch_libs += {target_base_arch: lib} endif @@ -4145,7 +4152,8 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak sources: src.all_sources() + genh, include_directories: inc, c_args: target_c_args, - dependencies: src.all_dependencies() + common_deps) + dependencies: src.all_dependencies() + common_deps + + system_deps + user_deps) target_common_arch_libs += {target_base_arch: lib} endif @@ -4157,7 +4165,7 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak sources: src.all_sources() + genh, include_directories: inc, c_args: target_system_c_args, - dependencies: src.all_dependencies() + common_deps) + dependencies: src.all_dependencies() + common_deps + system_deps) target_common_system_arch_libs += {target_base_arch: lib} endif endforeach @@ -4336,12 +4344,12 @@ foreach target : target_dirs arch_deps += src.dependencies() endif if target_type == 'system' - src = libsystem_ss.apply(config_target, strict: false) + src = system_ss.apply(config_target, strict: false) objects += libsystem.extract_objects(src.sources()) arch_deps += src.dependencies() endif if target_type == 'user' - src = libuser_ss.apply(config_target, strict: false) + src = user_ss.apply(config_target, strict: false) objects += libuser.extract_objects(src.sources()) arch_deps += src.dependencies() endif From d33717d7fca6a599aa991f771e3ea34b15978cee Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:13 -0700 Subject: [PATCH 1165/2760] meson: remove lib{system, user}_ss aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pierrick Bouvier Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-7-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- accel/tcg/meson.build | 8 ++++---- gdbstub/meson.build | 4 ++-- hw/core/meson.build | 4 ++-- meson.build | 2 -- plugins/meson.build | 4 ++-- system/meson.build | 2 +- tcg/meson.build | 4 ++-- 7 files changed, 13 insertions(+), 15 deletions(-) diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build index 97d5e5a711..575e92bb9e 100644 --- a/accel/tcg/meson.build +++ b/accel/tcg/meson.build @@ -18,15 +18,15 @@ if get_option('plugins') tcg_ss.add(files('plugin-gen.c')) endif -libuser_ss.add_all(tcg_ss) -libsystem_ss.add_all(tcg_ss) +user_ss.add_all(tcg_ss) +system_ss.add_all(tcg_ss) -libuser_ss.add(files( +user_ss.add(files( 'user-exec.c', 'user-exec-stub.c', )) -libsystem_ss.add(files( +system_ss.add(files( 'cputlb.c', 'icount-common.c', 'monitor.c', diff --git a/gdbstub/meson.build b/gdbstub/meson.build index b25db86767..15c666f575 100644 --- a/gdbstub/meson.build +++ b/gdbstub/meson.build @@ -5,13 +5,13 @@ # # We build two versions of gdbstub, one for each mode -libuser_ss.add(files( +user_ss.add(files( 'gdbstub.c', 'syscalls.c', 'user.c' )) -libsystem_ss.add(files( +system_ss.add(files( 'gdbstub.c', 'syscalls.c', 'system.c' diff --git a/hw/core/meson.build b/hw/core/meson.build index 547de6527c..b5a545a0ed 100644 --- a/hw/core/meson.build +++ b/hw/core/meson.build @@ -26,7 +26,7 @@ system_ss.add(when: 'CONFIG_XILINX_AXI', if_true: files('stream.c')) system_ss.add(when: 'CONFIG_PLATFORM_BUS', if_true: files('sysbus-fdt.c')) system_ss.add(when: 'CONFIG_EIF', if_true: [files('eif.c'), zlib, libcbor, gnutls]) -libsystem_ss.add(files( +system_ss.add(files( 'cpu-system.c', 'fw-path-provider.c', 'gpio.c', @@ -46,7 +46,7 @@ libsystem_ss.add(files( 'vm-change-state-handler.c', 'clock-vmstate.c', )) -libuser_ss.add(files( +user_ss.add(files( 'cpu-user.c', 'qdev-user.c', )) diff --git a/meson.build b/meson.build index ea54d15f4a..1c9f1aa91e 100644 --- a/meson.build +++ b/meson.build @@ -3694,14 +3694,12 @@ io_ss = ss.source_set() qmp_ss = ss.source_set() qom_ss = ss.source_set() system_ss = ss.source_set() -libsystem_ss = system_ss specific_fuzz_ss = ss.source_set() specific_ss = ss.source_set() rust_devices_ss = ss.source_set() stub_ss = ss.source_set() trace_ss = ss.source_set() user_ss = ss.source_set() -libuser_ss = user_ss util_ss = ss.source_set() # accel modules diff --git a/plugins/meson.build b/plugins/meson.build index 5383c7b88b..b20edfbabc 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -61,8 +61,8 @@ endif user_ss.add(files('user.c', 'api-user.c')) system_ss.add(files('system.c', 'api-system.c')) -libuser_ss.add(files('api.c', 'core.c')) -libsystem_ss.add(files('api.c', 'core.c')) +user_ss.add(files('api.c', 'core.c')) +system_ss.add(files('api.c', 'core.c')) common_ss.add(files('loader.c')) diff --git a/system/meson.build b/system/meson.build index c2f0082766..7514bf3455 100644 --- a/system/meson.build +++ b/system/meson.build @@ -7,7 +7,7 @@ system_ss.add(files( 'vl.c', ), sdl, libpmem, libdaxctl) -libsystem_ss.add(files( +system_ss.add(files( 'balloon.c', 'bootdevice.c', 'cpus.c', diff --git a/tcg/meson.build b/tcg/meson.build index bd2821e4b5..706a6eb260 100644 --- a/tcg/meson.build +++ b/tcg/meson.build @@ -27,5 +27,5 @@ if host_os == 'linux' tcg_ss.add(files('perf.c')) endif -libuser_ss.add_all(tcg_ss) -libsystem_ss.add_all(tcg_ss) +user_ss.add_all(tcg_ss) +system_ss.add_all(tcg_ss) From ddc25eb40444f4bbcfea276d22beee6494c3f18e Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Wed, 21 May 2025 15:34:14 -0700 Subject: [PATCH 1166/2760] meson: merge hw_common_arch in target_common_system_arch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No need to keep two different libraries, as both are compiled with exact same flags. As well, rename target common libraries to common_{arch} and system_{arch}, to follow what exists for common and system libraries. Signed-off-by: Pierrick Bouvier Tested-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250521223414.248276-8-pierrick.bouvier@linaro.org Signed-off-by: Paolo Bonzini --- meson.build | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/meson.build b/meson.build index 1c9f1aa91e..f614d11219 100644 --- a/meson.build +++ b/meson.build @@ -4101,7 +4101,6 @@ common_all = static_library('common', dependencies: common_ss.all_dependencies()) # construct common libraries per base architecture -hw_common_arch_libs = {} target_common_arch_libs = {} target_common_system_arch_libs = {} foreach target_base_arch, config_base_arch : config_base_arch_mak @@ -4130,22 +4129,10 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak target_c_args = ['-DCPU_DEFS_H'] target_system_c_args = target_c_args + ['-DCOMPILING_SYSTEM_VS_USER', '-DCONFIG_SOFTMMU'] - if target_base_arch in hw_common_arch - src = hw_common_arch[target_base_arch] - lib = static_library( - 'hw_' + target_base_arch, - build_by_default: false, - sources: src.all_sources() + genh, - include_directories: inc, - c_args: target_system_c_args, - dependencies: src.all_dependencies() + common_deps + system_deps) - hw_common_arch_libs += {target_base_arch: lib} - endif - if target_base_arch in target_common_arch src = target_common_arch[target_base_arch] lib = static_library( - 'target_' + target_base_arch, + 'common_' + target_base_arch, build_by_default: false, sources: src.all_sources() + genh, include_directories: inc, @@ -4155,10 +4142,20 @@ foreach target_base_arch, config_base_arch : config_base_arch_mak target_common_arch_libs += {target_base_arch: lib} endif + # merge hw_common_arch in target_common_system_arch + if target_base_arch in hw_common_arch + hw_src = hw_common_arch[target_base_arch] + if target_base_arch in target_common_system_arch + target_common_system_arch[target_base_arch].add_all(hw_src) + else + target_common_system_arch += {target_base_arch: hw_src} + endif + endif + if target_base_arch in target_common_system_arch src = target_common_system_arch[target_base_arch] lib = static_library( - 'target_system_' + target_base_arch, + 'system_' + target_base_arch, build_by_default: false, sources: src.all_sources() + genh, include_directories: inc, @@ -4351,12 +4348,6 @@ foreach target : target_dirs objects += libuser.extract_objects(src.sources()) arch_deps += src.dependencies() endif - if target_type == 'system' and target_base_arch in hw_common_arch_libs - src = hw_common_arch[target_base_arch].apply(config_target, strict: false) - lib = hw_common_arch_libs[target_base_arch] - objects += lib.extract_objects(src.sources()) - arch_deps += src.dependencies() - endif if target_type == 'system' and target_base_arch in target_common_system_arch_libs src = target_common_system_arch[target_base_arch].apply(config_target, strict: false) lib = target_common_system_arch_libs[target_base_arch] From d74169e09e1d424aaca138966f460520a0d4dd0d Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 20 May 2025 23:27:46 +0800 Subject: [PATCH 1167/2760] hw/timer/hpet: Reorganize register decoding For Rust HPET, since the commit 519088b7cf6d ("rust: hpet: decode HPET registers into enums"), it decodes register address by checking if the register belongs to global register space. And for C HPET, it checks timer register space first. While both approaches are fine, it's best to be as consistent as possible. Synchronize changes from the rust side to C side. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250520152750.2542612-2-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- hw/timer/hpet.c | 166 ++++++++++++++++++++++++------------------------ 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c index d1b7bc52b7..0fd1337a15 100644 --- a/hw/timer/hpet.c +++ b/hw/timer/hpet.c @@ -426,30 +426,11 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, uint64_t cur_tick; trace_hpet_ram_read(addr); + addr &= ~4; - /*address range of all TN regs*/ - if (addr >= 0x100 && addr <= 0x3ff) { - uint8_t timer_id = (addr - 0x100) / 0x20; - HPETTimer *timer = &s->timer[timer_id]; - - if (timer_id > s->num_timers) { - trace_hpet_timer_id_out_of_range(timer_id); - return 0; - } - - switch (addr & 0x18) { - case HPET_TN_CFG: // including interrupt capabilities - return timer->config >> shift; - case HPET_TN_CMP: // comparator register - return timer->cmp >> shift; - case HPET_TN_ROUTE: - return timer->fsb >> shift; - default: - trace_hpet_ram_read_invalid(); - break; - } - } else { - switch (addr & ~4) { + /*address range of all global regs*/ + if (addr <= 0xff) { + switch (addr) { case HPET_ID: // including HPET_PERIOD return s->capability >> shift; case HPET_CFG: @@ -468,6 +449,26 @@ static uint64_t hpet_ram_read(void *opaque, hwaddr addr, trace_hpet_ram_read_invalid(); break; } + } else { + uint8_t timer_id = (addr - 0x100) / 0x20; + HPETTimer *timer = &s->timer[timer_id]; + + if (timer_id > s->num_timers) { + trace_hpet_timer_id_out_of_range(timer_id); + return 0; + } + + switch (addr & 0x1f) { + case HPET_TN_CFG: // including interrupt capabilities + return timer->config >> shift; + case HPET_TN_CMP: // comparator register + return timer->cmp >> shift; + case HPET_TN_ROUTE: + return timer->fsb >> shift; + default: + trace_hpet_ram_read_invalid(); + break; + } } return 0; } @@ -482,9 +483,67 @@ static void hpet_ram_write(void *opaque, hwaddr addr, uint64_t old_val, new_val, cleared; trace_hpet_ram_write(addr, value); + addr &= ~4; - /*address range of all TN regs*/ - if (addr >= 0x100 && addr <= 0x3ff) { + /*address range of all global regs*/ + if (addr <= 0xff) { + switch (addr) { + case HPET_ID: + return; + case HPET_CFG: + old_val = s->config; + new_val = deposit64(old_val, shift, len, value); + new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); + s->config = new_val; + if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Enable main counter and interrupt generation. */ + s->hpet_offset = + ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); + for (i = 0; i < s->num_timers; i++) { + if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) { + update_irq(&s->timer[i], 1); + } + hpet_set_timer(&s->timer[i]); + } + } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { + /* Halt main counter and disable interrupt generation. */ + s->hpet_counter = hpet_get_ticks(s); + for (i = 0; i < s->num_timers; i++) { + hpet_del_timer(&s->timer[i]); + } + } + /* i8254 and RTC output pins are disabled + * when HPET is in legacy mode */ + if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + qemu_set_irq(s->pit_enabled, 0); + qemu_irq_lower(s->irqs[0]); + qemu_irq_lower(s->irqs[RTC_ISA_IRQ]); + } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { + qemu_irq_lower(s->irqs[0]); + qemu_set_irq(s->pit_enabled, 1); + qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); + } + break; + case HPET_STATUS: + new_val = value << shift; + cleared = new_val & s->isr; + for (i = 0; i < s->num_timers; i++) { + if (cleared & (1 << i)) { + update_irq(&s->timer[i], 0); + } + } + break; + case HPET_COUNTER: + if (hpet_enabled(s)) { + trace_hpet_ram_write_counter_write_while_enabled(); + } + s->hpet_counter = deposit64(s->hpet_counter, shift, len, value); + break; + default: + trace_hpet_ram_write_invalid(); + break; + } + } else { uint8_t timer_id = (addr - 0x100) / 0x20; HPETTimer *timer = &s->timer[timer_id]; @@ -550,63 +609,6 @@ static void hpet_ram_write(void *opaque, hwaddr addr, break; } return; - } else { - switch (addr & ~4) { - case HPET_ID: - return; - case HPET_CFG: - old_val = s->config; - new_val = deposit64(old_val, shift, len, value); - new_val = hpet_fixup_reg(new_val, old_val, HPET_CFG_WRITE_MASK); - s->config = new_val; - if (activating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Enable main counter and interrupt generation. */ - s->hpet_offset = - ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - for (i = 0; i < s->num_timers; i++) { - if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) { - update_irq(&s->timer[i], 1); - } - hpet_set_timer(&s->timer[i]); - } - } else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) { - /* Halt main counter and disable interrupt generation. */ - s->hpet_counter = hpet_get_ticks(s); - for (i = 0; i < s->num_timers; i++) { - hpet_del_timer(&s->timer[i]); - } - } - /* i8254 and RTC output pins are disabled - * when HPET is in legacy mode */ - if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - qemu_set_irq(s->pit_enabled, 0); - qemu_irq_lower(s->irqs[0]); - qemu_irq_lower(s->irqs[RTC_ISA_IRQ]); - } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) { - qemu_irq_lower(s->irqs[0]); - qemu_set_irq(s->pit_enabled, 1); - qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level); - } - break; - case HPET_STATUS: - new_val = value << shift; - cleared = new_val & s->isr; - for (i = 0; i < s->num_timers; i++) { - if (cleared & (1 << i)) { - update_irq(&s->timer[i], 0); - } - } - break; - case HPET_COUNTER: - if (hpet_enabled(s)) { - trace_hpet_ram_write_counter_write_while_enabled(); - } - s->hpet_counter = deposit64(s->hpet_counter, shift, len, value); - break; - default: - trace_hpet_ram_write_invalid(); - break; - } } } From 86c54a3a418e462e67444ac4db25b2757fd62079 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 20 May 2025 23:27:49 +0800 Subject: [PATCH 1168/2760] rust: Fix Zhao's email address No one could find Zhao Liu via zhai1.liu@intel.com. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250520152750.2542612-5-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/fw_cfg.rs | 2 +- rust/hw/timer/hpet/src/hpet.rs | 2 +- rust/hw/timer/hpet/src/lib.rs | 2 +- rust/qemu-api/src/bitops.rs | 2 +- rust/qemu-api/src/timer.rs | 2 +- rust/qemu-api/tests/vmstate_tests.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/hw/timer/hpet/src/fw_cfg.rs b/rust/hw/timer/hpet/src/fw_cfg.rs index aa08d28351..6c10316104 100644 --- a/rust/hw/timer/hpet/src/fw_cfg.rs +++ b/rust/hw/timer/hpet/src/fw_cfg.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later use std::ptr::addr_of_mut; diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/hpet.rs index 779681d650..e3ba62b287 100644 --- a/rust/hw/timer/hpet/src/hpet.rs +++ b/rust/hw/timer/hpet/src/hpet.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later use std::{ diff --git a/rust/hw/timer/hpet/src/lib.rs b/rust/hw/timer/hpet/src/lib.rs index 1954584a87..141aae229d 100644 --- a/rust/hw/timer/hpet/src/lib.rs +++ b/rust/hw/timer/hpet/src/lib.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later //! # HPET QEMU Device Model diff --git a/rust/qemu-api/src/bitops.rs b/rust/qemu-api/src/bitops.rs index 023ec1a998..b1e3a530ab 100644 --- a/rust/qemu-api/src/bitops.rs +++ b/rust/qemu-api/src/bitops.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later //! This module provides bit operation extensions to integer types. diff --git a/rust/qemu-api/src/timer.rs b/rust/qemu-api/src/timer.rs index 868bd88575..0a2d111d49 100644 --- a/rust/qemu-api/src/timer.rs +++ b/rust/qemu-api/src/timer.rs @@ -1,5 +1,5 @@ // Copyright (C) 2024 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later use std::{ diff --git a/rust/qemu-api/tests/vmstate_tests.rs b/rust/qemu-api/tests/vmstate_tests.rs index ad0fc5cd5d..bded836eb6 100644 --- a/rust/qemu-api/tests/vmstate_tests.rs +++ b/rust/qemu-api/tests/vmstate_tests.rs @@ -1,5 +1,5 @@ // Copyright (C) 2025 Intel Corporation. -// Author(s): Zhao Liu +// Author(s): Zhao Liu // SPDX-License-Identifier: GPL-2.0-or-later use std::{ From aef5ac8624c7b826ae2adde48bc6997286ee1303 Mon Sep 17 00:00:00 2001 From: Zhao Liu Date: Tue, 20 May 2025 23:27:50 +0800 Subject: [PATCH 1169/2760] rust: Fix the typos in doc These typos are found by "cargo spellcheck". Though it outputs a lot of noise and false positives, there still are some real typos. Signed-off-by: Zhao Liu Link: https://lore.kernel.org/r/20250520152750.2542612-6-zhao1.liu@intel.com Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/src/device.rs | 4 ++-- rust/qemu-api/src/qom.rs | 4 ++-- rust/qemu-api/src/vmstate.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/hw/char/pl011/src/device.rs b/rust/hw/char/pl011/src/device.rs index bde3be65c5..bd5cee0464 100644 --- a/rust/hw/char/pl011/src/device.rs +++ b/rust/hw/char/pl011/src/device.rs @@ -480,13 +480,13 @@ impl PL011Registers { } impl PL011State { - /// Initializes a pre-allocated, unitialized instance of `PL011State`. + /// Initializes a pre-allocated, uninitialized instance of `PL011State`. /// /// # Safety /// /// `self` must point to a correctly sized and aligned location for the /// `PL011State` type. It must not be called more than once on the same - /// location/instance. All its fields are expected to hold unitialized + /// location/instance. All its fields are expected to hold uninitialized /// values with the sole exception of `parent_obj`. unsafe fn init(&mut self) { static PL011_OPS: MemoryRegionOps = MemoryRegionOpsBuilder::::new() diff --git a/rust/qemu-api/src/qom.rs b/rust/qemu-api/src/qom.rs index 41e5a5e29a..14f98fee60 100644 --- a/rust/qemu-api/src/qom.rs +++ b/rust/qemu-api/src/qom.rs @@ -291,7 +291,7 @@ pub unsafe trait ObjectType: Sized { } /// Return the receiver as a const raw pointer to Object. - /// This is preferrable to `as_object_mut_ptr()` if a C + /// This is preferable to `as_object_mut_ptr()` if a C /// function only needs a `const Object *`. fn as_object_ptr(&self) -> *const bindings::Object { self.as_object().as_ptr() @@ -485,7 +485,7 @@ pub trait ObjectImpl: ObjectType + IsA { /// `INSTANCE_INIT` functions have been called. const INSTANCE_POST_INIT: Option = None; - /// Called on descendent classes after all parent class initialization + /// Called on descendant classes after all parent class initialization /// has occurred, but before the class itself is initialized. This /// is only useful if a class is not a leaf, and can be used to undo /// the effects of copying the contents of the parent's class struct diff --git a/rust/qemu-api/src/vmstate.rs b/rust/qemu-api/src/vmstate.rs index 9c8b2398e9..812f390d78 100644 --- a/rust/qemu-api/src/vmstate.rs +++ b/rust/qemu-api/src/vmstate.rs @@ -9,7 +9,7 @@ //! * [`vmstate_unused!`](crate::vmstate_unused) and //! [`vmstate_of!`](crate::vmstate_of), which are used to express the //! migration format for a struct. This is based on the [`VMState`] trait, -//! which is defined by all migrateable types. +//! which is defined by all migratable types. //! //! * [`impl_vmstate_forward`](crate::impl_vmstate_forward) and //! [`impl_vmstate_bitsized`](crate::impl_vmstate_bitsized), which help with From 734a1e9eeed2c791c8906d0ee08ad5c9b1f41fa0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 13 May 2025 12:18:12 +0200 Subject: [PATCH 1170/2760] rust: hpet: rename hpet module to "device" Follow a similar convention as pl011. Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/timer/hpet/src/{hpet.rs => device.rs} | 0 rust/hw/timer/hpet/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename rust/hw/timer/hpet/src/{hpet.rs => device.rs} (100%) diff --git a/rust/hw/timer/hpet/src/hpet.rs b/rust/hw/timer/hpet/src/device.rs similarity index 100% rename from rust/hw/timer/hpet/src/hpet.rs rename to rust/hw/timer/hpet/src/device.rs diff --git a/rust/hw/timer/hpet/src/lib.rs b/rust/hw/timer/hpet/src/lib.rs index 141aae229d..a95cf14ac9 100644 --- a/rust/hw/timer/hpet/src/lib.rs +++ b/rust/hw/timer/hpet/src/lib.rs @@ -7,7 +7,7 @@ //! This library implements a device model for the IA-PC HPET (High //! Precision Event Timers) device in QEMU. +pub mod device; pub mod fw_cfg; -pub mod hpet; pub const TYPE_HPET: &::std::ffi::CStr = c"hpet"; From 341ed3eae4179273788d2f74579862a10e18cf81 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 20 May 2025 14:53:29 +0200 Subject: [PATCH 1171/2760] target/i386/emulate: more lflags cleanups Signed-off-by: Paolo Bonzini --- target/i386/emulate/x86_flags.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/target/i386/emulate/x86_flags.c b/target/i386/emulate/x86_flags.c index 47bc19778c..cc138c7749 100644 --- a/target/i386/emulate/x86_flags.c +++ b/target/i386/emulate/x86_flags.c @@ -255,19 +255,19 @@ void lflags_to_rflags(CPUX86State *env) void rflags_to_lflags(CPUX86State *env) { - target_ulong cf_xor_of; + target_ulong cf_af, cf_xor_of; + /* Leave the low byte zero so that parity is always even... */ + env->cc_dst = !(env->eflags & CC_Z) << 8; + + /* ... and therefore cc_src always uses opposite polarity. */ env->cc_src = CC_P; env->cc_src ^= env->eflags & (CC_S | CC_P); /* rotate right by one to move CF and AF into the carry-out positions */ - env->cc_src |= ( - (env->eflags >> 1) | - (env->eflags << (TARGET_LONG_BITS - 1))) & (CC_C | CC_A); + cf_af = env->eflags & (CC_C | CC_A); + env->cc_src |= ((cf_af >> 1) | (cf_af << (TARGET_LONG_BITS - 1))); - cf_xor_of = (env->eflags & (CC_C | CC_O)) + (CC_O - CC_C); + cf_xor_of = ((env->eflags & (CC_C | CC_O)) + (CC_O - CC_C)) & CC_O; env->cc_src |= -cf_xor_of & LF_MASK_PO; - - /* Leave the low byte zero so that parity is not affected. */ - env->cc_dst = !(env->eflags & CC_Z) << 8; } From 4ec799dd17dcbb0fa4e90e685d5d6fcf8f72338a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Chigot?= Date: Fri, 25 Apr 2025 11:35:13 +0200 Subject: [PATCH 1172/2760] target/sparc: don't set FSR_NVA when comparing unordered floats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FSR_NVA should be set when one of the operands is a signaling NaN or when using FCMPEx instructions. But those cases are already handled within check_ieee_exception or floatxx_compare functions. Otherwise, it should be left untouched. FTR, this was detected by inf-compare-[5678] tests within gcc testsuites. Signed-off-by: Clément Chigot Message-Id: <20250425093513.863289-1-chigot@adacore.com> Acked-by: Mark Cave-Ayland Reviewed-by: Richard Henderson Signed-off-by: Mark Cave-Ayland --- target/sparc/fop_helper.c | 1 - 1 file changed, 1 deletion(-) diff --git a/target/sparc/fop_helper.c b/target/sparc/fop_helper.c index a49334150d..29fd166438 100644 --- a/target/sparc/fop_helper.c +++ b/target/sparc/fop_helper.c @@ -445,7 +445,6 @@ static uint32_t finish_fcmp(CPUSPARCState *env, FloatRelation r, uintptr_t ra) case float_relation_greater: return 2; case float_relation_unordered: - env->fsr |= FSR_NVA; return 3; } g_assert_not_reached(); From 428d1789df911bc863e55eed2d8f33ce991cbd09 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 May 2025 08:37:08 +0200 Subject: [PATCH 1173/2760] docs/about: Belatedly document tightening of QMP device_add checking Commit 4d8b0f0a9536 (v6.2.0) deprecated incorrectly typed device_add arguments. Commit be93fd53723c (qdev-monitor: avoid QemuOpts in QMP device_add) fixed them for v9.2.0, but neglected to update documentation. Do that now. Cc: Stefan Hajnoczi Signed-off-by: Markus Armbruster Message-ID: <20250521063711.29840-2-armbru@redhat.com> Reviewed-by: Stefan Hajnoczi [Commit message typo corrected] --- docs/about/deprecated.rst | 14 -------------- docs/about/removed-features.rst | 9 +++++++++ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 44d3427e98..9665bc6fcf 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -187,20 +187,6 @@ threads (for example, it only reports source side of multifd threads, without reporting any destination threads, or non-multifd source threads). For debugging purpose, please use ``-name $VM,debug-threads=on`` instead. -Incorrectly typed ``device_add`` arguments (since 6.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Due to shortcomings in the internal implementation of ``device_add``, QEMU -incorrectly accepts certain invalid arguments: Any object or list arguments are -silently ignored. Other argument types are not checked, but an implicit -conversion happens, so that e.g. string values can be assigned to integer -device properties or vice versa. - -This is a bug in QEMU that will be fixed in the future so that previously -accepted incorrect commands will return an error. Users should make sure that -all arguments passed to ``device_add`` are consistent with the documented -property types. - Host Architectures ------------------ diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 063284d4f8..92b5ba6218 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -722,6 +722,15 @@ Use ``multifd-channels`` instead. Use ``multifd-compression`` instead. +Incorrectly typed ``device_add`` arguments (since 9.2) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Due to shortcomings in the internal implementation of ``device_add``, +QEMU used to incorrectly accept certain invalid arguments. Any object +or list arguments were silently ignored. Other argument types were not +checked, but an implicit conversion happened, so that e.g. string +values could be assigned to integer device properties or vice versa. + QEMU Machine Protocol (QMP) events ---------------------------------- From c2fb6eaeb9d479a80b104914f459a0c6c32e5a88 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 May 2025 08:37:09 +0200 Subject: [PATCH 1174/2760] qapi/migration: Deprecate migrate argument @detach Argument @detach has always been ignored. Start the clock to get rid of it. Cc: Peter Xu Cc: Fabiano Rosas Signed-off-by: Markus Armbruster Message-ID: <20250521063711.29840-3-armbru@redhat.com> ACKed-by: Peter Krempa Reviewed-by: Fabiano Rosas Reviewed-by: Peter Xu --- docs/about/deprecated.rst | 5 +++++ qapi/migration.json | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 9665bc6fcf..ef4ea84e69 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -179,6 +179,11 @@ Use ``job-dismiss`` instead. Use ``job-finalize`` instead. +``migrate`` argument ``detach`` (since 10.1) +'''''''''''''''''''''''''''''''''''''''''''' + +This argument has always been ignored. + ``query-migrationthreads`` (since 9.2) '''''''''''''''''''''''''''''''''''''' diff --git a/qapi/migration.json b/qapi/migration.json index 8b9c53595c..ecd266f98e 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -1660,6 +1660,10 @@ # # @resume: resume one paused migration, default "off". (since 3.0) # +# Features: +# +# @deprecated: Argument @detach is deprecated. +# # Since: 0.14 # # .. admonition:: Notes @@ -1668,19 +1672,14 @@ # migration's progress and final result (this information is # provided by the 'status' member). # -# 2. All boolean arguments default to false. -# -# 3. The user Monitor's "detach" argument is invalid in QMP and -# should not be used. -# -# 4. The uri argument should have the Uniform Resource Identifier +# 2. The uri argument should have the Uniform Resource Identifier # of default destination VM. This connection will be bound to # default network. # -# 5. For now, number of migration streams is restricted to one, +# 3. For now, number of migration streams is restricted to one, # i.e. number of items in 'channels' list is just 1. # -# 6. The 'uri' and 'channels' arguments are mutually exclusive; +# 4. The 'uri' and 'channels' arguments are mutually exclusive; # exactly one of the two should be present. # # .. qmp-example:: @@ -1724,7 +1723,8 @@ { 'command': 'migrate', 'data': {'*uri': 'str', '*channels': [ 'MigrationChannel' ], - '*detach': 'bool', '*resume': 'bool' } } + '*detach': { 'type': 'bool', 'features': [ 'deprecated' ] }, + '*resume': 'bool' } } ## # @migrate-incoming: From 977dfcd552d0bef725f89bcabcedeb51593000ab Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 May 2025 08:37:10 +0200 Subject: [PATCH 1175/2760] docs/about/deprecated: Move deprecation notes to tidy up order The deprecation notes within a section are mostly in version order. Move the few that aren't so they are. Signed-off-by: Markus Armbruster Message-ID: <20250521063711.29840-4-armbru@redhat.com> Reviewed-by: Eric Blake --- docs/about/deprecated.rst | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index ef4ea84e69..4715d1ede5 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -148,6 +148,14 @@ options are removed in favor of using explicit ``blockdev-create`` and ``blockdev-add`` calls. See :doc:`/interop/live-block-operations` for details. +``query-migrationthreads`` (since 9.2) +'''''''''''''''''''''''''''''''''''''' + +To be removed with no replacement, as it reports only a limited set of +threads (for example, it only reports source side of multifd threads, +without reporting any destination threads, or non-multifd source threads). +For debugging purpose, please use ``-name $VM,debug-threads=on`` instead. + ``block-job-pause`` (since 10.1) '''''''''''''''''''''''''''''''' @@ -184,14 +192,6 @@ Use ``job-finalize`` instead. This argument has always been ignored. -``query-migrationthreads`` (since 9.2) -'''''''''''''''''''''''''''''''''''''' - -To be removed with no replacement, as it reports only a limited set of -threads (for example, it only reports source side of multifd threads, -without reporting any destination threads, or non-multifd source threads). -For debugging purpose, please use ``-name $VM,debug-threads=on`` instead. - Host Architectures ------------------ @@ -522,14 +522,6 @@ PCIe passthrough shall be the mainline solution. CPU device properties ''''''''''''''''''''' -``pcommit`` on x86 (since 9.1) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The PCOMMIT instruction was never included in any physical processor. -It was implemented as a no-op instruction in TCG up to QEMU 9.0, but -only with ``-cpu max`` (which does not guarantee migration compatibility -across versions). - ``pmu-num=n`` on RISC-V CPUs (since 8.2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -539,6 +531,14 @@ be calculated with ``((2 ^ n) - 1) << 3``. The least significant three bits must be left clear. +``pcommit`` on x86 (since 9.1) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The PCOMMIT instruction was never included in any physical processor. +It was implemented as a no-op instruction in TCG up to QEMU 9.0, but +only with ``-cpu max`` (which does not guarantee migration compatibility +across versions). + Backwards compatibility ----------------------- From 662b85aae131e7cb8dd8b03c9e44a95bc87573ca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Wed, 21 May 2025 08:37:11 +0200 Subject: [PATCH 1176/2760] docs/about/removed-features: Move removal notes to tidy up order The removal notes within a section are mostly in version order. Move the few that aren't so they are. Signed-off-by: Markus Armbruster Message-ID: <20250521063711.29840-5-armbru@redhat.com> Reviewed-by: Eric Blake --- docs/about/removed-features.rst | 60 ++++++++++++++++----------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 92b5ba6218..4819cb4665 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -162,6 +162,12 @@ specified with ``-mem-path`` can actually provide the guest RAM configured with The ``name`` parameter of the ``-net`` option was a synonym for the ``id`` parameter, which should now be used instead. +RISC-V firmware not booted by default (removed in 5.1) +'''''''''''''''''''''''''''''''''''''''''''''''''''''' + +QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default`` +for the RISC-V ``virt`` machine and ``sifive_u`` machine. + ``-numa node,mem=...`` (removed in 5.1) ''''''''''''''''''''''''''''''''''''''' @@ -324,12 +330,6 @@ devices. Drives the board doesn't pick up can no longer be used with This option was undocumented and not used in the field. Use ``-device usb-ccid`` instead. -RISC-V firmware not booted by default (removed in 5.1) -'''''''''''''''''''''''''''''''''''''''''''''''''''''' - -QEMU 5.1 changes the default behaviour from ``-bios none`` to ``-bios default`` -for the RISC-V ``virt`` machine and ``sifive_u`` machine. - ``-no-quit`` (removed in 7.0) ''''''''''''''''''''''''''''' @@ -911,14 +911,6 @@ The RISC-V no MMU cpus have been removed. The two CPUs: ``rv32imacu-nommu`` and ``rv64imacu-nommu`` can no longer be used. Instead the MMU status can be specified via the CPU ``mmu`` option when using the ``rv32`` or ``rv64`` CPUs. -RISC-V 'any' CPU type ``-cpu any`` (removed in 9.2) -''''''''''''''''''''''''''''''''''''''''''''''''''' - -The 'any' CPU type was introduced back in 2018 and was around since the -initial RISC-V QEMU port. Its usage was always been unclear: users don't know -what to expect from a CPU called 'any', and in fact the CPU does not do anything -special that isn't already done by the default CPUs rv32/rv64. - ``compat`` property of server class POWER CPUs (removed in 6.0) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' @@ -965,6 +957,14 @@ The CRIS architecture was pulled from Linux in 4.17 and the compiler was no longer packaged in any distro making it harder to run the ``check-tcg`` tests. +RISC-V 'any' CPU type ``-cpu any`` (removed in 9.2) +''''''''''''''''''''''''''''''''''''''''''''''''''' + +The 'any' CPU type was introduced back in 2018 and was around since the +initial RISC-V QEMU port. Its usage was always been unclear: users don't know +what to expect from a CPU called 'any', and in fact the CPU does not do anything +special that isn't already done by the default CPUs rv32/rv64. + System accelerators ------------------- @@ -975,18 +975,18 @@ Userspace local APIC with KVM (x86, removed in 8.0) a local APIC. The ``split`` setting is supported, as is using ``-M kernel-irqchip=off`` when the CPU does not have a local APIC. -HAXM (``-accel hax``) (removed in 8.2) -'''''''''''''''''''''''''''''''''''''' - -The HAXM project has been retired (see https://github.com/intel/haxm#status). -Use "whpx" (on Windows) or "hvf" (on macOS) instead. - MIPS "Trap-and-Emulate" KVM support (removed in 8.0) '''''''''''''''''''''''''''''''''''''''''''''''''''' The MIPS "Trap-and-Emulate" KVM host and guest support was removed from Linux in 2021, and is not supported anymore by QEMU either. +HAXM (``-accel hax``) (removed in 8.2) +'''''''''''''''''''''''''''''''''''''' + +The HAXM project has been retired (see https://github.com/intel/haxm#status). +Use "whpx" (on Windows) or "hvf" (on macOS) instead. + System emulator machines ------------------------ @@ -1044,16 +1044,6 @@ Aspeed ``swift-bmc`` machine (removed in 7.0) This machine was removed because it was unused. Alternative AST2500 based OpenPOWER machines are ``witherspoon-bmc`` and ``romulus-bmc``. -Aspeed ``tacoma-bmc`` machine (removed in 10.0) -''''''''''''''''''''''''''''''''''''''''''''''' - -The ``tacoma-bmc`` machine was removed because it didn't bring much -compared to the ``rainier-bmc`` machine. Also, the ``tacoma-bmc`` was -a board used for bring up of the AST2600 SoC that never left the -labs. It can be easily replaced by the ``rainier-bmc`` machine, which -was the actual final product, or by the ``ast2600-evb`` with some -tweaks. - ppc ``taihu`` machine (removed in 7.2) ''''''''''''''''''''''''''''''''''''''''''''' @@ -1084,6 +1074,16 @@ for all machine types using the PXA2xx and OMAP2 SoCs. We are also dropping the ``cheetah`` OMAP1 board, because we don't have any test images for it and don't know of anybody who does. +Aspeed ``tacoma-bmc`` machine (removed in 10.0) +''''''''''''''''''''''''''''''''''''''''''''''' + +The ``tacoma-bmc`` machine was removed because it didn't bring much +compared to the ``rainier-bmc`` machine. Also, the ``tacoma-bmc`` was +a board used for bring up of the AST2600 SoC that never left the +labs. It can be easily replaced by the ``rainier-bmc`` machine, which +was the actual final product, or by the ``ast2600-evb`` with some +tweaks. + ppc ``ref405ep`` machine (removed in 10.0) '''''''''''''''''''''''''''''''''''''''''' From 319b0c8d077401f51bf6314039b82db20d5267ee Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 24 May 2025 15:40:12 +0100 Subject: [PATCH 1177/2760] accel/tcg: Fix atomic_mmu_lookup vs TLB_FORCE_SLOW MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When we moved TLB_MMIO and TLB_DISCARD_WRITE to TLB_SLOW_FLAGS_MASK, we failed to update atomic_mmu_lookup to properly reconstruct flags. Fixes: 24b5e0fdb543 ("include/exec: Move TLB_MMIO, TLB_DISCARD_WRITE to slow flags") Reported-by: Jonathan Cameron Tested-by: Jonathan Cameron Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 5f6d7c601c..86d0deb08c 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1871,8 +1871,12 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, goto stop_the_world; } - /* Collect tlb flags for read. */ + /* Finish collecting tlb flags for both read and write. */ + full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; tlb_addr |= tlbe->addr_read; + tlb_addr &= TLB_FLAGS_MASK & ~TLB_FORCE_SLOW; + tlb_addr |= full->slow_flags[MMU_DATA_STORE]; + tlb_addr |= full->slow_flags[MMU_DATA_LOAD]; /* Notice an IO access or a needs-MMU-lookup access */ if (unlikely(tlb_addr & (TLB_MMIO | TLB_DISCARD_WRITE))) { @@ -1882,13 +1886,12 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, } hostaddr = (void *)((uintptr_t)addr + tlbe->addend); - full = &cpu->neg.tlb.d[mmu_idx].fulltlb[index]; if (unlikely(tlb_addr & TLB_NOTDIRTY)) { notdirty_write(cpu, addr, size, full, retaddr); } - if (unlikely(tlb_addr & TLB_FORCE_SLOW)) { + if (unlikely(tlb_addr & TLB_WATCHPOINT)) { int wp_flags = 0; if (full->slow_flags[MMU_DATA_STORE] & TLB_WATCHPOINT) { @@ -1897,10 +1900,8 @@ static void *atomic_mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, if (full->slow_flags[MMU_DATA_LOAD] & TLB_WATCHPOINT) { wp_flags |= BP_MEM_READ; } - if (wp_flags) { - cpu_check_watchpoint(cpu, addr, size, - full->attrs, wp_flags, retaddr); - } + cpu_check_watchpoint(cpu, addr, size, + full->attrs, wp_flags, retaddr); } return hostaddr; From 556d05d1e2ac687463ce2877cb4acd1b0589deed Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 15 May 2025 10:46:41 -0700 Subject: [PATCH 1178/2760] system/main: comment lock rationale Signed-off-by: Pierrick Bouvier Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: <20250515174641.4000309-1-pierrick.bouvier@linaro.org> --- system/main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/system/main.c b/system/main.c index 1c02206734..b8f7157cc3 100644 --- a/system/main.c +++ b/system/main.c @@ -69,8 +69,21 @@ int (*qemu_main)(void) = os_darwin_cfrunloop_main; int main(int argc, char **argv) { qemu_init(argc, argv); + + /* + * qemu_init acquires the BQL and replay mutex lock. BQL is acquired when + * initializing cpus, to block associated threads until initialization is + * complete. Replay_mutex lock is acquired on initialization, because it + * must be held when configuring icount_mode. + * + * On MacOS, qemu main event loop runs in a background thread, as main + * thread must be reserved for UI. Thus, we need to transfer lock ownership, + * and the simplest way to do that is to release them, and reacquire them + * from qemu_default_main. + */ bql_unlock(); replay_mutex_unlock(); + if (qemu_main) { QemuThread main_loop_thread; qemu_thread_create(&main_loop_thread, "qemu_main", From 19f036726a416c9248c19befe544a2d30b099a25 Mon Sep 17 00:00:00 2001 From: Andreas Schwab Date: Tue, 20 May 2025 16:07:37 +0200 Subject: [PATCH 1179/2760] linux-user: implement pgid field of /proc/self/stat Signed-off-by: Andreas Schwab Reviewed-by: Richard Henderson Signed-off-by: Richard Henderson Message-ID: --- linux-user/syscall.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 23b901b713..fc37028597 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -8235,6 +8235,9 @@ static int open_self_stat(CPUArchState *cpu_env, int fd) } else if (i == 3) { /* ppid */ g_string_printf(buf, FMT_pid " ", getppid()); + } else if (i == 4) { + /* pgid */ + g_string_printf(buf, FMT_pid " ", getpgrp()); } else if (i == 19) { /* num_threads */ int cpus = 0; From 67f2d507ca444cfff993c1a05df3aaa4346a372c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 12:30:21 -0800 Subject: [PATCH 1180/2760] target/microblaze: Split out mb_unaligned_access_internal Use an explicit 64-bit type for the address to store in EAR. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.c | 64 +++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 9203192483..5fe81e4b16 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -27,6 +27,42 @@ #include "qemu/host-utils.h" #include "exec/log.h" + +G_NORETURN +static void mb_unaligned_access_internal(CPUState *cs, uint64_t addr, + uintptr_t retaddr) +{ + CPUMBState *env = cpu_env(cs); + uint32_t esr, iflags; + + /* Recover the pc and iflags from the corresponding insn_start. */ + cpu_restore_state(cs, retaddr); + iflags = env->iflags; + + qemu_log_mask(CPU_LOG_INT, + "Unaligned access addr=0x%" PRIx64 " pc=%x iflags=%x\n", + addr, env->pc, iflags); + + esr = ESR_EC_UNALIGNED_DATA; + if (likely(iflags & ESR_ESS_FLAG)) { + esr |= iflags & ESR_ESS_MASK; + } else { + qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n"); + } + + env->ear = addr; + env->esr = esr; + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit(cs); +} + +void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr) +{ + mb_unaligned_access_internal(cs, addr, retaddr); +} + #ifndef CONFIG_USER_ONLY static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu, MMUAccessType access_type) @@ -269,31 +305,3 @@ bool mb_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } #endif /* !CONFIG_USER_ONLY */ - -void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr) -{ - MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); - uint32_t esr, iflags; - - /* Recover the pc and iflags from the corresponding insn_start. */ - cpu_restore_state(cs, retaddr); - iflags = cpu->env.iflags; - - qemu_log_mask(CPU_LOG_INT, - "Unaligned access addr=" TARGET_FMT_lx " pc=%x iflags=%x\n", - (target_ulong)addr, cpu->env.pc, iflags); - - esr = ESR_EC_UNALIGNED_DATA; - if (likely(iflags & ESR_ESS_FLAG)) { - esr |= iflags & ESR_ESS_MASK; - } else { - qemu_log_mask(LOG_UNIMP, "Unaligned access without ESR_ESS_FLAG\n"); - } - - cpu->env.ear = addr; - cpu->env.esr = esr; - cs->exception_index = EXCP_HW_EXCP; - cpu_loop_exit(cs); -} From 3f8d6b432dbdd63eecfb454d59d36b08f76c0c95 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 25 May 2025 16:10:03 +0100 Subject: [PATCH 1181/2760] target/microblaze: Introduce helper_unaligned_access Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.c | 7 +++++++ target/microblaze/helper.h | 12 ++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/target/microblaze/helper.c b/target/microblaze/helper.c index 5fe81e4b16..ef0e2f973f 100644 --- a/target/microblaze/helper.c +++ b/target/microblaze/helper.c @@ -26,6 +26,7 @@ #include "exec/target_page.h" #include "qemu/host-utils.h" #include "exec/log.h" +#include "exec/helper-proto.h" G_NORETURN @@ -64,6 +65,12 @@ void mb_cpu_do_unaligned_access(CPUState *cs, vaddr addr, } #ifndef CONFIG_USER_ONLY + +void HELPER(unaligned_access)(CPUMBState *env, uint64_t addr) +{ + mb_unaligned_access_internal(env_cpu(env), addr, GETPC()); +} + static bool mb_cpu_access_is_secure(MicroBlazeCPU *cpu, MMUAccessType access_type) { diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index f740835fcb..41f56a5601 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -20,12 +20,12 @@ DEF_HELPER_FLAGS_3(fcmp_ne, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_FLAGS_3(fcmp_ge, TCG_CALL_NO_WG, i32, env, i32, i32) DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_NO_RWG_SE, i32, i32, i32) -#if !defined(CONFIG_USER_ONLY) -DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32) -DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32) -#endif - DEF_HELPER_FLAGS_2(stackprot, TCG_CALL_NO_WG, void, env, tl) - DEF_HELPER_FLAGS_2(get, TCG_CALL_NO_RWG, i32, i32, i32) DEF_HELPER_FLAGS_3(put, TCG_CALL_NO_RWG, void, i32, i32, i32) + +#ifndef CONFIG_USER_ONLY +DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32) +DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32) +DEF_HELPER_FLAGS_2(unaligned_access, TCG_CALL_NO_WG, noreturn, env, i64) +#endif From 526b0d364af081792e469adabbc67aeaca8a4343 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 12:46:17 -0800 Subject: [PATCH 1182/2760] target/microblaze: Split out mb_transaction_failed_internal Use an explicit 64-bit type for the address to store in EAR. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/op_helper.c | 70 +++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 9e838dfa15..4c39207a55 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -393,38 +393,52 @@ void helper_mmu_write(CPUMBState *env, uint32_t ext, uint32_t rn, uint32_t v) mmu_write(env, ext, rn, v); } +static void mb_transaction_failed_internal(CPUState *cs, hwaddr physaddr, + uint64_t addr, unsigned size, + MMUAccessType access_type, + uintptr_t retaddr) +{ + CPUMBState *env = cpu_env(cs); + MicroBlazeCPU *cpu = env_archcpu(env); + const char *access_name = "INVALID"; + bool take = env->msr & MSR_EE; + uint32_t esr = ESR_EC_DATA_BUS; + + switch (access_type) { + case MMU_INST_FETCH: + access_name = "INST_FETCH"; + esr = ESR_EC_INSN_BUS; + take &= cpu->cfg.iopb_bus_exception; + break; + case MMU_DATA_LOAD: + access_name = "DATA_LOAD"; + take &= cpu->cfg.dopb_bus_exception; + break; + case MMU_DATA_STORE: + access_name = "DATA_STORE"; + take &= cpu->cfg.dopb_bus_exception; + break; + } + + qemu_log_mask(CPU_LOG_INT, "Transaction failed: addr 0x%" PRIx64 + "physaddr 0x" HWADDR_FMT_plx " size %d access-type %s (%s)\n", + addr, physaddr, size, access_name, + take ? "TAKEN" : "DROPPED"); + + if (take) { + env->esr = esr; + env->ear = addr; + cs->exception_index = EXCP_HW_EXCP; + cpu_loop_exit_restore(cs, retaddr); + } +} + void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, unsigned size, MMUAccessType access_type, int mmu_idx, MemTxAttrs attrs, MemTxResult response, uintptr_t retaddr) { - MicroBlazeCPU *cpu = MICROBLAZE_CPU(cs); - CPUMBState *env = &cpu->env; - - qemu_log_mask(CPU_LOG_INT, "Transaction failed: vaddr 0x%" VADDR_PRIx - " physaddr 0x" HWADDR_FMT_plx " size %d access type %s\n", - addr, physaddr, size, - access_type == MMU_INST_FETCH ? "INST_FETCH" : - (access_type == MMU_DATA_LOAD ? "DATA_LOAD" : "DATA_STORE")); - - if (!(env->msr & MSR_EE)) { - return; - } - - if (access_type == MMU_INST_FETCH) { - if (!cpu->cfg.iopb_bus_exception) { - return; - } - env->esr = ESR_EC_INSN_BUS; - } else { - if (!cpu->cfg.dopb_bus_exception) { - return; - } - env->esr = ESR_EC_DATA_BUS; - } - - env->ear = addr; - cs->exception_index = EXCP_HW_EXCP; - cpu_loop_exit_restore(cs, retaddr); + mb_transaction_failed_internal(cs, physaddr, addr, size, + access_type, retaddr); } #endif From beea772666fb1bb86136042fd8ee7140a01bb36f Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:20:58 -0800 Subject: [PATCH 1183/2760] target/microblaze: Implement extended address load/store out of line Use helpers and address_space_ld/st instead of inline loads and stores. This allows us to perform operations on physical addresses wider than virtual addresses. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/helper.h | 10 +++++++ target/microblaze/op_helper.c | 40 +++++++++++++++++++++++++++ target/microblaze/translate.c | 52 +++++++++++++++++++++++++++-------- 3 files changed, 90 insertions(+), 12 deletions(-) diff --git a/target/microblaze/helper.h b/target/microblaze/helper.h index 41f56a5601..ef4fad9b91 100644 --- a/target/microblaze/helper.h +++ b/target/microblaze/helper.h @@ -28,4 +28,14 @@ DEF_HELPER_FLAGS_3(put, TCG_CALL_NO_RWG, void, i32, i32, i32) DEF_HELPER_FLAGS_3(mmu_read, TCG_CALL_NO_RWG, i32, env, i32, i32) DEF_HELPER_FLAGS_4(mmu_write, TCG_CALL_NO_RWG, void, env, i32, i32, i32) DEF_HELPER_FLAGS_2(unaligned_access, TCG_CALL_NO_WG, noreturn, env, i64) +DEF_HELPER_FLAGS_2(lbuea, TCG_CALL_NO_WG, i32, env, i64) +DEF_HELPER_FLAGS_2(lhuea_be, TCG_CALL_NO_WG, i32, env, i64) +DEF_HELPER_FLAGS_2(lhuea_le, TCG_CALL_NO_WG, i32, env, i64) +DEF_HELPER_FLAGS_2(lwea_be, TCG_CALL_NO_WG, i32, env, i64) +DEF_HELPER_FLAGS_2(lwea_le, TCG_CALL_NO_WG, i32, env, i64) +DEF_HELPER_FLAGS_3(sbea, TCG_CALL_NO_WG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(shea_be, TCG_CALL_NO_WG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(shea_le, TCG_CALL_NO_WG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(swea_be, TCG_CALL_NO_WG, void, env, i32, i64) +DEF_HELPER_FLAGS_3(swea_le, TCG_CALL_NO_WG, void, env, i32, i64) #endif diff --git a/target/microblaze/op_helper.c b/target/microblaze/op_helper.c index 4c39207a55..b8365b3b1d 100644 --- a/target/microblaze/op_helper.c +++ b/target/microblaze/op_helper.c @@ -382,6 +382,8 @@ void helper_stackprot(CPUMBState *env, target_ulong addr) } #if !defined(CONFIG_USER_ONLY) +#include "system/memory.h" + /* Writes/reads to the MMU's special regs end up here. */ uint32_t helper_mmu_read(CPUMBState *env, uint32_t ext, uint32_t rn) { @@ -441,4 +443,42 @@ void mb_cpu_transaction_failed(CPUState *cs, hwaddr physaddr, vaddr addr, mb_transaction_failed_internal(cs, physaddr, addr, size, access_type, retaddr); } + +#define LD_EA(NAME, TYPE, FUNC) \ +uint32_t HELPER(NAME)(CPUMBState *env, uint64_t ea) \ +{ \ + CPUState *cs = env_cpu(env); \ + MemTxResult txres; \ + TYPE ret = FUNC(cs->as, ea, MEMTXATTRS_UNSPECIFIED, &txres); \ + if (unlikely(txres != MEMTX_OK)) { \ + mb_transaction_failed_internal(cs, ea, ea, sizeof(TYPE), \ + MMU_DATA_LOAD, GETPC()); \ + } \ + return ret; \ +} + +LD_EA(lbuea, uint8_t, address_space_ldub) +LD_EA(lhuea_be, uint16_t, address_space_lduw_be) +LD_EA(lhuea_le, uint16_t, address_space_lduw_le) +LD_EA(lwea_be, uint32_t, address_space_ldl_be) +LD_EA(lwea_le, uint32_t, address_space_ldl_le) + +#define ST_EA(NAME, TYPE, FUNC) \ +void HELPER(NAME)(CPUMBState *env, uint32_t data, uint64_t ea) \ +{ \ + CPUState *cs = env_cpu(env); \ + MemTxResult txres; \ + FUNC(cs->as, ea, data, MEMTXATTRS_UNSPECIFIED, &txres); \ + if (unlikely(txres != MEMTX_OK)) { \ + mb_transaction_failed_internal(cs, ea, ea, sizeof(TYPE), \ + MMU_DATA_STORE, GETPC()); \ + } \ +} + +ST_EA(sbea, uint8_t, address_space_stb) +ST_EA(shea_be, uint16_t, address_space_stw_be) +ST_EA(shea_le, uint16_t, address_space_stw_le) +ST_EA(swea_be, uint32_t, address_space_stl_be) +ST_EA(swea_le, uint32_t, address_space_stl_le) + #endif diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 671b1ae4db..3d9756391e 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -700,6 +700,20 @@ static void record_unaligned_ess(DisasContext *dc, int rd, tcg_set_insn_start_param(dc->base.insn_start, 1, iflags); } + +static void gen_alignment_check_ea(DisasContext *dc, TCGv_i64 ea, int rb, + int rd, MemOp size, bool store) +{ + if (rb && (dc->tb_flags & MSR_EE) && dc->cfg->unaligned_exceptions) { + TCGLabel *over = gen_new_label(); + + record_unaligned_ess(dc, rd, size, store); + + tcg_gen_brcondi_i64(TCG_COND_TSTEQ, ea, (1 << size) - 1, over); + gen_helper_unaligned_access(tcg_env, ea); + gen_set_label(over); + } +} #endif static inline MemOp mo_endian(DisasContext *dc) @@ -765,10 +779,11 @@ static bool trans_lbuea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_load(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); + gen_helper_lbuea(reg_for_write(dc, arg->rd), tcg_env, addr); + return true; #endif } @@ -796,10 +811,13 @@ static bool trans_lhuea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_load(dc, arg->rd, addr, MO_UW, MMU_NOMMU_IDX, false); + gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, false); + (mo_endian(dc) == MO_BE ? gen_helper_lhuea_be : gen_helper_lhuea_le) + (reg_for_write(dc, arg->rd), tcg_env, addr); + return true; #endif } @@ -827,10 +845,13 @@ static bool trans_lwea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_load(dc, arg->rd, addr, MO_UL, MMU_NOMMU_IDX, false); + gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, false); + (mo_endian(dc) == MO_BE ? gen_helper_lwea_be : gen_helper_lwea_le) + (reg_for_write(dc, arg->rd), tcg_env, addr); + return true; #endif } @@ -918,10 +939,11 @@ static bool trans_sbea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_store(dc, arg->rd, addr, MO_UB, MMU_NOMMU_IDX, false); + gen_helper_sbea(tcg_env, reg_for_read(dc, arg->rd), addr); + return true; #endif } @@ -949,10 +971,13 @@ static bool trans_shea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_store(dc, arg->rd, addr, MO_UW, MMU_NOMMU_IDX, false); + gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, true); + (mo_endian(dc) == MO_BE ? gen_helper_shea_be : gen_helper_shea_le) + (tcg_env, reg_for_read(dc, arg->rd), addr); + return true; #endif } @@ -980,10 +1005,13 @@ static bool trans_swea(DisasContext *dc, arg_typea *arg) return true; } #ifdef CONFIG_USER_ONLY - return true; + g_assert_not_reached(); #else TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); - return do_store(dc, arg->rd, addr, MO_UL, MMU_NOMMU_IDX, false); + gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, true); + (mo_endian(dc) == MO_BE ? gen_helper_swea_be : gen_helper_swea_le) + (tcg_env, reg_for_read(dc, arg->rd), addr); + return true; #endif } From 8cea8bd4d3909b7828310a0f76d5194d1bf0095a Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:24:08 -0800 Subject: [PATCH 1184/2760] target/microblaze: Use uint64_t for CPUMBState.ear Use an explicit 64-bit type for EAR. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/cpu.h | 2 +- target/microblaze/translate.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/microblaze/cpu.h b/target/microblaze/cpu.h index 6ad8643f2e..3ce28b302f 100644 --- a/target/microblaze/cpu.h +++ b/target/microblaze/cpu.h @@ -248,7 +248,7 @@ struct CPUArchState { uint32_t pc; uint32_t msr; /* All bits of MSR except MSR[C] and MSR[CC] */ uint32_t msr_c; /* MSR[C], in low bit; other bits must be 0 */ - target_ulong ear; + uint64_t ear; uint32_t esr; uint32_t fsr; uint32_t btr; diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 3d9756391e..b1fc9e5624 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -1857,7 +1857,7 @@ void mb_cpu_dump_state(CPUState *cs, FILE *f, int flags) } qemu_fprintf(f, "\nesr=0x%04x fsr=0x%02x btr=0x%08x edr=0x%x\n" - "ear=0x" TARGET_FMT_lx " slr=0x%x shr=0x%x\n", + "ear=0x%" PRIx64 " slr=0x%x shr=0x%x\n", env->esr, env->fsr, env->btr, env->edr, env->ear, env->slr, env->shr); From 14c1d81354c425d98423c41f60db5907f70cf216 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:28:18 -0800 Subject: [PATCH 1185/2760] target/microblaze: Use TCGv_i64 for compute_ldst_addr_ea Use an explicit 64-bit type for extended addresses. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index b1fc9e5624..dc597b36e6 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -660,23 +660,23 @@ static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) } #ifndef CONFIG_USER_ONLY -static TCGv compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) +static TCGv_i64 compute_ldst_addr_ea(DisasContext *dc, int ra, int rb) { int addr_size = dc->cfg->addr_size; - TCGv ret = tcg_temp_new(); + TCGv_i64 ret = tcg_temp_new_i64(); if (addr_size == 32 || ra == 0) { if (rb) { - tcg_gen_extu_i32_tl(ret, cpu_R[rb]); + tcg_gen_extu_i32_i64(ret, cpu_R[rb]); } else { - tcg_gen_movi_tl(ret, 0); + return tcg_constant_i64(0); } } else { if (rb) { tcg_gen_concat_i32_i64(ret, cpu_R[rb], cpu_R[ra]); } else { - tcg_gen_extu_i32_tl(ret, cpu_R[ra]); - tcg_gen_shli_tl(ret, ret, 32); + tcg_gen_extu_i32_i64(ret, cpu_R[ra]); + tcg_gen_shli_i64(ret, ret, 32); } if (addr_size < 64) { /* Mask off out of range bits. */ @@ -781,7 +781,7 @@ static bool trans_lbuea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_helper_lbuea(reg_for_write(dc, arg->rd), tcg_env, addr); return true; #endif @@ -813,7 +813,7 @@ static bool trans_lhuea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, false); (mo_endian(dc) == MO_BE ? gen_helper_lhuea_be : gen_helper_lhuea_le) (reg_for_write(dc, arg->rd), tcg_env, addr); @@ -847,7 +847,7 @@ static bool trans_lwea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, false); (mo_endian(dc) == MO_BE ? gen_helper_lwea_be : gen_helper_lwea_le) (reg_for_write(dc, arg->rd), tcg_env, addr); @@ -941,7 +941,7 @@ static bool trans_sbea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_helper_sbea(tcg_env, reg_for_read(dc, arg->rd), addr); return true; #endif @@ -973,7 +973,7 @@ static bool trans_shea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_16, true); (mo_endian(dc) == MO_BE ? gen_helper_shea_be : gen_helper_shea_le) (tcg_env, reg_for_read(dc, arg->rd), addr); @@ -1007,7 +1007,7 @@ static bool trans_swea(DisasContext *dc, arg_typea *arg) #ifdef CONFIG_USER_ONLY g_assert_not_reached(); #else - TCGv addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); + TCGv_i64 addr = compute_ldst_addr_ea(dc, arg->ra, arg->rb); gen_alignment_check_ea(dc, addr, arg->rb, arg->rd, MO_32, true); (mo_endian(dc) == MO_BE ? gen_helper_swea_be : gen_helper_swea_le) (tcg_env, reg_for_read(dc, arg->rd), addr); From 17ac97a9581fa9dd9c433d7562506a514f7292b3 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:34:52 -0800 Subject: [PATCH 1186/2760] target/microblaze: Fix printf format in mmu_translate Use TARGET_FMT_lx to match the target_ulong type of vaddr. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target/microblaze/mmu.c b/target/microblaze/mmu.c index 95a12e16f8..8703ff5c65 100644 --- a/target/microblaze/mmu.c +++ b/target/microblaze/mmu.c @@ -172,7 +172,8 @@ unsigned int mmu_translate(MicroBlazeCPU *cpu, MicroBlazeMMULookup *lu, } done: qemu_log_mask(CPU_LOG_MMU, - "MMU vaddr=%" PRIx64 " rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n", + "MMU vaddr=0x" TARGET_FMT_lx + " rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n", vaddr, rw, tlb_wr, tlb_ex, hit); return hit; } From b52ee0c1a4205c8d698c37557401d2f55e071fba Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:37:39 -0800 Subject: [PATCH 1187/2760] target/microblaze: Use TARGET_LONG_BITS == 32 for system mode Now that the extended address instructions are handled separately from virtual addresses, we can narrow the emulation to 32-bit. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- configs/targets/microblaze-softmmu.mak | 4 +--- configs/targets/microblazeel-softmmu.mak | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/configs/targets/microblaze-softmmu.mak b/configs/targets/microblaze-softmmu.mak index 23457d0ae6..bab7b498c2 100644 --- a/configs/targets/microblaze-softmmu.mak +++ b/configs/targets/microblaze-softmmu.mak @@ -3,6 +3,4 @@ TARGET_BIG_ENDIAN=y # needed by boot.c TARGET_NEED_FDT=y TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml -# System mode can address up to 64 bits via lea/sea instructions. -# TODO: These bypass the mmu, so we could emulate these differently. -TARGET_LONG_BITS=64 +TARGET_LONG_BITS=32 diff --git a/configs/targets/microblazeel-softmmu.mak b/configs/targets/microblazeel-softmmu.mak index c82c509623..8aee7ebc5c 100644 --- a/configs/targets/microblazeel-softmmu.mak +++ b/configs/targets/microblazeel-softmmu.mak @@ -2,6 +2,4 @@ TARGET_ARCH=microblaze # needed by boot.c TARGET_NEED_FDT=y TARGET_XML_FILES=gdb-xml/microblaze-core.xml gdb-xml/microblaze-stack-protect.xml -# System mode can address up to 64 bits via lea/sea instructions. -# TODO: These bypass the mmu, so we could emulate these differently. -TARGET_LONG_BITS=64 +TARGET_LONG_BITS=32 From bd07403fc146a9bfc5312404a63f24cc48701c97 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:54:18 -0800 Subject: [PATCH 1188/2760] target/microblaze: Drop DisasContext.r0 Return a constant 0 from reg_for_read, and a new temporary from reg_for_write. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index dc597b36e6..047d97e2c5 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -63,9 +63,6 @@ typedef struct DisasContext { DisasContextBase base; const MicroBlazeCPUConfig *cfg; - TCGv_i32 r0; - bool r0_set; - /* Decoder. */ uint32_t ext_imm; unsigned int tb_flags; @@ -179,14 +176,7 @@ static TCGv_i32 reg_for_read(DisasContext *dc, int reg) if (likely(reg != 0)) { return cpu_R[reg]; } - if (!dc->r0_set) { - if (dc->r0 == NULL) { - dc->r0 = tcg_temp_new_i32(); - } - tcg_gen_movi_i32(dc->r0, 0); - dc->r0_set = true; - } - return dc->r0; + return tcg_constant_i32(0); } static TCGv_i32 reg_for_write(DisasContext *dc, int reg) @@ -194,10 +184,7 @@ static TCGv_i32 reg_for_write(DisasContext *dc, int reg) if (likely(reg != 0)) { return cpu_R[reg]; } - if (dc->r0 == NULL) { - dc->r0 = tcg_temp_new_i32(); - } - return dc->r0; + return tcg_temp_new_i32(); } static bool do_typea(DisasContext *dc, arg_typea *arg, bool side_effects, @@ -1635,8 +1622,6 @@ static void mb_tr_init_disas_context(DisasContextBase *dcb, CPUState *cs) dc->cfg = &cpu->cfg; dc->tb_flags = dc->base.tb->flags; dc->ext_imm = dc->base.tb->cs_base; - dc->r0 = NULL; - dc->r0_set = false; dc->mem_index = cpu_mmu_index(cs, false); dc->jmp_cond = dc->tb_flags & D_FLAG ? TCG_COND_ALWAYS : TCG_COND_NEVER; dc->jmp_dest = -1; @@ -1675,11 +1660,6 @@ static void mb_tr_translate_insn(DisasContextBase *dcb, CPUState *cs) trap_illegal(dc, true); } - if (dc->r0) { - dc->r0 = NULL; - dc->r0_set = false; - } - /* Discard the imm global when its contents cannot be used. */ if ((dc->tb_flags & ~dc->tb_flags_to_set) & IMM_FLAG) { tcg_gen_discard_i32(cpu_imm); From 36a9529e60e09b0d0b6b5ebad614255c97bf9322 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 12 Feb 2025 13:56:32 -0800 Subject: [PATCH 1189/2760] target/microblaze: Simplify compute_ldst_addr_type{a,b} Require TCGv_i32 and TCGv be identical, so drop the extensions. Return constants when possible instead of a mov into a temporary. Return register inputs unchanged when possible. Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- target/microblaze/translate.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/target/microblaze/translate.c b/target/microblaze/translate.c index 047d97e2c5..5098a1db4d 100644 --- a/target/microblaze/translate.c +++ b/target/microblaze/translate.c @@ -606,19 +606,18 @@ DO_TYPEBI(xori, false, tcg_gen_xori_i32) static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) { - TCGv ret = tcg_temp_new(); + TCGv ret; /* If any of the regs is r0, set t to the value of the other reg. */ if (ra && rb) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_add_i32(tmp, cpu_R[ra], cpu_R[rb]); - tcg_gen_extu_i32_tl(ret, tmp); + ret = tcg_temp_new_i32(); + tcg_gen_add_i32(ret, cpu_R[ra], cpu_R[rb]); } else if (ra) { - tcg_gen_extu_i32_tl(ret, cpu_R[ra]); + ret = cpu_R[ra]; } else if (rb) { - tcg_gen_extu_i32_tl(ret, cpu_R[rb]); + ret = cpu_R[rb]; } else { - tcg_gen_movi_tl(ret, 0); + ret = tcg_constant_i32(0); } if ((ra == 1 || rb == 1) && dc->cfg->stackprot) { @@ -629,15 +628,16 @@ static TCGv compute_ldst_addr_typea(DisasContext *dc, int ra, int rb) static TCGv compute_ldst_addr_typeb(DisasContext *dc, int ra, int imm) { - TCGv ret = tcg_temp_new(); + TCGv ret; /* If any of the regs is r0, set t to the value of the other reg. */ - if (ra) { - TCGv_i32 tmp = tcg_temp_new_i32(); - tcg_gen_addi_i32(tmp, cpu_R[ra], imm); - tcg_gen_extu_i32_tl(ret, tmp); + if (ra && imm) { + ret = tcg_temp_new_i32(); + tcg_gen_addi_i32(ret, cpu_R[ra], imm); + } else if (ra) { + ret = cpu_R[ra]; } else { - tcg_gen_movi_tl(ret, (uint32_t)imm); + ret = tcg_constant_i32(imm); } if (ra == 1 && dc->cfg->stackprot) { From 9cfcf8c3b7b7a95e754a9fce565a88c6c76ce128 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 1 May 2025 11:16:31 -0700 Subject: [PATCH 1190/2760] tcg: Drop TCGContext.tlb_dyn_max_bits This was an extremely minor optimization for aarch64 and x86_64, to use a 32-bit AND instruction when the guest softmmu tlb maximum was sufficiently small. Both hosts can simply use a 64-bit AND insn instead. Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 2 -- include/tcg/tcg.h | 1 - tcg/aarch64/tcg-target.c.inc | 6 +----- tcg/i386/tcg-target.c.inc | 6 ++---- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 451b383aa8..6735a40ade 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -24,7 +24,6 @@ #include "tcg/tcg.h" #include "exec/mmap-lock.h" #include "tb-internal.h" -#include "tlb-bounds.h" #include "exec/tb-flush.h" #include "qemu/cacheinfo.h" #include "qemu/target-info.h" @@ -316,7 +315,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) #ifdef CONFIG_SOFTMMU tcg_ctx->page_bits = TARGET_PAGE_BITS; tcg_ctx->page_mask = TARGET_PAGE_MASK; - tcg_ctx->tlb_dyn_max_bits = CPU_TLB_DYN_MAX_BITS; #endif tcg_ctx->guest_mo = cpu->cc->tcg_ops->guest_default_memory_order; diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index 3fa5a7aed2..e440c889c8 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -368,7 +368,6 @@ struct TCGContext { int page_mask; uint8_t page_bits; - uint8_t tlb_dyn_max_bits; TCGBar guest_mo; TCGRegSet reserved_regs; diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 4cb647cb34..6356a81c2a 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1661,7 +1661,6 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, unsigned s_mask = (1u << s_bits) - 1; unsigned mem_index = get_mmuidx(oi); TCGReg addr_adj; - TCGType mask_type; uint64_t compare_mask; ldst = new_ldst_label(s); @@ -1669,9 +1668,6 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, ldst->oi = oi; ldst->addr_reg = addr_reg; - mask_type = (s->page_bits + s->tlb_dyn_max_bits > 32 - ? TCG_TYPE_I64 : TCG_TYPE_I32); - /* Load cpu->neg.tlb.f[mmu_idx].{mask,table} into {tmp0,tmp1}. */ QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, mask) != 0); QEMU_BUILD_BUG_ON(offsetof(CPUTLBDescFast, table) != 8); @@ -1679,7 +1675,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tlb_mask_table_ofs(s, mem_index), 1, 0); /* Extract the TLB index from the address into X0. */ - tcg_out_insn(s, 3502S, AND_LSR, mask_type == TCG_TYPE_I64, + tcg_out_insn(s, 3502S, AND_LSR, TCG_TYPE_I64, TCG_REG_TMP0, TCG_REG_TMP0, addr_reg, s->page_bits - CPU_TLB_ENTRY_BITS); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 09fce27b06..2990912080 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2199,10 +2199,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, trexw = (ttype == TCG_TYPE_I32 ? 0 : P_REXW); if (TCG_TYPE_PTR == TCG_TYPE_I64) { hrexw = P_REXW; - if (s->page_bits + s->tlb_dyn_max_bits > 32) { - tlbtype = TCG_TYPE_I64; - tlbrexw = P_REXW; - } + tlbtype = TCG_TYPE_I64; + tlbrexw = P_REXW; } } From 11efde54f248c2da9e164910b8b1945e78a7168e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Thu, 1 May 2025 11:38:03 -0700 Subject: [PATCH 1191/2760] tcg: Drop TCGContext.page_{mask,bits} Use exec/target_page.h instead of independent variables. Signed-off-by: Richard Henderson --- accel/tcg/translate-all.c | 4 ---- include/tcg/tcg.h | 3 --- tcg/aarch64/tcg-target.c.inc | 4 ++-- tcg/arm/tcg-target.c.inc | 10 +++++----- tcg/i386/tcg-target.c.inc | 4 ++-- tcg/loongarch64/tcg-target.c.inc | 4 ++-- tcg/mips/tcg-target.c.inc | 6 +++--- tcg/perf.c | 2 +- tcg/ppc/tcg-target.c.inc | 14 +++++++------- tcg/riscv/tcg-target.c.inc | 4 ++-- tcg/s390x/tcg-target.c.inc | 4 ++-- tcg/sparc64/tcg-target.c.inc | 4 ++-- tcg/tcg-op-ldst.c | 3 ++- tcg/tcg.c | 1 + 14 files changed, 31 insertions(+), 36 deletions(-) diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c index 6735a40ade..d468667b0d 100644 --- a/accel/tcg/translate-all.c +++ b/accel/tcg/translate-all.c @@ -312,10 +312,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu, TCGTBCPUState s) tcg_ctx->gen_tb = tb; tcg_ctx->addr_type = target_long_bits() == 32 ? TCG_TYPE_I32 : TCG_TYPE_I64; -#ifdef CONFIG_SOFTMMU - tcg_ctx->page_bits = TARGET_PAGE_BITS; - tcg_ctx->page_mask = TARGET_PAGE_MASK; -#endif tcg_ctx->guest_mo = cpu->cc->tcg_ops->guest_default_memory_order; restart_translate: diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h index e440c889c8..125323f153 100644 --- a/include/tcg/tcg.h +++ b/include/tcg/tcg.h @@ -365,9 +365,6 @@ struct TCGContext { int nb_indirects; int nb_ops; TCGType addr_type; /* TCG_TYPE_I32 or TCG_TYPE_I64 */ - - int page_mask; - uint8_t page_bits; TCGBar guest_mo; TCGRegSet reserved_regs; diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc index 6356a81c2a..3b088b7bd9 100644 --- a/tcg/aarch64/tcg-target.c.inc +++ b/tcg/aarch64/tcg-target.c.inc @@ -1677,7 +1677,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Extract the TLB index from the address into X0. */ tcg_out_insn(s, 3502S, AND_LSR, TCG_TYPE_I64, TCG_REG_TMP0, TCG_REG_TMP0, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); /* Add the tlb_table pointer, forming the CPUTLBEntry address. */ tcg_out_insn(s, 3502, ADD, 1, TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_TMP0); @@ -1703,7 +1703,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_insn(s, 3401, ADDI, addr_type, addr_adj, addr_reg, s_mask - a_mask); } - compare_mask = (uint64_t)s->page_mask | a_mask; + compare_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; /* Store the page mask part of the address into TMP2. */ tcg_out_logicali(s, I3404_ANDI, addr_type, TCG_REG_TMP2, diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc index 447e43583e..836894b16a 100644 --- a/tcg/arm/tcg-target.c.inc +++ b/tcg/arm/tcg-target.c.inc @@ -1427,7 +1427,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Extract the tlb index from the address into R0. */ tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_R0, TCG_REG_R0, addr, - SHIFT_IMM_LSR(s->page_bits - CPU_TLB_ENTRY_BITS)); + SHIFT_IMM_LSR(TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)); /* * Add the tlb_table pointer, creating the CPUTLBEntry address in R1. @@ -1463,8 +1463,8 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_dat_imm(s, COND_AL, ARITH_ADD, t_addr, addr, s_mask - a_mask); } - if (use_armv7_instructions && s->page_bits <= 16) { - tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(s->page_mask | a_mask)); + if (use_armv7_instructions && TARGET_PAGE_BITS <= 16) { + tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(TARGET_PAGE_MASK | a_mask)); tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP, t_addr, TCG_REG_TMP, 0); tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, @@ -1475,10 +1475,10 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addr, a_mask); } tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, t_addr, - SHIFT_IMM_LSR(s->page_bits)); + SHIFT_IMM_LSR(TARGET_PAGE_BITS)); tcg_out_dat_reg(s, (a_mask ? COND_EQ : COND_AL), ARITH_CMP, 0, TCG_REG_R2, TCG_REG_TMP, - SHIFT_IMM_LSL(s->page_bits)); + SHIFT_IMM_LSL(TARGET_PAGE_BITS)); } } else if (a_mask) { ldst = new_ldst_label(s); diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc index 2990912080..088c6c9264 100644 --- a/tcg/i386/tcg-target.c.inc +++ b/tcg/i386/tcg-target.c.inc @@ -2206,7 +2206,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_mov(s, tlbtype, TCG_REG_L0, addr); tcg_out_shifti(s, SHIFT_SHR + tlbrexw, TCG_REG_L0, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); tcg_out_modrm_offset(s, OPC_AND_GvEv + trexw, TCG_REG_L0, TCG_AREG0, fast_ofs + offsetof(CPUTLBDescFast, mask)); @@ -2225,7 +2225,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_modrm_offset(s, OPC_LEA + trexw, TCG_REG_L1, addr, s_mask - a_mask); } - tlb_mask = s->page_mask | a_mask; + tlb_mask = TARGET_PAGE_MASK | a_mask; tgen_arithi(s, ARITH_AND + trexw, TCG_REG_L1, tlb_mask, 0); /* cmp 0(TCG_REG_L0), TCG_REG_L1 */ diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc index e5580d69a8..10c69211ac 100644 --- a/tcg/loongarch64/tcg-target.c.inc +++ b/tcg/loongarch64/tcg-target.c.inc @@ -1065,7 +1065,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); tcg_out_opc_srli_d(s, TCG_REG_TMP2, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); tcg_out_opc_and(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); tcg_out_opc_add_d(s, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); @@ -1091,7 +1091,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, tcg_out_mov(s, addr_type, TCG_REG_TMP1, addr_reg); } tcg_out_opc_bstrins_d(s, TCG_REG_TMP1, TCG_REG_ZERO, - a_bits, s->page_bits - 1); + a_bits, TARGET_PAGE_BITS - 1); /* Compare masked address with the TLB entry. */ ldst->label_ptr[0] = s->code_ptr; diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc index 2c0457e588..400eafbab4 100644 --- a/tcg/mips/tcg-target.c.inc +++ b/tcg/mips/tcg-target.c.inc @@ -1199,9 +1199,9 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Extract the TLB index from the address into TMP3. */ if (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32) { tcg_out_opc_sa(s, OPC_SRL, TCG_TMP3, addr, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); } else { - tcg_out_dsrl(s, TCG_TMP3, addr, s->page_bits - CPU_TLB_ENTRY_BITS); + tcg_out_dsrl(s, TCG_TMP3, addr, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); } tcg_out_opc_reg(s, OPC_AND, TCG_TMP3, TCG_TMP3, TCG_TMP0); @@ -1224,7 +1224,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, * For unaligned accesses, compare against the end of the access to * verify that it does not cross a page boundary. */ - tcg_out_movi(s, addr_type, TCG_TMP1, s->page_mask | a_mask); + tcg_out_movi(s, addr_type, TCG_TMP1, TARGET_PAGE_MASK | a_mask); if (a_mask < s_mask) { tcg_out_opc_imm(s, (TCG_TARGET_REG_BITS == 32 || addr_type == TCG_TYPE_I32 diff --git a/tcg/perf.c b/tcg/perf.c index 4e8d2c1bee..8fa5fa9991 100644 --- a/tcg/perf.c +++ b/tcg/perf.c @@ -334,7 +334,7 @@ void perf_report_code(uint64_t guest_pc, TranslationBlock *tb, /* FIXME: This replicates the restore_state_to_opc() logic. */ q[insn].address = gen_insn_data[insn * INSN_START_WORDS + 0]; if (tb_cflags(tb) & CF_PCREL) { - q[insn].address |= (guest_pc & qemu_target_page_mask()); + q[insn].address |= guest_pc & TARGET_PAGE_MASK; } q[insn].flags = DEBUGINFO_SYMBOL | (jitdump ? DEBUGINFO_LINE : 0); } diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc index 2e94778104..b8b23d44d5 100644 --- a/tcg/ppc/tcg-target.c.inc +++ b/tcg/ppc/tcg-target.c.inc @@ -2440,10 +2440,10 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Extract the page index, shifted into place for tlb index. */ if (TCG_TARGET_REG_BITS == 32) { tcg_out_shri32(s, TCG_REG_R0, addr, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); } else { tcg_out_shri64(s, TCG_REG_R0, addr, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); } tcg_out32(s, AND | SAB(TCG_REG_TMP1, TCG_REG_TMP1, TCG_REG_R0)); @@ -2480,7 +2480,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, a_bits = s_bits; } tcg_out_rlw(s, RLWINM, TCG_REG_R0, addr, 0, - (32 - a_bits) & 31, 31 - s->page_bits); + (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS); } else { TCGReg t = addr; @@ -2501,13 +2501,13 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Mask the address for the requested alignment. */ if (addr_type == TCG_TYPE_I32) { tcg_out_rlw(s, RLWINM, TCG_REG_R0, t, 0, - (32 - a_bits) & 31, 31 - s->page_bits); + (32 - a_bits) & 31, 31 - TARGET_PAGE_BITS); } else if (a_bits == 0) { - tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - s->page_bits); + tcg_out_rld(s, RLDICR, TCG_REG_R0, t, 0, 63 - TARGET_PAGE_BITS); } else { tcg_out_rld(s, RLDICL, TCG_REG_R0, t, - 64 - s->page_bits, s->page_bits - a_bits); - tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, s->page_bits, 0); + 64 - TARGET_PAGE_BITS, TARGET_PAGE_BITS - a_bits); + tcg_out_rld(s, RLDICL, TCG_REG_R0, TCG_REG_R0, TARGET_PAGE_BITS, 0); } } diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc index f9417d15f7..1800fd5077 100644 --- a/tcg/riscv/tcg-target.c.inc +++ b/tcg/riscv/tcg-target.c.inc @@ -1706,7 +1706,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase, tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_TMP1, TCG_AREG0, table_ofs); tcg_out_opc_imm(s, OPC_SRLI, TCG_REG_TMP2, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); tcg_out_opc_reg(s, OPC_AND, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP0); tcg_out_opc_reg(s, OPC_ADD, TCG_REG_TMP2, TCG_REG_TMP2, TCG_REG_TMP1); @@ -1722,7 +1722,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, TCGReg *pbase, tcg_out_opc_imm(s, addr_type == TCG_TYPE_I32 ? OPC_ADDIW : OPC_ADDI, addr_adj, addr_reg, s_mask - a_mask); } - compare_mask = s->page_mask | a_mask; + compare_mask = TARGET_PAGE_MASK | a_mask; if (compare_mask == sextreg(compare_mask, 0, 12)) { tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_adj, compare_mask); } else { diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc index 7ca0071f24..84a9e73a46 100644 --- a/tcg/s390x/tcg-target.c.inc +++ b/tcg/s390x/tcg-target.c.inc @@ -2004,7 +2004,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, ldst->addr_reg = addr_reg; tcg_out_sh64(s, RSY_SRLG, TCG_TMP0, addr_reg, TCG_REG_NONE, - s->page_bits - CPU_TLB_ENTRY_BITS); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); tcg_out_insn(s, RXY, NG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, mask_off); tcg_out_insn(s, RXY, AG, TCG_TMP0, TCG_AREG0, TCG_REG_NONE, table_off); @@ -2016,7 +2016,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, * byte of the access. */ a_off = (a_mask >= s_mask ? 0 : s_mask - a_mask); - tlb_mask = (uint64_t)s->page_mask | a_mask; + tlb_mask = (uint64_t)TARGET_PAGE_MASK | a_mask; if (a_off == 0) { tgen_andi_risbg(s, TCG_REG_R0, addr_reg, tlb_mask); } else { diff --git a/tcg/sparc64/tcg-target.c.inc b/tcg/sparc64/tcg-target.c.inc index 9e004fb511..5e5c3f1cda 100644 --- a/tcg/sparc64/tcg-target.c.inc +++ b/tcg/sparc64/tcg-target.c.inc @@ -1120,7 +1120,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, /* Extract the page index, shifted into place for tlb index. */ tcg_out_arithi(s, TCG_REG_T1, addr_reg, - s->page_bits - CPU_TLB_ENTRY_BITS, SHIFT_SRL); + TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, SHIFT_SRL); tcg_out_arith(s, TCG_REG_T1, TCG_REG_T1, TCG_REG_T2, ARITH_AND); /* Add the tlb_table pointer, creating the CPUTLBEntry address into R2. */ @@ -1136,7 +1136,7 @@ static TCGLabelQemuLdst *prepare_host_addr(TCGContext *s, HostAddress *h, h->base = TCG_REG_T1; /* Mask out the page offset, except for the required alignment. */ - compare_mask = s->page_mask | a_mask; + compare_mask = TARGET_PAGE_MASK | a_mask; if (check_fit_tl(compare_mask, 13)) { tcg_out_arithi(s, TCG_REG_T3, addr_reg, compare_mask, ARITH_AND); } else { diff --git a/tcg/tcg-op-ldst.c b/tcg/tcg-op-ldst.c index fa9e52277b..548496002d 100644 --- a/tcg/tcg-op-ldst.c +++ b/tcg/tcg-op-ldst.c @@ -27,6 +27,7 @@ #include "tcg/tcg-temp-internal.h" #include "tcg/tcg-op-common.h" #include "tcg/tcg-mo.h" +#include "exec/target_page.h" #include "exec/translation-block.h" #include "exec/plugin-gen.h" #include "tcg-internal.h" @@ -40,7 +41,7 @@ static void check_max_alignment(unsigned a_bits) * FIXME: Must keep the count up-to-date with "exec/tlb-flags.h". */ if (tcg_use_softmmu) { - tcg_debug_assert(a_bits + 5 <= tcg_ctx->page_bits); + tcg_debug_assert(a_bits + 5 <= TARGET_PAGE_BITS); } } diff --git a/tcg/tcg.c b/tcg/tcg.c index ae27a2607d..d714ae2889 100644 --- a/tcg/tcg.c +++ b/tcg/tcg.c @@ -34,6 +34,7 @@ #include "qemu/cacheflush.h" #include "qemu/cacheinfo.h" #include "qemu/timer.h" +#include "exec/target_page.h" #include "exec/translation-block.h" #include "exec/tlb-common.h" #include "tcg/startup.h" From eb978e50e42f3439e7a7a104e76aafc81bc4a028 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 3 May 2025 13:40:26 -0700 Subject: [PATCH 1192/2760] target/sh4: Use MO_ALIGN for system UNALIGN() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should have been done before removing TARGET_ALIGNED_ONLY, as we did for hppa and alpha. Cc: Yoshinori Sato Reviewed-by: Philippe Mathieu-Daudé Fixes: 8244189419f9 ("target/sh4: Remove TARGET_ALIGNED_ONLY") Signed-off-by: Richard Henderson --- target/sh4/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/sh4/translate.c b/target/sh4/translate.c index bf8828fce8..70fd13aa3f 100644 --- a/target/sh4/translate.c +++ b/target/sh4/translate.c @@ -54,7 +54,7 @@ typedef struct DisasContext { #define UNALIGN(C) (ctx->tbflags & TB_FLAG_UNALIGN ? MO_UNALN : MO_ALIGN) #else #define IS_USER(ctx) (!(ctx->tbflags & (1u << SR_MD))) -#define UNALIGN(C) 0 +#define UNALIGN(C) MO_ALIGN #endif /* Target-specific values for ctx->base.is_jmp. */ From bdf26b5d16dd2264553308aa6bbf24b4749fcc07 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 3 May 2025 13:17:17 -0700 Subject: [PATCH 1193/2760] accel/tcg: Add TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 6 ++++++ include/accel/tcg/cpu-ops.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 86d0deb08c..81ff725cbc 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1773,6 +1773,12 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, l->page[1].size = l->page[0].size - size0; l->page[0].size = size0; + if (cpu->cc->tcg_ops->pointer_wrap) { + l->page[1].addr = cpu->cc->tcg_ops->pointer_wrap(cpu, l->mmu_idx, + l->page[1].addr, + addr); + } + /* * Lookup both pages, recognizing exceptions from either. If the * second lookup potentially resized, refresh first CPUTLBEntryFull. diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index cd22e5d5b9..83b2c2c864 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -222,6 +222,13 @@ struct TCGCPUOps { bool (*tlb_fill)(CPUState *cpu, vaddr address, int size, MMUAccessType access_type, int mmu_idx, bool probe, uintptr_t retaddr); + /** + * @pointer_wrap: + * + * We have incremented @base to @result, resulting in a page change. + * For the current cpu state, adjust @result for possible overflow. + */ + vaddr (*pointer_wrap)(CPUState *cpu, int mmu_idx, vaddr result, vaddr base); /** * @do_transaction_failed: Callback for handling failed memory transactions * (ie bus faults or external aborts; not MMU faults) From a4027ed7d4becb4cb67c912c75ecd4846b148829 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 3 May 2025 13:45:26 -0700 Subject: [PATCH 1194/2760] target: Use cpu_pointer_wrap_notreached for strict align targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alpha, HPPA, and SH4 always use aligned addresses, and therefore never produce accesses that cross pages. Cc: Helge Deller Cc: Yoshinori Sato Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 13 +++++++++++++ include/accel/tcg/cpu-ops.h | 5 +++++ target/alpha/cpu.c | 1 + target/hppa/cpu.c | 1 + target/sh4/cpu.c | 1 + 5 files changed, 21 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 81ff725cbc..49ec3ee5dc 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2933,3 +2933,16 @@ uint64_t cpu_ldq_code_mmu(CPUArchState *env, vaddr addr, { return do_ld8_mmu(env_cpu(env), addr, oi, retaddr, MMU_INST_FETCH); } + +/* + * Common pointer_wrap implementations. + */ + +/* + * To be used for strict alignment targets. + * Because no accesses are unaligned, no accesses wrap either. + */ +vaddr cpu_pointer_wrap_notreached(CPUState *cs, int idx, vaddr res, vaddr base) +{ + g_assert_not_reached(); +} diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 83b2c2c864..4f3b4fd3bc 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -322,6 +322,11 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len, */ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len); +/* + * Common pointer_wrap implementations. + */ +vaddr cpu_pointer_wrap_notreached(CPUState *, int, vaddr, vaddr); + #endif #endif /* TCG_CPU_OPS_H */ diff --git a/target/alpha/cpu.c b/target/alpha/cpu.c index 890b84c032..2082db45ea 100644 --- a/target/alpha/cpu.c +++ b/target/alpha/cpu.c @@ -261,6 +261,7 @@ static const TCGCPUOps alpha_tcg_ops = { .record_sigbus = alpha_cpu_record_sigbus, #else .tlb_fill = alpha_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_notreached, .cpu_exec_interrupt = alpha_cpu_exec_interrupt, .cpu_exec_halt = alpha_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/hppa/cpu.c b/target/hppa/cpu.c index 6465181543..24777727e6 100644 --- a/target/hppa/cpu.c +++ b/target/hppa/cpu.c @@ -269,6 +269,7 @@ static const TCGCPUOps hppa_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill_align = hppa_cpu_tlb_fill_align, + .pointer_wrap = cpu_pointer_wrap_notreached, .cpu_exec_interrupt = hppa_cpu_exec_interrupt, .cpu_exec_halt = hppa_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c index b35f18e250..4f561e8c91 100644 --- a/target/sh4/cpu.c +++ b/target/sh4/cpu.c @@ -296,6 +296,7 @@ static const TCGCPUOps superh_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = superh_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_notreached, .cpu_exec_interrupt = superh_cpu_exec_interrupt, .cpu_exec_halt = superh_cpu_has_work, .cpu_exec_reset = cpu_reset, From 981f2beb161b9bcaeedc1f91ad22bff255856cb2 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 3 May 2025 14:23:41 -0700 Subject: [PATCH 1195/2760] target: Use cpu_pointer_wrap_uint32 for 32-bit targets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M68K, MicroBlaze, OpenRISC, RX, TriCore and Xtensa are all 32-bit targets. AVR is more complicated, but using a 32-bit wrap preserves current behaviour. Cc: Michael Rolnik Cc: Laurent Vivier Cc: Stafford Horne Cc: Yoshinori Sato Cc: Max Filippov Tested-by Bastian Koppelmann (tricore) Reviewed-by: Bastian Koppelmann Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Edgar E. Iglesias Signed-off-by: Richard Henderson --- accel/tcg/cputlb.c | 6 ++++++ include/accel/tcg/cpu-ops.h | 1 + target/avr/cpu.c | 6 ++++++ target/m68k/cpu.c | 1 + target/microblaze/cpu.c | 1 + target/openrisc/cpu.c | 1 + target/rx/cpu.c | 1 + target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 1 + 9 files changed, 19 insertions(+) diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index 49ec3ee5dc..a734859396 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -2946,3 +2946,9 @@ vaddr cpu_pointer_wrap_notreached(CPUState *cs, int idx, vaddr res, vaddr base) { g_assert_not_reached(); } + +/* To be used for strict 32-bit targets. */ +vaddr cpu_pointer_wrap_uint32(CPUState *cs, int idx, vaddr res, vaddr base) +{ + return (uint32_t)res; +} diff --git a/include/accel/tcg/cpu-ops.h b/include/accel/tcg/cpu-ops.h index 4f3b4fd3bc..dd8ea30016 100644 --- a/include/accel/tcg/cpu-ops.h +++ b/include/accel/tcg/cpu-ops.h @@ -326,6 +326,7 @@ int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len); * Common pointer_wrap implementations. */ vaddr cpu_pointer_wrap_notreached(CPUState *, int, vaddr, vaddr); +vaddr cpu_pointer_wrap_uint32(CPUState *, int, vaddr, vaddr); #endif diff --git a/target/avr/cpu.c b/target/avr/cpu.c index 250241541b..6995de6a12 100644 --- a/target/avr/cpu.c +++ b/target/avr/cpu.c @@ -250,6 +250,12 @@ static const TCGCPUOps avr_tcg_ops = { .cpu_exec_reset = cpu_reset, .tlb_fill = avr_cpu_tlb_fill, .do_interrupt = avr_cpu_do_interrupt, + /* + * TODO: code and data wrapping are different, but for the most part + * AVR only references bytes or aligned code fetches. But we use + * non-aligned MO_16 accesses for stack push/pop. + */ + .pointer_wrap = cpu_pointer_wrap_uint32, }; static void avr_cpu_class_init(ObjectClass *oc, const void *data) diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c index c5196a612e..6a09db3a6f 100644 --- a/target/m68k/cpu.c +++ b/target/m68k/cpu.c @@ -619,6 +619,7 @@ static const TCGCPUOps m68k_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = m68k_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = m68k_cpu_exec_interrupt, .cpu_exec_halt = m68k_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/microblaze/cpu.c b/target/microblaze/cpu.c index 615a959200..ee0a869a94 100644 --- a/target/microblaze/cpu.c +++ b/target/microblaze/cpu.c @@ -447,6 +447,7 @@ static const TCGCPUOps mb_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = mb_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = mb_cpu_exec_interrupt, .cpu_exec_halt = mb_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c index 054ad33360..dfbb2df643 100644 --- a/target/openrisc/cpu.c +++ b/target/openrisc/cpu.c @@ -265,6 +265,7 @@ static const TCGCPUOps openrisc_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = openrisc_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = openrisc_cpu_exec_interrupt, .cpu_exec_halt = openrisc_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/rx/cpu.c b/target/rx/cpu.c index 36eba75545..c6dd5d6f83 100644 --- a/target/rx/cpu.c +++ b/target/rx/cpu.c @@ -225,6 +225,7 @@ static const TCGCPUOps rx_tcg_ops = { .restore_state_to_opc = rx_restore_state_to_opc, .mmu_index = rx_cpu_mmu_index, .tlb_fill = rx_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = rx_cpu_exec_interrupt, .cpu_exec_halt = rx_cpu_has_work, diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c index e56f90fde9..4f035b6f76 100644 --- a/target/tricore/cpu.c +++ b/target/tricore/cpu.c @@ -190,6 +190,7 @@ static const TCGCPUOps tricore_tcg_ops = { .restore_state_to_opc = tricore_restore_state_to_opc, .mmu_index = tricore_cpu_mmu_index, .tlb_fill = tricore_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = tricore_cpu_exec_interrupt, .cpu_exec_halt = tricore_cpu_has_work, .cpu_exec_reset = cpu_reset, diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c index 91b71b6caa..ea9b6df3aa 100644 --- a/target/xtensa/cpu.c +++ b/target/xtensa/cpu.c @@ -318,6 +318,7 @@ static const TCGCPUOps xtensa_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = xtensa_cpu_tlb_fill, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = xtensa_cpu_exec_interrupt, .cpu_exec_halt = xtensa_cpu_has_work, .cpu_exec_reset = cpu_reset, From d21144a48c1a9d1998c594d976d5e906276eca4c Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 09:27:42 -0700 Subject: [PATCH 1196/2760] target/arm: Fill in TCGCPUOps.pointer_wrap For a-profile, check A32 vs A64 state. For m-profile, use cpu_pointer_wrap_uint32. Cc: qemu-arm@nongnu.org Signed-off-by: Richard Henderson --- target/arm/cpu.c | 24 ++++++++++++++++++++++++ target/arm/tcg/cpu-v7m.c | 1 + 2 files changed, 25 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index ca5ed7892e..e025e241ed 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -2703,6 +2703,29 @@ static const struct SysemuCPUOps arm_sysemu_ops = { #endif #ifdef CONFIG_TCG +#ifndef CONFIG_USER_ONLY +static vaddr aprofile_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + /* + * The Stage2 and Phys indexes are only used for ptw on arm32, + * and all pte's are aligned, so we never produce a wrap for these. + * Double check that we're not truncating a 40-bit physical address. + */ + assert((unsigned)mmu_idx < (ARMMMUIdx_Stage2_S & ARM_MMU_IDX_COREIDX_MASK)); + + if (!is_a64(cpu_env(cs))) { + return (uint32_t)result; + } + + /* + * TODO: For FEAT_CPA2, decide how to we want to resolve + * Unpredictable_CPACHECK in AddressIncrement. + */ + return result; +} +#endif /* !CONFIG_USER_ONLY */ + static const TCGCPUOps arm_tcg_ops = { .mttcg_supported = true, /* ARM processors have a weak memory model */ @@ -2722,6 +2745,7 @@ static const TCGCPUOps arm_tcg_ops = { .untagged_addr = aarch64_untagged_addr, #else .tlb_fill_align = arm_cpu_tlb_fill_align, + .pointer_wrap = aprofile_pointer_wrap, .cpu_exec_interrupt = arm_cpu_exec_interrupt, .cpu_exec_halt = arm_cpu_exec_halt, .cpu_exec_reset = cpu_reset, diff --git a/target/arm/tcg/cpu-v7m.c b/target/arm/tcg/cpu-v7m.c index 95b23d9b55..8e1a083b91 100644 --- a/target/arm/tcg/cpu-v7m.c +++ b/target/arm/tcg/cpu-v7m.c @@ -249,6 +249,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = { .record_sigbus = arm_cpu_record_sigbus, #else .tlb_fill_align = arm_cpu_tlb_fill_align, + .pointer_wrap = cpu_pointer_wrap_uint32, .cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt, .cpu_exec_halt = arm_cpu_exec_halt, .cpu_exec_reset = cpu_reset, From 7174cd2eec67d9b7bf969cdc87e656b4c4c93465 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 09:46:28 -0700 Subject: [PATCH 1197/2760] target/i386: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check 32 vs 64-bit state. Cc: Paolo Bonzini Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/i386/tcg/tcg-cpu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/i386/tcg/tcg-cpu.c b/target/i386/tcg/tcg-cpu.c index 179dfdf064..6f5dc06b3b 100644 --- a/target/i386/tcg/tcg-cpu.c +++ b/target/i386/tcg/tcg-cpu.c @@ -149,6 +149,12 @@ static void x86_cpu_exec_reset(CPUState *cs) do_cpu_init(env_archcpu(env)); cs->exception_index = EXCP_HALTED; } + +static vaddr x86_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + return cpu_env(cs)->hflags & HF_CS64_MASK ? result : (uint32_t)result; +} #endif const TCGCPUOps x86_tcg_ops = { @@ -172,6 +178,7 @@ const TCGCPUOps x86_tcg_ops = { .record_sigbus = x86_cpu_record_sigbus, #else .tlb_fill = x86_cpu_tlb_fill, + .pointer_wrap = x86_pointer_wrap, .do_interrupt = x86_cpu_do_interrupt, .cpu_exec_halt = x86_cpu_exec_halt, .cpu_exec_interrupt = x86_cpu_exec_interrupt, From 353f703cf1959228affc23b5bba8a18738736cf4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 09:50:08 -0700 Subject: [PATCH 1198/2760] target/loongarch: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check va32 state. Reviewed-by: Song Gao Reviewed-by: Bibo Mao Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/loongarch/cpu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/loongarch/cpu.c b/target/loongarch/cpu.c index f7535d1be7..abad84c054 100644 --- a/target/loongarch/cpu.c +++ b/target/loongarch/cpu.c @@ -334,6 +334,12 @@ static bool loongarch_cpu_exec_interrupt(CPUState *cs, int interrupt_request) } return false; } + +static vaddr loongarch_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + return is_va32(cpu_env(cs)) ? (uint32_t)result : result; +} #endif static TCGTBCPUState loongarch_get_tb_cpu_state(CPUState *cs) @@ -889,6 +895,7 @@ static const TCGCPUOps loongarch_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = loongarch_cpu_tlb_fill, + .pointer_wrap = loongarch_pointer_wrap, .cpu_exec_interrupt = loongarch_cpu_exec_interrupt, .cpu_exec_halt = loongarch_cpu_has_work, .cpu_exec_reset = cpu_reset, From 396c12d00e3944e79159c9f3cb934f26f32ef861 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 09:59:29 -0700 Subject: [PATCH 1199/2760] target/mips: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check 32 vs 64-bit addressing state. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/mips/cpu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/mips/cpu.c b/target/mips/cpu.c index 4cbfb9435a..1f6c41fd34 100644 --- a/target/mips/cpu.c +++ b/target/mips/cpu.c @@ -560,6 +560,14 @@ static TCGTBCPUState mips_get_tb_cpu_state(CPUState *cs) }; } +#ifndef CONFIG_USER_ONLY +static vaddr mips_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + return cpu_env(cs)->hflags & MIPS_HFLAG_AWRAP ? (int32_t)result : result; +} +#endif + static const TCGCPUOps mips_tcg_ops = { .mttcg_supported = TARGET_LONG_BITS == 32, .guest_default_memory_order = 0, @@ -573,6 +581,7 @@ static const TCGCPUOps mips_tcg_ops = { #if !defined(CONFIG_USER_ONLY) .tlb_fill = mips_cpu_tlb_fill, + .pointer_wrap = mips_pointer_wrap, .cpu_exec_interrupt = mips_cpu_exec_interrupt, .cpu_exec_halt = mips_cpu_has_work, .cpu_exec_reset = cpu_reset, From 4031eb4facfd8793defeb83c05712643c161e32e Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 10:20:02 -0700 Subject: [PATCH 1200/2760] target/ppc: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check 32 vs 64-bit state. Cc: qemu-ppc@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/ppc/cpu_init.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c index 9642812a71..a0e77f2673 100644 --- a/target/ppc/cpu_init.c +++ b/target/ppc/cpu_init.c @@ -7386,6 +7386,12 @@ static void ppc_cpu_exec_exit(CPUState *cs) cpu->vhyp_class->cpu_exec_exit(cpu->vhyp, cpu); } } + +static vaddr ppc_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + return (cpu_env(cs)->hflags >> HFLAGS_64) & 1 ? result : (uint32_t)result; +} #endif /* CONFIG_TCG */ #endif /* !CONFIG_USER_ONLY */ @@ -7490,6 +7496,7 @@ static const TCGCPUOps ppc_tcg_ops = { .record_sigsegv = ppc_cpu_record_sigsegv, #else .tlb_fill = ppc_cpu_tlb_fill, + .pointer_wrap = ppc_pointer_wrap, .cpu_exec_interrupt = ppc_cpu_exec_interrupt, .cpu_exec_halt = ppc_cpu_has_work, .cpu_exec_reset = cpu_reset, From 8024f004155ea5a3f492c35a792ea7863176e1a9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 10:59:39 -0700 Subject: [PATCH 1201/2760] target/riscv: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check 32 vs 64-bit and pointer masking state. Cc: qemu-riscv@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Acked-by: Alistair Francis Signed-off-by: Richard Henderson --- target/riscv/tcg/tcg-cpu.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 305912b8dd..55fd9e5584 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -237,6 +237,31 @@ static void riscv_restore_state_to_opc(CPUState *cs, env->excp_uw2 = data[2]; } +#ifndef CONFIG_USER_ONLY +static vaddr riscv_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + CPURISCVState *env = cpu_env(cs); + uint32_t pm_len; + bool pm_signext; + + if (cpu_address_xl(env) == MXL_RV32) { + return (uint32_t)result; + } + + pm_len = riscv_pm_get_pmlen(riscv_pm_get_pmm(env)); + if (pm_len == 0) { + return result; + } + + pm_signext = riscv_cpu_virt_mem_enabled(env); + if (pm_signext) { + return sextract64(result, 0, 64 - pm_len); + } + return extract64(result, 0, 64 - pm_len); +} +#endif + const TCGCPUOps riscv_tcg_ops = { .mttcg_supported = true, .guest_default_memory_order = 0, @@ -250,6 +275,7 @@ const TCGCPUOps riscv_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = riscv_cpu_tlb_fill, + .pointer_wrap = riscv_pointer_wrap, .cpu_exec_interrupt = riscv_cpu_exec_interrupt, .cpu_exec_halt = riscv_cpu_has_work, .cpu_exec_reset = cpu_reset, From c2a0439f1ee99cb29883311f75ba08d9cca759c9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 11:04:55 -0700 Subject: [PATCH 1202/2760] target/s390x: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the existing wrap_address function. Cc: qemu-s390x@nongnu.org Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/s390x/cpu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 9c1158ebcc..f05ce317da 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -347,6 +347,14 @@ static TCGTBCPUState s390x_get_tb_cpu_state(CPUState *cs) }; } +#ifndef CONFIG_USER_ONLY +static vaddr s390_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ + return wrap_address(cpu_env(cs), result); +} +#endif + static const TCGCPUOps s390_tcg_ops = { .mttcg_supported = true, .precise_smc = true, @@ -367,6 +375,7 @@ static const TCGCPUOps s390_tcg_ops = { .record_sigbus = s390_cpu_record_sigbus, #else .tlb_fill = s390_cpu_tlb_fill, + .pointer_wrap = s390_pointer_wrap, .cpu_exec_interrupt = s390_cpu_exec_interrupt, .cpu_exec_halt = s390_cpu_has_work, .cpu_exec_reset = cpu_reset, From 90f80e4b0fedfc78163c1c112bb74ccbfcae2365 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 11:14:01 -0700 Subject: [PATCH 1203/2760] target/sparc: Fill in TCGCPUOps.pointer_wrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check address masking state for sparc64. Cc: Mark Cave-Ayland Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- target/sparc/cpu.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/target/sparc/cpu.c b/target/sparc/cpu.c index 2a3e408923..ed7701b02f 100644 --- a/target/sparc/cpu.c +++ b/target/sparc/cpu.c @@ -1002,6 +1002,18 @@ static const struct SysemuCPUOps sparc_sysemu_ops = { #ifdef CONFIG_TCG #include "accel/tcg/cpu-ops.h" +#ifndef CONFIG_USER_ONLY +static vaddr sparc_pointer_wrap(CPUState *cs, int mmu_idx, + vaddr result, vaddr base) +{ +#ifdef TARGET_SPARC64 + return cpu_env(cs)->pstate & PS_AM ? (uint32_t)result : result; +#else + return (uint32_t)result; +#endif +} +#endif + static const TCGCPUOps sparc_tcg_ops = { /* * From Oracle SPARC Architecture 2015: @@ -1036,6 +1048,7 @@ static const TCGCPUOps sparc_tcg_ops = { #ifndef CONFIG_USER_ONLY .tlb_fill = sparc_cpu_tlb_fill, + .pointer_wrap = sparc_pointer_wrap, .cpu_exec_interrupt = sparc_cpu_exec_interrupt, .cpu_exec_halt = sparc_cpu_has_work, .cpu_exec_reset = cpu_reset, From 5c2891601ccdaa41427187ef95bc25c828b355e4 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sun, 4 May 2025 11:19:17 -0700 Subject: [PATCH 1204/2760] accel/tcg: Assert TCGCPUOps.pointer_wrap is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All targets now provide the function, so we can make the call unconditional. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Richard Henderson --- accel/tcg/cpu-exec.c | 1 + accel/tcg/cputlb.c | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c index cc5f362305..713bdb2056 100644 --- a/accel/tcg/cpu-exec.c +++ b/accel/tcg/cpu-exec.c @@ -1039,6 +1039,7 @@ bool tcg_exec_realizefn(CPUState *cpu, Error **errp) assert(tcg_ops->cpu_exec_halt); assert(tcg_ops->cpu_exec_interrupt); assert(tcg_ops->cpu_exec_reset); + assert(tcg_ops->pointer_wrap); #endif /* !CONFIG_USER_ONLY */ assert(tcg_ops->translate_code); assert(tcg_ops->get_tb_cpu_state); diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c index a734859396..87e14bde4f 100644 --- a/accel/tcg/cputlb.c +++ b/accel/tcg/cputlb.c @@ -1773,11 +1773,8 @@ static bool mmu_lookup(CPUState *cpu, vaddr addr, MemOpIdx oi, l->page[1].size = l->page[0].size - size0; l->page[0].size = size0; - if (cpu->cc->tcg_ops->pointer_wrap) { - l->page[1].addr = cpu->cc->tcg_ops->pointer_wrap(cpu, l->mmu_idx, - l->page[1].addr, - addr); - } + l->page[1].addr = cpu->cc->tcg_ops->pointer_wrap(cpu, l->mmu_idx, + l->page[1].addr, addr); /* * Lookup both pages, recognizing exceptions from either. If the From a78a91feeea66270badd87c65a7236e90baa5984 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:28 -0700 Subject: [PATCH 1205/2760] qapi: expose rtc-reset-reinjection command unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_I386 condition from the rtc-reset-reinjection command. This requires providing a QMP command stub for non-i386 target. This in turn requires moving the command out of misc-target.json, since that will trigger symbol poisoning errors when built from target independent code. Rather than putting the command into misc.json, it is proposed to create misc-$TARGET.json files to hold commands whose impl is conceptually only applicable to a single target. This gives an obvious docs hint to consumers that the command is only useful in relation a specific target, while misc.json is for commands applicable to 2 or more targets. The current impl of qmp_rtc_reset_reinject() is a no-op if the i386 RTC is disabled in Kconfig, or if the running machine type lack any RTC device. The stub impl for non-i386 targets retains this no-op behaviour. However, it is now reporting an Error mentioning this command is not available for current target. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-2-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- hw/i386/monitor.c | 2 +- qapi/meson.build | 1 + qapi/misc-i386.json | 24 ++++++++++++++++++++++++ qapi/misc-target.json | 17 ----------------- qapi/qapi-schema.json | 1 + stubs/meson.build | 1 + stubs/monitor-i386-rtc.c | 12 ++++++++++++ 7 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 qapi/misc-i386.json create mode 100644 stubs/monitor-i386-rtc.c diff --git a/hw/i386/monitor.c b/hw/i386/monitor.c index 1921e4d52e..79df96562f 100644 --- a/hw/i386/monitor.c +++ b/hw/i386/monitor.c @@ -26,7 +26,7 @@ #include "monitor/monitor.h" #include "qobject/qdict.h" #include "qapi/error.h" -#include "qapi/qapi-commands-misc-target.h" +#include "qapi/qapi-commands-misc-i386.h" #include "hw/i386/x86.h" #include "hw/rtc/mc146818rtc.h" diff --git a/qapi/meson.build b/qapi/meson.build index eadde4db30..3a9bd06104 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -64,6 +64,7 @@ if have_system 'qdev', 'pci', 'rocker', + 'misc-i386', 'tpm', 'uefi', ] diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json new file mode 100644 index 0000000000..d5bfd91405 --- /dev/null +++ b/qapi/misc-i386.json @@ -0,0 +1,24 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# @rtc-reset-reinjection: +# +# This command will reset the RTC interrupt reinjection backlog. Can +# be used if another mechanism to synchronize guest time is in effect, +# for example QEMU guest agent's guest-set-time command. +# +# Use of this command is only applicable for x86 machines with an RTC, +# and on other machines will silently return without performing any +# action. +# +# Since: 2.1 +# +# .. qmp-example:: +# +# -> { "execute": "rtc-reset-reinjection" } +# <- { "return": {} } +## +{ 'command': 'rtc-reset-reinjection' } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index f7ec695caa..c5f9f6be7e 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -2,23 +2,6 @@ # vim: filetype=python # -## -# @rtc-reset-reinjection: -# -# This command will reset the RTC interrupt reinjection backlog. Can -# be used if another mechanism to synchronize guest time is in effect, -# for example QEMU guest agent's guest-set-time command. -# -# Since: 2.1 -# -# .. qmp-example:: -# -# -> { "execute": "rtc-reset-reinjection" } -# <- { "return": {} } -## -{ 'command': 'rtc-reset-reinjection', - 'if': 'TARGET_I386' } - ## # @SevState: # diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 7bc600bb76..96f6aa4413 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -61,6 +61,7 @@ { 'include': 'replay.json' } { 'include': 'yank.json' } { 'include': 'misc.json' } +{ 'include': 'misc-i386.json' } { 'include': 'misc-target.json' } { 'include': 'audio.json' } { 'include': 'acpi.json' } diff --git a/stubs/meson.build b/stubs/meson.build index 63392f5e78..9907b54c1e 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -77,6 +77,7 @@ if have_system stub_ss.add(files('target-monitor-defs.c')) stub_ss.add(files('win32-kbd-hook.c')) stub_ss.add(files('xen-hw-stub.c')) + stub_ss.add(files('monitor-i386-rtc.c')) endif if have_system or have_user diff --git a/stubs/monitor-i386-rtc.c b/stubs/monitor-i386-rtc.c new file mode 100644 index 0000000000..8420d7c93c --- /dev/null +++ b/stubs/monitor-i386-rtc.c @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc-i386.h" + +void qmp_rtc_reset_reinjection(Error **errp) +{ + error_setg(errp, + "RTC interrupt reinjection backlog reset is not available for" + "this machine"); +} From 9215d072d2da3054b74080227a6a3e0a2daf44d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:29 -0700 Subject: [PATCH 1206/2760] qapi: expand docs for SEV commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This gives some more context about the behaviour of the commands in unsupported guest configuration or platform scenarios. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-3-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster [Tweak query-sev doc, turn error descriptions into Errors sections, delate a stray #, normalize whitespace, wrap lines] --- qapi/misc-target.json | 50 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/qapi/misc-target.json b/qapi/misc-target.json index c5f9f6be7e..e19a12e88a 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -110,7 +110,11 @@ ## # @query-sev: # -# Returns information about SEV +# Returns information about SEV/SEV-ES/SEV-SNP. +# +# If unavailable due to an incompatible configuration the returned +# @enabled field is set to 'false' and the state of all other fields +# is unspecified. # # Returns: @SevInfo # @@ -141,10 +145,19 @@ ## # @query-sev-launch-measure: # -# Query the SEV guest launch information. +# Query the SEV/SEV-ES guest launch information. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. The launch +# measurement for SEV-SNP guests is only available within the guest. # # Returns: The @SevLaunchMeasureInfo for the guest # +# Errors: +# - If the launch measurement is unavailable, either due to an +# invalid guest configuration or if the guest has not reached +# the required SEV state, GenericError +# # Since: 2.12 # # .. qmp-example:: @@ -185,11 +198,15 @@ ## # @query-sev-capabilities: # -# This command is used to get the SEV capabilities, and is supported -# on AMD X86 platforms only. +# Get SEV capabilities. +# +# This is only supported on AMD X86 platforms with KVM enabled. # # Returns: SevCapability objects. # +# Errors: +# - If SEV is not available on the platform, GenericError +# # Since: 2.12 # # .. qmp-example:: @@ -205,7 +222,12 @@ ## # @sev-inject-launch-secret: # -# This command injects a secret blob into memory of SEV guest. +# This command injects a secret blob into memory of a SEV/SEV-ES +# guest. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. SEV-SNP guests do +# not support launch secret injection. # # @packet-header: the launch secret packet header encoded in base64 # @@ -213,6 +235,11 @@ # # @gpa: the guest physical address where secret will be injected. # +# Errors: +# - If launch secret injection is not possible, either due to +# an invalid guest configuration, or if the guest has not +# reached the required SEV state, GenericError +# # Since: 6.0 ## { 'command': 'sev-inject-launch-secret', @@ -236,14 +263,23 @@ ## # @query-sev-attestation-report: # -# This command is used to get the SEV attestation report, and is -# supported on AMD X86 platforms only. +# This command is used to get the SEV attestation report. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. The attestation +# report for SEV-SNP guests is only available within the guest. # # @mnonce: a random 16 bytes value encoded in base64 (it will be # included in report) # # Returns: SevAttestationReport objects. # +# Errors: +# - This will return an error if the attestation report is +# unavailable, either due to an invalid guest configuration +# or if the guest has not reached the required SEV state, +# GenericError +# # Since: 6.1 # # .. qmp-example:: From 7373759583650fff6f724c6c21d4234bf31b2af0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:30 -0700 Subject: [PATCH 1207/2760] qapi: make SEV commands unconditionally available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_I386 condition from the SEV confidential virtualization commands, moving them to the recently introduced misc-i386.json QAPI file, given they are inherantly i386 specific commands. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-4-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- qapi/misc-i386.json | 278 ++++++++++++++++++++++++++++++++ qapi/misc-target.json | 291 ---------------------------------- stubs/meson.build | 1 + stubs/monitor-i386-sev.c | 36 +++++ target/i386/sev-system-stub.c | 32 ---- target/i386/sev.c | 2 +- 6 files changed, 316 insertions(+), 324 deletions(-) create mode 100644 stubs/monitor-i386-sev.c diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json index d5bfd91405..360adadfe0 100644 --- a/qapi/misc-i386.json +++ b/qapi/misc-i386.json @@ -22,3 +22,281 @@ # <- { "return": {} } ## { 'command': 'rtc-reset-reinjection' } + +## +# @SevState: +# +# An enumeration of SEV state information used during @query-sev. +# +# @uninit: The guest is uninitialized. +# +# @launch-update: The guest is currently being launched; plaintext +# data and register state is being imported. +# +# @launch-secret: The guest is currently being launched; ciphertext +# data is being imported. +# +# @running: The guest is fully launched or migrated in. +# +# @send-update: The guest is currently being migrated out to another +# machine. +# +# @receive-update: The guest is currently being migrated from another +# machine. +# +# Since: 2.12 +## +{ 'enum': 'SevState', + 'data': ['uninit', 'launch-update', 'launch-secret', 'running', + 'send-update', 'receive-update' ] } + +## +# @SevGuestType: +# +# An enumeration indicating the type of SEV guest being run. +# +# @sev: The guest is a legacy SEV or SEV-ES guest. +# +# @sev-snp: The guest is an SEV-SNP guest. +# +# Since: 6.2 +## +{ 'enum': 'SevGuestType', + 'data': [ 'sev', 'sev-snp' ] } + +## +# @SevGuestInfo: +# +# Information specific to legacy SEV/SEV-ES guests. +# +# @policy: SEV policy value +# +# @handle: SEV firmware handle +# +# Since: 2.12 +## +{ 'struct': 'SevGuestInfo', + 'data': { 'policy': 'uint32', + 'handle': 'uint32' } } + +## +# @SevSnpGuestInfo: +# +# Information specific to SEV-SNP guests. +# +# @snp-policy: SEV-SNP policy value +# +# Since: 9.1 +## +{ 'struct': 'SevSnpGuestInfo', + 'data': { 'snp-policy': 'uint64' } } + +## +# @SevInfo: +# +# Information about Secure Encrypted Virtualization (SEV) support +# +# @enabled: true if SEV is active +# +# @api-major: SEV API major version +# +# @api-minor: SEV API minor version +# +# @build-id: SEV FW build id +# +# @state: SEV guest state +# +# @sev-type: Type of SEV guest being run +# +# Since: 2.12 +## +{ 'union': 'SevInfo', + 'base': { 'enabled': 'bool', + 'api-major': 'uint8', + 'api-minor' : 'uint8', + 'build-id' : 'uint8', + 'state' : 'SevState', + 'sev-type' : 'SevGuestType' }, + 'discriminator': 'sev-type', + 'data': { + 'sev': 'SevGuestInfo', + 'sev-snp': 'SevSnpGuestInfo' } } + + +## +# @query-sev: +# +# Returns information about SEV/SEV-ES/SEV-SNP. +# +# If unavailable due to an incompatible configuration the returned +# @enabled field is set to 'false' and the state of all other fields +# is unspecified. +# +# Returns: @SevInfo +# +# Since: 2.12 +# +# .. qmp-example:: +# +# -> { "execute": "query-sev" } +# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0, +# "build-id" : 0, "policy" : 0, "state" : "running", +# "handle" : 1 } } +## +{ 'command': 'query-sev', 'returns': 'SevInfo' } + +## +# @SevLaunchMeasureInfo: +# +# SEV Guest Launch measurement information +# +# @data: the measurement value encoded in base64 +# +# Since: 2.12 +## +{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'} } + +## +# @query-sev-launch-measure: +# +# Query the SEV/SEV-ES guest launch information. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. The launch +# measurement for SEV-SNP guests is only available within the guest. +# +# Returns: The @SevLaunchMeasureInfo for the guest +# +# Errors: +# - If the launch measurement is unavailable, either due to an +# invalid guest configuration or if the guest has not reached +# the required SEV state, GenericError +# +# Since: 2.12 +# +# .. qmp-example:: +# +# -> { "execute": "query-sev-launch-measure" } +# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } } +## +{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo' } + +## +# @SevCapability: +# +# The struct describes capability for a Secure Encrypted +# Virtualization feature. +# +# @pdh: Platform Diffie-Hellman key (base64 encoded) +# +# @cert-chain: PDH certificate chain (base64 encoded) +# +# @cpu0-id: Unique ID of CPU0 (base64 encoded) (since 7.1) +# +# @cbitpos: C-bit location in page table entry +# +# @reduced-phys-bits: Number of physical Address bit reduction when +# SEV is enabled +# +# Since: 2.12 +## +{ 'struct': 'SevCapability', + 'data': { 'pdh': 'str', + 'cert-chain': 'str', + 'cpu0-id': 'str', + 'cbitpos': 'int', + 'reduced-phys-bits': 'int'} } + +## +# @query-sev-capabilities: +# +# Get SEV capabilities. +# +# This is only supported on AMD X86 platforms with KVM enabled. +# +# Returns: SevCapability objects. +# +# Errors: +# - If SEV is not available on the platform, GenericError +# +# Since: 2.12 +# +# .. qmp-example:: +# +# -> { "execute": "query-sev-capabilities" } +# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE", +# "cpu0-id": "2lvmGwo+...61iEinw==", +# "cbitpos": 47, "reduced-phys-bits": 1}} +## +{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability' } + +## +# @sev-inject-launch-secret: +# +# This command injects a secret blob into memory of a SEV/SEV-ES +# guest. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. SEV-SNP guests do +# not support launch secret injection. +# +# @packet-header: the launch secret packet header encoded in base64 +# +# @secret: the launch secret data to be injected encoded in base64 +# +# @gpa: the guest physical address where secret will be injected. +# +# Errors: +# - If launch secret injection is not possible, either due to +# an invalid guest configuration, or if the guest has not +# reached the required SEV state, GenericError +# +# Since: 6.0 +## +{ 'command': 'sev-inject-launch-secret', + 'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' } } + +## +# @SevAttestationReport: +# +# The struct describes attestation report for a Secure Encrypted +# Virtualization feature. +# +# @data: guest attestation report (base64 encoded) +# +# Since: 6.1 +## +{ 'struct': 'SevAttestationReport', + 'data': { 'data': 'str'} } + +## +# @query-sev-attestation-report: +# +# This command is used to get the SEV attestation report. +# +# This is only valid on x86 machines configured with KVM and the +# 'sev-guest' confidential virtualization object. The attestation +# report for SEV-SNP guests is only available within the guest. +# +# @mnonce: a random 16 bytes value encoded in base64 (it will be +# included in report) +# +# Returns: SevAttestationReport objects. +# +# Errors: +# - This will return an error if the attestation report is +# unavailable, either due to an invalid guest configuration +# or if the guest has not reached the required SEV state, +# GenericError +# +# Since: 6.1 +# +# .. qmp-example:: +# +# -> { "execute" : "query-sev-attestation-report", +# "arguments": { "mnonce": "aaaaaaa" } } +# <- { "return" : { "data": "aaaaaaaabbbddddd"} } +## +{ 'command': 'query-sev-attestation-report', + 'data': { 'mnonce': 'str' }, + 'returns': 'SevAttestationReport' } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index e19a12e88a..c0d7b311f3 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -2,297 +2,6 @@ # vim: filetype=python # -## -# @SevState: -# -# An enumeration of SEV state information used during @query-sev. -# -# @uninit: The guest is uninitialized. -# -# @launch-update: The guest is currently being launched; plaintext -# data and register state is being imported. -# -# @launch-secret: The guest is currently being launched; ciphertext -# data is being imported. -# -# @running: The guest is fully launched or migrated in. -# -# @send-update: The guest is currently being migrated out to another -# machine. -# -# @receive-update: The guest is currently being migrated from another -# machine. -# -# Since: 2.12 -## -{ 'enum': 'SevState', - 'data': ['uninit', 'launch-update', 'launch-secret', 'running', - 'send-update', 'receive-update' ], - 'if': 'TARGET_I386' } - -## -# @SevGuestType: -# -# An enumeration indicating the type of SEV guest being run. -# -# @sev: The guest is a legacy SEV or SEV-ES guest. -# -# @sev-snp: The guest is an SEV-SNP guest. -# -# Since: 6.2 -## -{ 'enum': 'SevGuestType', - 'data': [ 'sev', 'sev-snp' ], - 'if': 'TARGET_I386' } - -## -# @SevGuestInfo: -# -# Information specific to legacy SEV/SEV-ES guests. -# -# @policy: SEV policy value -# -# @handle: SEV firmware handle -# -# Since: 2.12 -## -{ 'struct': 'SevGuestInfo', - 'data': { 'policy': 'uint32', - 'handle': 'uint32' }, - 'if': 'TARGET_I386' } - -## -# @SevSnpGuestInfo: -# -# Information specific to SEV-SNP guests. -# -# @snp-policy: SEV-SNP policy value -# -# Since: 9.1 -## -{ 'struct': 'SevSnpGuestInfo', - 'data': { 'snp-policy': 'uint64' }, - 'if': 'TARGET_I386' } - -## -# @SevInfo: -# -# Information about Secure Encrypted Virtualization (SEV) support -# -# @enabled: true if SEV is active -# -# @api-major: SEV API major version -# -# @api-minor: SEV API minor version -# -# @build-id: SEV FW build id -# -# @state: SEV guest state -# -# @sev-type: Type of SEV guest being run -# -# Since: 2.12 -## -{ 'union': 'SevInfo', - 'base': { 'enabled': 'bool', - 'api-major': 'uint8', - 'api-minor' : 'uint8', - 'build-id' : 'uint8', - 'state' : 'SevState', - 'sev-type' : 'SevGuestType' }, - 'discriminator': 'sev-type', - 'data': { - 'sev': 'SevGuestInfo', - 'sev-snp': 'SevSnpGuestInfo' }, - 'if': 'TARGET_I386' } - - -## -# @query-sev: -# -# Returns information about SEV/SEV-ES/SEV-SNP. -# -# If unavailable due to an incompatible configuration the returned -# @enabled field is set to 'false' and the state of all other fields -# is unspecified. -# -# Returns: @SevInfo -# -# Since: 2.12 -# -# .. qmp-example:: -# -# -> { "execute": "query-sev" } -# <- { "return": { "enabled": true, "api-major" : 0, "api-minor" : 0, -# "build-id" : 0, "policy" : 0, "state" : "running", -# "handle" : 1 } } -## -{ 'command': 'query-sev', 'returns': 'SevInfo', - 'if': 'TARGET_I386' } - -## -# @SevLaunchMeasureInfo: -# -# SEV Guest Launch measurement information -# -# @data: the measurement value encoded in base64 -# -# Since: 2.12 -## -{ 'struct': 'SevLaunchMeasureInfo', 'data': {'data': 'str'}, - 'if': 'TARGET_I386' } - -## -# @query-sev-launch-measure: -# -# Query the SEV/SEV-ES guest launch information. -# -# This is only valid on x86 machines configured with KVM and the -# 'sev-guest' confidential virtualization object. The launch -# measurement for SEV-SNP guests is only available within the guest. -# -# Returns: The @SevLaunchMeasureInfo for the guest -# -# Errors: -# - If the launch measurement is unavailable, either due to an -# invalid guest configuration or if the guest has not reached -# the required SEV state, GenericError -# -# Since: 2.12 -# -# .. qmp-example:: -# -# -> { "execute": "query-sev-launch-measure" } -# <- { "return": { "data": "4l8LXeNlSPUDlXPJG5966/8%YZ" } } -## -{ 'command': 'query-sev-launch-measure', 'returns': 'SevLaunchMeasureInfo', - 'if': 'TARGET_I386' } - -## -# @SevCapability: -# -# The struct describes capability for a Secure Encrypted -# Virtualization feature. -# -# @pdh: Platform Diffie-Hellman key (base64 encoded) -# -# @cert-chain: PDH certificate chain (base64 encoded) -# -# @cpu0-id: Unique ID of CPU0 (base64 encoded) (since 7.1) -# -# @cbitpos: C-bit location in page table entry -# -# @reduced-phys-bits: Number of physical Address bit reduction when -# SEV is enabled -# -# Since: 2.12 -## -{ 'struct': 'SevCapability', - 'data': { 'pdh': 'str', - 'cert-chain': 'str', - 'cpu0-id': 'str', - 'cbitpos': 'int', - 'reduced-phys-bits': 'int'}, - 'if': 'TARGET_I386' } - -## -# @query-sev-capabilities: -# -# Get SEV capabilities. -# -# This is only supported on AMD X86 platforms with KVM enabled. -# -# Returns: SevCapability objects. -# -# Errors: -# - If SEV is not available on the platform, GenericError -# -# Since: 2.12 -# -# .. qmp-example:: -# -# -> { "execute": "query-sev-capabilities" } -# <- { "return": { "pdh": "8CCDD8DDD", "cert-chain": "888CCCDDDEE", -# "cpu0-id": "2lvmGwo+...61iEinw==", -# "cbitpos": 47, "reduced-phys-bits": 1}} -## -{ 'command': 'query-sev-capabilities', 'returns': 'SevCapability', - 'if': 'TARGET_I386' } - -## -# @sev-inject-launch-secret: -# -# This command injects a secret blob into memory of a SEV/SEV-ES -# guest. -# -# This is only valid on x86 machines configured with KVM and the -# 'sev-guest' confidential virtualization object. SEV-SNP guests do -# not support launch secret injection. -# -# @packet-header: the launch secret packet header encoded in base64 -# -# @secret: the launch secret data to be injected encoded in base64 -# -# @gpa: the guest physical address where secret will be injected. -# -# Errors: -# - If launch secret injection is not possible, either due to -# an invalid guest configuration, or if the guest has not -# reached the required SEV state, GenericError -# -# Since: 6.0 -## -{ 'command': 'sev-inject-launch-secret', - 'data': { 'packet-header': 'str', 'secret': 'str', '*gpa': 'uint64' }, - 'if': 'TARGET_I386' } - -## -# @SevAttestationReport: -# -# The struct describes attestation report for a Secure Encrypted -# Virtualization feature. -# -# @data: guest attestation report (base64 encoded) -# -# Since: 6.1 -## -{ 'struct': 'SevAttestationReport', - 'data': { 'data': 'str'}, - 'if': 'TARGET_I386' } - -## -# @query-sev-attestation-report: -# -# This command is used to get the SEV attestation report. -# -# This is only valid on x86 machines configured with KVM and the -# 'sev-guest' confidential virtualization object. The attestation -# report for SEV-SNP guests is only available within the guest. -# -# @mnonce: a random 16 bytes value encoded in base64 (it will be -# included in report) -# -# Returns: SevAttestationReport objects. -# -# Errors: -# - This will return an error if the attestation report is -# unavailable, either due to an invalid guest configuration -# or if the guest has not reached the required SEV state, -# GenericError -# -# Since: 6.1 -# -# .. qmp-example:: -# -# -> { "execute" : "query-sev-attestation-report", -# "arguments": { "mnonce": "aaaaaaa" } } -# <- { "return" : { "data": "aaaaaaaabbbddddd"} } -## -{ 'command': 'query-sev-attestation-report', - 'data': { 'mnonce': 'str' }, - 'returns': 'SevAttestationReport', - 'if': 'TARGET_I386' } - ## # @GICCapability: # diff --git a/stubs/meson.build b/stubs/meson.build index 9907b54c1e..9922ec7b88 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -78,6 +78,7 @@ if have_system stub_ss.add(files('win32-kbd-hook.c')) stub_ss.add(files('xen-hw-stub.c')) stub_ss.add(files('monitor-i386-rtc.c')) + stub_ss.add(files('monitor-i386-sev.c')) endif if have_system or have_user diff --git a/stubs/monitor-i386-sev.c b/stubs/monitor-i386-sev.c new file mode 100644 index 0000000000..d4f024128c --- /dev/null +++ b/stubs/monitor-i386-sev.c @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc-i386.h" + +SevInfo *qmp_query_sev(Error **errp) +{ + error_setg(errp, "SEV is not available in this QEMU"); + return NULL; +} + +SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp) +{ + error_setg(errp, "SEV is not available in this QEMU"); + return NULL; +} + +SevCapability *qmp_query_sev_capabilities(Error **errp) +{ + error_setg(errp, "SEV is not available in this QEMU"); + return NULL; +} + +void qmp_sev_inject_launch_secret(const char *packet_header, const char *secret, + bool has_gpa, uint64_t gpa, Error **errp) +{ + error_setg(errp, "SEV is not available in this QEMU"); +} + +SevAttestationReport *qmp_query_sev_attestation_report(const char *mnonce, + Error **errp) +{ + error_setg(errp, "SEV is not available in this QEMU"); + return NULL; +} diff --git a/target/i386/sev-system-stub.c b/target/i386/sev-system-stub.c index d5bf886e79..7c5c02a565 100644 --- a/target/i386/sev-system-stub.c +++ b/target/i386/sev-system-stub.c @@ -14,34 +14,9 @@ #include "qemu/osdep.h" #include "monitor/monitor.h" #include "monitor/hmp-target.h" -#include "qapi/qapi-commands-misc-target.h" #include "qapi/error.h" #include "sev.h" -SevInfo *qmp_query_sev(Error **errp) -{ - error_setg(errp, "SEV is not available in this QEMU"); - return NULL; -} - -SevLaunchMeasureInfo *qmp_query_sev_launch_measure(Error **errp) -{ - error_setg(errp, "SEV is not available in this QEMU"); - return NULL; -} - -SevCapability *qmp_query_sev_capabilities(Error **errp) -{ - error_setg(errp, "SEV is not available in this QEMU"); - return NULL; -} - -void qmp_sev_inject_launch_secret(const char *packet_header, const char *secret, - bool has_gpa, uint64_t gpa, Error **errp) -{ - error_setg(errp, "SEV is not available in this QEMU"); -} - int sev_encrypt_flash(hwaddr gpa, uint8_t *ptr, uint64_t len, Error **errp) { g_assert_not_reached(); @@ -56,13 +31,6 @@ int sev_es_save_reset_vector(void *flash_ptr, uint64_t flash_size) g_assert_not_reached(); } -SevAttestationReport *qmp_query_sev_attestation_report(const char *mnonce, - Error **errp) -{ - error_setg(errp, "SEV is not available in this QEMU"); - return NULL; -} - void hmp_info_sev(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "SEV is not available in this QEMU\n"); diff --git a/target/i386/sev.c b/target/i386/sev.c index 7ee700d6a3..56dd64e659 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -37,7 +37,7 @@ #include "qom/object.h" #include "monitor/monitor.h" #include "monitor/hmp-target.h" -#include "qapi/qapi-commands-misc-target.h" +#include "qapi/qapi-commands-misc-i386.h" #include "confidential-guest.h" #include "hw/i386/pc.h" #include "system/address-spaces.h" From 30fbb258717d81c32f11a0e4b7218442a43c4856 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:31 -0700 Subject: [PATCH 1208/2760] qapi: expose query-gic-capability command unconditionally MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_ARM condition from the query-gic-capability command. This requires providing a QMP command stub for non-ARM targets. This in turn requires moving the command out of misc-target.json, since that will trigger symbol poisoning errors when built from target independent code. Following the earlier precedent, this creates a misc-arm.json file to hold this ARM specific command. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-5-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- qapi/meson.build | 1 + qapi/misc-arm.json | 49 +++++++++++++++++++++++++++++++++++++++ qapi/misc-target.json | 44 ----------------------------------- qapi/qapi-schema.json | 1 + stubs/meson.build | 1 + stubs/monitor-arm-gic.c | 12 ++++++++++ target/arm/arm-qmp-cmds.c | 2 +- 7 files changed, 65 insertions(+), 45 deletions(-) create mode 100644 qapi/misc-arm.json create mode 100644 stubs/monitor-arm-gic.c diff --git a/qapi/meson.build b/qapi/meson.build index 3a9bd06104..5e93e6b8cf 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -64,6 +64,7 @@ if have_system 'qdev', 'pci', 'rocker', + 'misc-arm', 'misc-i386', 'tpm', 'uefi', diff --git a/qapi/misc-arm.json b/qapi/misc-arm.json new file mode 100644 index 0000000000..f5341372f5 --- /dev/null +++ b/qapi/misc-arm.json @@ -0,0 +1,49 @@ +# -*- Mode: Python -*- +# vim: filetype=python +# +# SPDX-License-Identifier: GPL-2.0-or-later + +## +# @GICCapability: +# +# The struct describes capability for a specific GIC (Generic +# Interrupt Controller) version. These bits are not only decided by +# QEMU/KVM software version, but also decided by the hardware that the +# program is running upon. +# +# @version: version of GIC to be described. Currently, only 2 and 3 +# are supported. +# +# @emulated: whether current QEMU/hardware supports emulated GIC +# device in user space. +# +# @kernel: whether current QEMU/hardware supports hardware accelerated +# GIC device in kernel. +# +# Since: 2.6 +## +{ 'struct': 'GICCapability', + 'data': { 'version': 'int', + 'emulated': 'bool', + 'kernel': 'bool' } } + +## +# @query-gic-capabilities: +# +# It will return a list of GICCapability objects that describe its +# capability bits. +# +# On non-ARM targets this command will report an error as the GIC +# technology is not applicable. +# +# Returns: a list of GICCapability objects. +# +# Since: 2.6 +# +# .. qmp-example:: +# +# -> { "execute": "query-gic-capabilities" } +# <- { "return": [{ "version": 2, "emulated": true, "kernel": false }, +# { "version": 3, "emulated": false, "kernel": true } ] } +## +{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index c0d7b311f3..cc472ce91c 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -2,50 +2,6 @@ # vim: filetype=python # -## -# @GICCapability: -# -# The struct describes capability for a specific GIC (Generic -# Interrupt Controller) version. These bits are not only decided by -# QEMU/KVM software version, but also decided by the hardware that the -# program is running upon. -# -# @version: version of GIC to be described. Currently, only 2 and 3 -# are supported. -# -# @emulated: whether current QEMU/hardware supports emulated GIC -# device in user space. -# -# @kernel: whether current QEMU/hardware supports hardware accelerated -# GIC device in kernel. -# -# Since: 2.6 -## -{ 'struct': 'GICCapability', - 'data': { 'version': 'int', - 'emulated': 'bool', - 'kernel': 'bool' }, - 'if': 'TARGET_ARM' } - -## -# @query-gic-capabilities: -# -# This command is ARM-only. It will return a list of GICCapability -# objects that describe its capability bits. -# -# Returns: a list of GICCapability objects. -# -# Since: 2.6 -# -# .. qmp-example:: -# -# -> { "execute": "query-gic-capabilities" } -# <- { "return": [{ "version": 2, "emulated": true, "kernel": false }, -# { "version": 3, "emulated": false, "kernel": true } ] } -## -{ 'command': 'query-gic-capabilities', 'returns': ['GICCapability'], - 'if': 'TARGET_ARM' } - ## # @SgxEpcSection: # diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index 96f6aa4413..e96bff8d38 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -61,6 +61,7 @@ { 'include': 'replay.json' } { 'include': 'yank.json' } { 'include': 'misc.json' } +{ 'include': 'misc-arm.json' } { 'include': 'misc-i386.json' } { 'include': 'misc-target.json' } { 'include': 'audio.json' } diff --git a/stubs/meson.build b/stubs/meson.build index 9922ec7b88..07e9d3799a 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -77,6 +77,7 @@ if have_system stub_ss.add(files('target-monitor-defs.c')) stub_ss.add(files('win32-kbd-hook.c')) stub_ss.add(files('xen-hw-stub.c')) + stub_ss.add(files('monitor-arm-gic.c')) stub_ss.add(files('monitor-i386-rtc.c')) stub_ss.add(files('monitor-i386-sev.c')) endif diff --git a/stubs/monitor-arm-gic.c b/stubs/monitor-arm-gic.c new file mode 100644 index 0000000000..b3429243ef --- /dev/null +++ b/stubs/monitor-arm-gic.c @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc-arm.h" + + +GICCapabilityList *qmp_query_gic_capabilities(Error **errp) +{ + error_setg(errp, "GIC hardware is not available on this target"); + return NULL; +} diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c index a1a944adb4..ef18c867ca 100644 --- a/target/arm/arm-qmp-cmds.c +++ b/target/arm/arm-qmp-cmds.c @@ -27,7 +27,7 @@ #include "qapi/visitor.h" #include "qapi/qobject-input-visitor.h" #include "qapi/qapi-commands-machine-target.h" -#include "qapi/qapi-commands-misc-target.h" +#include "qapi/qapi-commands-misc-arm.h" #include "qobject/qdict.h" #include "qom/qom-qobject.h" From 28a6a99834cd126f80f426ac3fe00625f165ebea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:32 -0700 Subject: [PATCH 1209/2760] qapi: make SGX commands unconditionally available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_I386 condition from the SGX confidential virtualization commands, moving them to the recently introduced misc-i386.json QAPI file, given they are inherantly i386 specific commands. Observe a pre-existing bug that the "SGXEPCSection" struct lacked a TARGET_I386 condition, despite its only usage being behind a TARGET_I386 condition. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-6-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- hw/i386/sgx-stub.c | 2 +- hw/i386/sgx.c | 2 +- qapi/misc-i386.json | 77 +++++++++++++++++++++++++++++++++++++++ qapi/misc-target.json | 79 ---------------------------------------- stubs/meson.build | 1 + stubs/monitor-i386-sgx.c | 17 +++++++++ 6 files changed, 97 insertions(+), 81 deletions(-) create mode 100644 stubs/monitor-i386-sgx.c diff --git a/hw/i386/sgx-stub.c b/hw/i386/sgx-stub.c index ccb21a975d..d295e54d23 100644 --- a/hw/i386/sgx-stub.c +++ b/hw/i386/sgx-stub.c @@ -3,8 +3,8 @@ #include "monitor/hmp-target.h" #include "hw/i386/pc.h" #include "hw/i386/sgx-epc.h" +#include "qapi/qapi-commands-misc-i386.h" #include "qapi/error.h" -#include "qapi/qapi-commands-misc-target.h" void sgx_epc_build_srat(GArray *table_data) { diff --git a/hw/i386/sgx.c b/hw/i386/sgx.c index c80203b438..e2801546ad 100644 --- a/hw/i386/sgx.c +++ b/hw/i386/sgx.c @@ -19,7 +19,7 @@ #include "monitor/hmp-target.h" #include "qapi/error.h" #include "qemu/error-report.h" -#include "qapi/qapi-commands-misc-target.h" +#include "qapi/qapi-commands-misc-i386.h" #include "system/address-spaces.h" #include "system/hw_accel.h" #include "system/reset.h" diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json index 360adadfe0..d5d1af55a4 100644 --- a/qapi/misc-i386.json +++ b/qapi/misc-i386.json @@ -300,3 +300,80 @@ { 'command': 'query-sev-attestation-report', 'data': { 'mnonce': 'str' }, 'returns': 'SevAttestationReport' } + +## +# @SgxEpcSection: +# +# Information about intel SGX EPC section +# +# @node: the numa node +# +# @size: the size of EPC section +# +# Since: 7.0 +## +{ 'struct': 'SgxEpcSection', + 'data': { 'node': 'int', + 'size': 'uint64'}} + +## +# @SgxInfo: +# +# Information about intel Safe Guard eXtension (SGX) support +# +# @sgx: true if SGX is supported +# +# @sgx1: true if SGX1 is supported +# +# @sgx2: true if SGX2 is supported +# +# @flc: true if FLC is supported +# +# @sections: The EPC sections information (Since: 7.0) +# +# Since: 6.2 +## +{ 'struct': 'SgxInfo', + 'data': { 'sgx': 'bool', + 'sgx1': 'bool', + 'sgx2': 'bool', + 'flc': 'bool', + 'sections': ['SgxEpcSection']} } + +## +# @query-sgx: +# +# Returns information about configured SGX capabilities of guest +# +# Returns: @SgxInfo +# +# Since: 6.2 +# +# .. qmp-example:: +# +# -> { "execute": "query-sgx" } +# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, +# "flc": true, +# "sections": [{"node": 0, "size": 67108864}, +# {"node": 1, "size": 29360128}]} } +## +{ 'command': 'query-sgx', 'returns': 'SgxInfo' } + +## +# @query-sgx-capabilities: +# +# Returns information about SGX capabilities of host +# +# Returns: @SgxInfo +# +# Since: 6.2 +# +# .. qmp-example:: +# +# -> { "execute": "query-sgx-capabilities" } +# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, +# "flc": true, +# "section" : [{"node": 0, "size": 67108864}, +# {"node": 1, "size": 29360128}]} } +## +{ 'command': 'query-sgx-capabilities', 'returns': 'SgxInfo' } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index cc472ce91c..d62db37d7c 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -2,85 +2,6 @@ # vim: filetype=python # -## -# @SgxEpcSection: -# -# Information about intel SGX EPC section -# -# @node: the numa node -# -# @size: the size of EPC section -# -# Since: 7.0 -## -{ 'struct': 'SgxEpcSection', - 'data': { 'node': 'int', - 'size': 'uint64'}} - -## -# @SgxInfo: -# -# Information about intel Safe Guard eXtension (SGX) support -# -# @sgx: true if SGX is supported -# -# @sgx1: true if SGX1 is supported -# -# @sgx2: true if SGX2 is supported -# -# @flc: true if FLC is supported -# -# @sections: The EPC sections information (Since: 7.0) -# -# Since: 6.2 -## -{ 'struct': 'SgxInfo', - 'data': { 'sgx': 'bool', - 'sgx1': 'bool', - 'sgx2': 'bool', - 'flc': 'bool', - 'sections': ['SgxEpcSection']}, - 'if': 'TARGET_I386' } - -## -# @query-sgx: -# -# Returns information about configured SGX capabilities of guest -# -# Returns: @SgxInfo -# -# Since: 6.2 -# -# .. qmp-example:: -# -# -> { "execute": "query-sgx" } -# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, -# "flc": true, -# "sections": [{"node": 0, "size": 67108864}, -# {"node": 1, "size": 29360128}]} } -## -{ 'command': 'query-sgx', 'returns': 'SgxInfo', 'if': 'TARGET_I386' } - -## -# @query-sgx-capabilities: -# -# Returns information about SGX capabilities of host -# -# Returns: @SgxInfo -# -# Since: 6.2 -# -# .. qmp-example:: -# -# -> { "execute": "query-sgx-capabilities" } -# <- { "return": { "sgx": true, "sgx1" : true, "sgx2" : true, -# "flc": true, -# "section" : [{"node": 0, "size": 67108864}, -# {"node": 1, "size": 29360128}]} } -## -{ 'command': 'query-sgx-capabilities', 'returns': 'SgxInfo', 'if': 'TARGET_I386' } - - ## # @EvtchnPortType: # diff --git a/stubs/meson.build b/stubs/meson.build index 07e9d3799a..f2eb488018 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -80,6 +80,7 @@ if have_system stub_ss.add(files('monitor-arm-gic.c')) stub_ss.add(files('monitor-i386-rtc.c')) stub_ss.add(files('monitor-i386-sev.c')) + stub_ss.add(files('monitor-i386-sgx.c')) endif if have_system or have_user diff --git a/stubs/monitor-i386-sgx.c b/stubs/monitor-i386-sgx.c new file mode 100644 index 0000000000..00e081d52d --- /dev/null +++ b/stubs/monitor-i386-sgx.c @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc-i386.h" + +SgxInfo *qmp_query_sgx(Error **errp) +{ + error_setg(errp, "SGX support is not compiled in"); + return NULL; +} + +SgxInfo *qmp_query_sgx_capabilities(Error **errp) +{ + error_setg(errp, "SGX support is not compiled in"); + return NULL; +} From 4b679a94c69db2526ddf77d4a0bd6b041b9fa133 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:33 -0700 Subject: [PATCH 1210/2760] qapi: make Xen event commands unconditionally available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_I386 condition from the Xen event channel commands, moving them to the recently introduced misc-i386.json QAPI file, given they are inherantly i386 specific commands. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Acked-by: David Woodhouse Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-7-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- hw/i386/kvm/xen-stubs.c | 13 ----- hw/i386/kvm/xen_evtchn.c | 2 +- qapi/misc-i386.json | 107 +++++++++++++++++++++++++++++++++++++ qapi/misc-target.json | 111 --------------------------------------- stubs/meson.build | 1 + stubs/monitor-i386-xen.c | 16 ++++++ 6 files changed, 125 insertions(+), 125 deletions(-) create mode 100644 stubs/monitor-i386-xen.c diff --git a/hw/i386/kvm/xen-stubs.c b/hw/i386/kvm/xen-stubs.c index d03131e686..ce73119ee7 100644 --- a/hw/i386/kvm/xen-stubs.c +++ b/hw/i386/kvm/xen-stubs.c @@ -12,7 +12,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qapi/qapi-commands-misc-target.h" #include "xen_evtchn.h" #include "xen_primary_console.h" @@ -38,15 +37,3 @@ void xen_primary_console_create(void) void xen_primary_console_set_be_port(uint16_t port) { } -#ifdef TARGET_I386 -EvtchnInfoList *qmp_xen_event_list(Error **errp) -{ - error_setg(errp, "Xen event channel emulation not enabled"); - return NULL; -} - -void qmp_xen_event_inject(uint32_t port, Error **errp) -{ - error_setg(errp, "Xen event channel emulation not enabled"); -} -#endif diff --git a/hw/i386/kvm/xen_evtchn.c b/hw/i386/kvm/xen_evtchn.c index b5190549a8..dd566c4967 100644 --- a/hw/i386/kvm/xen_evtchn.c +++ b/hw/i386/kvm/xen_evtchn.c @@ -19,7 +19,7 @@ #include "monitor/monitor.h" #include "monitor/hmp.h" #include "qapi/error.h" -#include "qapi/qapi-commands-misc-target.h" +#include "qapi/qapi-commands-misc-i386.h" #include "qobject/qdict.h" #include "qom/object.h" #include "exec/target_page.h" diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json index d5d1af55a4..3f88a5b28e 100644 --- a/qapi/misc-i386.json +++ b/qapi/misc-i386.json @@ -377,3 +377,110 @@ # {"node": 1, "size": 29360128}]} } ## { 'command': 'query-sgx-capabilities', 'returns': 'SgxInfo' } + +## +# @EvtchnPortType: +# +# An enumeration of Xen event channel port types. +# +# @closed: The port is unused. +# +# @unbound: The port is allocated and ready to be bound. +# +# @interdomain: The port is connected as an interdomain interrupt. +# +# @pirq: The port is bound to a physical IRQ (PIRQ). +# +# @virq: The port is bound to a virtual IRQ (VIRQ). +# +# @ipi: The post is an inter-processor interrupt (IPI). +# +# Since: 8.0 +## +{ 'enum': 'EvtchnPortType', + 'data': ['closed', 'unbound', 'interdomain', 'pirq', 'virq', 'ipi'] } + +## +# @EvtchnInfo: +# +# Information about a Xen event channel port +# +# @port: the port number +# +# @vcpu: target vCPU for this port +# +# @type: the port type +# +# @remote-domain: remote domain for interdomain ports +# +# @target: remote port ID, or virq/pirq number +# +# @pending: port is currently active pending delivery +# +# @masked: port is masked +# +# Since: 8.0 +## +{ 'struct': 'EvtchnInfo', + 'data': {'port': 'uint16', + 'vcpu': 'uint32', + 'type': 'EvtchnPortType', + 'remote-domain': 'str', + 'target': 'uint16', + 'pending': 'bool', + 'masked': 'bool'} } + + +## +# @xen-event-list: +# +# Query the Xen event channels opened by the guest. +# +# Returns: list of open event channel ports. +# +# Since: 8.0 +# +# .. qmp-example:: +# +# -> { "execute": "xen-event-list" } +# <- { "return": [ +# { +# "pending": false, +# "port": 1, +# "vcpu": 1, +# "remote-domain": "qemu", +# "masked": false, +# "type": "interdomain", +# "target": 1 +# }, +# { +# "pending": false, +# "port": 2, +# "vcpu": 0, +# "remote-domain": "", +# "masked": false, +# "type": "virq", +# "target": 0 +# } +# ] +# } +## +{ 'command': 'xen-event-list', + 'returns': ['EvtchnInfo'] } + +## +# @xen-event-inject: +# +# Inject a Xen event channel port (interrupt) to the guest. +# +# @port: The port number +# +# Since: 8.0 +# +# .. qmp-example:: +# +# -> { "execute": "xen-event-inject", "arguments": { "port": 1 } } +# <- { "return": { } } +## +{ 'command': 'xen-event-inject', + 'data': { 'port': 'uint32' } } diff --git a/qapi/misc-target.json b/qapi/misc-target.json index d62db37d7c..c9ea1ab23e 100644 --- a/qapi/misc-target.json +++ b/qapi/misc-target.json @@ -1,114 +1,3 @@ # -*- Mode: Python -*- # vim: filetype=python # - -## -# @EvtchnPortType: -# -# An enumeration of Xen event channel port types. -# -# @closed: The port is unused. -# -# @unbound: The port is allocated and ready to be bound. -# -# @interdomain: The port is connected as an interdomain interrupt. -# -# @pirq: The port is bound to a physical IRQ (PIRQ). -# -# @virq: The port is bound to a virtual IRQ (VIRQ). -# -# @ipi: The post is an inter-processor interrupt (IPI). -# -# Since: 8.0 -## -{ 'enum': 'EvtchnPortType', - 'data': ['closed', 'unbound', 'interdomain', 'pirq', 'virq', 'ipi'], - 'if': 'TARGET_I386' } - -## -# @EvtchnInfo: -# -# Information about a Xen event channel port -# -# @port: the port number -# -# @vcpu: target vCPU for this port -# -# @type: the port type -# -# @remote-domain: remote domain for interdomain ports -# -# @target: remote port ID, or virq/pirq number -# -# @pending: port is currently active pending delivery -# -# @masked: port is masked -# -# Since: 8.0 -## -{ 'struct': 'EvtchnInfo', - 'data': {'port': 'uint16', - 'vcpu': 'uint32', - 'type': 'EvtchnPortType', - 'remote-domain': 'str', - 'target': 'uint16', - 'pending': 'bool', - 'masked': 'bool'}, - 'if': 'TARGET_I386' } - - -## -# @xen-event-list: -# -# Query the Xen event channels opened by the guest. -# -# Returns: list of open event channel ports. -# -# Since: 8.0 -# -# .. qmp-example:: -# -# -> { "execute": "xen-event-list" } -# <- { "return": [ -# { -# "pending": false, -# "port": 1, -# "vcpu": 1, -# "remote-domain": "qemu", -# "masked": false, -# "type": "interdomain", -# "target": 1 -# }, -# { -# "pending": false, -# "port": 2, -# "vcpu": 0, -# "remote-domain": "", -# "masked": false, -# "type": "virq", -# "target": 0 -# } -# ] -# } -## -{ 'command': 'xen-event-list', - 'returns': ['EvtchnInfo'], - 'if': 'TARGET_I386' } - -## -# @xen-event-inject: -# -# Inject a Xen event channel port (interrupt) to the guest. -# -# @port: The port number -# -# Since: 8.0 -# -# .. qmp-example:: -# -# -> { "execute": "xen-event-inject", "arguments": { "port": 1 } } -# <- { "return": { } } -## -{ 'command': 'xen-event-inject', - 'data': { 'port': 'uint32' }, - 'if': 'TARGET_I386' } diff --git a/stubs/meson.build b/stubs/meson.build index f2eb488018..0ef11976a2 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -81,6 +81,7 @@ if have_system stub_ss.add(files('monitor-i386-rtc.c')) stub_ss.add(files('monitor-i386-sev.c')) stub_ss.add(files('monitor-i386-sgx.c')) + stub_ss.add(files('monitor-i386-xen.c')) endif if have_system or have_user diff --git a/stubs/monitor-i386-xen.c b/stubs/monitor-i386-xen.c new file mode 100644 index 0000000000..95b826f979 --- /dev/null +++ b/stubs/monitor-i386-xen.c @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-misc-i386.h" + +EvtchnInfoList *qmp_xen_event_list(Error **errp) +{ + error_setg(errp, "Xen event channel emulation not enabled"); + return NULL; +} + +void qmp_xen_event_inject(uint32_t port, Error **errp) +{ + error_setg(errp, "Xen event channel emulation not enabled"); +} From 0a1f83c3fb63229a77e2d0c5f1fe5d7e09dbf3b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:34 -0700 Subject: [PATCH 1211/2760] qapi: remove the misc-target.json file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This file is now empty and can thus be removed. Observe the pre-existing bug with s390-skeys.c and target/i386/monitor.c both including qapi-commands-misc-target.h despite not requiring it. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-8-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- hw/s390x/s390-skeys.c | 1 - qapi/meson.build | 1 - qapi/misc-target.json | 3 --- qapi/qapi-schema.json | 1 - target/i386/monitor.c | 1 - 5 files changed, 7 deletions(-) delete mode 100644 qapi/misc-target.json diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index aedb62b2d3..8eeecfd58f 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -17,7 +17,6 @@ #include "hw/s390x/storage-keys.h" #include "qapi/error.h" #include "qapi/qapi-commands-machine.h" -#include "qapi/qapi-commands-misc-target.h" #include "qobject/qdict.h" #include "qemu/error-report.h" #include "system/memory_mapping.h" diff --git a/qapi/meson.build b/qapi/meson.build index 5e93e6b8cf..ffe44f9e0b 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -42,7 +42,6 @@ qapi_all_modules = [ 'machine-target', 'migration', 'misc', - 'misc-target', 'net', 'pragma', 'qom', diff --git a/qapi/misc-target.json b/qapi/misc-target.json deleted file mode 100644 index c9ea1ab23e..0000000000 --- a/qapi/misc-target.json +++ /dev/null @@ -1,3 +0,0 @@ -# -*- Mode: Python -*- -# vim: filetype=python -# diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index e96bff8d38..d8eb79cfda 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -63,7 +63,6 @@ { 'include': 'misc.json' } { 'include': 'misc-arm.json' } { 'include': 'misc-i386.json' } -{ 'include': 'misc-target.json' } { 'include': 'audio.json' } { 'include': 'acpi.json' } { 'include': 'pci.json' } diff --git a/target/i386/monitor.c b/target/i386/monitor.c index 3ea92b066e..3c9b6ca62f 100644 --- a/target/i386/monitor.c +++ b/target/i386/monitor.c @@ -29,7 +29,6 @@ #include "monitor/hmp.h" #include "qobject/qdict.h" #include "qapi/error.h" -#include "qapi/qapi-commands-misc-target.h" #include "qapi/qapi-commands-misc.h" /* Perform linear address sign extension */ From 448553bb7c2a2fe518d7dc41c58a25d6d31831da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 22 May 2025 12:05:35 -0700 Subject: [PATCH 1212/2760] qapi: Make CpuModelExpansionInfo::deprecated-props optional and generic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We'd like to have some unified QAPI schema. Having a structure field conditional to a target being built in is not very practical. While @deprecated-props is only used by s390x target, it is generic enough and could be used by other targets (assuming we expand CpuModelExpansionType enum values). Let's always include this field, regardless of the target, but make it optional. This is not a compatibility break only because the field remains present always on S390x. Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-9-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- qapi/machine-target.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 426ce4ee82..d8dbda4b50 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -244,19 +244,18 @@ # # @model: the expanded CpuModelInfo. # -# @deprecated-props: a list of properties that are flagged as +# @deprecated-props: an optional list of properties that are flagged as # deprecated by the CPU vendor. The list depends on the # CpuModelExpansionType: "static" properties are a subset of the # enabled-properties for the expanded model; "full" properties are # a set of properties that are deprecated across all models for -# the architecture. (since: 9.1). +# the architecture. (since: 10.1 -- since 9.1 on s390x --). # # Since: 2.8 ## { 'struct': 'CpuModelExpansionInfo', 'data': { 'model': 'CpuModelInfo', - 'deprecated-props' : { 'type': ['str'], - 'if': 'TARGET_S390X' } }, + '*deprecated-props' : ['str'] }, 'if': { 'any': [ 'TARGET_S390X', 'TARGET_I386', 'TARGET_ARM', From d6758495d888e0ef8175824dadcdeb85274c14f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:36 -0700 Subject: [PATCH 1213/2760] qapi: make most CPU commands unconditionally available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_* conditions from all the CPU commands that are conceptually target independent. Top level stubs are provided to cope with targets which do not currently implement all of the commands. Adjust the doc comments accordingly. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-10-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- MAINTAINERS | 1 - qapi/machine-target.json | 397 -------------------------- qapi/machine.json | 363 +++++++++++++++++++++++ stubs/meson.build | 2 + stubs/monitor-cpu-s390x.c | 23 ++ stubs/monitor-cpu.c | 21 ++ target/arm/arm-qmp-cmds.c | 2 +- target/i386/cpu-system.c | 2 +- target/i386/cpu.c | 2 +- target/loongarch/loongarch-qmp-cmds.c | 2 +- target/mips/system/mips-qmp-cmds.c | 12 +- target/ppc/ppc-qmp-cmds.c | 12 +- target/riscv/riscv-qmp-cmds.c | 2 +- target/s390x/cpu_models_system.c | 2 +- 14 files changed, 437 insertions(+), 406 deletions(-) create mode 100644 stubs/monitor-cpu-s390x.c create mode 100644 stubs/monitor-cpu.c diff --git a/MAINTAINERS b/MAINTAINERS index 7060cf49b9..e27d1458c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1938,7 +1938,6 @@ F: hw/core/numa.c F: hw/cpu/cluster.c F: qapi/machine.json F: qapi/machine-common.json -F: qapi/machine-target.json F: include/hw/boards.h F: include/hw/core/cpu.h F: include/hw/cpu/cluster.h diff --git a/qapi/machine-target.json b/qapi/machine-target.json index d8dbda4b50..f19e34adaf 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -6,403 +6,6 @@ { 'include': 'machine-common.json' } -## -# @CpuModelInfo: -# -# Virtual CPU model. -# -# A CPU model consists of the name of a CPU definition, to which delta -# changes are applied (e.g. features added/removed). Most magic -# values that an architecture might require should be hidden behind -# the name. However, if required, architectures can expose relevant -# properties. -# -# @name: the name of the CPU definition the model is based on -# -# @props: a dictionary of QOM properties to be applied -# -# Since: 2.8 -## -{ 'struct': 'CpuModelInfo', - 'data': { 'name': 'str', - '*props': 'any' } } - -## -# @CpuModelExpansionType: -# -# An enumeration of CPU model expansion types. -# -# @static: Expand to a static CPU model, a combination of a static -# base model name and property delta changes. As the static base -# model will never change, the expanded CPU model will be the -# same, independent of QEMU version, machine type, machine -# options, and accelerator options. Therefore, the resulting -# model can be used by tooling without having to specify a -# compatibility machine - e.g. when displaying the "host" model. -# The @static CPU models are migration-safe. -# -# @full: Expand all properties. The produced model is not guaranteed -# to be migration-safe, but allows tooling to get an insight and -# work with model details. -# -# .. note:: When a non-migration-safe CPU model is expanded in static -# mode, some features enabled by the CPU model may be omitted, -# because they can't be implemented by a static CPU model -# definition (e.g. cache info passthrough and PMU passthrough in -# x86). If you need an accurate representation of the features -# enabled by a non-migration-safe CPU model, use @full. If you -# need a static representation that will keep ABI compatibility -# even when changing QEMU version or machine-type, use @static (but -# keep in mind that some features may be omitted). -# -# Since: 2.8 -## -{ 'enum': 'CpuModelExpansionType', - 'data': [ 'static', 'full' ] } - -## -# @CpuModelCompareResult: -# -# An enumeration of CPU model comparison results. The result is -# usually calculated using e.g. CPU features or CPU generations. -# -# @incompatible: If model A is incompatible to model B, model A is not -# guaranteed to run where model B runs and the other way around. -# -# @identical: If model A is identical to model B, model A is -# guaranteed to run where model B runs and the other way around. -# -# @superset: If model A is a superset of model B, model B is -# guaranteed to run where model A runs. There are no guarantees -# about the other way. -# -# @subset: If model A is a subset of model B, model A is guaranteed to -# run where model B runs. There are no guarantees about the other -# way. -# -# Since: 2.8 -## -{ 'enum': 'CpuModelCompareResult', - 'data': [ 'incompatible', 'identical', 'superset', 'subset' ] } - -## -# @CpuModelBaselineInfo: -# -# The result of a CPU model baseline. -# -# @model: the baselined CpuModelInfo. -# -# Since: 2.8 -## -{ 'struct': 'CpuModelBaselineInfo', - 'data': { 'model': 'CpuModelInfo' }, - 'if': 'TARGET_S390X' } - -## -# @CpuModelCompareInfo: -# -# The result of a CPU model comparison. -# -# @result: The result of the compare operation. -# -# @responsible-properties: List of properties that led to the -# comparison result not being identical. -# -# @responsible-properties is a list of QOM property names that led to -# both CPUs not being detected as identical. For identical models, -# this list is empty. If a QOM property is read-only, that means -# there's no known way to make the CPU models identical. If the -# special property name "type" is included, the models are by -# definition not identical and cannot be made identical. -# -# Since: 2.8 -## -{ 'struct': 'CpuModelCompareInfo', - 'data': { 'result': 'CpuModelCompareResult', - 'responsible-properties': ['str'] }, - 'if': 'TARGET_S390X' } - -## -# @query-cpu-model-comparison: -# -# Compares two CPU models, @modela and @modelb, returning how they -# compare in a specific configuration. The results indicates how -# both models compare regarding runnability. This result can be -# used by tooling to make decisions if a certain CPU model will -# run in a certain configuration or if a compatible CPU model has -# to be created by baselining. -# -# Usually, a CPU model is compared against the maximum possible CPU -# model of a certain configuration (e.g. the "host" model for KVM). -# If that CPU model is identical or a subset, it will run in that -# configuration. -# -# The result returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU -# version. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the -# machine-type. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, -# CPU models may look different depending on machine and accelerator -# options. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu -# option and global properties may affect expansion of CPU models. -# Using query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support comparing CPU models. s390x -# supports comparing CPU models. -# -# @modela: description of the first CPU model to compare, referred to -# as "model A" in CpuModelCompareResult -# -# @modelb: description of the second CPU model to compare, referred to -# as "model B" in CpuModelCompareResult -# -# Returns: a CpuModelCompareInfo describing how both CPU models -# compare -# -# Errors: -# - if comparing CPU models is not supported -# - if a model cannot be used -# - if a model contains an unknown cpu definition name, unknown -# properties or properties with wrong types. -# -# .. note:: This command isn't specific to s390x, but is only -# implemented on this architecture currently. -# -# Since: 2.8 -## -{ 'command': 'query-cpu-model-comparison', - 'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' }, - 'returns': 'CpuModelCompareInfo', - 'if': 'TARGET_S390X' } - -## -# @query-cpu-model-baseline: -# -# Baseline two CPU models, @modela and @modelb, creating a compatible -# third model. The created model will always be a static, -# migration-safe CPU model (see "static" CPU model expansion for -# details). -# -# This interface can be used by tooling to create a compatible CPU -# model out two CPU models. The created CPU model will be identical -# to or a subset of both CPU models when comparing them. Therefore, -# the created CPU model is guaranteed to run where the given CPU -# models run. -# -# The result returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU -# version. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the -# machine-type. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, -# CPU models may look different depending on machine and accelerator -# options. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu -# option and global properties may affect expansion of CPU models. -# Using query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support baselining CPU models. s390x -# supports baselining CPU models. -# -# @modela: description of the first CPU model to baseline -# -# @modelb: description of the second CPU model to baseline -# -# Returns: a CpuModelBaselineInfo describing the baselined CPU model -# -# Errors: -# - if baselining CPU models is not supported -# - if a model cannot be used -# - if a model contains an unknown cpu definition name, unknown -# properties or properties with wrong types. -# -# .. note:: This command isn't specific to s390x, but is only -# implemented on this architecture currently. -# -# Since: 2.8 -## -{ 'command': 'query-cpu-model-baseline', - 'data': { 'modela': 'CpuModelInfo', - 'modelb': 'CpuModelInfo' }, - 'returns': 'CpuModelBaselineInfo', - 'if': 'TARGET_S390X' } - -## -# @CpuModelExpansionInfo: -# -# The result of a cpu model expansion. -# -# @model: the expanded CpuModelInfo. -# -# @deprecated-props: an optional list of properties that are flagged as -# deprecated by the CPU vendor. The list depends on the -# CpuModelExpansionType: "static" properties are a subset of the -# enabled-properties for the expanded model; "full" properties are -# a set of properties that are deprecated across all models for -# the architecture. (since: 10.1 -- since 9.1 on s390x --). -# -# Since: 2.8 -## -{ 'struct': 'CpuModelExpansionInfo', - 'data': { 'model': 'CpuModelInfo', - '*deprecated-props' : ['str'] }, - 'if': { 'any': [ 'TARGET_S390X', - 'TARGET_I386', - 'TARGET_ARM', - 'TARGET_LOONGARCH64', - 'TARGET_RISCV' ] } } - -## -# @query-cpu-model-expansion: -# -# Expands a given CPU model, @model, (or a combination of CPU model + -# additional options) to different granularities, specified by @type, -# allowing tooling to get an understanding what a specific CPU model -# looks like in QEMU under a certain configuration. -# -# This interface can be used to query the "host" CPU model. -# -# The data returned by this command may be affected by: -# -# * QEMU version: CPU models may look different depending on the QEMU -# version. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine-type: CPU model may look different depending on the -# machine-type. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * machine options (including accelerator): in some architectures, -# CPU models may look different depending on machine and accelerator -# options. (Except for CPU models reported as "static" in -# query-cpu-definitions.) -# * "-cpu" arguments and global properties: arguments to the -cpu -# option and global properties may affect expansion of CPU models. -# Using query-cpu-model-expansion while using these is not advised. -# -# Some architectures may not support all expansion types. s390x -# supports "full" and "static". Arm only supports "full". -# -# @model: description of the CPU model to expand -# -# @type: expansion type, specifying how to expand the CPU model -# -# Returns: a CpuModelExpansionInfo describing the expanded CPU model -# -# Errors: -# - if expanding CPU models is not supported -# - if the model cannot be expanded -# - if the model contains an unknown CPU definition name, unknown -# properties or properties with a wrong type -# - if an expansion type is not supported -# -# Since: 2.8 -## -{ 'command': 'query-cpu-model-expansion', - 'data': { 'type': 'CpuModelExpansionType', - 'model': 'CpuModelInfo' }, - 'returns': 'CpuModelExpansionInfo', - 'if': { 'any': [ 'TARGET_S390X', - 'TARGET_I386', - 'TARGET_ARM', - 'TARGET_LOONGARCH64', - 'TARGET_RISCV' ] } } - -## -# @CpuDefinitionInfo: -# -# Virtual CPU definition. -# -# @name: the name of the CPU definition -# -# @migration-safe: whether a CPU definition can be safely used for -# migration in combination with a QEMU compatibility machine when -# migrating between different QEMU versions and between hosts with -# different sets of (hardware or software) capabilities. If not -# provided, information is not available and callers should not -# assume the CPU definition to be migration-safe. (since 2.8) -# -# @static: whether a CPU definition is static and will not change -# depending on QEMU version, machine type, machine options and -# accelerator options. A static model is always migration-safe. -# (since 2.8) -# -# @unavailable-features: List of properties that prevent the CPU model -# from running in the current host. (since 2.8) -# -# @typename: Type name that can be used as argument to -# @device-list-properties, to introspect properties configurable -# using -cpu or -global. (since 2.9) -# -# @alias-of: Name of CPU model this model is an alias for. The target -# of the CPU model alias may change depending on the machine type. -# Management software is supposed to translate CPU model aliases -# in the VM configuration, because aliases may stop being -# migration-safe in the future (since 4.1) -# -# @deprecated: If true, this CPU model is deprecated and may be -# removed in some future version of QEMU according to the QEMU -# deprecation policy. (since 5.2) -# -# @unavailable-features is a list of QOM property names that represent -# CPU model attributes that prevent the CPU from running. If the QOM -# property is read-only, that means there's no known way to make the -# CPU model run in the current host. Implementations that choose not -# to provide specific information return the property name "type". If -# the property is read-write, it means that it MAY be possible to run -# the CPU model in the current host if that property is changed. -# Management software can use it as hints to suggest or choose an -# alternative for the user, or just to generate meaningful error -# messages explaining why the CPU model can't be used. If -# @unavailable-features is an empty list, the CPU model is runnable -# using the current host and machine-type. If @unavailable-features -# is not present, runnability information for the CPU is not -# available. -# -# Since: 1.2 -## -{ 'struct': 'CpuDefinitionInfo', - 'data': { 'name': 'str', - '*migration-safe': 'bool', - 'static': 'bool', - '*unavailable-features': [ 'str' ], - 'typename': 'str', - '*alias-of' : 'str', - 'deprecated' : 'bool' }, - 'if': { 'any': [ 'TARGET_PPC', - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', - 'TARGET_MIPS', - 'TARGET_LOONGARCH64', - 'TARGET_RISCV' ] } } - -## -# @query-cpu-definitions: -# -# Return a list of supported virtual CPU definitions -# -# Returns: a list of CpuDefinitionInfo -# -# Since: 1.2 -## -{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'], - 'if': { 'any': [ 'TARGET_PPC', - 'TARGET_ARM', - 'TARGET_I386', - 'TARGET_S390X', - 'TARGET_MIPS', - 'TARGET_LOONGARCH64', - 'TARGET_RISCV' ] } } - ## # @S390CpuPolarization: # diff --git a/qapi/machine.json b/qapi/machine.json index c8feb9fe17..e6b4b2dfef 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1916,3 +1916,366 @@ ## { 'command': 'dump-skeys', 'data': { 'filename': 'str' } } + +## +# @CpuModelInfo: +# +# Virtual CPU model. +# +# A CPU model consists of the name of a CPU definition, to which delta +# changes are applied (e.g. features added/removed). Most magic +# values that an architecture might require should be hidden behind +# the name. However, if required, architectures can expose relevant +# properties. +# +# @name: the name of the CPU definition the model is based on +# +# @props: a dictionary of QOM properties to be applied +# +# Since: 2.8 +## +{ 'struct': 'CpuModelInfo', + 'data': { 'name': 'str', + '*props': 'any' } } + +## +# @CpuModelExpansionType: +# +# An enumeration of CPU model expansion types. +# +# @static: Expand to a static CPU model, a combination of a static +# base model name and property delta changes. As the static base +# model will never change, the expanded CPU model will be the +# same, independent of QEMU version, machine type, machine +# options, and accelerator options. Therefore, the resulting +# model can be used by tooling without having to specify a +# compatibility machine - e.g. when displaying the "host" model. +# The @static CPU models are migration-safe. +# +# @full: Expand all properties. The produced model is not guaranteed +# to be migration-safe, but allows tooling to get an insight and +# work with model details. +# +# .. note:: When a non-migration-safe CPU model is expanded in static +# mode, some features enabled by the CPU model may be omitted, +# because they can't be implemented by a static CPU model +# definition (e.g. cache info passthrough and PMU passthrough in +# x86). If you need an accurate representation of the features +# enabled by a non-migration-safe CPU model, use @full. If you +# need a static representation that will keep ABI compatibility +# even when changing QEMU version or machine-type, use @static (but +# keep in mind that some features may be omitted). +# +# Since: 2.8 +## +{ 'enum': 'CpuModelExpansionType', + 'data': [ 'static', 'full' ] } + +## +# @CpuModelCompareResult: +# +# An enumeration of CPU model comparison results. The result is +# usually calculated using e.g. CPU features or CPU generations. +# +# @incompatible: If model A is incompatible to model B, model A is not +# guaranteed to run where model B runs and the other way around. +# +# @identical: If model A is identical to model B, model A is +# guaranteed to run where model B runs and the other way around. +# +# @superset: If model A is a superset of model B, model B is +# guaranteed to run where model A runs. There are no guarantees +# about the other way. +# +# @subset: If model A is a subset of model B, model A is guaranteed to +# run where model B runs. There are no guarantees about the other +# way. +# +# Since: 2.8 +## +{ 'enum': 'CpuModelCompareResult', + 'data': [ 'incompatible', 'identical', 'superset', 'subset' ] } + +## +# @CpuModelBaselineInfo: +# +# The result of a CPU model baseline. +# +# @model: the baselined CpuModelInfo. +# +# Since: 2.8 +## +{ 'struct': 'CpuModelBaselineInfo', + 'data': { 'model': 'CpuModelInfo' } } + +## +# @CpuModelCompareInfo: +# +# The result of a CPU model comparison. +# +# @result: The result of the compare operation. +# +# @responsible-properties: List of properties that led to the +# comparison result not being identical. +# +# @responsible-properties is a list of QOM property names that led to +# both CPUs not being detected as identical. For identical models, +# this list is empty. If a QOM property is read-only, that means +# there's no known way to make the CPU models identical. If the +# special property name "type" is included, the models are by +# definition not identical and cannot be made identical. +# +# Since: 2.8 +## +{ 'struct': 'CpuModelCompareInfo', + 'data': { 'result': 'CpuModelCompareResult', + 'responsible-properties': ['str'] } } + +## +# @query-cpu-model-comparison: +# +# Compares two CPU models, @modela and @modelb, returning how they +# compare in a specific configuration. The results indicates how +# both models compare regarding runnability. This result can be +# used by tooling to make decisions if a certain CPU model will +# run in a certain configuration or if a compatible CPU model has +# to be created by baselining. +# +# Usually, a CPU model is compared against the maximum possible CPU +# model of a certain configuration (e.g. the "host" model for KVM). +# If that CPU model is identical or a subset, it will run in that +# configuration. +# +# The result returned by this command may be affected by: +# +# * QEMU version: CPU models may look different depending on the QEMU +# version. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine-type: CPU model may look different depending on the +# machine-type. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine options (including accelerator): in some architectures, +# CPU models may look different depending on machine and accelerator +# options. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * "-cpu" arguments and global properties: arguments to the -cpu +# option and global properties may affect expansion of CPU models. +# Using query-cpu-model-expansion while using these is not advised. +# +# Some architectures may not support comparing CPU models. s390x +# supports comparing CPU models. +# +# @modela: description of the first CPU model to compare, referred to +# as "model A" in CpuModelCompareResult +# +# @modelb: description of the second CPU model to compare, referred to +# as "model B" in CpuModelCompareResult +# +# Returns: a CpuModelCompareInfo describing how both CPU models +# compare +# +# Errors: +# - if comparing CPU models is not supported by the target +# - if a model cannot be used +# - if a model contains an unknown cpu definition name, unknown +# properties or properties with wrong types. +# +# Since: 2.8 +## +{ 'command': 'query-cpu-model-comparison', + 'data': { 'modela': 'CpuModelInfo', 'modelb': 'CpuModelInfo' }, + 'returns': 'CpuModelCompareInfo' } + +## +# @query-cpu-model-baseline: +# +# Baseline two CPU models, @modela and @modelb, creating a compatible +# third model. The created model will always be a static, +# migration-safe CPU model (see "static" CPU model expansion for +# details). +# +# This interface can be used by tooling to create a compatible CPU +# model out two CPU models. The created CPU model will be identical +# to or a subset of both CPU models when comparing them. Therefore, +# the created CPU model is guaranteed to run where the given CPU +# models run. +# +# The result returned by this command may be affected by: +# +# * QEMU version: CPU models may look different depending on the QEMU +# version. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine-type: CPU model may look different depending on the +# machine-type. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine options (including accelerator): in some architectures, +# CPU models may look different depending on machine and accelerator +# options. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * "-cpu" arguments and global properties: arguments to the -cpu +# option and global properties may affect expansion of CPU models. +# Using query-cpu-model-expansion while using these is not advised. +# +# Some architectures may not support baselining CPU models. s390x +# supports baselining CPU models. +# +# @modela: description of the first CPU model to baseline +# +# @modelb: description of the second CPU model to baseline +# +# Returns: a CpuModelBaselineInfo describing the baselined CPU model +# +# Errors: +# - if baselining CPU models is not supported by the target +# - if a model cannot be used +# - if a model contains an unknown cpu definition name, unknown +# properties or properties with wrong types. +# +# Since: 2.8 +## +{ 'command': 'query-cpu-model-baseline', + 'data': { 'modela': 'CpuModelInfo', + 'modelb': 'CpuModelInfo' }, + 'returns': 'CpuModelBaselineInfo' } + +## +# @CpuModelExpansionInfo: +# +# The result of a cpu model expansion. +# +# @model: the expanded CpuModelInfo. +# +# @deprecated-props: an optional list of properties that are flagged as +# deprecated by the CPU vendor. The list depends on the +# CpuModelExpansionType: "static" properties are a subset of the +# enabled-properties for the expanded model; "full" properties are +# a set of properties that are deprecated across all models for +# the architecture. (since: 10.1 -- since 9.1 on s390x --). +# +# Since: 2.8 +## +{ 'struct': 'CpuModelExpansionInfo', + 'data': { 'model': 'CpuModelInfo', + '*deprecated-props' : ['str'] } } + +## +# @query-cpu-model-expansion: +# +# Expands a given CPU model, @model, (or a combination of CPU model + +# additional options) to different granularities, specified by @type, +# allowing tooling to get an understanding what a specific CPU model +# looks like in QEMU under a certain configuration. +# +# This interface can be used to query the "host" CPU model. +# +# The data returned by this command may be affected by: +# +# * QEMU version: CPU models may look different depending on the QEMU +# version. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine-type: CPU model may look different depending on the +# machine-type. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * machine options (including accelerator): in some architectures, +# CPU models may look different depending on machine and accelerator +# options. (Except for CPU models reported as "static" in +# query-cpu-definitions.) +# * "-cpu" arguments and global properties: arguments to the -cpu +# option and global properties may affect expansion of CPU models. +# Using query-cpu-model-expansion while using these is not advised. +# +# Some architectures may not support all expansion types. s390x +# supports "full" and "static". Arm only supports "full". +# +# @model: description of the CPU model to expand +# +# @type: expansion type, specifying how to expand the CPU model +# +# Returns: a CpuModelExpansionInfo describing the expanded CPU model +# +# Errors: +# - if expanding CPU models is not supported +# - if the model cannot be expanded +# - if the model contains an unknown CPU definition name, unknown +# properties or properties with a wrong type +# - if an expansion type is not supported +# +# Since: 2.8 +## +{ 'command': 'query-cpu-model-expansion', + 'data': { 'type': 'CpuModelExpansionType', + 'model': 'CpuModelInfo' }, + 'returns': 'CpuModelExpansionInfo' } + +## +# @CpuDefinitionInfo: +# +# Virtual CPU definition. +# +# @name: the name of the CPU definition +# +# @migration-safe: whether a CPU definition can be safely used for +# migration in combination with a QEMU compatibility machine when +# migrating between different QEMU versions and between hosts with +# different sets of (hardware or software) capabilities. If not +# provided, information is not available and callers should not +# assume the CPU definition to be migration-safe. (since 2.8) +# +# @static: whether a CPU definition is static and will not change +# depending on QEMU version, machine type, machine options and +# accelerator options. A static model is always migration-safe. +# (since 2.8) +# +# @unavailable-features: List of properties that prevent the CPU model +# from running in the current host. (since 2.8) +# +# @typename: Type name that can be used as argument to +# @device-list-properties, to introspect properties configurable +# using -cpu or -global. (since 2.9) +# +# @alias-of: Name of CPU model this model is an alias for. The target +# of the CPU model alias may change depending on the machine type. +# Management software is supposed to translate CPU model aliases +# in the VM configuration, because aliases may stop being +# migration-safe in the future (since 4.1) +# +# @deprecated: If true, this CPU model is deprecated and may be +# removed in some future version of QEMU according to the QEMU +# deprecation policy. (since 5.2) +# +# @unavailable-features is a list of QOM property names that represent +# CPU model attributes that prevent the CPU from running. If the QOM +# property is read-only, that means there's no known way to make the +# CPU model run in the current host. Implementations that choose not +# to provide specific information return the property name "type". If +# the property is read-write, it means that it MAY be possible to run +# the CPU model in the current host if that property is changed. +# Management software can use it as hints to suggest or choose an +# alternative for the user, or just to generate meaningful error +# messages explaining why the CPU model can't be used. If +# @unavailable-features is an empty list, the CPU model is runnable +# using the current host and machine-type. If @unavailable-features +# is not present, runnability information for the CPU is not +# available. +# +# Since: 1.2 +## +{ 'struct': 'CpuDefinitionInfo', + 'data': { 'name': 'str', + '*migration-safe': 'bool', + 'static': 'bool', + '*unavailable-features': [ 'str' ], + 'typename': 'str', + '*alias-of' : 'str', + 'deprecated' : 'bool' } } + +## +# @query-cpu-definitions: +# +# Return a list of supported virtual CPU definitions +# +# Returns: a list of CpuDefinitionInfo +# +# Since: 1.2 +## +{ 'command': 'query-cpu-definitions', 'returns': ['CpuDefinitionInfo'] } diff --git a/stubs/meson.build b/stubs/meson.build index 0ef11976a2..3b2fad0824 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -82,6 +82,8 @@ if have_system stub_ss.add(files('monitor-i386-sev.c')) stub_ss.add(files('monitor-i386-sgx.c')) stub_ss.add(files('monitor-i386-xen.c')) + stub_ss.add(files('monitor-cpu.c')) + stub_ss.add(files('monitor-cpu-s390x.c')) endif if have_system or have_user diff --git a/stubs/monitor-cpu-s390x.c b/stubs/monitor-cpu-s390x.c new file mode 100644 index 0000000000..71e794482b --- /dev/null +++ b/stubs/monitor-cpu-s390x.c @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" + +CpuModelCompareInfo * +qmp_query_cpu_model_comparison(CpuModelInfo *infoa, + CpuModelInfo *infob, + Error **errp) +{ + error_setg(errp, "CPU model comparison is not supported on this target"); + return NULL; +} + +CpuModelBaselineInfo * +qmp_query_cpu_model_baseline(CpuModelInfo *infoa, + CpuModelInfo *infob, + Error **errp) +{ + error_setg(errp, "CPU model baseline is not supported on this target"); + return NULL; +} diff --git a/stubs/monitor-cpu.c b/stubs/monitor-cpu.c new file mode 100644 index 0000000000..a8c7ee89b9 --- /dev/null +++ b/stubs/monitor-cpu.c @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" + +CpuModelExpansionInfo * +qmp_query_cpu_model_expansion(CpuModelExpansionType type, + CpuModelInfo *model, + Error **errp) +{ + error_setg(errp, "CPU model expansion is not supported on this target"); + return NULL; +} + +CpuDefinitionInfoList * +qmp_query_cpu_definitions(Error **errp) +{ + error_setg(errp, "CPU model definitions are not supported on this target"); + return NULL; +} diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c index ef18c867ca..cca6b9722b 100644 --- a/target/arm/arm-qmp-cmds.c +++ b/target/arm/arm-qmp-cmds.c @@ -26,7 +26,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "qapi/qobject-input-visitor.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" #include "qapi/qapi-commands-misc-arm.h" #include "qobject/qdict.h" #include "qom/qom-qobject.h" diff --git a/target/i386/cpu-system.c b/target/i386/cpu-system.c index 55f192e819..b1494aa674 100644 --- a/target/i386/cpu-system.c +++ b/target/i386/cpu-system.c @@ -24,7 +24,7 @@ #include "qobject/qdict.h" #include "qapi/qobject-input-visitor.h" #include "qom/qom-qobject.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" #include "cpu-internal.h" diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9689f6374e..33afc3ec60 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -38,7 +38,7 @@ #include "exec/watchpoint.h" #ifndef CONFIG_USER_ONLY #include "system/reset.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" #include "system/address-spaces.h" #include "hw/boards.h" #include "hw/i386/sgx-epc.h" diff --git a/target/loongarch/loongarch-qmp-cmds.c b/target/loongarch/loongarch-qmp-cmds.c index 6f732d80f3..f5f1cd0009 100644 --- a/target/loongarch/loongarch-qmp-cmds.c +++ b/target/loongarch/loongarch-qmp-cmds.c @@ -8,7 +8,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" #include "cpu.h" #include "qobject/qdict.h" #include "qapi/qobject-input-visitor.h" diff --git a/target/mips/system/mips-qmp-cmds.c b/target/mips/system/mips-qmp-cmds.c index 7340ac70ba..d98d6623f2 100644 --- a/target/mips/system/mips-qmp-cmds.c +++ b/target/mips/system/mips-qmp-cmds.c @@ -7,9 +7,19 @@ */ #include "qemu/osdep.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" #include "cpu.h" +CpuModelExpansionInfo * +qmp_query_cpu_model_expansion(CpuModelExpansionType type, + CpuModelInfo *model, + Error **errp) +{ + error_setg(errp, "CPU model expansion is not supported on this target"); + return NULL; +} + static void mips_cpu_add_definition(gpointer data, gpointer user_data) { ObjectClass *oc = data; diff --git a/target/ppc/ppc-qmp-cmds.c b/target/ppc/ppc-qmp-cmds.c index a25d86a8d1..7022564604 100644 --- a/target/ppc/ppc-qmp-cmds.c +++ b/target/ppc/ppc-qmp-cmds.c @@ -28,7 +28,8 @@ #include "qemu/ctype.h" #include "monitor/hmp-target.h" #include "monitor/hmp.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine.h" #include "cpu-models.h" #include "cpu-qom.h" @@ -175,6 +176,15 @@ int target_get_monitor_def(CPUState *cs, const char *name, uint64_t *pval) return -EINVAL; } +CpuModelExpansionInfo * +qmp_query_cpu_model_expansion(CpuModelExpansionType type, + CpuModelInfo *model, + Error **errp) +{ + error_setg(errp, "CPU model expansion is not supported on this target"); + return NULL; +} + static void ppc_cpu_defs_entry(gpointer data, gpointer user_data) { ObjectClass *oc = data; diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c index d0a324364d..8ba8aa0d5f 100644 --- a/target/riscv/riscv-qmp-cmds.c +++ b/target/riscv/riscv-qmp-cmds.c @@ -25,7 +25,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" #include "qobject/qbool.h" #include "qobject/qdict.h" #include "qapi/qobject-input-visitor.h" diff --git a/target/s390x/cpu_models_system.c b/target/s390x/cpu_models_system.c index 4351182f72..9d84faa3c9 100644 --- a/target/s390x/cpu_models_system.c +++ b/target/s390x/cpu_models_system.c @@ -19,7 +19,7 @@ #include "qapi/visitor.h" #include "qapi/qobject-input-visitor.h" #include "qobject/qdict.h" -#include "qapi/qapi-commands-machine-target.h" +#include "qapi/qapi-commands-machine.h" static void list_add_feat(const char *name, void *opaque); From f8d41d0511114edcde8c589ffc76887b3a2dc39b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Thu, 22 May 2025 12:05:37 -0700 Subject: [PATCH 1214/2760] qapi: make s390x specific CPU commands unconditionally available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the TARGET_S390X and CONFIG_KVM conditions from the CPU commands that are conceptually specific to s390x. Top level stubs are provided to cope with non-s390x targets, or builds without KVM. The removal of CONFIG_KVM is justified by the fact there is no conceptual difference between running 'qemu-system-s390x -accel tcg' on a build with and without KVM built-in, so apps only using TCG can't rely on the CONFIG_KVM in the schema. Reviewed-by: Richard Henderson Signed-off-by: Daniel P. Berrangé Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-11-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- hw/s390x/cpu-topology.c | 4 ++-- include/hw/s390x/cpu-topology.h | 2 +- ...machine-target.json => machine-s390x.json} | 16 +++++--------- qapi/meson.build | 2 +- qapi/qapi-schema.json | 2 +- stubs/meson.build | 1 + stubs/monitor-cpu-s390x-kvm.c | 22 +++++++++++++++++++ tests/qtest/qmp-cmd-test.c | 1 + 8 files changed, 35 insertions(+), 15 deletions(-) rename qapi/{machine-target.json => machine-s390x.json} (85%) create mode 100644 stubs/monitor-cpu-s390x-kvm.c diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 7d4e1f5472..b513f8936e 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -23,8 +23,8 @@ #include "target/s390x/cpu.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/cpu-topology.h" -#include "qapi/qapi-commands-machine-target.h" -#include "qapi/qapi-events-machine-target.h" +#include "qapi/qapi-commands-machine-s390x.h" +#include "qapi/qapi-events-machine-s390x.h" /* * s390_topology is used to keep the topology information. diff --git a/include/hw/s390x/cpu-topology.h b/include/hw/s390x/cpu-topology.h index 9283c948e3..d5e9aa43f8 100644 --- a/include/hw/s390x/cpu-topology.h +++ b/include/hw/s390x/cpu-topology.h @@ -13,7 +13,7 @@ #include "qemu/queue.h" #include "hw/boards.h" -#include "qapi/qapi-types-machine-target.h" +#include "qapi/qapi-types-machine-s390x.h" #define S390_TOPOLOGY_CPU_IFL 0x03 diff --git a/qapi/machine-target.json b/qapi/machine-s390x.json similarity index 85% rename from qapi/machine-target.json rename to qapi/machine-s390x.json index f19e34adaf..966dbd61d2 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-s390x.json @@ -1,6 +1,7 @@ # -*- Mode: Python -*- # vim: filetype=python # +# SPDX-License-Identifier: GPL-2.0-or-later # This work is licensed under the terms of the GNU GPL, version 2 or later. # See the COPYING file in the top-level directory. @@ -15,8 +16,7 @@ # Since: 8.2 ## { 'enum': 'S390CpuPolarization', - 'data': [ 'horizontal', 'vertical' ], - 'if': 'TARGET_S390X' + 'data': [ 'horizontal', 'vertical' ] } ## @@ -54,8 +54,7 @@ '*entitlement': 'S390CpuEntitlement', '*dedicated': 'bool' }, - 'features': [ 'unstable' ], - 'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] } + 'features': [ 'unstable' ] } ## @@ -90,8 +89,7 @@ ## { 'event': 'CPU_POLARIZATION_CHANGE', 'data': { 'polarization': 'S390CpuPolarization' }, - 'features': [ 'unstable' ], - 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } + 'features': [ 'unstable' ] } ## @@ -104,8 +102,7 @@ # Since: 8.2 ## { 'struct': 'CpuPolarizationInfo', - 'data': { 'polarization': 'S390CpuPolarization' }, - 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } + 'data': { 'polarization': 'S390CpuPolarization' } } ## @@ -120,6 +117,5 @@ # Since: 8.2 ## { 'command': 'query-s390x-cpu-polarization', 'returns': 'CpuPolarizationInfo', - 'features': [ 'unstable' ], - 'if': { 'all': [ 'TARGET_S390X', 'CONFIG_KVM' ] } + 'features': [ 'unstable' ] } diff --git a/qapi/meson.build b/qapi/meson.build index ffe44f9e0b..e038b636c9 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -39,7 +39,7 @@ qapi_all_modules = [ 'job', 'machine-common', 'machine', - 'machine-target', + 'machine-s390x', 'migration', 'misc', 'net', diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json index d8eb79cfda..a8f66163cb 100644 --- a/qapi/qapi-schema.json +++ b/qapi/qapi-schema.json @@ -57,7 +57,7 @@ { 'include': 'qdev.json' } { 'include': 'machine-common.json' } { 'include': 'machine.json' } -{ 'include': 'machine-target.json' } +{ 'include': 'machine-s390x.json' } { 'include': 'replay.json' } { 'include': 'yank.json' } { 'include': 'misc.json' } diff --git a/stubs/meson.build b/stubs/meson.build index 3b2fad0824..cef046e685 100644 --- a/stubs/meson.build +++ b/stubs/meson.build @@ -84,6 +84,7 @@ if have_system stub_ss.add(files('monitor-i386-xen.c')) stub_ss.add(files('monitor-cpu.c')) stub_ss.add(files('monitor-cpu-s390x.c')) + stub_ss.add(files('monitor-cpu-s390x-kvm.c')) endif if have_system or have_user diff --git a/stubs/monitor-cpu-s390x-kvm.c b/stubs/monitor-cpu-s390x-kvm.c new file mode 100644 index 0000000000..8683dd2d4c --- /dev/null +++ b/stubs/monitor-cpu-s390x-kvm.c @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qapi/qapi-commands-machine-s390x.h" + +void qmp_set_cpu_topology(uint16_t core, + bool has_socket, uint16_t socket, + bool has_book, uint16_t book, + bool has_drawer, uint16_t drawer, + bool has_entitlement, S390CpuEntitlement entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + error_setg(errp, "CPU topology change is not supported on this target"); +} + +CpuPolarizationInfo *qmp_query_s390x_cpu_polarization(Error **errp) +{ + error_setg(errp, "CPU polarization is not supported on this target"); + return NULL; +} diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c index 15c88248b7..040d042810 100644 --- a/tests/qtest/qmp-cmd-test.c +++ b/tests/qtest/qmp-cmd-test.c @@ -100,6 +100,7 @@ static bool query_is_ignored(const char *cmd) /* Success depends on target arch: */ "query-cpu-definitions", /* arm, i386, ppc, s390x */ "query-gic-capabilities", /* arm */ + "query-s390x-cpu-polarization", /* s390x */ /* Success depends on target-specific build configuration: */ "query-pci", /* CONFIG_PCI */ "x-query-virtio", /* CONFIG_VIRTIO */ From d9cbcbff811bafc0e0081a07ce47c9e8f3051e0c Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 22 May 2025 12:05:38 -0700 Subject: [PATCH 1215/2760] qapi: remove qapi_specific_outputs from meson.build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no more QAPI files that need to be compiled per target, so we can remove this. qapi_specific_outputs is now empty, so we can remove the associated logic in meson. Reviewed-by: Daniel P. Berrangé Reviewed-by: Richard Henderson Reviewed-by: Markus Armbruster Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-12-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- qapi/meson.build | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/qapi/meson.build b/qapi/meson.build index e038b636c9..7582c2b5bc 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -92,7 +92,6 @@ qapi_util_outputs = [ ] qapi_inputs = [] -qapi_specific_outputs = [] foreach module : qapi_all_modules qapi_inputs += [ files(module + '.json') ] qapi_module_outputs = [ @@ -110,15 +109,11 @@ foreach module : qapi_all_modules 'qapi-commands-@0@.trace-events'.format(module), ] endif - if module.endswith('-target') - qapi_specific_outputs += qapi_module_outputs - else - qapi_util_outputs += qapi_module_outputs - endif + qapi_util_outputs += qapi_module_outputs endforeach qapi_files = custom_target('shared QAPI source files', - output: qapi_util_outputs + qapi_specific_outputs + qapi_nonmodule_outputs, + output: qapi_util_outputs + qapi_nonmodule_outputs, input: [ files('qapi-schema.json') ], command: [ qapi_gen, '-o', 'qapi', '-b', '@INPUT0@' ], depend_files: [ qapi_inputs, qapi_gen_depends ]) @@ -138,7 +133,7 @@ foreach output : qapi_util_outputs i = i + 1 endforeach -foreach output : qapi_specific_outputs + qapi_nonmodule_outputs +foreach output : qapi_nonmodule_outputs if output.endswith('.h') genh += qapi_files[i] endif From fdbb616f4dd55b4f3efd6cb56bf675046fb6e4f3 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 22 May 2025 12:05:39 -0700 Subject: [PATCH 1216/2760] qapi: make all generated files common Monolithic files (qapi_nonmodule_outputs) can now be compiled just once, so we can remove qapi_util_outputs logic. This removes the need for any specific_ss file. Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-13-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster --- qapi/meson.build | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/qapi/meson.build b/qapi/meson.build index 7582c2b5bc..3b035aea33 100644 --- a/qapi/meson.build +++ b/qapi/meson.build @@ -85,8 +85,7 @@ qapi_nonmodule_outputs = [ 'qapi-emit-events.c', 'qapi-emit-events.h', ] -# First build all sources -qapi_util_outputs = [ +qapi_outputs = qapi_nonmodule_outputs + [ 'qapi-builtin-types.c', 'qapi-builtin-visit.c', 'qapi-builtin-types.h', 'qapi-builtin-visit.h', ] @@ -109,20 +108,17 @@ foreach module : qapi_all_modules 'qapi-commands-@0@.trace-events'.format(module), ] endif - qapi_util_outputs += qapi_module_outputs + qapi_outputs += qapi_module_outputs endforeach qapi_files = custom_target('shared QAPI source files', - output: qapi_util_outputs + qapi_nonmodule_outputs, + output: qapi_outputs, input: [ files('qapi-schema.json') ], command: [ qapi_gen, '-o', 'qapi', '-b', '@INPUT0@' ], depend_files: [ qapi_inputs, qapi_gen_depends ]) -# Now go through all the outputs and add them to the right sourceset. -# These loops must be synchronized with the output of the above custom target. - i = 0 -foreach output : qapi_util_outputs +foreach output : qapi_outputs if output.endswith('.h') genh += qapi_files[i] endif @@ -132,14 +128,3 @@ foreach output : qapi_util_outputs util_ss.add(qapi_files[i]) i = i + 1 endforeach - -foreach output : qapi_nonmodule_outputs - if output.endswith('.h') - genh += qapi_files[i] - endif - if output.endswith('.trace-events') - qapi_trace_events += qapi_files[i] - endif - specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: qapi_files[i]) - i = i + 1 -endforeach From e1a80c3241631ee0e7a687a54f71407b6d3828b7 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier Date: Thu, 22 May 2025 12:05:40 -0700 Subject: [PATCH 1217/2760] qapi: use imperative style in documentation As requested by Markus: > We prefer imperative mood "Return" over "Returns". Signed-off-by: Pierrick Bouvier Message-ID: <20250522190542.588267-14-pierrick.bouvier@linaro.org> Reviewed-by: Markus Armbruster [Change several more] --- qapi/audio.json | 2 +- qapi/block.json | 2 +- qapi/char.json | 4 ++-- qapi/control.json | 2 +- qapi/cryptodev.json | 2 +- qapi/dump.json | 2 +- qapi/machine.json | 8 ++++---- qapi/migration.json | 10 +++++----- qapi/misc-i386.json | 6 +++--- qapi/misc.json | 2 +- qapi/ui.json | 10 +++++----- qapi/virtio.json | 2 +- 12 files changed, 26 insertions(+), 26 deletions(-) diff --git a/qapi/audio.json b/qapi/audio.json index 49633cf317..8de4430578 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -533,7 +533,7 @@ ## # @query-audiodevs: # -# Returns information about audiodev configuration +# Return information about audiodev configuration # # Returns: array of @Audiodev # diff --git a/qapi/block.json b/qapi/block.json index e66666f5c6..f5374bd86c 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -83,7 +83,7 @@ ## # @query-pr-managers: # -# Returns a list of information about each persistent reservation +# Return a list of information about each persistent reservation # manager. # # Returns: a list of @PRManagerInfo for each persistent reservation diff --git a/qapi/char.json b/qapi/char.json index dde2f9538f..447c10b91a 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -34,7 +34,7 @@ ## # @query-chardev: # -# Returns information about current character devices. +# Return information about current character devices. # # Returns: a list of @ChardevInfo # @@ -80,7 +80,7 @@ ## # @query-chardev-backends: # -# Returns information about character device backends. +# Return information about character device backends. # # Returns: a list of @ChardevBackendInfo # diff --git a/qapi/control.json b/qapi/control.json index 336386f79e..34b733f63b 100644 --- a/qapi/control.json +++ b/qapi/control.json @@ -91,7 +91,7 @@ ## # @query-version: # -# Returns the current version of QEMU. +# Return the current version of QEMU. # # Returns: A @VersionInfo object describing the current version of # QEMU. diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json index 04d0e21d20..28b97eb3da 100644 --- a/qapi/cryptodev.json +++ b/qapi/cryptodev.json @@ -94,7 +94,7 @@ ## # @query-cryptodev: # -# Returns information about current crypto devices. +# Return information about current crypto devices. # # Returns: a list of @QCryptodevInfo # diff --git a/qapi/dump.json b/qapi/dump.json index d7826c0e32..f2835c0b47 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -195,7 +195,7 @@ ## # @query-dump-guest-memory-capability: # -# Returns the available formats for dump-guest-memory +# Return the available formats for dump-guest-memory # # Returns: A @DumpGuestMemoryCapability object listing available # formats for dump-guest-memory diff --git a/qapi/machine.json b/qapi/machine.json index e6b4b2dfef..5373e1368c 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -99,7 +99,7 @@ ## # @query-cpus-fast: # -# Returns information about all virtual CPUs. +# Return information about all virtual CPUs. # # Returns: list of @CpuInfoFast # @@ -467,7 +467,7 @@ ## # @query-kvm: # -# Returns information about KVM acceleration +# Return information about KVM acceleration # # Returns: @KvmInfo # @@ -930,7 +930,7 @@ ## # @query-memdev: # -# Returns information for all memory backends. +# Return information for all memory backends. # # Returns: a list of @Memdev. # @@ -1235,7 +1235,7 @@ ## # @query-hv-balloon-status-report: # -# Returns the hv-balloon driver data contained in the last received +# Return the hv-balloon driver data contained in the last received # "STATUS" message from the guest. # # Returns: diff --git a/qapi/migration.json b/qapi/migration.json index 8b9c53595c..ce8d1663d8 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -282,7 +282,7 @@ ## # @query-migrate: # -# Returns information about current migration process. If migration +# Return information about current migration process. If migration # is active there will be another json-object with RAM migration # status. # @@ -535,7 +535,7 @@ ## # @query-migrate-capabilities: # -# Returns information about the current migration capabilities status +# Return information about the current migration capabilities status # # Returns: @MigrationCapabilityStatus # @@ -1320,7 +1320,7 @@ ## # @query-migrate-parameters: # -# Returns information about the current migration parameters +# Return information about the current migration parameters # # Returns: @MigrationParameters # @@ -2294,7 +2294,7 @@ ## # @query-vcpu-dirty-limit: # -# Returns information about virtual CPU dirty page rate limits, if +# Return information about virtual CPU dirty page rate limits, if # any. # # Since: 7.1 @@ -2327,7 +2327,7 @@ ## # @query-migrationthreads: # -# Returns information of migration threads +# Return information of migration threads # # Features: # diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json index 3f88a5b28e..3b5346425a 100644 --- a/qapi/misc-i386.json +++ b/qapi/misc-i386.json @@ -126,7 +126,7 @@ ## # @query-sev: # -# Returns information about SEV/SEV-ES/SEV-SNP. +# Return information about SEV/SEV-ES/SEV-SNP. # # If unavailable due to an incompatible configuration the returned # @enabled field is set to 'false' and the state of all other fields @@ -343,7 +343,7 @@ ## # @query-sgx: # -# Returns information about configured SGX capabilities of guest +# Return information about configured SGX capabilities of guest # # Returns: @SgxInfo # @@ -362,7 +362,7 @@ ## # @query-sgx-capabilities: # -# Returns information about SGX capabilities of host +# Return information about SGX capabilities of host # # Returns: @SgxInfo # diff --git a/qapi/misc.json b/qapi/misc.json index 559b66f201..dcf9f7df5b 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -101,7 +101,7 @@ ## # @query-iothreads: # -# Returns a list of information about each iothread. +# Return a list of information about each iothread. # # .. note:: This list excludes the QEMU main loop thread, which is not # declared using the ``-object iothread`` command-line option. It diff --git a/qapi/ui.json b/qapi/ui.json index c536d4e524..3d0c853c9a 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -323,7 +323,7 @@ ## # @query-spice: # -# Returns information about the current SPICE server +# Return information about the current SPICE server # # Returns: @SpiceInfo # @@ -654,7 +654,7 @@ ## # @query-vnc: # -# Returns information about the current VNC server +# Return information about the current VNC server # # Returns: @VncInfo # @@ -685,7 +685,7 @@ ## # @query-vnc-servers: # -# Returns a list of vnc servers. The list can be empty. +# Return a list of vnc servers. The list can be empty. # # Returns: a list of @VncInfo2 # @@ -820,7 +820,7 @@ ## # @query-mice: # -# Returns information about each active mouse device +# Return information about each active mouse device # # Returns: a list of @MouseInfo for each device # @@ -1562,7 +1562,7 @@ ## # @query-display-options: # -# Returns information about display configuration +# Return information about display configuration # # Returns: @DisplayOptions # diff --git a/qapi/virtio.json b/qapi/virtio.json index d351d2166e..73df718a26 100644 --- a/qapi/virtio.json +++ b/qapi/virtio.json @@ -24,7 +24,7 @@ ## # @x-query-virtio: # -# Returns a list of all realized VirtIODevices +# Return a list of all realized VirtIODevices # # Features: # From 5150004ccf5fe72c35b3263fbed6f4d06ed3cc6a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 28 May 2025 11:20:13 +0200 Subject: [PATCH 1218/2760] rocker: do not pollute the namespace Do not leave the __le* macros defined, in fact do not use them at all. Fixes a build failure on Alpine with the TDX patches: In file included from ../hw/net/rocker/rocker_of_dpa.c:25: ../hw/net/rocker/rocker_hw.h:14:16: error: conflicting types for 'uint64_t'; have '__u64' {aka 'long long unsigned int'} 14 | #define __le64 uint64_t | ^~~~~~~~ In file included from /usr/include/stdint.h:20, from ../include/qemu/osdep.h:111, from ../hw/net/rocker/rocker_of_dpa.c:17: /usr/include/bits/alltypes.h:136:25: note: previous declaration of 'uint64_t' with type 'uint64_t' {aka 'long unsigned int'} 136 | typedef unsigned _Int64 uint64_t; | ^~~~~~~~ because the Linux headers include a typedef of __leNN. Signed-off-by: Paolo Bonzini --- hw/net/rocker/rocker.h | 14 +++--------- hw/net/rocker/rocker_hw.h | 20 +++++++----------- hw/net/rocker/rocker_of_dpa.c | 40 +++++++++++++++++------------------ 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/hw/net/rocker/rocker.h b/hw/net/rocker/rocker.h index 6e0962f47a..ae06c1c72a 100644 --- a/hw/net/rocker/rocker.h +++ b/hw/net/rocker/rocker.h @@ -36,15 +36,7 @@ static inline G_GNUC_PRINTF(1, 2) int DPRINTF(const char *fmt, ...) } #endif -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - -#define __be16 uint16_t -#define __be32 uint32_t -#define __be64 uint64_t - -static inline bool ipv4_addr_is_multicast(__be32 addr) +static inline bool ipv4_addr_is_multicast(uint32_t addr) { return (addr & htonl(0xf0000000)) == htonl(0xe0000000); } @@ -52,8 +44,8 @@ static inline bool ipv4_addr_is_multicast(__be32 addr) typedef struct ipv6_addr { union { uint8_t addr8[16]; - __be16 addr16[8]; - __be32 addr32[4]; + uint16_t addr16[8]; + uint32_t addr32[4]; }; } Ipv6Addr; diff --git a/hw/net/rocker/rocker_hw.h b/hw/net/rocker/rocker_hw.h index 1786323fa4..7ec6bfbcb9 100644 --- a/hw/net/rocker/rocker_hw.h +++ b/hw/net/rocker/rocker_hw.h @@ -9,10 +9,6 @@ #ifndef ROCKER_HW_H #define ROCKER_HW_H -#define __le16 uint16_t -#define __le32 uint32_t -#define __le64 uint64_t - /* * Return codes */ @@ -124,12 +120,12 @@ enum { */ typedef struct rocker_desc { - __le64 buf_addr; + uint64_t buf_addr; uint64_t cookie; - __le16 buf_size; - __le16 tlv_size; - __le16 rsvd[5]; /* pad to 32 bytes */ - __le16 comp_err; + uint16_t buf_size; + uint16_t tlv_size; + uint16_t rsvd[5]; /* pad to 32 bytes */ + uint16_t comp_err; } __attribute__((packed, aligned(8))) RockerDesc; /* @@ -137,9 +133,9 @@ typedef struct rocker_desc { */ typedef struct rocker_tlv { - __le32 type; - __le16 len; - __le16 rsvd; + uint32_t type; + uint16_t len; + uint16_t rsvd; } __attribute__((packed, aligned(8))) RockerTlv; /* cmd msg */ diff --git a/hw/net/rocker/rocker_of_dpa.c b/hw/net/rocker/rocker_of_dpa.c index 3378f63110..4aed178756 100644 --- a/hw/net/rocker/rocker_of_dpa.c +++ b/hw/net/rocker/rocker_of_dpa.c @@ -52,10 +52,10 @@ typedef struct of_dpa_flow_key { uint32_t tunnel_id; /* overlay tunnel id */ uint32_t tbl_id; /* table id */ struct { - __be16 vlan_id; /* 0 if no VLAN */ + uint16_t vlan_id; /* 0 if no VLAN */ MACAddr src; /* ethernet source address */ MACAddr dst; /* ethernet destination address */ - __be16 type; /* ethernet frame type */ + uint16_t type; /* ethernet frame type */ } eth; struct { uint8_t proto; /* IP protocol or ARP opcode */ @@ -66,14 +66,14 @@ typedef struct of_dpa_flow_key { union { struct { struct { - __be32 src; /* IP source address */ - __be32 dst; /* IP destination address */ + uint32_t src; /* IP source address */ + uint32_t dst; /* IP destination address */ } addr; union { struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ + uint16_t src; /* TCP/UDP/SCTP source port */ + uint16_t dst; /* TCP/UDP/SCTP destination port */ + uint16_t flags; /* TCP flags */ } tp; struct { MACAddr sha; /* ARP source hardware address */ @@ -86,11 +86,11 @@ typedef struct of_dpa_flow_key { Ipv6Addr src; /* IPv6 source address */ Ipv6Addr dst; /* IPv6 destination address */ } addr; - __be32 label; /* IPv6 flow label */ + uint32_t label; /* IPv6 flow label */ struct { - __be16 src; /* TCP/UDP/SCTP source port */ - __be16 dst; /* TCP/UDP/SCTP destination port */ - __be16 flags; /* TCP flags */ + uint16_t src; /* TCP/UDP/SCTP source port */ + uint16_t dst; /* TCP/UDP/SCTP destination port */ + uint16_t flags; /* TCP flags */ } tp; struct { Ipv6Addr target; /* ND target address */ @@ -112,13 +112,13 @@ typedef struct of_dpa_flow_action { struct { uint32_t group_id; uint32_t tun_log_lport; - __be16 vlan_id; + uint16_t vlan_id; } write; struct { - __be16 new_vlan_id; + uint16_t new_vlan_id; uint32_t out_pport; uint8_t copy_to_cpu; - __be16 vlan_id; + uint16_t vlan_id; } apply; } OfDpaFlowAction; @@ -143,7 +143,7 @@ typedef struct of_dpa_flow { typedef struct of_dpa_flow_pkt_fields { uint32_t tunnel_id; struct eth_header *ethhdr; - __be16 *h_proto; + uint16_t *h_proto; struct vlan_header *vlanhdr; struct ip_header *ipv4hdr; struct ip6_header *ipv6hdr; @@ -180,7 +180,7 @@ typedef struct of_dpa_group { uint32_t group_id; MACAddr src_mac; MACAddr dst_mac; - __be16 vlan_id; + uint16_t vlan_id; } l2_rewrite; struct { uint16_t group_count; @@ -190,13 +190,13 @@ typedef struct of_dpa_group { uint32_t group_id; MACAddr src_mac; MACAddr dst_mac; - __be16 vlan_id; + uint16_t vlan_id; uint8_t ttl_check; } l3_unicast; }; } OfDpaGroup; -static int of_dpa_mask2prefix(__be32 mask) +static int of_dpa_mask2prefix(uint32_t mask) { int i; int count = 32; @@ -451,7 +451,7 @@ static void of_dpa_flow_pkt_parse(OfDpaFlowContext *fc, fc->iovcnt = iovcnt + 2; } -static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, __be16 vlan_id) +static void of_dpa_flow_pkt_insert_vlan(OfDpaFlowContext *fc, uint16_t vlan_id) { OfDpaFlowPktFields *fields = &fc->fields; uint16_t h_proto = fields->ethhdr->h_proto; @@ -486,7 +486,7 @@ static void of_dpa_flow_pkt_strip_vlan(OfDpaFlowContext *fc) static void of_dpa_flow_pkt_hdr_rewrite(OfDpaFlowContext *fc, uint8_t *src_mac, uint8_t *dst_mac, - __be16 vlan_id) + uint16_t vlan_id) { OfDpaFlowPktFields *fields = &fc->fields; From 756e12e791771034ac105a5d2c9887bbbb6b7c73 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:08 -0400 Subject: [PATCH 1219/2760] i386: Introduce tdx-guest object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce tdx-guest object which inherits X86_CONFIDENTIAL_GUEST, and will be used to create TDX VMs (TDs) by qemu -machine ...,confidential-guest-support=tdx0 \ -object tdx-guest,id=tdx0 It has one QAPI member 'attributes' defined, which allows user to set TD's attributes directly. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-3-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- configs/devices/i386-softmmu/default.mak | 1 + hw/i386/Kconfig | 5 +++ qapi/qom.json | 15 +++++++++ target/i386/kvm/meson.build | 2 ++ target/i386/kvm/tdx.c | 43 ++++++++++++++++++++++++ target/i386/kvm/tdx.h | 21 ++++++++++++ 6 files changed, 87 insertions(+) create mode 100644 target/i386/kvm/tdx.c create mode 100644 target/i386/kvm/tdx.h diff --git a/configs/devices/i386-softmmu/default.mak b/configs/devices/i386-softmmu/default.mak index 4faf2f0315..bc0479a7e0 100644 --- a/configs/devices/i386-softmmu/default.mak +++ b/configs/devices/i386-softmmu/default.mak @@ -18,6 +18,7 @@ #CONFIG_QXL=n #CONFIG_SEV=n #CONFIG_SGA=n +#CONFIG_TDX=n #CONFIG_TEST_DEVICES=n #CONFIG_TPM_CRB=n #CONFIG_TPM_TIS_ISA=n diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index d34ce07b21..cce9521ba9 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -10,6 +10,10 @@ config SGX bool depends on KVM +config TDX + bool + depends on KVM + config PC bool imply APPLESMC @@ -26,6 +30,7 @@ config PC imply QXL imply SEV imply SGX + imply TDX imply TEST_DEVICES imply TPM_CRB imply TPM_TIS_ISA diff --git a/qapi/qom.json b/qapi/qom.json index 04c118e4d6..3d7e11efc3 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1047,6 +1047,19 @@ '*host-data': 'str', '*vcek-disabled': 'bool' } } +## +# @TdxGuestProperties: +# +# Properties for tdx-guest objects. +# +# @attributes: The 'attributes' of a TD guest that is passed to +# KVM_TDX_INIT_VM +# +# Since: 10.1 +## +{ 'struct': 'TdxGuestProperties', + 'data': { '*attributes': 'uint64' } } + ## # @ThreadContextProperties: # @@ -1132,6 +1145,7 @@ 'sev-snp-guest', 'thread-context', 's390-pv-guest', + 'tdx-guest', 'throttle-group', 'tls-creds-anon', 'tls-creds-psk', @@ -1204,6 +1218,7 @@ 'if': 'CONFIG_SECRET_KEYRING' }, 'sev-guest': 'SevGuestProperties', 'sev-snp-guest': 'SevSnpGuestProperties', + 'tdx-guest': 'TdxGuestProperties', 'thread-context': 'ThreadContextProperties', 'throttle-group': 'ThrottleGroupProperties', 'tls-creds-anon': 'TlsCredsAnonProperties', diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index 3996cafaf2..466bccb9cb 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -8,6 +8,8 @@ i386_kvm_ss.add(files( i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) +i386_kvm_ss.add(when: 'CONFIG_TDX', if_true: files('tdx.c')) + i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) i386_system_ss.add_all(when: 'CONFIG_KVM', if_true: i386_kvm_ss) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c new file mode 100644 index 0000000000..ab70566c7d --- /dev/null +++ b/target/i386/kvm/tdx.c @@ -0,0 +1,43 @@ +/* + * QEMU TDX support + * + * Copyright (c) 2025 Intel Corporation + * + * Author: + * Xiaoyao Li + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qom/object_interfaces.h" + +#include "tdx.h" + +/* tdx guest */ +OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest, + tdx_guest, + TDX_GUEST, + X86_CONFIDENTIAL_GUEST, + { TYPE_USER_CREATABLE }, + { NULL }) + +static void tdx_guest_init(Object *obj) +{ + ConfidentialGuestSupport *cgs = CONFIDENTIAL_GUEST_SUPPORT(obj); + TdxGuest *tdx = TDX_GUEST(obj); + + cgs->require_guest_memfd = true; + tdx->attributes = 0; + + object_property_add_uint64_ptr(obj, "attributes", &tdx->attributes, + OBJ_PROP_FLAG_READWRITE); +} + +static void tdx_guest_finalize(Object *obj) +{ +} + +static void tdx_guest_class_init(ObjectClass *oc, const void *data) +{ +} diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h new file mode 100644 index 0000000000..f3b7253361 --- /dev/null +++ b/target/i386/kvm/tdx.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef QEMU_I386_TDX_H +#define QEMU_I386_TDX_H + +#include "confidential-guest.h" + +#define TYPE_TDX_GUEST "tdx-guest" +#define TDX_GUEST(obj) OBJECT_CHECK(TdxGuest, (obj), TYPE_TDX_GUEST) + +typedef struct TdxGuestClass { + X86ConfidentialGuestClass parent_class; +} TdxGuestClass; + +typedef struct TdxGuest { + X86ConfidentialGuest parent_obj; + + uint64_t attributes; /* TD attributes */ +} TdxGuest; + +#endif /* QEMU_I386_TDX_H */ From b455880e5515a9fc2b923bfc6c60bb54519b51d3 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:09 -0400 Subject: [PATCH 1220/2760] i386/tdx: Implement tdx_kvm_type() for TDX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDX VM requires VM type to be KVM_X86_TDX_VM. Implement tdx_kvm_type() as X86ConfidentialGuestClass->kvm_type. Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-4-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 1 + target/i386/kvm/tdx.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index c9a3c02e3e..653a8f46c2 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -192,6 +192,7 @@ static const char *vm_type_name[] = { [KVM_X86_SEV_VM] = "SEV", [KVM_X86_SEV_ES_VM] = "SEV-ES", [KVM_X86_SNP_VM] = "SEV-SNP", + [KVM_X86_TDX_VM] = "TDX", }; bool kvm_is_vm_type_supported(int type) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index ab70566c7d..21a4f87756 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -12,8 +12,17 @@ #include "qemu/osdep.h" #include "qom/object_interfaces.h" +#include "kvm_i386.h" #include "tdx.h" +static int tdx_kvm_type(X86ConfidentialGuest *cg) +{ + /* Do the object check */ + TDX_GUEST(cg); + + return KVM_X86_TDX_VM; +} + /* tdx guest */ OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest, tdx_guest, @@ -40,4 +49,7 @@ static void tdx_guest_finalize(Object *obj) static void tdx_guest_class_init(ObjectClass *oc, const void *data) { + X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc); + + x86_klass->kvm_type = tdx_kvm_type; } From 631a2ac5a4beab740b342367550562cd659b4c4a Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:10 -0400 Subject: [PATCH 1221/2760] i386/tdx: Implement tdx_kvm_init() to initialize TDX VM context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement TDX specific ConfidentialGuestSupportClass::kvm_init() callback, tdx_kvm_init(). Mark guest state is proctected for TDX VM. More TDX specific initialization will be added later. Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-5-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 11 +---------- target/i386/kvm/tdx.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 653a8f46c2..d29376c599 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3207,16 +3207,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) Error *local_err = NULL; /* - * Initialize SEV context, if required - * - * If no memory encryption is requested (ms->cgs == NULL) this is - * a no-op. - * - * It's also a no-op if a non-SEV confidential guest support - * mechanism is selected. SEV is the only mechanism available to - * select on x86 at present, so this doesn't arise, but if new - * mechanisms are supported in future (e.g. TDX), they'll need - * their own initialization either here or elsewhere. + * Initialize confidential guest (SEV/TDX) context, if required */ if (ms->cgs) { ret = confidential_guest_kvm_init(ms->cgs, &local_err); diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 21a4f87756..2b060fb52b 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -12,9 +12,17 @@ #include "qemu/osdep.h" #include "qom/object_interfaces.h" +#include "hw/i386/x86.h" #include "kvm_i386.h" #include "tdx.h" +static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) +{ + kvm_mark_guest_state_protected(); + + return 0; +} + static int tdx_kvm_type(X86ConfidentialGuest *cg) { /* Do the object check */ @@ -49,7 +57,9 @@ static void tdx_guest_finalize(Object *obj) static void tdx_guest_class_init(ObjectClass *oc, const void *data) { + ConfidentialGuestSupportClass *klass = CONFIDENTIAL_GUEST_SUPPORT_CLASS(oc); X86ConfidentialGuestClass *x86_klass = X86_CONFIDENTIAL_GUEST_CLASS(oc); + klass->kvm_init = tdx_kvm_init; x86_klass->kvm_type = tdx_kvm_type; } From 8eddedc3701d2190db976a05155a8263c8ec175b Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:11 -0400 Subject: [PATCH 1222/2760] i386/tdx: Get tdx_capabilities via KVM_TDX_CAPABILITIES KVM provides TDX capabilities via sub command KVM_TDX_CAPABILITIES of IOCTL(KVM_MEMORY_ENCRYPT_OP). Get the capabilities when initializing TDX context. It will be used to validate user's setting later. Since there is no interface reporting how many cpuid configs contains in KVM_TDX_CAPABILITIES, QEMU chooses to try starting with a known number and abort when it exceeds KVM_MAX_CPUID_ENTRIES. Besides, introduce the interfaces to invoke TDX "ioctls" at VCPU scope in preparation. Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250508150002.689633-6-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 2 - target/i386/kvm/kvm_i386.h | 2 + target/i386/kvm/tdx.c | 109 ++++++++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index d29376c599..6d88495d47 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1780,8 +1780,6 @@ static int hyperv_init_vcpu(X86CPU *cpu) static Error *invtsc_mig_blocker; -#define KVM_MAX_CPUID_ENTRIES 100 - static void kvm_init_xsave(CPUX86State *env) { if (has_xsave2) { diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 88565e8dba..ed1e61fb8b 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -13,6 +13,8 @@ #include "system/kvm.h" +#define KVM_MAX_CPUID_ENTRIES 100 + /* always false if !CONFIG_KVM */ #define kvm_pit_in_kernel() \ (kvm_irqchip_in_kernel() && !kvm_irqchip_is_split()) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 2b060fb52b..f8ec4fa217 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -10,19 +10,124 @@ */ #include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "qapi/error.h" #include "qom/object_interfaces.h" #include "hw/i386/x86.h" #include "kvm_i386.h" #include "tdx.h" -static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) +static struct kvm_tdx_capabilities *tdx_caps; + +enum tdx_ioctl_level { + TDX_VM_IOCTL, + TDX_VCPU_IOCTL, +}; + +static int tdx_ioctl_internal(enum tdx_ioctl_level level, void *state, + int cmd_id, __u32 flags, void *data, + Error **errp) { - kvm_mark_guest_state_protected(); + struct kvm_tdx_cmd tdx_cmd = {}; + int r; + + const char *tdx_ioctl_name[] = { + [KVM_TDX_CAPABILITIES] = "KVM_TDX_CAPABILITIES", + [KVM_TDX_INIT_VM] = "KVM_TDX_INIT_VM", + [KVM_TDX_INIT_VCPU] = "KVM_TDX_INIT_VCPU", + [KVM_TDX_INIT_MEM_REGION] = "KVM_TDX_INIT_MEM_REGION", + [KVM_TDX_FINALIZE_VM] = "KVM_TDX_FINALIZE_VM", + [KVM_TDX_GET_CPUID] = "KVM_TDX_GET_CPUID", + }; + + tdx_cmd.id = cmd_id; + tdx_cmd.flags = flags; + tdx_cmd.data = (__u64)(unsigned long)data; + + switch (level) { + case TDX_VM_IOCTL: + r = kvm_vm_ioctl(kvm_state, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd); + break; + case TDX_VCPU_IOCTL: + r = kvm_vcpu_ioctl(state, KVM_MEMORY_ENCRYPT_OP, &tdx_cmd); + break; + default: + error_setg(errp, "Invalid tdx_ioctl_level %d", level); + return -EINVAL; + } + + if (r < 0) { + error_setg_errno(errp, -r, "TDX ioctl %s failed, hw_errors: 0x%llx", + tdx_ioctl_name[cmd_id], tdx_cmd.hw_error); + } + return r; +} + +static inline int tdx_vm_ioctl(int cmd_id, __u32 flags, void *data, + Error **errp) +{ + return tdx_ioctl_internal(TDX_VM_IOCTL, NULL, cmd_id, flags, data, errp); +} + +static inline int tdx_vcpu_ioctl(CPUState *cpu, int cmd_id, __u32 flags, + void *data, Error **errp) +{ + return tdx_ioctl_internal(TDX_VCPU_IOCTL, cpu, cmd_id, flags, data, errp); +} + +static int get_tdx_capabilities(Error **errp) +{ + struct kvm_tdx_capabilities *caps; + /* 1st generation of TDX reports 6 cpuid configs */ + int nr_cpuid_configs = 6; + size_t size; + int r; + + do { + Error *local_err = NULL; + size = sizeof(struct kvm_tdx_capabilities) + + nr_cpuid_configs * sizeof(struct kvm_cpuid_entry2); + caps = g_malloc0(size); + caps->cpuid.nent = nr_cpuid_configs; + + r = tdx_vm_ioctl(KVM_TDX_CAPABILITIES, 0, caps, &local_err); + if (r == -E2BIG) { + g_free(caps); + nr_cpuid_configs *= 2; + if (nr_cpuid_configs > KVM_MAX_CPUID_ENTRIES) { + error_report("KVM TDX seems broken that number of CPUID entries" + " in kvm_tdx_capabilities exceeds limit: %d", + KVM_MAX_CPUID_ENTRIES); + error_propagate(errp, local_err); + return r; + } + error_free(local_err); + } else if (r < 0) { + g_free(caps); + error_propagate(errp, local_err); + return r; + } + } while (r == -E2BIG); + + tdx_caps = caps; return 0; } +static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) +{ + int r = 0; + + kvm_mark_guest_state_protected(); + + if (!tdx_caps) { + r = get_tdx_capabilities(errp); + } + + return r; +} + static int tdx_kvm_type(X86ConfidentialGuest *cg) { /* Do the object check */ From 1619d0e45be0d1e48a46d80963b4e77dc1b000a2 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:12 -0400 Subject: [PATCH 1223/2760] i386/tdx: Introduce is_tdx_vm() helper and cache tdx_guest object It will need special handling for TDX VMs all around the QEMU. Introduce is_tdx_vm() helper to query if it's a TDX VM. Cache tdx_guest object thus no need to cast from ms->cgs every time. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Isaku Yamahata Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-7-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 15 ++++++++++++++- target/i386/kvm/tdx.h | 10 ++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index f8ec4fa217..3750889453 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -18,8 +18,16 @@ #include "kvm_i386.h" #include "tdx.h" +static TdxGuest *tdx_guest; + static struct kvm_tdx_capabilities *tdx_caps; +/* Valid after kvm_arch_init()->confidential_guest_kvm_init()->tdx_kvm_init() */ +bool is_tdx_vm(void) +{ + return !!tdx_guest; +} + enum tdx_ioctl_level { TDX_VM_IOCTL, TDX_VCPU_IOCTL, @@ -117,15 +125,20 @@ static int get_tdx_capabilities(Error **errp) static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { + TdxGuest *tdx = TDX_GUEST(cgs); int r = 0; kvm_mark_guest_state_protected(); if (!tdx_caps) { r = get_tdx_capabilities(errp); + if (r) { + return r; + } } - return r; + tdx_guest = tdx; + return 0; } static int tdx_kvm_type(X86ConfidentialGuest *cg) diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index f3b7253361..de8ae91961 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -3,6 +3,10 @@ #ifndef QEMU_I386_TDX_H #define QEMU_I386_TDX_H +#ifndef CONFIG_USER_ONLY +#include CONFIG_DEVICES /* CONFIG_TDX */ +#endif + #include "confidential-guest.h" #define TYPE_TDX_GUEST "tdx-guest" @@ -18,4 +22,10 @@ typedef struct TdxGuest { uint64_t attributes; /* TD attributes */ } TdxGuest; +#ifdef CONFIG_TDX +bool is_tdx_vm(void); +#else +#define is_tdx_vm() 0 +#endif /* CONFIG_TDX */ + #endif /* QEMU_I386_TDX_H */ From a668268dc08f7f4d30cecd513054bb38ce48c0d6 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:13 -0400 Subject: [PATCH 1224/2760] kvm: Introduce kvm_arch_pre_create_vcpu() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce kvm_arch_pre_create_vcpu(), to perform arch-dependent work prior to create any vcpu. This is for i386 TDX because it needs call TDX_INIT_VM before creating any vcpu. The specific implementation for i386 will be added in the future patch. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-8-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 5 +++++ include/system/kvm.h | 1 + target/arm/kvm.c | 5 +++++ target/i386/kvm/kvm.c | 5 +++++ target/loongarch/kvm/kvm.c | 4 ++++ target/mips/kvm.c | 5 +++++ target/ppc/kvm.c | 5 +++++ target/riscv/kvm/kvm-cpu.c | 5 +++++ target/s390x/kvm/kvm.c | 5 +++++ 9 files changed, 40 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 278a50690c..42d239cf8f 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -545,6 +545,11 @@ int kvm_init_vcpu(CPUState *cpu, Error **errp) trace_kvm_init_vcpu(cpu->cpu_index, kvm_arch_vcpu_id(cpu)); + ret = kvm_arch_pre_create_vcpu(cpu, errp); + if (ret < 0) { + goto err; + } + ret = kvm_create_vcpu(cpu); if (ret < 0) { error_setg_errno(errp, -ret, diff --git a/include/system/kvm.h b/include/system/kvm.h index b690dda137..62ec131d4d 100644 --- a/include/system/kvm.h +++ b/include/system/kvm.h @@ -376,6 +376,7 @@ int kvm_arch_get_default_type(MachineState *ms); int kvm_arch_init(MachineState *ms, KVMState *s); +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp); int kvm_arch_init_vcpu(CPUState *cpu); int kvm_arch_destroy_vcpu(CPUState *cpu); diff --git a/target/arm/kvm.c b/target/arm/kvm.c index a2791aa866..74fda8b809 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -1846,6 +1846,11 @@ static int kvm_arm_sve_set_vls(ARMCPU *cpu) #define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { int ret; diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 6d88495d47..446f0600d4 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2051,6 +2051,11 @@ full: abort(); } +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { struct { diff --git a/target/loongarch/kvm/kvm.c b/target/loongarch/kvm/kvm.c index 1bda570482..c66bdd5302 100644 --- a/target/loongarch/kvm/kvm.c +++ b/target/loongarch/kvm/kvm.c @@ -1071,7 +1071,11 @@ static int kvm_cpu_check_pv_features(CPUState *cs, Error **errp) env->pv_features |= BIT(KVM_FEATURE_VIRT_EXTIOI); } } + return 0; +} +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ return 0; } diff --git a/target/mips/kvm.c b/target/mips/kvm.c index d67b7c1a8e..ec53acb51a 100644 --- a/target/mips/kvm.c +++ b/target/mips/kvm.c @@ -61,6 +61,11 @@ int kvm_arch_irqchip_create(KVMState *s) return 0; } +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { CPUMIPSState *env = cpu_env(cs); diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 8a957c3c7d..015658049e 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -479,6 +479,11 @@ static void kvmppc_hw_debug_points_init(CPUPPCState *cenv) } } +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { PowerPCCPU *cpu = POWERPC_CPU(cs); diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index efb41fac53..e1a04be20f 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1472,6 +1472,11 @@ static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs) return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, ®); } +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { int ret = 0; diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c index 6cd2ebc5f1..67d9a1977c 100644 --- a/target/s390x/kvm/kvm.c +++ b/target/s390x/kvm/kvm.c @@ -398,6 +398,11 @@ unsigned long kvm_arch_vcpu_id(CPUState *cpu) return cpu->cpu_index; } +int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return 0; +} + int kvm_arch_init_vcpu(CPUState *cs) { unsigned int max_cpus = MACHINE(qdev_get_machine())->smp.max_cpus; From f15898b0f50609d66465326221aa54b6699da674 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:14 -0400 Subject: [PATCH 1225/2760] i386/tdx: Initialize TDX before creating TD vcpus Invoke KVM_TDX_INIT_VM in kvm_arch_pre_create_vcpu() that KVM_TDX_INIT_VM configures global TD configurations, e.g. the canonical CPUID config, and must be executed prior to creating vCPUs. Use kvm_x86_arch_cpuid() to setup the CPUID settings for TDX VM. Note, this doesn't address the fact that QEMU may change the CPUID configuration when creating vCPUs, i.e. punts on refactoring QEMU to provide a stable CPUID config prior to kvm_arch_init(). Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Acked-by: Markus Armbruster Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-9-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 16 +++--- target/i386/kvm/kvm_i386.h | 5 ++ target/i386/kvm/meson.build | 2 +- target/i386/kvm/tdx-stub.c | 10 ++++ target/i386/kvm/tdx.c | 105 ++++++++++++++++++++++++++++++++++++ target/i386/kvm/tdx.h | 6 +++ 6 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 target/i386/kvm/tdx-stub.c diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 446f0600d4..e98f1ee26a 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -38,6 +38,7 @@ #include "kvm_i386.h" #include "../confidential-guest.h" #include "sev.h" +#include "tdx.h" #include "xen-emu.h" #include "hyperv.h" #include "hyperv-proto.h" @@ -415,9 +416,9 @@ static uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg) /* Find matching entry for function/index on kvm_cpuid2 struct */ -static struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid, - uint32_t function, - uint32_t index) +struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid, + uint32_t function, + uint32_t index) { int i; for (i = 0; i < cpuid->nent; ++i) { @@ -1822,9 +1823,8 @@ static void kvm_init_nested_state(CPUX86State *env) } } -static uint32_t kvm_x86_build_cpuid(CPUX86State *env, - struct kvm_cpuid_entry2 *entries, - uint32_t cpuid_i) +uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, + uint32_t cpuid_i) { uint32_t limit, i, j; uint32_t unused; @@ -2053,6 +2053,10 @@ full: int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) { + if (is_tdx_vm()) { + return tdx_pre_create_vcpu(cpu, errp); + } + return 0; } diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index ed1e61fb8b..dc696cb723 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -59,6 +59,11 @@ uint64_t kvm_swizzle_msi_ext_dest_id(uint64_t address); void kvm_update_msi_routes_all(void *private, bool global, uint32_t index, uint32_t mask); +struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid, + uint32_t function, + uint32_t index); +uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, + uint32_t cpuid_i); #endif /* CONFIG_KVM */ void kvm_pc_setup_irq_routing(bool pci_enabled); diff --git a/target/i386/kvm/meson.build b/target/i386/kvm/meson.build index 466bccb9cb..3f44cdedb7 100644 --- a/target/i386/kvm/meson.build +++ b/target/i386/kvm/meson.build @@ -8,7 +8,7 @@ i386_kvm_ss.add(files( i386_kvm_ss.add(when: 'CONFIG_XEN_EMU', if_true: files('xen-emu.c')) -i386_kvm_ss.add(when: 'CONFIG_TDX', if_true: files('tdx.c')) +i386_kvm_ss.add(when: 'CONFIG_TDX', if_true: files('tdx.c'), if_false: files('tdx-stub.c')) i386_system_ss.add(when: 'CONFIG_HYPERV', if_true: files('hyperv.c'), if_false: files('hyperv-stub.c')) diff --git a/target/i386/kvm/tdx-stub.c b/target/i386/kvm/tdx-stub.c new file mode 100644 index 0000000000..2344433594 --- /dev/null +++ b/target/i386/kvm/tdx-stub.c @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "qemu/osdep.h" + +#include "tdx.h" + +int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + return -EINVAL; +} diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 3750889453..2d2d48c083 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -149,6 +149,109 @@ static int tdx_kvm_type(X86ConfidentialGuest *cg) return KVM_X86_TDX_VM; } +static int setup_td_xfam(X86CPU *x86cpu, Error **errp) +{ + CPUX86State *env = &x86cpu->env; + uint64_t xfam; + + xfam = env->features[FEAT_XSAVE_XCR0_LO] | + env->features[FEAT_XSAVE_XCR0_HI] | + env->features[FEAT_XSAVE_XSS_LO] | + env->features[FEAT_XSAVE_XSS_HI]; + + if (xfam & ~tdx_caps->supported_xfam) { + error_setg(errp, "Invalid XFAM 0x%lx for TDX VM (supported: 0x%llx))", + xfam, tdx_caps->supported_xfam); + return -1; + } + + tdx_guest->xfam = xfam; + return 0; +} + +static void tdx_filter_cpuid(struct kvm_cpuid2 *cpuids) +{ + int i, dest_cnt = 0; + struct kvm_cpuid_entry2 *src, *dest, *conf; + + for (i = 0; i < cpuids->nent; i++) { + src = cpuids->entries + i; + conf = cpuid_find_entry(&tdx_caps->cpuid, src->function, src->index); + if (!conf) { + continue; + } + dest = cpuids->entries + dest_cnt; + + dest->function = src->function; + dest->index = src->index; + dest->flags = src->flags; + dest->eax = src->eax & conf->eax; + dest->ebx = src->ebx & conf->ebx; + dest->ecx = src->ecx & conf->ecx; + dest->edx = src->edx & conf->edx; + + dest_cnt++; + } + cpuids->nent = dest_cnt++; +} + +int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) +{ + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + g_autofree struct kvm_tdx_init_vm *init_vm = NULL; + Error *local_err = NULL; + int retry = 10000; + int r = 0; + + QEMU_LOCK_GUARD(&tdx_guest->lock); + if (tdx_guest->initialized) { + return r; + } + + init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) + + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); + + r = setup_td_xfam(x86cpu, errp); + if (r) { + return r; + } + + init_vm->cpuid.nent = kvm_x86_build_cpuid(env, init_vm->cpuid.entries, 0); + tdx_filter_cpuid(&init_vm->cpuid); + + init_vm->attributes = tdx_guest->attributes; + init_vm->xfam = tdx_guest->xfam; + + /* + * KVM_TDX_INIT_VM gets -EAGAIN when KVM side SEAMCALL(TDH_MNG_CREATE) + * gets TDX_RND_NO_ENTROPY due to Random number generation (e.g., RDRAND or + * RDSEED) is busy. + * + * Retry for the case. + */ + do { + error_free(local_err); + local_err = NULL; + r = tdx_vm_ioctl(KVM_TDX_INIT_VM, 0, init_vm, &local_err); + } while (r == -EAGAIN && --retry); + + if (r < 0) { + if (!retry) { + error_append_hint(&local_err, "Hardware RNG (Random Number " + "Generator) is busy occupied by someone (via RDRAND/RDSEED) " + "maliciously, which leads to KVM_TDX_INIT_VM keeping failure " + "due to lack of entropy.\n"); + } + error_propagate(errp, local_err); + return r; + } + + tdx_guest->initialized = true; + + return 0; +} + /* tdx guest */ OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest, tdx_guest, @@ -162,6 +265,8 @@ static void tdx_guest_init(Object *obj) ConfidentialGuestSupport *cgs = CONFIDENTIAL_GUEST_SUPPORT(obj); TdxGuest *tdx = TDX_GUEST(obj); + qemu_mutex_init(&tdx->lock); + cgs->require_guest_memfd = true; tdx->attributes = 0; diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index de8ae91961..4e2b5c61ff 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -19,7 +19,11 @@ typedef struct TdxGuestClass { typedef struct TdxGuest { X86ConfidentialGuest parent_obj; + QemuMutex lock; + + bool initialized; uint64_t attributes; /* TD attributes */ + uint64_t xfam; } TdxGuest; #ifdef CONFIG_TDX @@ -28,4 +32,6 @@ bool is_tdx_vm(void); #define is_tdx_vm() 0 #endif /* CONFIG_TDX */ +int tdx_pre_create_vcpu(CPUState *cpu, Error **errp); + #endif /* QEMU_I386_TDX_H */ From 6016e2972d94c90307b6caf55a8e3aee5424c09b Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:15 -0400 Subject: [PATCH 1226/2760] i386/tdx: Add property sept-ve-disable for tdx-guest object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bit 28 of TD attribute, named SEPT_VE_DISABLE. When set to 1, it disables EPT violation conversion to #VE on guest TD access of PENDING pages. Some guest OS (e.g., Linux TD guest) may require this bit as 1. Otherwise refuse to boot. Add sept-ve-disable property for tdx-guest object, for user to configure this bit. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Acked-by: Markus Armbruster Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-10-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- qapi/qom.json | 8 +++++++- target/i386/kvm/tdx.c | 23 +++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index 3d7e11efc3..5a88d36423 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1055,10 +1055,16 @@ # @attributes: The 'attributes' of a TD guest that is passed to # KVM_TDX_INIT_VM # +# @sept-ve-disable: toggle bit 28 of TD attributes to control disabling +# of EPT violation conversion to #VE on guest TD access of PENDING +# pages. Some guest OS (e.g., Linux TD guest) may require this to +# be set, otherwise they refuse to boot. +# # Since: 10.1 ## { 'struct': 'TdxGuestProperties', - 'data': { '*attributes': 'uint64' } } + 'data': { '*attributes': 'uint64', + '*sept-ve-disable': 'bool' } } ## # @ThreadContextProperties: diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 2d2d48c083..32ba3982ff 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -18,6 +18,8 @@ #include "kvm_i386.h" #include "tdx.h" +#define TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE BIT_ULL(28) + static TdxGuest *tdx_guest; static struct kvm_tdx_capabilities *tdx_caps; @@ -252,6 +254,24 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) return 0; } +static bool tdx_guest_get_sept_ve_disable(Object *obj, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + return !!(tdx->attributes & TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE); +} + +static void tdx_guest_set_sept_ve_disable(Object *obj, bool value, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + if (value) { + tdx->attributes |= TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE; + } else { + tdx->attributes &= ~TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE; + } +} + /* tdx guest */ OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest, tdx_guest, @@ -272,6 +292,9 @@ static void tdx_guest_init(Object *obj) object_property_add_uint64_ptr(obj, "attributes", &tdx->attributes, OBJ_PROP_FLAG_READWRITE); + object_property_add_bool(obj, "sept-ve-disable", + tdx_guest_get_sept_ve_disable, + tdx_guest_set_sept_ve_disable); } static void tdx_guest_finalize(Object *obj) From 714af52276e74a1829674d180ef26ecb6261834c Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 8 May 2025 10:59:16 -0400 Subject: [PATCH 1227/2760] i386/tdx: Make sept_ve_disable set by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For TDX KVM use case, Linux guest is the most major one. It requires sept_ve_disable set. Make it default for the main use case. For other use case, it can be enabled/disabled via qemu command line. Signed-off-by: Isaku Yamahata Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-11-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 32ba3982ff..a30731b1a3 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -288,7 +288,7 @@ static void tdx_guest_init(Object *obj) qemu_mutex_init(&tdx->lock); cgs->require_guest_memfd = true; - tdx->attributes = 0; + tdx->attributes = TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE; object_property_add_uint64_ptr(obj, "attributes", &tdx->attributes, OBJ_PROP_FLAG_READWRITE); From bb3be394cf80d68251e5b89e823dddc679b6e644 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:17 -0400 Subject: [PATCH 1228/2760] i386/tdx: Wire CPU features up with attributes of TD guest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For QEMU VMs, - PKS is configured via CPUID_7_0_ECX_PKS, e.g., -cpu xxx,+pks and - PMU is configured by x86cpu->enable_pmu, e.g., -cpu xxx,pmu=on While the bit 30 (PKS) and bit 63 (PERFMON) of TD's attributes are also used to configure the PKS and PERFMON/PMU of TD, reuse the existing configuration interfaces of 'cpu' for TD's attributes. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-12-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index a30731b1a3..22d66bdb14 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -19,6 +19,8 @@ #include "tdx.h" #define TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE BIT_ULL(28) +#define TDX_TD_ATTRIBUTES_PKS BIT_ULL(30) +#define TDX_TD_ATTRIBUTES_PERFMON BIT_ULL(63) static TdxGuest *tdx_guest; @@ -151,6 +153,15 @@ static int tdx_kvm_type(X86ConfidentialGuest *cg) return KVM_X86_TDX_VM; } +static void setup_td_guest_attributes(X86CPU *x86cpu) +{ + CPUX86State *env = &x86cpu->env; + + tdx_guest->attributes |= (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS) ? + TDX_TD_ATTRIBUTES_PKS : 0; + tdx_guest->attributes |= x86cpu->enable_pmu ? TDX_TD_ATTRIBUTES_PERFMON : 0; +} + static int setup_td_xfam(X86CPU *x86cpu, Error **errp) { CPUX86State *env = &x86cpu->env; @@ -214,6 +225,8 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); + setup_td_guest_attributes(x86cpu); + r = setup_td_xfam(x86cpu, errp); if (r) { return r; From 53b6f406b4f1a215fb3ec60e56ddba2e019a45ef Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:18 -0400 Subject: [PATCH 1229/2760] i386/tdx: Validate TD attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate TD attributes with tdx_caps that only supported bits are allowed by KVM. Besides, sanity check the attribute bits that have not been supported by QEMU yet. e.g., debug bit, it will be allowed in the future when debug TD support lands in QEMU. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Reviewed-by: Daniel P. Berrangé Link: https://lore.kernel.org/r/20250508150002.689633-13-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 22d66bdb14..c78a0e8b5e 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -18,10 +18,15 @@ #include "kvm_i386.h" #include "tdx.h" +#define TDX_TD_ATTRIBUTES_DEBUG BIT_ULL(0) #define TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE BIT_ULL(28) #define TDX_TD_ATTRIBUTES_PKS BIT_ULL(30) #define TDX_TD_ATTRIBUTES_PERFMON BIT_ULL(63) +#define TDX_SUPPORTED_TD_ATTRS (TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE |\ + TDX_TD_ATTRIBUTES_PKS | \ + TDX_TD_ATTRIBUTES_PERFMON) + static TdxGuest *tdx_guest; static struct kvm_tdx_capabilities *tdx_caps; @@ -153,13 +158,34 @@ static int tdx_kvm_type(X86ConfidentialGuest *cg) return KVM_X86_TDX_VM; } -static void setup_td_guest_attributes(X86CPU *x86cpu) +static int tdx_validate_attributes(TdxGuest *tdx, Error **errp) +{ + if ((tdx->attributes & ~tdx_caps->supported_attrs)) { + error_setg(errp, "Invalid attributes 0x%lx for TDX VM " + "(KVM supported: 0x%llx)", tdx->attributes, + tdx_caps->supported_attrs); + return -1; + } + + if (tdx->attributes & ~TDX_SUPPORTED_TD_ATTRS) { + error_setg(errp, "Some QEMU unsupported TD attribute bits being " + "requested: 0x%lx (QEMU supported: 0x%llx)", + tdx->attributes, TDX_SUPPORTED_TD_ATTRS); + return -1; + } + + return 0; +} + +static int setup_td_guest_attributes(X86CPU *x86cpu, Error **errp) { CPUX86State *env = &x86cpu->env; tdx_guest->attributes |= (env->features[FEAT_7_0_ECX] & CPUID_7_0_ECX_PKS) ? TDX_TD_ATTRIBUTES_PKS : 0; tdx_guest->attributes |= x86cpu->enable_pmu ? TDX_TD_ATTRIBUTES_PERFMON : 0; + + return tdx_validate_attributes(tdx_guest, errp); } static int setup_td_xfam(X86CPU *x86cpu, Error **errp) @@ -225,7 +251,10 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); - setup_td_guest_attributes(x86cpu); + r = setup_td_guest_attributes(x86cpu, errp); + if (r) { + return r; + } r = setup_td_xfam(x86cpu, errp); if (r) { From d05a0858cf876f79b57a622716fbad07f5b2ea08 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 8 May 2025 10:59:19 -0400 Subject: [PATCH 1230/2760] i386/tdx: Support user configurable mrconfigid/mrowner/mrownerconfig Three sha384 hash values, mrconfigid, mrowner and mrownerconfig, of a TD can be provided for TDX attestation. Detailed meaning of them can be found: https://lore.kernel.org/qemu-devel/31d6dbc1-f453-4cef-ab08-4813f4e0ff92@intel.com/ Allow user to specify those values via property mrconfigid, mrowner and mrownerconfig. They are all in base64 format. example -object tdx-guest, \ mrconfigid=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83v,\ mrowner=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83v,\ mrownerconfig=ASNFZ4mrze8BI0VniavN7wEjRWeJq83vASNFZ4mrze8BI0VniavN7wEjRWeJq83v Signed-off-by: Isaku Yamahata Co-developed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Acked-by: Markus Armbruster Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-14-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- qapi/qom.json | 16 +++++++- target/i386/kvm/tdx.c | 95 +++++++++++++++++++++++++++++++++++++++++++ target/i386/kvm/tdx.h | 3 ++ 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/qapi/qom.json b/qapi/qom.json index 5a88d36423..45cd47508b 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -1060,11 +1060,25 @@ # pages. Some guest OS (e.g., Linux TD guest) may require this to # be set, otherwise they refuse to boot. # +# @mrconfigid: ID for non-owner-defined configuration of the guest TD, +# e.g., run-time or OS configuration (base64 encoded SHA384 digest). +# Defaults to all zeros. +# +# @mrowner: ID for the guest TD’s owner (base64 encoded SHA384 digest). +# Defaults to all zeros. +# +# @mrownerconfig: ID for owner-defined configuration of the guest TD, +# e.g., specific to the workload rather than the run-time or OS +# (base64 encoded SHA384 digest). Defaults to all zeros. +# # Since: 10.1 ## { 'struct': 'TdxGuestProperties', 'data': { '*attributes': 'uint64', - '*sept-ve-disable': 'bool' } } + '*sept-ve-disable': 'bool', + '*mrconfigid': 'str', + '*mrowner': 'str', + '*mrownerconfig': 'str' } } ## # @ThreadContextProperties: diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index c78a0e8b5e..671f23d910 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -11,8 +11,10 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" +#include "qemu/base64.h" #include "qapi/error.h" #include "qom/object_interfaces.h" +#include "crypto/hash.h" #include "hw/i386/x86.h" #include "kvm_i386.h" @@ -240,6 +242,7 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) CPUX86State *env = &x86cpu->env; g_autofree struct kvm_tdx_init_vm *init_vm = NULL; Error *local_err = NULL; + size_t data_len; int retry = 10000; int r = 0; @@ -251,6 +254,45 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); + if (tdx_guest->mrconfigid) { + g_autofree uint8_t *data = qbase64_decode(tdx_guest->mrconfigid, + strlen(tdx_guest->mrconfigid), &data_len, errp); + if (!data) { + return -1; + } + if (data_len != QCRYPTO_HASH_DIGEST_LEN_SHA384) { + error_setg(errp, "TDX: failed to decode mrconfigid"); + return -1; + } + memcpy(init_vm->mrconfigid, data, data_len); + } + + if (tdx_guest->mrowner) { + g_autofree uint8_t *data = qbase64_decode(tdx_guest->mrowner, + strlen(tdx_guest->mrowner), &data_len, errp); + if (!data) { + return -1; + } + if (data_len != QCRYPTO_HASH_DIGEST_LEN_SHA384) { + error_setg(errp, "TDX: failed to decode mrowner"); + return -1; + } + memcpy(init_vm->mrowner, data, data_len); + } + + if (tdx_guest->mrownerconfig) { + g_autofree uint8_t *data = qbase64_decode(tdx_guest->mrownerconfig, + strlen(tdx_guest->mrownerconfig), &data_len, errp); + if (!data) { + return -1; + } + if (data_len != QCRYPTO_HASH_DIGEST_LEN_SHA384) { + error_setg(errp, "TDX: failed to decode mrownerconfig"); + return -1; + } + memcpy(init_vm->mrownerconfig, data, data_len); + } + r = setup_td_guest_attributes(x86cpu, errp); if (r) { return r; @@ -314,6 +356,51 @@ static void tdx_guest_set_sept_ve_disable(Object *obj, bool value, Error **errp) } } +static char *tdx_guest_get_mrconfigid(Object *obj, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + return g_strdup(tdx->mrconfigid); +} + +static void tdx_guest_set_mrconfigid(Object *obj, const char *value, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + g_free(tdx->mrconfigid); + tdx->mrconfigid = g_strdup(value); +} + +static char *tdx_guest_get_mrowner(Object *obj, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + return g_strdup(tdx->mrowner); +} + +static void tdx_guest_set_mrowner(Object *obj, const char *value, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + g_free(tdx->mrowner); + tdx->mrowner = g_strdup(value); +} + +static char *tdx_guest_get_mrownerconfig(Object *obj, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + return g_strdup(tdx->mrownerconfig); +} + +static void tdx_guest_set_mrownerconfig(Object *obj, const char *value, Error **errp) +{ + TdxGuest *tdx = TDX_GUEST(obj); + + g_free(tdx->mrownerconfig); + tdx->mrownerconfig = g_strdup(value); +} + /* tdx guest */ OBJECT_DEFINE_TYPE_WITH_INTERFACES(TdxGuest, tdx_guest, @@ -337,6 +424,14 @@ static void tdx_guest_init(Object *obj) object_property_add_bool(obj, "sept-ve-disable", tdx_guest_get_sept_ve_disable, tdx_guest_set_sept_ve_disable); + object_property_add_str(obj, "mrconfigid", + tdx_guest_get_mrconfigid, + tdx_guest_set_mrconfigid); + object_property_add_str(obj, "mrowner", + tdx_guest_get_mrowner, tdx_guest_set_mrowner); + object_property_add_str(obj, "mrownerconfig", + tdx_guest_get_mrownerconfig, + tdx_guest_set_mrownerconfig); } static void tdx_guest_finalize(Object *obj) diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index 4e2b5c61ff..e472b11fb0 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -24,6 +24,9 @@ typedef struct TdxGuest { bool initialized; uint64_t attributes; /* TD attributes */ uint64_t xfam; + char *mrconfigid; /* base64 encoded sha348 digest */ + char *mrowner; /* base64 encoded sha348 digest */ + char *mrownerconfig; /* base64 encoded sha348 digest */ } TdxGuest; #ifdef CONFIG_TDX From d529a2ac5ef4620173439942f78ec668f9165fc1 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:20 -0400 Subject: [PATCH 1231/2760] i386/tdx: Set APIC bus rate to match with what TDX module enforces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDX advertises core crystal clock with cpuid[0x15] as 25MHz for TD guests and it's unchangeable from VMM. As a result, TDX guest reads the APIC timer at the same frequency, 25MHz. While KVM's default emulated frequency for APIC bus is 1GHz, set the APIC bus rate to match with TDX explicitly to ensure KVM provide correct emulated APIC timer for TD guest. Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-15-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 13 +++++++++++++ target/i386/kvm/tdx.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 671f23d910..58983edd80 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -254,6 +254,19 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) init_vm = g_malloc0(sizeof(struct kvm_tdx_init_vm) + sizeof(struct kvm_cpuid_entry2) * KVM_MAX_CPUID_ENTRIES); + if (!kvm_check_extension(kvm_state, KVM_CAP_X86_APIC_BUS_CYCLES_NS)) { + error_setg(errp, "KVM doesn't support KVM_CAP_X86_APIC_BUS_CYCLES_NS"); + return -EOPNOTSUPP; + } + + r = kvm_vm_enable_cap(kvm_state, KVM_CAP_X86_APIC_BUS_CYCLES_NS, + 0, TDX_APIC_BUS_CYCLES_NS); + if (r < 0) { + error_setg_errno(errp, -r, + "Unable to set core crystal clock frequency to 25MHz"); + return r; + } + if (tdx_guest->mrconfigid) { g_autofree uint8_t *data = qbase64_decode(tdx_guest->mrconfigid, strlen(tdx_guest->mrconfigid), &data_len, errp); diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index e472b11fb0..d39e733d9f 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -16,6 +16,9 @@ typedef struct TdxGuestClass { X86ConfidentialGuestClass parent_class; } TdxGuestClass; +/* TDX requires bus frequency 25MHz */ +#define TDX_APIC_BUS_CYCLES_NS 40 + typedef struct TdxGuest { X86ConfidentialGuest parent_obj; From 0e73b843616e52882940ab89e1b0e86e22be2162 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:21 -0400 Subject: [PATCH 1232/2760] i386/tdx: Implement user specified tsc frequency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse "-cpu,tsc-frequency=" to get user wanted tsc frequency and call VM scope VM_SET_TSC_KHZ to set the tsc frequency of TD before KVM_TDX_INIT_VM. Besides, sanity check the tsc frequency to be in the legal range and legal granularity (required by TDX module). Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-16-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 9 +++++++++ target/i386/kvm/tdx.c | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index e98f1ee26a..fd1817fc5e 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -870,6 +870,15 @@ static int kvm_arch_set_tsc_khz(CPUState *cs) int r, cur_freq; bool set_ioctl = false; + /* + * TSC of TD vcpu is immutable, it cannot be set/changed via vcpu scope + * VM_SET_TSC_KHZ, but only be initialized via VM scope VM_SET_TSC_KHZ + * before ioctl KVM_TDX_INIT_VM in tdx_pre_create_vcpu() + */ + if (is_tdx_vm()) { + return 0; + } + if (!env->tsc_khz) { return 0; } diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 58983edd80..93a16a1aaa 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -20,6 +20,9 @@ #include "kvm_i386.h" #include "tdx.h" +#define TDX_MIN_TSC_FREQUENCY_KHZ (100 * 1000) +#define TDX_MAX_TSC_FREQUENCY_KHZ (10 * 1000 * 1000) + #define TDX_TD_ATTRIBUTES_DEBUG BIT_ULL(0) #define TDX_TD_ATTRIBUTES_SEPT_VE_DISABLE BIT_ULL(28) #define TDX_TD_ATTRIBUTES_PKS BIT_ULL(30) @@ -267,6 +270,28 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) return r; } + if (env->tsc_khz && (env->tsc_khz < TDX_MIN_TSC_FREQUENCY_KHZ || + env->tsc_khz > TDX_MAX_TSC_FREQUENCY_KHZ)) { + error_setg(errp, "Invalid TSC %ld KHz, must specify cpu_frequency " + "between [%d, %d] kHz", env->tsc_khz, + TDX_MIN_TSC_FREQUENCY_KHZ, TDX_MAX_TSC_FREQUENCY_KHZ); + return -EINVAL; + } + + if (env->tsc_khz % (25 * 1000)) { + error_setg(errp, "Invalid TSC %ld KHz, it must be multiple of 25MHz", + env->tsc_khz); + return -EINVAL; + } + + /* it's safe even env->tsc_khz is 0. KVM uses host's tsc_khz in this case */ + r = kvm_vm_ioctl(kvm_state, KVM_SET_TSC_KHZ, env->tsc_khz); + if (r < 0) { + error_setg_errno(errp, -r, "Unable to set TSC frequency to %ld kHz", + env->tsc_khz); + return r; + } + if (tdx_guest->mrconfigid) { g_autofree uint8_t *data = qbase64_decode(tdx_guest->mrconfigid, strlen(tdx_guest->mrconfigid), &data_len, errp); From 0dd5fe5ebeabefc7b3d7f043991b1edfe6b8eda9 Mon Sep 17 00:00:00 2001 From: Chao Peng Date: Thu, 8 May 2025 10:59:22 -0400 Subject: [PATCH 1233/2760] i386/tdx: load TDVF for TD guest TDVF(OVMF) needs to run at private memory for TD guest. TDX cannot support pflash device since it doesn't support read-only private memory. Thus load TDVF(OVMF) with -bios option for TDs. Use memory_region_init_ram_guest_memfd() to allocate the MemoryRegion for TDVF because it needs to be located at private memory. Also store the MemoryRegion pointer of TDVF since the shared ramblock of it can be discared after it gets copied to private ramblock. Signed-off-by: Chao Peng Co-developed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-17-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/x86-common.c | 6 +++++- target/i386/kvm/tdx.c | 6 ++++++ target/i386/kvm/tdx.h | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c index 1b0671c523..b1b5f11e73 100644 --- a/hw/i386/x86-common.c +++ b/hw/i386/x86-common.c @@ -44,6 +44,7 @@ #include "standard-headers/asm-x86/bootparam.h" #include CONFIG_DEVICES #include "kvm/kvm_i386.h" +#include "kvm/tdx.h" #ifdef CONFIG_XEN_EMU #include "hw/xen/xen.h" @@ -1035,11 +1036,14 @@ void x86_bios_rom_init(X86MachineState *x86ms, const char *default_firmware, if (machine_require_guest_memfd(MACHINE(x86ms))) { memory_region_init_ram_guest_memfd(&x86ms->bios, NULL, "pc.bios", bios_size, &error_fatal); + if (is_tdx_vm()) { + tdx_set_tdvf_region(&x86ms->bios); + } } else { memory_region_init_ram(&x86ms->bios, NULL, "pc.bios", bios_size, &error_fatal); } - if (sev_enabled()) { + if (sev_enabled() || is_tdx_vm()) { /* * The concept of a "reset" simply doesn't exist for * confidential computing guests, we have to destroy and diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 93a16a1aaa..0f5acbf980 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -137,6 +137,12 @@ static int get_tdx_capabilities(Error **errp) return 0; } +void tdx_set_tdvf_region(MemoryRegion *tdvf_mr) +{ + assert(!tdx_guest->tdvf_mr); + tdx_guest->tdvf_mr = tdvf_mr; +} + static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { TdxGuest *tdx = TDX_GUEST(cgs); diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index d39e733d9f..b73461b8d8 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -30,6 +30,8 @@ typedef struct TdxGuest { char *mrconfigid; /* base64 encoded sha348 digest */ char *mrowner; /* base64 encoded sha348 digest */ char *mrownerconfig; /* base64 encoded sha348 digest */ + + MemoryRegion *tdvf_mr; } TdxGuest; #ifdef CONFIG_TDX @@ -39,5 +41,6 @@ bool is_tdx_vm(void); #endif /* CONFIG_TDX */ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp); +void tdx_set_tdvf_region(MemoryRegion *tdvf_mr); #endif /* QEMU_I386_TDX_H */ From b65a6011d16c4f7cb2eb227ab1bc735850475288 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 8 May 2025 10:59:23 -0400 Subject: [PATCH 1234/2760] i386/tdvf: Introduce function to parse TDVF metadata TDX VM needs to boot with its specialized firmware, Trusted Domain Virtual Firmware (TDVF). QEMU needs to parse TDVF and map it in TD guest memory prior to running the TDX VM. A TDVF Metadata in TDVF image describes the structure of firmware. QEMU refers to it to setup memory for TDVF. Introduce function tdvf_parse_metadata() to parse the metadata from TDVF image and store the info of each TDVF section. TDX metadata is located by a TDX metadata offset block, which is a GUID-ed structure. The data portion of the GUID structure contains only an 4-byte field that is the offset of TDX metadata to the end of firmware file. Select X86_FW_OVMF when TDX is enable to leverage existing functions to parse and search OVMF's GUID-ed structures. Signed-off-by: Isaku Yamahata Co-developed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-18-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/Kconfig | 1 + hw/i386/meson.build | 1 + hw/i386/tdvf.c | 188 +++++++++++++++++++++++++++++++++++++++++ include/hw/i386/tdvf.h | 38 +++++++++ 4 files changed, 228 insertions(+) create mode 100644 hw/i386/tdvf.c create mode 100644 include/hw/i386/tdvf.h diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig index cce9521ba9..eb65bda6e0 100644 --- a/hw/i386/Kconfig +++ b/hw/i386/Kconfig @@ -12,6 +12,7 @@ config SGX config TDX bool + select X86_FW_OVMF depends on KVM config PC diff --git a/hw/i386/meson.build b/hw/i386/meson.build index 10bdfde27c..3bc1da2b6e 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -32,6 +32,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files( 'port92.c')) i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'), if_false: files('pc_sysfw_ovmf-stubs.c')) +i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c')) subdir('kvm') subdir('xen') diff --git a/hw/i386/tdvf.c b/hw/i386/tdvf.c new file mode 100644 index 0000000000..e2d486946a --- /dev/null +++ b/hw/i386/tdvf.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2025 Intel Corporation + * Author: Isaku Yamahata + * + * Xiaoyao Li + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" + +#include "hw/i386/pc.h" +#include "hw/i386/tdvf.h" +#include "system/kvm.h" + +#define TDX_METADATA_OFFSET_GUID "e47a6535-984a-4798-865e-4685a7bf8ec2" +#define TDX_METADATA_VERSION 1 +#define TDVF_SIGNATURE 0x46564454 /* TDVF as little endian */ +#define TDVF_ALIGNMENT 4096 + +/* + * the raw structs read from TDVF keeps the name convention in + * TDVF Design Guide spec. + */ +typedef struct { + uint32_t DataOffset; + uint32_t RawDataSize; + uint64_t MemoryAddress; + uint64_t MemoryDataSize; + uint32_t Type; + uint32_t Attributes; +} TdvfSectionEntry; + +typedef struct { + uint32_t Signature; + uint32_t Length; + uint32_t Version; + uint32_t NumberOfSectionEntries; + TdvfSectionEntry SectionEntries[]; +} TdvfMetadata; + +struct tdx_metadata_offset { + uint32_t offset; +}; + +static TdvfMetadata *tdvf_get_metadata(void *flash_ptr, int size) +{ + TdvfMetadata *metadata; + uint32_t offset = 0; + uint8_t *data; + + if ((uint32_t) size != size) { + return NULL; + } + + if (pc_system_ovmf_table_find(TDX_METADATA_OFFSET_GUID, &data, NULL)) { + offset = size - le32_to_cpu(((struct tdx_metadata_offset *)data)->offset); + + if (offset + sizeof(*metadata) > size) { + return NULL; + } + } else { + error_report("Cannot find TDX_METADATA_OFFSET_GUID"); + return NULL; + } + + metadata = flash_ptr + offset; + + /* Finally, verify the signature to determine if this is a TDVF image. */ + metadata->Signature = le32_to_cpu(metadata->Signature); + if (metadata->Signature != TDVF_SIGNATURE) { + error_report("Invalid TDVF signature in metadata!"); + return NULL; + } + + /* Sanity check that the TDVF doesn't overlap its own metadata. */ + metadata->Length = le32_to_cpu(metadata->Length); + if (offset + metadata->Length > size) { + return NULL; + } + + /* Only version 1 is supported/defined. */ + metadata->Version = le32_to_cpu(metadata->Version); + if (metadata->Version != TDX_METADATA_VERSION) { + return NULL; + } + + return metadata; +} + +static int tdvf_parse_and_check_section_entry(const TdvfSectionEntry *src, + TdxFirmwareEntry *entry) +{ + entry->data_offset = le32_to_cpu(src->DataOffset); + entry->data_len = le32_to_cpu(src->RawDataSize); + entry->address = le64_to_cpu(src->MemoryAddress); + entry->size = le64_to_cpu(src->MemoryDataSize); + entry->type = le32_to_cpu(src->Type); + entry->attributes = le32_to_cpu(src->Attributes); + + /* sanity check */ + if (entry->size < entry->data_len) { + error_report("Broken metadata RawDataSize 0x%x MemoryDataSize 0x%lx", + entry->data_len, entry->size); + return -1; + } + if (!QEMU_IS_ALIGNED(entry->address, TDVF_ALIGNMENT)) { + error_report("MemoryAddress 0x%lx not page aligned", entry->address); + return -1; + } + if (!QEMU_IS_ALIGNED(entry->size, TDVF_ALIGNMENT)) { + error_report("MemoryDataSize 0x%lx not page aligned", entry->size); + return -1; + } + + switch (entry->type) { + case TDVF_SECTION_TYPE_BFV: + case TDVF_SECTION_TYPE_CFV: + /* The sections that must be copied from firmware image to TD memory */ + if (entry->data_len == 0) { + error_report("%d section with RawDataSize == 0", entry->type); + return -1; + } + break; + case TDVF_SECTION_TYPE_TD_HOB: + case TDVF_SECTION_TYPE_TEMP_MEM: + /* The sections that no need to be copied from firmware image */ + if (entry->data_len != 0) { + error_report("%d section with RawDataSize 0x%x != 0", + entry->type, entry->data_len); + return -1; + } + break; + default: + error_report("TDVF contains unsupported section type %d", entry->type); + return -1; + } + + return 0; +} + +int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size) +{ + g_autofree TdvfSectionEntry *sections = NULL; + TdvfMetadata *metadata; + ssize_t entries_size; + int i; + + metadata = tdvf_get_metadata(flash_ptr, size); + if (!metadata) { + return -EINVAL; + } + + /* load and parse metadata entries */ + fw->nr_entries = le32_to_cpu(metadata->NumberOfSectionEntries); + if (fw->nr_entries < 2) { + error_report("Invalid number of fw entries (%u) in TDVF Metadata", + fw->nr_entries); + return -EINVAL; + } + + entries_size = fw->nr_entries * sizeof(TdvfSectionEntry); + if (metadata->Length != sizeof(*metadata) + entries_size) { + error_report("TDVF metadata len (0x%x) mismatch, expected (0x%x)", + metadata->Length, + (uint32_t)(sizeof(*metadata) + entries_size)); + return -EINVAL; + } + + fw->entries = g_new(TdxFirmwareEntry, fw->nr_entries); + sections = g_new(TdvfSectionEntry, fw->nr_entries); + + memcpy(sections, (void *)metadata + sizeof(*metadata), entries_size); + + for (i = 0; i < fw->nr_entries; i++) { + if (tdvf_parse_and_check_section_entry(§ions[i], &fw->entries[i])) { + goto err; + } + } + + return 0; + +err: + fw->entries = 0; + g_free(fw->entries); + return -EINVAL; +} diff --git a/include/hw/i386/tdvf.h b/include/hw/i386/tdvf.h new file mode 100644 index 0000000000..7ebcac42a3 --- /dev/null +++ b/include/hw/i386/tdvf.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2025 Intel Corporation + * Author: Isaku Yamahata + * + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_I386_TDVF_H +#define HW_I386_TDVF_H + +#include "qemu/osdep.h" + +#define TDVF_SECTION_TYPE_BFV 0 +#define TDVF_SECTION_TYPE_CFV 1 +#define TDVF_SECTION_TYPE_TD_HOB 2 +#define TDVF_SECTION_TYPE_TEMP_MEM 3 + +#define TDVF_SECTION_ATTRIBUTES_MR_EXTEND (1U << 0) +#define TDVF_SECTION_ATTRIBUTES_PAGE_AUG (1U << 1) + +typedef struct TdxFirmwareEntry { + uint32_t data_offset; + uint32_t data_len; + uint64_t address; + uint64_t size; + uint32_t type; + uint32_t attributes; +} TdxFirmwareEntry; + +typedef struct TdxFirmware { + uint32_t nr_entries; + TdxFirmwareEntry *entries; +} TdxFirmware; + +int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size); + +#endif /* HW_I386_TDVF_H */ From cb5d65a854e58abeb705a2ce14cc3eb28973c606 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:24 -0400 Subject: [PATCH 1235/2760] i386/tdx: Parse TDVF metadata for TDX VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After TDVF is loaded to bios MemoryRegion, it needs parse TDVF metadata. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-19-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/pc_sysfw.c | 7 +++++++ target/i386/kvm/tdx-stub.c | 5 +++++ target/i386/kvm/tdx.c | 5 +++++ target/i386/kvm/tdx.h | 3 +++ 4 files changed, 20 insertions(+) diff --git a/hw/i386/pc_sysfw.c b/hw/i386/pc_sysfw.c index 1eeb58ab37..821396c16e 100644 --- a/hw/i386/pc_sysfw.c +++ b/hw/i386/pc_sysfw.c @@ -37,6 +37,7 @@ #include "hw/block/flash.h" #include "system/kvm.h" #include "target/i386/sev.h" +#include "kvm/tdx.h" #define FLASH_SECTOR_SIZE 4096 @@ -280,5 +281,11 @@ void x86_firmware_configure(hwaddr gpa, void *ptr, int size) } sev_encrypt_flash(gpa, ptr, size, &error_fatal); + } else if (is_tdx_vm()) { + ret = tdx_parse_tdvf(ptr, size); + if (ret) { + error_report("failed to parse TDVF for TDX VM"); + exit(1); + } } } diff --git a/target/i386/kvm/tdx-stub.c b/target/i386/kvm/tdx-stub.c index 2344433594..7748b6d0a4 100644 --- a/target/i386/kvm/tdx-stub.c +++ b/target/i386/kvm/tdx-stub.c @@ -8,3 +8,8 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) { return -EINVAL; } + +int tdx_parse_tdvf(void *flash_ptr, int size) +{ + return -EINVAL; +} diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 0f5acbf980..18beba2f5c 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -382,6 +382,11 @@ int tdx_pre_create_vcpu(CPUState *cpu, Error **errp) return 0; } +int tdx_parse_tdvf(void *flash_ptr, int size) +{ + return tdvf_parse_metadata(&tdx_guest->tdvf, flash_ptr, size); +} + static bool tdx_guest_get_sept_ve_disable(Object *obj, Error **errp) { TdxGuest *tdx = TDX_GUEST(obj); diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index b73461b8d8..28a03c2a7b 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -8,6 +8,7 @@ #endif #include "confidential-guest.h" +#include "hw/i386/tdvf.h" #define TYPE_TDX_GUEST "tdx-guest" #define TDX_GUEST(obj) OBJECT_CHECK(TdxGuest, (obj), TYPE_TDX_GUEST) @@ -32,6 +33,7 @@ typedef struct TdxGuest { char *mrownerconfig; /* base64 encoded sha348 digest */ MemoryRegion *tdvf_mr; + TdxFirmware tdvf; } TdxGuest; #ifdef CONFIG_TDX @@ -42,5 +44,6 @@ bool is_tdx_vm(void); int tdx_pre_create_vcpu(CPUState *cpu, Error **errp); void tdx_set_tdvf_region(MemoryRegion *tdvf_mr); +int tdx_parse_tdvf(void *flash_ptr, int size); #endif /* QEMU_I386_TDX_H */ From 49b1f0f812372129736c1df0421c8f67d86d362b Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:25 -0400 Subject: [PATCH 1236/2760] i386/tdx: Don't initialize pc.rom for TDX VMs For TDX, the address below 1MB are entirely general RAM. No need to initialize pc.rom memory region for TDs. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-20-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/pc.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 70656157ca..a403987a64 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -44,6 +44,7 @@ #include "system/xen.h" #include "system/reset.h" #include "kvm/kvm_i386.h" +#include "kvm/tdx.h" #include "hw/xen/xen.h" #include "qobject/qlist.h" #include "qemu/error-report.h" @@ -976,21 +977,23 @@ void pc_memory_init(PCMachineState *pcms, /* Initialize PC system firmware */ pc_system_firmware_init(pcms, rom_memory); - option_rom_mr = g_malloc(sizeof(*option_rom_mr)); - if (machine_require_guest_memfd(machine)) { - memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom", - PC_ROM_SIZE, &error_fatal); - } else { - memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, - &error_fatal); - if (pcmc->pci_enabled) { - memory_region_set_readonly(option_rom_mr, true); + if (!is_tdx_vm()) { + option_rom_mr = g_malloc(sizeof(*option_rom_mr)); + if (machine_require_guest_memfd(machine)) { + memory_region_init_ram_guest_memfd(option_rom_mr, NULL, "pc.rom", + PC_ROM_SIZE, &error_fatal); + } else { + memory_region_init_ram(option_rom_mr, NULL, "pc.rom", PC_ROM_SIZE, + &error_fatal); + if (pcmc->pci_enabled) { + memory_region_set_readonly(option_rom_mr, true); + } } + memory_region_add_subregion_overlap(rom_memory, + PC_ROM_MIN_VGA, + option_rom_mr, + 1); } - memory_region_add_subregion_overlap(rom_memory, - PC_ROM_MIN_VGA, - option_rom_mr, - 1); fw_cfg = fw_cfg_arch_create(machine, x86ms->boot_cpus, x86ms->apic_id_limit); From 4420ba0ebbf014acc68f78669e0767e288313ed6 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:26 -0400 Subject: [PATCH 1237/2760] i386/tdx: Track mem_ptr for each firmware entry of TDVF For each TDVF sections, QEMU needs to copy the content to guest private memory via KVM API (KVM_TDX_INIT_MEM_REGION). Introduce a field @mem_ptr for TdxFirmwareEntry to track the memory pointer of each TDVF sections. So that QEMU can add/copy them to guest private memory later. TDVF sections can be classified into two groups: - Firmware itself, e.g., TDVF BFV and CFV, that located separately from guest RAM. Its memory pointer is the bios pointer. - Sections located at guest RAM, e.g., TEMP_MEM and TD_HOB. mmap a new memory range for them. Register a machine_init_done callback to do the stuff. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-21-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/tdvf.c | 1 + include/hw/i386/tdvf.h | 7 +++++++ target/i386/kvm/tdx.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/hw/i386/tdvf.c b/hw/i386/tdvf.c index e2d486946a..bd993ea2f0 100644 --- a/hw/i386/tdvf.c +++ b/hw/i386/tdvf.c @@ -179,6 +179,7 @@ int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size) } } + fw->mem_ptr = flash_ptr; return 0; err: diff --git a/include/hw/i386/tdvf.h b/include/hw/i386/tdvf.h index 7ebcac42a3..e75c8d1acc 100644 --- a/include/hw/i386/tdvf.h +++ b/include/hw/i386/tdvf.h @@ -26,13 +26,20 @@ typedef struct TdxFirmwareEntry { uint64_t size; uint32_t type; uint32_t attributes; + + void *mem_ptr; } TdxFirmwareEntry; typedef struct TdxFirmware { + void *mem_ptr; + uint32_t nr_entries; TdxFirmwareEntry *entries; } TdxFirmware; +#define for_each_tdx_fw_entry(fw, e) \ + for (e = (fw)->entries; e != (fw)->entries + (fw)->nr_entries; e++) + int tdvf_parse_metadata(TdxFirmware *fw, void *flash_ptr, int size); #endif /* HW_I386_TDVF_H */ diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 18beba2f5c..bfdae4f1c0 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -12,10 +12,13 @@ #include "qemu/osdep.h" #include "qemu/error-report.h" #include "qemu/base64.h" +#include "qemu/mmap-alloc.h" #include "qapi/error.h" #include "qom/object_interfaces.h" #include "crypto/hash.h" +#include "system/system.h" +#include "hw/i386/tdvf.h" #include "hw/i386/x86.h" #include "kvm_i386.h" #include "tdx.h" @@ -143,6 +146,38 @@ void tdx_set_tdvf_region(MemoryRegion *tdvf_mr) tdx_guest->tdvf_mr = tdvf_mr; } +static void tdx_finalize_vm(Notifier *notifier, void *unused) +{ + TdxFirmware *tdvf = &tdx_guest->tdvf; + TdxFirmwareEntry *entry; + + for_each_tdx_fw_entry(tdvf, entry) { + switch (entry->type) { + case TDVF_SECTION_TYPE_BFV: + case TDVF_SECTION_TYPE_CFV: + entry->mem_ptr = tdvf->mem_ptr + entry->data_offset; + break; + case TDVF_SECTION_TYPE_TD_HOB: + case TDVF_SECTION_TYPE_TEMP_MEM: + entry->mem_ptr = qemu_ram_mmap(-1, entry->size, + qemu_real_host_page_size(), 0, 0); + if (entry->mem_ptr == MAP_FAILED) { + error_report("Failed to mmap memory for TDVF section %d", + entry->type); + exit(1); + } + break; + default: + error_report("Unsupported TDVF section %d", entry->type); + exit(1); + } + } +} + +static Notifier tdx_machine_done_notify = { + .notify = tdx_finalize_vm, +}; + static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { TdxGuest *tdx = TDX_GUEST(cgs); @@ -157,6 +192,8 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) } } + qemu_add_machine_init_done_notifier(&tdx_machine_done_notify); + tdx_guest = tdx; return 0; } From f18672e4cf91feed4b91ef85a264a500935a2865 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:27 -0400 Subject: [PATCH 1238/2760] i386/tdx: Track RAM entries for TDX VM The RAM of TDX VM can be classified into two types: - TDX_RAM_UNACCEPTED: default type of TDX memory, which needs to be accepted by TDX guest before it can be used and will be all-zeros after being accepted. - TDX_RAM_ADDED: the RAM that is ADD'ed to TD guest before running, and can be used directly. E.g., TD HOB and TEMP MEM that needed by TDVF. Maintain TdxRamEntries[] which grabs the initial RAM info from e820 table and mark each RAM range as default type TDX_RAM_UNACCEPTED. Then turn the range of TD HOB and TEMP MEM to TDX_RAM_ADDED since these ranges will be ADD'ed before TD runs and no need to be accepted runtime. The TdxRamEntries[] are later used to setup the memory TD resource HOB that passes memory info from QEMU to TDVF. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-22-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 109 ++++++++++++++++++++++++++++++++++++++++++ target/i386/kvm/tdx.h | 14 ++++++ 2 files changed, 123 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index bfdae4f1c0..e06f5d0bd4 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -18,6 +18,7 @@ #include "crypto/hash.h" #include "system/system.h" +#include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" #include "kvm_i386.h" @@ -146,11 +147,110 @@ void tdx_set_tdvf_region(MemoryRegion *tdvf_mr) tdx_guest->tdvf_mr = tdvf_mr; } +static void tdx_add_ram_entry(uint64_t address, uint64_t length, + enum TdxRamType type) +{ + uint32_t nr_entries = tdx_guest->nr_ram_entries; + tdx_guest->ram_entries = g_renew(TdxRamEntry, tdx_guest->ram_entries, + nr_entries + 1); + + tdx_guest->ram_entries[nr_entries].address = address; + tdx_guest->ram_entries[nr_entries].length = length; + tdx_guest->ram_entries[nr_entries].type = type; + tdx_guest->nr_ram_entries++; +} + +static int tdx_accept_ram_range(uint64_t address, uint64_t length) +{ + uint64_t head_start, tail_start, head_length, tail_length; + uint64_t tmp_address, tmp_length; + TdxRamEntry *e; + int i = 0; + + do { + if (i == tdx_guest->nr_ram_entries) { + return -1; + } + + e = &tdx_guest->ram_entries[i++]; + } while (address + length <= e->address || address >= e->address + e->length); + + /* + * The to-be-accepted ram range must be fully contained by one + * RAM entry. + */ + if (e->address > address || + e->address + e->length < address + length) { + return -1; + } + + if (e->type == TDX_RAM_ADDED) { + return 0; + } + + tmp_address = e->address; + tmp_length = e->length; + + e->address = address; + e->length = length; + e->type = TDX_RAM_ADDED; + + head_length = address - tmp_address; + if (head_length > 0) { + head_start = tmp_address; + tdx_add_ram_entry(head_start, head_length, TDX_RAM_UNACCEPTED); + } + + tail_start = address + length; + if (tail_start < tmp_address + tmp_length) { + tail_length = tmp_address + tmp_length - tail_start; + tdx_add_ram_entry(tail_start, tail_length, TDX_RAM_UNACCEPTED); + } + + return 0; +} + +static int tdx_ram_entry_compare(const void *lhs_, const void* rhs_) +{ + const TdxRamEntry *lhs = lhs_; + const TdxRamEntry *rhs = rhs_; + + if (lhs->address == rhs->address) { + return 0; + } + if (le64_to_cpu(lhs->address) > le64_to_cpu(rhs->address)) { + return 1; + } + return -1; +} + +static void tdx_init_ram_entries(void) +{ + unsigned i, j, nr_e820_entries; + + nr_e820_entries = e820_get_table(NULL); + tdx_guest->ram_entries = g_new(TdxRamEntry, nr_e820_entries); + + for (i = 0, j = 0; i < nr_e820_entries; i++) { + uint64_t addr, len; + + if (e820_get_entry(i, E820_RAM, &addr, &len)) { + tdx_guest->ram_entries[j].address = addr; + tdx_guest->ram_entries[j].length = len; + tdx_guest->ram_entries[j].type = TDX_RAM_UNACCEPTED; + j++; + } + } + tdx_guest->nr_ram_entries = j; +} + static void tdx_finalize_vm(Notifier *notifier, void *unused) { TdxFirmware *tdvf = &tdx_guest->tdvf; TdxFirmwareEntry *entry; + tdx_init_ram_entries(); + for_each_tdx_fw_entry(tdvf, entry) { switch (entry->type) { case TDVF_SECTION_TYPE_BFV: @@ -166,12 +266,21 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) entry->type); exit(1); } + if (tdx_accept_ram_range(entry->address, entry->size)) { + error_report("Failed to accept memory for TDVF section %d", + entry->type); + qemu_ram_munmap(-1, entry->mem_ptr, entry->size); + exit(1); + } break; default: error_report("Unsupported TDVF section %d", entry->type); exit(1); } } + + qsort(tdx_guest->ram_entries, tdx_guest->nr_ram_entries, + sizeof(TdxRamEntry), &tdx_ram_entry_compare); } static Notifier tdx_machine_done_notify = { diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index 28a03c2a7b..36a7400e74 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -20,6 +20,17 @@ typedef struct TdxGuestClass { /* TDX requires bus frequency 25MHz */ #define TDX_APIC_BUS_CYCLES_NS 40 +enum TdxRamType { + TDX_RAM_UNACCEPTED, + TDX_RAM_ADDED, +}; + +typedef struct TdxRamEntry { + uint64_t address; + uint64_t length; + enum TdxRamType type; +} TdxRamEntry; + typedef struct TdxGuest { X86ConfidentialGuest parent_obj; @@ -34,6 +45,9 @@ typedef struct TdxGuest { MemoryRegion *tdvf_mr; TdxFirmware tdvf; + + uint32_t nr_ram_entries; + TdxRamEntry *ram_entries; } TdxGuest; #ifdef CONFIG_TDX From 88aa6576e4ab40b538f543852128cb17fce37f87 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:28 -0400 Subject: [PATCH 1239/2760] headers: Add definitions from UEFI spec for volumes, resources, etc... Add UEFI definitions for literals, enums, structs, GUIDs, etc... that will be used by TDX to build the UEFI Hand-Off Block (HOB) that is passed to the Trusted Domain Virtual Firmware (TDVF). All values come from the UEFI specification [1], PI spec [2] and TDVF design guide[3]. [1] UEFI Specification v2.1.0 https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf [2] UEFI PI spec v1.8 https://uefi.org/sites/default/files/resources/UEFI_PI_Spec_1_8_March3.pdf [3] https://software.intel.com/content/dam/develop/external/us/en/documents/tdx-virtual-firmware-design-guide-rev-1.pdf Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-23-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- include/standard-headers/uefi/uefi.h | 187 +++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 include/standard-headers/uefi/uefi.h diff --git a/include/standard-headers/uefi/uefi.h b/include/standard-headers/uefi/uefi.h new file mode 100644 index 0000000000..5256349ec0 --- /dev/null +++ b/include/standard-headers/uefi/uefi.h @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2025 Intel Corporation + * + * Author: Isaku Yamahata + * + * Xiaoyao Li + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef HW_I386_UEFI_H +#define HW_I386_UEFI_H + +/***************************************************************************/ +/* + * basic EFI definitions + * supplemented with UEFI Specification Version 2.8 (Errata A) + * released February 2020 + */ +/* UEFI integer is little endian */ + +typedef struct { + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +} EFI_GUID; + +typedef enum { + EfiReservedMemoryType, + EfiLoaderCode, + EfiLoaderData, + EfiBootServicesCode, + EfiBootServicesData, + EfiRuntimeServicesCode, + EfiRuntimeServicesData, + EfiConventionalMemory, + EfiUnusableMemory, + EfiACPIReclaimMemory, + EfiACPIMemoryNVS, + EfiMemoryMappedIO, + EfiMemoryMappedIOPortSpace, + EfiPalCode, + EfiPersistentMemory, + EfiUnacceptedMemoryType, + EfiMaxMemoryType +} EFI_MEMORY_TYPE; + +#define EFI_HOB_HANDOFF_TABLE_VERSION 0x0009 + +#define EFI_HOB_TYPE_HANDOFF 0x0001 +#define EFI_HOB_TYPE_MEMORY_ALLOCATION 0x0002 +#define EFI_HOB_TYPE_RESOURCE_DESCRIPTOR 0x0003 +#define EFI_HOB_TYPE_GUID_EXTENSION 0x0004 +#define EFI_HOB_TYPE_FV 0x0005 +#define EFI_HOB_TYPE_CPU 0x0006 +#define EFI_HOB_TYPE_MEMORY_POOL 0x0007 +#define EFI_HOB_TYPE_FV2 0x0009 +#define EFI_HOB_TYPE_LOAD_PEIM_UNUSED 0x000A +#define EFI_HOB_TYPE_UEFI_CAPSULE 0x000B +#define EFI_HOB_TYPE_FV3 0x000C +#define EFI_HOB_TYPE_UNUSED 0xFFFE +#define EFI_HOB_TYPE_END_OF_HOB_LIST 0xFFFF + +typedef struct { + uint16_t HobType; + uint16_t HobLength; + uint32_t Reserved; +} EFI_HOB_GENERIC_HEADER; + +typedef uint64_t EFI_PHYSICAL_ADDRESS; +typedef uint32_t EFI_BOOT_MODE; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + uint32_t Version; + EFI_BOOT_MODE BootMode; + EFI_PHYSICAL_ADDRESS EfiMemoryTop; + EFI_PHYSICAL_ADDRESS EfiMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryTop; + EFI_PHYSICAL_ADDRESS EfiFreeMemoryBottom; + EFI_PHYSICAL_ADDRESS EfiEndOfHobList; +} EFI_HOB_HANDOFF_INFO_TABLE; + +#define EFI_RESOURCE_SYSTEM_MEMORY 0x00000000 +#define EFI_RESOURCE_MEMORY_MAPPED_IO 0x00000001 +#define EFI_RESOURCE_IO 0x00000002 +#define EFI_RESOURCE_FIRMWARE_DEVICE 0x00000003 +#define EFI_RESOURCE_MEMORY_MAPPED_IO_PORT 0x00000004 +#define EFI_RESOURCE_MEMORY_RESERVED 0x00000005 +#define EFI_RESOURCE_IO_RESERVED 0x00000006 +#define EFI_RESOURCE_MEMORY_UNACCEPTED 0x00000007 +#define EFI_RESOURCE_MAX_MEMORY_TYPE 0x00000008 + +#define EFI_RESOURCE_ATTRIBUTE_PRESENT 0x00000001 +#define EFI_RESOURCE_ATTRIBUTE_INITIALIZED 0x00000002 +#define EFI_RESOURCE_ATTRIBUTE_TESTED 0x00000004 +#define EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC 0x00000008 +#define EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC 0x00000010 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_1 0x00000020 +#define EFI_RESOURCE_ATTRIBUTE_ECC_RESERVED_2 0x00000040 +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED 0x00000080 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED 0x00000100 +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED 0x00000200 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE 0x00000400 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE 0x00000800 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE 0x00001000 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE 0x00002000 +#define EFI_RESOURCE_ATTRIBUTE_16_BIT_IO 0x00004000 +#define EFI_RESOURCE_ATTRIBUTE_32_BIT_IO 0x00008000 +#define EFI_RESOURCE_ATTRIBUTE_64_BIT_IO 0x00010000 +#define EFI_RESOURCE_ATTRIBUTE_UNCACHED_EXPORTED 0x00020000 +#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED 0x00040000 +#define EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTABLE 0x00080000 +#define EFI_RESOURCE_ATTRIBUTE_READ_PROTECTABLE 0x00100000 +#define EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTABLE 0x00200000 +#define EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTABLE 0x00400000 +#define EFI_RESOURCE_ATTRIBUTE_PERSISTENT 0x00800000 +#define EFI_RESOURCE_ATTRIBUTE_PERSISTABLE 0x01000000 +#define EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE 0x02000000 + +typedef uint32_t EFI_RESOURCE_TYPE; +typedef uint32_t EFI_RESOURCE_ATTRIBUTE_TYPE; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Owner; + EFI_RESOURCE_TYPE ResourceType; + EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute; + EFI_PHYSICAL_ADDRESS PhysicalStart; + uint64_t ResourceLength; +} EFI_HOB_RESOURCE_DESCRIPTOR; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_GUID Name; + + /* guid specific data follows */ +} EFI_HOB_GUID_TYPE; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + uint64_t Length; +} EFI_HOB_FIRMWARE_VOLUME; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + uint64_t Length; + EFI_GUID FvName; + EFI_GUID FileName; +} EFI_HOB_FIRMWARE_VOLUME2; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + EFI_PHYSICAL_ADDRESS BaseAddress; + uint64_t Length; + uint32_t AuthenticationStatus; + bool ExtractedFv; + EFI_GUID FvName; + EFI_GUID FileName; +} EFI_HOB_FIRMWARE_VOLUME3; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + uint8_t SizeOfMemorySpace; + uint8_t SizeOfIoSpace; + uint8_t Reserved[6]; +} EFI_HOB_CPU; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; +} EFI_HOB_MEMORY_POOL; + +typedef struct { + EFI_HOB_GENERIC_HEADER Header; + + EFI_PHYSICAL_ADDRESS BaseAddress; + uint64_t Length; +} EFI_HOB_UEFI_CAPSULE; + +#define EFI_HOB_OWNER_ZERO \ + ((EFI_GUID){ 0x00000000, 0x0000, 0x0000, \ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }) + +#endif From a731425980a4d3f8bb96fc41893b6437672875ee Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:29 -0400 Subject: [PATCH 1240/2760] i386/tdx: Setup the TD HOB list The TD HOB list is used to pass the information from VMM to TDVF. The TD HOB must include PHIT HOB and Resource Descriptor HOB. More details can be found in TDVF specification and PI specification. Build the TD HOB in TDX's machine_init_done callback. Co-developed-by: Isaku Yamahata Signed-off-by: Isaku Yamahata Co-developed-by: Sean Christopherson Signed-off-by: Sean Christopherson Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-24-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/meson.build | 2 +- hw/i386/tdvf-hob.c | 130 ++++++++++++++++++++++++++++++++++++++++++ hw/i386/tdvf-hob.h | 26 +++++++++ target/i386/kvm/tdx.c | 16 ++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 hw/i386/tdvf-hob.c create mode 100644 hw/i386/tdvf-hob.h diff --git a/hw/i386/meson.build b/hw/i386/meson.build index 3bc1da2b6e..7896f348cf 100644 --- a/hw/i386/meson.build +++ b/hw/i386/meson.build @@ -32,7 +32,7 @@ i386_ss.add(when: 'CONFIG_PC', if_true: files( 'port92.c')) i386_ss.add(when: 'CONFIG_X86_FW_OVMF', if_true: files('pc_sysfw_ovmf.c'), if_false: files('pc_sysfw_ovmf-stubs.c')) -i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c')) +i386_ss.add(when: 'CONFIG_TDX', if_true: files('tdvf.c', 'tdvf-hob.c')) subdir('kvm') subdir('xen') diff --git a/hw/i386/tdvf-hob.c b/hw/i386/tdvf-hob.c new file mode 100644 index 0000000000..782b3d1578 --- /dev/null +++ b/hw/i386/tdvf-hob.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025 Intel Corporation + * Author: Isaku Yamahata + * + * Xiaoyao Li + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu/error-report.h" +#include "standard-headers/uefi/uefi.h" +#include "hw/pci/pcie_host.h" +#include "tdvf-hob.h" + +typedef struct TdvfHob { + hwaddr hob_addr; + void *ptr; + int size; + + /* working area */ + void *current; + void *end; +} TdvfHob; + +static uint64_t tdvf_current_guest_addr(const TdvfHob *hob) +{ + return hob->hob_addr + (hob->current - hob->ptr); +} + +static void tdvf_align(TdvfHob *hob, size_t align) +{ + hob->current = QEMU_ALIGN_PTR_UP(hob->current, align); +} + +static void *tdvf_get_area(TdvfHob *hob, uint64_t size) +{ + void *ret; + + if (hob->current + size > hob->end) { + error_report("TD_HOB overrun, size = 0x%" PRIx64, size); + exit(1); + } + + ret = hob->current; + hob->current += size; + tdvf_align(hob, 8); + return ret; +} + +static void tdvf_hob_add_memory_resources(TdxGuest *tdx, TdvfHob *hob) +{ + EFI_HOB_RESOURCE_DESCRIPTOR *region; + EFI_RESOURCE_ATTRIBUTE_TYPE attr; + EFI_RESOURCE_TYPE resource_type; + + TdxRamEntry *e; + int i; + + for (i = 0; i < tdx->nr_ram_entries; i++) { + e = &tdx->ram_entries[i]; + + if (e->type == TDX_RAM_UNACCEPTED) { + resource_type = EFI_RESOURCE_MEMORY_UNACCEPTED; + attr = EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED; + } else if (e->type == TDX_RAM_ADDED) { + resource_type = EFI_RESOURCE_SYSTEM_MEMORY; + attr = EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE; + } else { + error_report("unknown TDX_RAM_ENTRY type %d", e->type); + exit(1); + } + + region = tdvf_get_area(hob, sizeof(*region)); + *region = (EFI_HOB_RESOURCE_DESCRIPTOR) { + .Header = { + .HobType = EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, + .HobLength = cpu_to_le16(sizeof(*region)), + .Reserved = cpu_to_le32(0), + }, + .Owner = EFI_HOB_OWNER_ZERO, + .ResourceType = cpu_to_le32(resource_type), + .ResourceAttribute = cpu_to_le32(attr), + .PhysicalStart = cpu_to_le64(e->address), + .ResourceLength = cpu_to_le64(e->length), + }; + } +} + +void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob) +{ + TdvfHob hob = { + .hob_addr = td_hob->address, + .size = td_hob->size, + .ptr = td_hob->mem_ptr, + + .current = td_hob->mem_ptr, + .end = td_hob->mem_ptr + td_hob->size, + }; + + EFI_HOB_GENERIC_HEADER *last_hob; + EFI_HOB_HANDOFF_INFO_TABLE *hit; + + /* Note, Efi{Free}Memory{Bottom,Top} are ignored, leave 'em zeroed. */ + hit = tdvf_get_area(&hob, sizeof(*hit)); + *hit = (EFI_HOB_HANDOFF_INFO_TABLE) { + .Header = { + .HobType = EFI_HOB_TYPE_HANDOFF, + .HobLength = cpu_to_le16(sizeof(*hit)), + .Reserved = cpu_to_le32(0), + }, + .Version = cpu_to_le32(EFI_HOB_HANDOFF_TABLE_VERSION), + .BootMode = cpu_to_le32(0), + .EfiMemoryTop = cpu_to_le64(0), + .EfiMemoryBottom = cpu_to_le64(0), + .EfiFreeMemoryTop = cpu_to_le64(0), + .EfiFreeMemoryBottom = cpu_to_le64(0), + .EfiEndOfHobList = cpu_to_le64(0), /* initialized later */ + }; + + tdvf_hob_add_memory_resources(tdx, &hob); + + last_hob = tdvf_get_area(&hob, sizeof(*last_hob)); + *last_hob = (EFI_HOB_GENERIC_HEADER) { + .HobType = EFI_HOB_TYPE_END_OF_HOB_LIST, + .HobLength = cpu_to_le16(sizeof(*last_hob)), + .Reserved = cpu_to_le32(0), + }; + hit->EfiEndOfHobList = tdvf_current_guest_addr(&hob); +} diff --git a/hw/i386/tdvf-hob.h b/hw/i386/tdvf-hob.h new file mode 100644 index 0000000000..4fc6a3740a --- /dev/null +++ b/hw/i386/tdvf-hob.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef HW_I386_TD_HOB_H +#define HW_I386_TD_HOB_H + +#include "hw/i386/tdvf.h" +#include "target/i386/kvm/tdx.h" + +void tdvf_hob_create(TdxGuest *tdx, TdxFirmwareEntry *td_hob); + +#define EFI_RESOURCE_ATTRIBUTE_TDVF_PRIVATE \ + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED) + +#define EFI_RESOURCE_ATTRIBUTE_TDVF_UNACCEPTED \ + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED) + +#define EFI_RESOURCE_ATTRIBUTE_TDVF_MMIO \ + (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE) + +#endif diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e06f5d0bd4..e20ffee955 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -21,6 +21,7 @@ #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" +#include "hw/i386/tdvf-hob.h" #include "kvm_i386.h" #include "tdx.h" @@ -147,6 +148,19 @@ void tdx_set_tdvf_region(MemoryRegion *tdvf_mr) tdx_guest->tdvf_mr = tdvf_mr; } +static TdxFirmwareEntry *tdx_get_hob_entry(TdxGuest *tdx) +{ + TdxFirmwareEntry *entry; + + for_each_tdx_fw_entry(&tdx->tdvf, entry) { + if (entry->type == TDVF_SECTION_TYPE_TD_HOB) { + return entry; + } + } + error_report("TDVF metadata doesn't specify TD_HOB location."); + exit(1); +} + static void tdx_add_ram_entry(uint64_t address, uint64_t length, enum TdxRamType type) { @@ -281,6 +295,8 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) qsort(tdx_guest->ram_entries, tdx_guest->nr_ram_entries, sizeof(TdxRamEntry), &tdx_ram_entry_compare); + + tdvf_hob_create(tdx_guest, tdx_get_hob_entry(tdx_guest)); } static Notifier tdx_machine_done_notify = { From ebc2d2b497c59414ac3c91de32bc546d27940e74 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 8 May 2025 10:59:30 -0400 Subject: [PATCH 1241/2760] i386/tdx: Add TDVF memory via KVM_TDX_INIT_MEM_REGION TDVF firmware (CODE and VARS) needs to be copied to TD's private memory via KVM_TDX_INIT_MEM_REGION, as well as TD HOB and TEMP memory. If the TDVF section has TDVF_SECTION_ATTRIBUTES_MR_EXTEND set in the flag, calling KVM_TDX_EXTEND_MEMORY to extend the measurement. After populating the TDVF memory, the original image located in shared ramblock can be discarded. Signed-off-by: Isaku Yamahata Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-25-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e20ffee955..43529a9e0e 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -17,6 +17,7 @@ #include "qom/object_interfaces.h" #include "crypto/hash.h" #include "system/system.h" +#include "system/ramblock.h" #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" @@ -262,6 +263,9 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) { TdxFirmware *tdvf = &tdx_guest->tdvf; TdxFirmwareEntry *entry; + RAMBlock *ram_block; + Error *local_err = NULL; + int r; tdx_init_ram_entries(); @@ -297,6 +301,44 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) sizeof(TdxRamEntry), &tdx_ram_entry_compare); tdvf_hob_create(tdx_guest, tdx_get_hob_entry(tdx_guest)); + + for_each_tdx_fw_entry(tdvf, entry) { + struct kvm_tdx_init_mem_region region; + uint32_t flags; + + region = (struct kvm_tdx_init_mem_region) { + .source_addr = (uint64_t)entry->mem_ptr, + .gpa = entry->address, + .nr_pages = entry->size >> 12, + }; + + flags = entry->attributes & TDVF_SECTION_ATTRIBUTES_MR_EXTEND ? + KVM_TDX_MEASURE_MEMORY_REGION : 0; + + do { + error_free(local_err); + local_err = NULL; + r = tdx_vcpu_ioctl(first_cpu, KVM_TDX_INIT_MEM_REGION, flags, + ®ion, &local_err); + } while (r == -EAGAIN || r == -EINTR); + if (r < 0) { + error_report_err(local_err); + exit(1); + } + + if (entry->type == TDVF_SECTION_TYPE_TD_HOB || + entry->type == TDVF_SECTION_TYPE_TEMP_MEM) { + qemu_ram_munmap(-1, entry->mem_ptr, entry->size); + entry->mem_ptr = NULL; + } + } + + /* + * TDVF image has been copied into private region above via + * KVM_MEMORY_MAPPING. It becomes useless. + */ + ram_block = tdx_guest->tdvf_mr->ram_block; + ram_block_discard_range(ram_block, 0, ram_block->max_length); } static Notifier tdx_machine_done_notify = { From 41f7fd22073561a23229c0479d9d708dee9d3a1e Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:31 -0400 Subject: [PATCH 1242/2760] i386/tdx: Call KVM_TDX_INIT_VCPU to initialize TDX vcpu TDX vcpu needs to be initialized by SEAMCALL(TDH.VP.INIT) and KVM provides vcpu level IOCTL KVM_TDX_INIT_VCPU for it. KVM_TDX_INIT_VCPU needs the address of the HOB as input. Invoke it for each vcpu after HOB list is created. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-26-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 43529a9e0e..99d13bd844 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -259,6 +259,18 @@ static void tdx_init_ram_entries(void) tdx_guest->nr_ram_entries = j; } +static void tdx_post_init_vcpus(void) +{ + TdxFirmwareEntry *hob; + CPUState *cpu; + + hob = tdx_get_hob_entry(tdx_guest); + CPU_FOREACH(cpu) { + tdx_vcpu_ioctl(cpu, KVM_TDX_INIT_VCPU, 0, (void *)hob->address, + &error_fatal); + } +} + static void tdx_finalize_vm(Notifier *notifier, void *unused) { TdxFirmware *tdvf = &tdx_guest->tdvf; @@ -302,6 +314,8 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) tdvf_hob_create(tdx_guest, tdx_get_hob_entry(tdx_guest)); + tdx_post_init_vcpus(); + for_each_tdx_fw_entry(tdvf, entry) { struct kvm_tdx_init_mem_region region; uint32_t flags; From ae60ff4e9f9e5790f79abf866ec67270c28ca477 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:32 -0400 Subject: [PATCH 1243/2760] i386/tdx: Finalize TDX VM Invoke KVM_TDX_FINALIZE_VM to finalize the TD's measurement and make the TD vCPUs runnable once machine initialization is complete. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-27-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 99d13bd844..287bf7147e 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -353,6 +353,9 @@ static void tdx_finalize_vm(Notifier *notifier, void *unused) */ ram_block = tdx_guest->tdvf_mr->ram_block; ram_block_discard_range(ram_block, 0, ram_block->max_length); + + tdx_vm_ioctl(KVM_TDX_FINALIZE_VM, 0, NULL, &error_fatal); + CONFIDENTIAL_GUEST_SUPPORT(tdx_guest)->ready = true; } static Notifier tdx_machine_done_notify = { From 1ff5048d74e661943260c33e864c4118acb37ab4 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:33 -0400 Subject: [PATCH 1244/2760] i386/tdx: Enable user exit on KVM_HC_MAP_GPA_RANGE KVM translates TDG.VP.VMCALL to KVM_HC_MAP_GPA_RANGE, and QEMU needs to enable user exit on KVM_HC_MAP_GPA_RANGE in order to handle the memory conversion requested by TD guest. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-28-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 287bf7147e..971f4becfa 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -19,6 +19,8 @@ #include "system/system.h" #include "system/ramblock.h" +#include + #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" @@ -376,6 +378,11 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) } } + /* TDX relies on KVM_HC_MAP_GPA_RANGE to handle TDG.VP.VMCALL */ + if (!kvm_enable_hypercall(BIT_ULL(KVM_HC_MAP_GPA_RANGE))) { + return -EOPNOTSUPP; + } + qemu_add_machine_init_done_notifier(&tdx_machine_done_notify); tdx_guest = tdx; From 98dbfd6849f117de02ac6f513f2a1f95563e60ae Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:34 -0400 Subject: [PATCH 1245/2760] i386/tdx: Handle KVM_SYSTEM_EVENT_TDX_FATAL TD guest can use TDG.VP.VMCALL to request termination. KVM translates such request into KVM_EXIT_SYSTEM_EVENT with type of KVM_SYSTEM_EVENT_TDX_FATAL. Add hanlder for such exit. Parse and print the error message, and terminate the TD guest in the handler. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-29-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 10 +++++++++ target/i386/kvm/tdx-stub.c | 5 +++++ target/i386/kvm/tdx.c | 46 ++++++++++++++++++++++++++++++++++++++ target/i386/kvm/tdx.h | 2 ++ 4 files changed, 63 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index fd1817fc5e..c5c692a034 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -6129,6 +6129,16 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) case KVM_EXIT_HYPERCALL: ret = kvm_handle_hypercall(run); break; + case KVM_EXIT_SYSTEM_EVENT: + switch (run->system_event.type) { + case KVM_SYSTEM_EVENT_TDX_FATAL: + ret = tdx_handle_report_fatal_error(cpu, run); + break; + default: + ret = -1; + break; + } + break; default: fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); ret = -1; diff --git a/target/i386/kvm/tdx-stub.c b/target/i386/kvm/tdx-stub.c index 7748b6d0a4..720a4ff046 100644 --- a/target/i386/kvm/tdx-stub.c +++ b/target/i386/kvm/tdx-stub.c @@ -13,3 +13,8 @@ int tdx_parse_tdvf(void *flash_ptr, int size) { return -EINVAL; } + +int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) +{ + return -EINVAL; +} diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 971f4becfa..16ad1af3c5 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -615,6 +615,52 @@ int tdx_parse_tdvf(void *flash_ptr, int size) return tdvf_parse_metadata(&tdx_guest->tdvf, flash_ptr, size); } +/* + * Only 8 registers can contain valid ASCII byte stream to form the fatal + * message, and their sequence is: R14, R15, RBX, RDI, RSI, R8, R9, RDX + */ +#define TDX_FATAL_MESSAGE_MAX 64 + +int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) +{ + uint64_t error_code = run->system_event.data[R_R12]; + uint64_t reg_mask = run->system_event.data[R_ECX]; + char *message = NULL; + uint64_t *tmp; + + if (error_code & 0xffff) { + error_report("TDX: REPORT_FATAL_ERROR: invalid error code: 0x%lx", + error_code); + return -1; + } + + if (reg_mask) { + message = g_malloc0(TDX_FATAL_MESSAGE_MAX + 1); + tmp = (uint64_t *)message; + +#define COPY_REG(REG) \ + do { \ + if (reg_mask & BIT_ULL(REG)) { \ + *(tmp++) = run->system_event.data[REG]; \ + } \ + } while (0) + + COPY_REG(R_R14); + COPY_REG(R_R15); + COPY_REG(R_EBX); + COPY_REG(R_EDI); + COPY_REG(R_ESI); + COPY_REG(R_R8); + COPY_REG(R_R9); + COPY_REG(R_EDX); + *((char *)tmp) = '\0'; + } +#undef COPY_REG + + error_report("TD guest reports fatal error. %s", message ? : ""); + return -1; +} + static bool tdx_guest_get_sept_ve_disable(Object *obj, Error **errp) { TdxGuest *tdx = TDX_GUEST(obj); diff --git a/target/i386/kvm/tdx.h b/target/i386/kvm/tdx.h index 36a7400e74..04b5afe199 100644 --- a/target/i386/kvm/tdx.h +++ b/target/i386/kvm/tdx.h @@ -8,6 +8,7 @@ #endif #include "confidential-guest.h" +#include "cpu.h" #include "hw/i386/tdvf.h" #define TYPE_TDX_GUEST "tdx-guest" @@ -59,5 +60,6 @@ bool is_tdx_vm(void); int tdx_pre_create_vcpu(CPUState *cpu, Error **errp); void tdx_set_tdvf_region(MemoryRegion *tdvf_mr); int tdx_parse_tdvf(void *flash_ptr, int size); +int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run); #endif /* QEMU_I386_TDX_H */ From 6e250463b08b4028123f201343ee72099ef81e68 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:35 -0400 Subject: [PATCH 1246/2760] i386/tdx: Wire TDX_REPORT_FATAL_ERROR with GuestPanic facility Integrate TDX's TDX_REPORT_FATAL_ERROR into QEMU GuestPanic facility Originated-from: Isaku Yamahata Signed-off-by: Xiaoyao Li Acked-by: Markus Armbruster Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-30-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- qapi/run-state.json | 31 +++++++++++++++++++-- system/runstate.c | 65 +++++++++++++++++++++++++++++++++++++++++++ target/i386/kvm/tdx.c | 25 ++++++++++++++++- 3 files changed, 118 insertions(+), 3 deletions(-) diff --git a/qapi/run-state.json b/qapi/run-state.json index ce95cfa46b..ee11adc508 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -501,10 +501,12 @@ # # @s390: s390 guest panic information type (Since: 2.12) # +# @tdx: tdx guest panic information type (Since: 10.1) +# # Since: 2.9 ## { 'enum': 'GuestPanicInformationType', - 'data': [ 'hyper-v', 's390' ] } + 'data': [ 'hyper-v', 's390', 'tdx' ] } ## # @GuestPanicInformation: @@ -519,7 +521,8 @@ 'base': {'type': 'GuestPanicInformationType'}, 'discriminator': 'type', 'data': {'hyper-v': 'GuestPanicInformationHyperV', - 's390': 'GuestPanicInformationS390'}} + 's390': 'GuestPanicInformationS390', + 'tdx' : 'GuestPanicInformationTdx'}} ## # @GuestPanicInformationHyperV: @@ -598,6 +601,30 @@ 'psw-addr': 'uint64', 'reason': 'S390CrashReason'}} +## +# @GuestPanicInformationTdx: +# +# TDX Guest panic information specific to TDX, as specified in the +# "Guest-Hypervisor Communication Interface (GHCI) Specification", +# section TDG.VP.VMCALL. +# +# @error-code: TD-specific error code +# +# @message: Human-readable error message provided by the guest. Not +# to be trusted. +# +# @gpa: guest-physical address of a page that contains more verbose +# error information, as zero-terminated string. Present when the +# "GPA valid" bit (bit 63) is set in @error-code. +# +# +# Since: 10.1 +## +{'struct': 'GuestPanicInformationTdx', + 'data': {'error-code': 'uint32', + 'message': 'str', + '*gpa': 'uint64'}} + ## # @MEMORY_FAILURE: # diff --git a/system/runstate.c b/system/runstate.c index de74d962bc..38900c935a 100644 --- a/system/runstate.c +++ b/system/runstate.c @@ -590,6 +590,58 @@ static void qemu_system_wakeup(void) } } +static char *tdx_parse_panic_message(char *message) +{ + bool printable = false; + char *buf = NULL; + int len = 0, i; + + /* + * Although message is defined as a json string, we shouldn't + * unconditionally treat it as is because the guest generated it and + * it's not necessarily trustable. + */ + if (message) { + /* The caller guarantees the NULL-terminated string. */ + len = strlen(message); + + printable = len > 0; + for (i = 0; i < len; i++) { + if (!(0x20 <= message[i] && message[i] <= 0x7e)) { + printable = false; + break; + } + } + } + + if (len == 0) { + buf = g_malloc(1); + buf[0] = '\0'; + } else { + if (!printable) { + /* 3 = length of "%02x " */ + buf = g_malloc(len * 3); + for (i = 0; i < len; i++) { + if (message[i] == '\0') { + break; + } else { + sprintf(buf + 3 * i, "%02x ", message[i]); + } + } + if (i > 0) { + /* replace the last ' '(space) to NULL */ + buf[i * 3 - 1] = '\0'; + } else { + buf[0] = '\0'; + } + } else { + buf = g_strdup(message); + } + } + + return buf; +} + void qemu_system_guest_panicked(GuestPanicInformation *info) { qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed"); @@ -631,7 +683,20 @@ void qemu_system_guest_panicked(GuestPanicInformation *info) S390CrashReason_str(info->u.s390.reason), info->u.s390.psw_mask, info->u.s390.psw_addr); + } else if (info->type == GUEST_PANIC_INFORMATION_TYPE_TDX) { + char *message = tdx_parse_panic_message(info->u.tdx.message); + qemu_log_mask(LOG_GUEST_ERROR, + "\nTDX guest reports fatal error." + " error code: 0x%" PRIx32 " error message:\"%s\"\n", + info->u.tdx.error_code, message); + g_free(message); + if (info->u.tdx.gpa != -1ull) { + qemu_log_mask(LOG_GUEST_ERROR, "Additional error information " + "can be found at gpa page: 0x%" PRIx64 "\n", + info->u.tdx.gpa); + } } + qapi_free_GuestPanicInformation(info); } } diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 16ad1af3c5..ae3740a230 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -16,6 +16,7 @@ #include "qapi/error.h" #include "qom/object_interfaces.h" #include "crypto/hash.h" +#include "system/runstate.h" #include "system/system.h" #include "system/ramblock.h" @@ -615,18 +616,35 @@ int tdx_parse_tdvf(void *flash_ptr, int size) return tdvf_parse_metadata(&tdx_guest->tdvf, flash_ptr, size); } +static void tdx_panicked_on_fatal_error(X86CPU *cpu, uint64_t error_code, + char *message, uint64_t gpa) +{ + GuestPanicInformation *panic_info; + + panic_info = g_new0(GuestPanicInformation, 1); + panic_info->type = GUEST_PANIC_INFORMATION_TYPE_TDX; + panic_info->u.tdx.error_code = (uint32_t) error_code; + panic_info->u.tdx.message = message; + panic_info->u.tdx.gpa = gpa; + + qemu_system_guest_panicked(panic_info); +} + /* * Only 8 registers can contain valid ASCII byte stream to form the fatal * message, and their sequence is: R14, R15, RBX, RDI, RSI, R8, R9, RDX */ #define TDX_FATAL_MESSAGE_MAX 64 +#define TDX_REPORT_FATAL_ERROR_GPA_VALID BIT_ULL(63) + int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) { uint64_t error_code = run->system_event.data[R_R12]; uint64_t reg_mask = run->system_event.data[R_ECX]; char *message = NULL; uint64_t *tmp; + uint64_t gpa = -1ull; if (error_code & 0xffff) { error_report("TDX: REPORT_FATAL_ERROR: invalid error code: 0x%lx", @@ -657,7 +675,12 @@ int tdx_handle_report_fatal_error(X86CPU *cpu, struct kvm_run *run) } #undef COPY_REG - error_report("TD guest reports fatal error. %s", message ? : ""); + if (error_code & TDX_REPORT_FATAL_ERROR_GPA_VALID) { + gpa = run->system_event.data[R_R13]; + } + + tdx_panicked_on_fatal_error(cpu, error_code, message, gpa); + return -1; } From 77b5403a0298a5460554f768a2098fd21588e555 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:36 -0400 Subject: [PATCH 1247/2760] kvm: Check KVM_CAP_MAX_VCPUS at vm level KVM with TDX support starts to report different KVM_CAP_MAX_VCPUS per different VM types. So switch to check the KVM_CAP_MAX_VCPUS at vm level. KVM still returns the global KVM_CAP_MAX_VCPUS when the KVM is old that doesn't report different value at vm level. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-31-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 42d239cf8f..71e6060458 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -2431,7 +2431,7 @@ static int kvm_recommended_vcpus(KVMState *s) static int kvm_max_vcpus(KVMState *s) { - int ret = kvm_check_extension(s, KVM_CAP_MAX_VCPUS); + int ret = kvm_vm_check_extension(s, KVM_CAP_MAX_VCPUS); return (ret) ? ret : kvm_recommended_vcpus(s); } From 8583c53e2b619b1b9569d3f2d3f3cb2904a573ad Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:37 -0400 Subject: [PATCH 1248/2760] i386/cpu: introduce x86_confidential_guest_cpu_instance_init() To allow execute confidential guest specific cpu init operations. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-32-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/confidential-guest.h | 11 +++++++++++ target/i386/cpu.c | 8 ++++++++ 2 files changed, 19 insertions(+) diff --git a/target/i386/confidential-guest.h b/target/i386/confidential-guest.h index 164be7633a..a86c42a475 100644 --- a/target/i386/confidential-guest.h +++ b/target/i386/confidential-guest.h @@ -39,6 +39,7 @@ struct X86ConfidentialGuestClass { /* */ int (*kvm_type)(X86ConfidentialGuest *cg); + void (*cpu_instance_init)(X86ConfidentialGuest *cg, CPUState *cpu); uint32_t (*mask_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, int reg, uint32_t value); }; @@ -59,6 +60,16 @@ static inline int x86_confidential_guest_kvm_type(X86ConfidentialGuest *cg) } } +static inline void x86_confidential_guest_cpu_instance_init(X86ConfidentialGuest *cg, + CPUState *cpu) +{ + X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg); + + if (klass->cpu_instance_init) { + klass->cpu_instance_init(cg, cpu); + } +} + /** * x86_confidential_guest_mask_cpuid_features: * diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 9689f6374e..4a7c319bb9 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -37,6 +37,7 @@ #include "hw/i386/topology.h" #include "exec/watchpoint.h" #ifndef CONFIG_USER_ONLY +#include "confidential-guest.h" #include "system/reset.h" #include "qapi/qapi-commands-machine-target.h" #include "system/address-spaces.h" @@ -8543,6 +8544,13 @@ static void x86_cpu_post_initfn(Object *obj) } accel_cpu_instance_init(CPU(obj)); + +#ifndef CONFIG_USER_ONLY + if (current_machine && current_machine->cgs) { + x86_confidential_guest_cpu_instance_init( + X86_CONFIDENTIAL_GUEST(current_machine->cgs), (CPU(obj))); + } +#endif } static void x86_cpu_init_default_topo(X86CPU *cpu) From 7c615242671dbe65e198c20889dcaa9b4b9a1624 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:38 -0400 Subject: [PATCH 1249/2760] i386/tdx: implement tdx_cpu_instance_init() Currently, pmu is not supported for TDX by KVM. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-33-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index ae3740a230..7c5e59c559 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -398,6 +398,11 @@ static int tdx_kvm_type(X86ConfidentialGuest *cg) return KVM_X86_TDX_VM; } +static void tdx_cpu_instance_init(X86ConfidentialGuest *cg, CPUState *cpu) +{ + object_property_set_bool(OBJECT(cpu), "pmu", false, &error_abort); +} + static int tdx_validate_attributes(TdxGuest *tdx, Error **errp) { if ((tdx->attributes & ~tdx_caps->supported_attrs)) { @@ -791,4 +796,5 @@ static void tdx_guest_class_init(ObjectClass *oc, const void *data) klass->kvm_init = tdx_kvm_init; x86_klass->kvm_type = tdx_kvm_type; + x86_klass->cpu_instance_init = tdx_cpu_instance_init; } From ab8bd85adf75900edc2764d0ebe8b53867cc54aa Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:39 -0400 Subject: [PATCH 1250/2760] i386/cpu: Introduce enable_cpuid_0x1f to force exposing CPUID 0x1f Currently, QEMU exposes CPUID 0x1f to guest only when necessary, i.e., when topology level that cannot be enumerated by leaf 0xB, e.g., die or module level, are configured for the guest, e.g., -smp xx,dies=2. However, TDX architecture forces to require CPUID 0x1f to configure CPU topology. Introduce a bool flag, enable_cpuid_0x1f, in CPU for the case that requires CPUID leaf 0x1f to be exposed to guest. Introduce a new function x86_has_cpuid_0x1f(), which is the wrapper of cpu->enable_cpuid_0x1f and x86_has_extended_topo() to check if it needs to enable cpuid leaf 0x1f for the guest. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-34-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++-- target/i386/cpu.h | 9 +++++++++ target/i386/kvm/kvm.c | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4a7c319bb9..6a97d7549e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -7045,7 +7045,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0x1F: /* V2 Extended Topology Enumeration Leaf */ - if (!x86_has_extended_topo(env->avail_cpu_topo)) { + if (!x86_has_cpuid_0x1f(cpu)) { *eax = *ebx = *ecx = *edx = 0; break; } @@ -7909,7 +7909,7 @@ void x86_cpu_expand_features(X86CPU *cpu, Error **errp) * cpu->vendor_cpuid_only has been unset for compatibility with older * machine types. */ - if (x86_has_extended_topo(env->avail_cpu_topo) && + if (x86_has_cpuid_0x1f(cpu) && (IS_INTEL_CPU(env) || !cpu->vendor_cpuid_only)) { x86_cpu_adjust_level(cpu, &env->cpuid_min_level, 0x1F); } diff --git a/target/i386/cpu.h b/target/i386/cpu.h index c51e0a43d0..ad0e3d8cdd 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2239,6 +2239,9 @@ struct ArchCPU { /* Compatibility bits for old machine types: */ bool enable_cpuid_0xb; + /* Force to enable cpuid 0x1f */ + bool enable_cpuid_0x1f; + /* Enable auto level-increase for all CPUID leaves */ bool full_cpuid_auto_level; @@ -2500,6 +2503,12 @@ void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); bool cpu_has_x2apic_feature(CPUX86State *env); +static inline bool x86_has_cpuid_0x1f(X86CPU *cpu) +{ + return cpu->enable_cpuid_0x1f || + x86_has_extended_topo(cpu->env.avail_cpu_topo); +} + /* helper.c */ void x86_cpu_set_a20(X86CPU *cpu, int a20_state); void cpu_sync_avx_hflag(CPUX86State *env); diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index c5c692a034..ee33797fdd 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -1872,7 +1872,7 @@ uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, break; } case 0x1f: - if (!x86_has_extended_topo(env->avail_cpu_topo)) { + if (!x86_has_cpuid_0x1f(env_archcpu(env))) { cpuid_i--; break; } From 9002494f80b751a7655045c5f46bf90bc1d3bbd0 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:40 -0400 Subject: [PATCH 1251/2760] i386/tdx: Force exposing CPUID 0x1f TDX uses CPUID 0x1f to configure TD guest's CPU topology. So set enable_cpuid_0x1f for TDs. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-35-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 7c5e59c559..accaefb401 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -400,7 +400,11 @@ static int tdx_kvm_type(X86ConfidentialGuest *cg) static void tdx_cpu_instance_init(X86ConfidentialGuest *cg, CPUState *cpu) { + X86CPU *x86cpu = X86_CPU(cpu); + object_property_set_bool(OBJECT(cpu), "pmu", false, &error_abort); + + x86cpu->enable_cpuid_0x1f = true; } static int tdx_validate_attributes(TdxGuest *tdx, Error **errp) From da6728658bf63d6a3989f1587a33566b3e54bed8 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:41 -0400 Subject: [PATCH 1252/2760] i386/tdx: Set kvm_readonly_mem_enabled to false for TDX VM TDX only supports readonly for shared memory but not for private memory. In the view of QEMU, it has no idea whether a memslot is used as shared memory of private. Thus just mark kvm_readonly_mem_enabled to false to TDX VM for simplicity. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-36-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index accaefb401..344e560b4b 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -384,6 +384,15 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) return -EOPNOTSUPP; } + /* + * Set kvm_readonly_mem_allowed to false, because TDX only supports readonly + * memory for shared memory but not for private memory. Besides, whether a + * memslot is private or shared is not determined by QEMU. + * + * Thus, just mark readonly memory not supported for simplicity. + */ + kvm_readonly_mem_allowed = false; + qemu_add_machine_init_done_notifier(&tdx_machine_done_notify); tdx_guest = tdx; From 810d4e83d07ca0d072205453a42c324a51d5a5fa Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:42 -0400 Subject: [PATCH 1253/2760] i386/tdx: Disable SMM for TDX VMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TDX doesn't support SMM and VMM cannot emulate SMM for TDX VMs because VMM cannot manipulate TDX VM's memory. Disable SMM for TDX VMs and error out if user requests to enable SMM. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-37-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 344e560b4b..87c5bf0496 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -367,11 +367,20 @@ static Notifier tdx_machine_done_notify = { static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { + MachineState *ms = MACHINE(qdev_get_machine()); + X86MachineState *x86ms = X86_MACHINE(ms); TdxGuest *tdx = TDX_GUEST(cgs); int r = 0; kvm_mark_guest_state_protected(); + if (x86ms->smm == ON_OFF_AUTO_AUTO) { + x86ms->smm = ON_OFF_AUTO_OFF; + } else if (x86ms->smm == ON_OFF_AUTO_ON) { + error_setg(errp, "TDX VM doesn't support SMM"); + return -EINVAL; + } + if (!tdx_caps) { r = get_tdx_capabilities(errp); if (r) { From e7ef60892c80a9ce5b8504ceb13a81f4e0d4b3f7 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:43 -0400 Subject: [PATCH 1254/2760] i386/tdx: Disable PIC for TDX VMs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Legacy PIC (8259) cannot be supported for TDX VMs since TDX module doesn't allow directly interrupt injection. Using posted interrupts for the PIC is not a viable option as the guest BIOS/kernel will not do EOI for PIC IRQs, i.e. will leave the vIRR bit set. Hence disable PIC for TDX VMs and error out if user wants PIC. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-38-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 87c5bf0496..32c3f3795d 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -381,6 +381,13 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) return -EINVAL; } + if (x86ms->pic == ON_OFF_AUTO_AUTO) { + x86ms->pic = ON_OFF_AUTO_OFF; + } else if (x86ms->pic == ON_OFF_AUTO_ON) { + error_setg(errp, "TDX VM doesn't support PIC"); + return -EINVAL; + } + if (!tdx_caps) { r = get_tdx_capabilities(errp); if (r) { From bb45580d842530d78b58179eaf80b6331b15324e Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:44 -0400 Subject: [PATCH 1255/2760] i386/tdx: Set and check kernel_irqchip mode for TDX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit KVM mandates kernel_irqchip to be split mode. Set it to split mode automatically when users don't provide an explicit value, otherwise check it to be the split mode. Suggested-by: Daniel P. Berrangé Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-39-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 32c3f3795d..68ed3b9f98 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -16,6 +16,7 @@ #include "qapi/error.h" #include "qom/object_interfaces.h" #include "crypto/hash.h" +#include "system/kvm_int.h" #include "system/runstate.h" #include "system/system.h" #include "system/ramblock.h" @@ -388,6 +389,13 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) return -EINVAL; } + if (kvm_state->kernel_irqchip_split == ON_OFF_AUTO_AUTO) { + kvm_state->kernel_irqchip_split = ON_OFF_AUTO_ON; + } else if (kvm_state->kernel_irqchip_split != ON_OFF_AUTO_ON) { + error_setg(errp, "TDX VM requires kernel_irqchip to be split"); + return -EINVAL; + } + if (!tdx_caps) { r = get_tdx_capabilities(errp); if (r) { From 0ed55865b49b703af93e160d48935812a7114e07 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 8 May 2025 10:59:45 -0400 Subject: [PATCH 1256/2760] i386/tdx: Don't synchronize guest tsc for TDs TSC of TDs is not accessible and KVM doesn't allow access of MSR_IA32_TSC for TDs. To avoid the assert() in kvm_get_tsc, make kvm_synchronize_all_tsc() noop for TDs, Signed-off-by: Isaku Yamahata Reviewed-by: Connor Kuehl Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-40-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index ee33797fdd..4fc37cc370 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -328,7 +328,7 @@ void kvm_synchronize_all_tsc(void) { CPUState *cpu; - if (kvm_enabled()) { + if (kvm_enabled() && !is_tdx_vm()) { CPU_FOREACH(cpu) { run_on_cpu(cpu, do_kvm_synchronize_tsc, RUN_ON_CPU_NULL); } From f9aaad3362a5886d78e7d4d50d563ac16c6acdde Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:46 -0400 Subject: [PATCH 1257/2760] i386/tdx: Only configure MSR_IA32_UCODE_REV in kvm_init_msrs() for TDs For TDs, only MSR_IA32_UCODE_REV in kvm_init_msrs() can be configured by VMM, while the features enumerated/controlled by other MSRs except MSR_IA32_UCODE_REV in kvm_init_msrs() are not under control of VMM. Only configure MSR_IA32_UCODE_REV for TDs. Signed-off-by: Xiaoyao Li Acked-by: Gerd Hoffmann Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-41-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/kvm.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 4fc37cc370..90a0dac4a1 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -3864,32 +3864,34 @@ static void kvm_init_msrs(X86CPU *cpu) CPUX86State *env = &cpu->env; kvm_msr_buf_reset(cpu); - if (has_msr_arch_capabs) { - kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES, - env->features[FEAT_ARCH_CAPABILITIES]); - } - if (has_msr_core_capabs) { - kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY, - env->features[FEAT_CORE_CAPABILITY]); - } + if (!is_tdx_vm()) { + if (has_msr_arch_capabs) { + kvm_msr_entry_add(cpu, MSR_IA32_ARCH_CAPABILITIES, + env->features[FEAT_ARCH_CAPABILITIES]); + } - if (has_msr_perf_capabs && cpu->enable_pmu) { - kvm_msr_entry_add_perf(cpu, env->features); + if (has_msr_core_capabs) { + kvm_msr_entry_add(cpu, MSR_IA32_CORE_CAPABILITY, + env->features[FEAT_CORE_CAPABILITY]); + } + + if (has_msr_perf_capabs && cpu->enable_pmu) { + kvm_msr_entry_add_perf(cpu, env->features); + } + + /* + * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but + * all kernels with MSR features should have them. + */ + if (kvm_feature_msrs && cpu_has_vmx(env)) { + kvm_msr_entry_add_vmx(cpu, env->features); + } } if (has_msr_ucode_rev) { kvm_msr_entry_add(cpu, MSR_IA32_UCODE_REV, cpu->ucode_rev); } - - /* - * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but - * all kernels with MSR features should have them. - */ - if (kvm_feature_msrs && cpu_has_vmx(env)) { - kvm_msr_entry_add_vmx(cpu, env->features); - } - assert(kvm_buf_set_msrs(cpu) == 0); } From 62a1a8b89d90cd3fbee0e6d38e6a4c0d833e978a Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:47 -0400 Subject: [PATCH 1258/2760] i386/apic: Skip kvm_apic_put() for TDX KVM neithers allow writing to MSR_IA32_APICBASE for TDs, nor allow for KVM_SET_LAPIC[*]. Note, KVM_GET_LAPIC is also disallowed for TDX. It is called in the path do_kvm_cpu_synchronize_state() -> kvm_arch_get_registers() -> kvm_get_apic() and it's already disllowed for confidential guest through guest_state_protected. [*] https://lore.kernel.org/all/Z3w4Ku4Jq0CrtXne@google.com/ Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-42-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- hw/i386/kvm/apic.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/kvm/apic.c b/hw/i386/kvm/apic.c index 39035db042..1be9bfe36e 100644 --- a/hw/i386/kvm/apic.c +++ b/hw/i386/kvm/apic.c @@ -17,6 +17,7 @@ #include "system/hw_accel.h" #include "system/kvm.h" #include "kvm/kvm_i386.h" +#include "kvm/tdx.h" static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic, int reg_id, uint32_t val) @@ -141,6 +142,10 @@ static void kvm_apic_put(CPUState *cs, run_on_cpu_data data) struct kvm_lapic_state kapic; int ret; + if (is_tdx_vm()) { + return; + } + kvm_put_apicbase(s->cpu, s->apicbase); kvm_put_apic_state(s, &kapic); From b4b7fb5a773e1d2215c2aaa99789eca51914b78f Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:48 -0400 Subject: [PATCH 1259/2760] cpu: Don't set vcpu_dirty when guest_state_protected QEMU calls kvm_arch_put_registers() when vcpu_dirty is true in kvm_vcpu_exec(). However, for confidential guest, like TDX, putting registers is disallowed due to guest state is protected. Only set vcpu_dirty to true with guest state is not protected when creating the vcpu. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-43-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- accel/kvm/kvm-all.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 71e6060458..51526d301b 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -471,7 +471,9 @@ int kvm_create_vcpu(CPUState *cpu) cpu->kvm_fd = kvm_fd; cpu->kvm_state = s; - cpu->vcpu_dirty = true; + if (!s->guest_state_protected) { + cpu->vcpu_dirty = true; + } cpu->dirty_pages = 0; cpu->throttle_us_per_full = 0; From 695bfaee7153153708228946aa26c6d879599c04 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:49 -0400 Subject: [PATCH 1260/2760] i386/cgs: Rename *mask_cpuid_features() to *adjust_cpuid_features() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because for TDX case, there are also fixed-1 bits that enforced by TDX module. Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-44-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/confidential-guest.h | 20 ++++++++++---------- target/i386/kvm/kvm.c | 2 +- target/i386/sev.c | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/target/i386/confidential-guest.h b/target/i386/confidential-guest.h index a86c42a475..777d43cc96 100644 --- a/target/i386/confidential-guest.h +++ b/target/i386/confidential-guest.h @@ -40,8 +40,8 @@ struct X86ConfidentialGuestClass { /* */ int (*kvm_type)(X86ConfidentialGuest *cg); void (*cpu_instance_init)(X86ConfidentialGuest *cg, CPUState *cpu); - uint32_t (*mask_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, - int reg, uint32_t value); + uint32_t (*adjust_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature, + uint32_t index, int reg, uint32_t value); }; /** @@ -71,21 +71,21 @@ static inline void x86_confidential_guest_cpu_instance_init(X86ConfidentialGuest } /** - * x86_confidential_guest_mask_cpuid_features: + * x86_confidential_guest_adjust_cpuid_features: * - * Removes unsupported features from a confidential guest's CPUID values, returns - * the value with the bits removed. The bits removed should be those that KVM - * provides independent of host-supported CPUID features, but are not supported by - * the confidential computing firmware. + * Adjust the supported features from a confidential guest's CPUID values, + * returns the adjusted value. There are bits being removed that are not + * supported by the confidential computing firmware or bits being added that + * are forcibly exposed to guest by the confidential computing firmware. */ -static inline int x86_confidential_guest_mask_cpuid_features(X86ConfidentialGuest *cg, +static inline int x86_confidential_guest_adjust_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, int reg, uint32_t value) { X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg); - if (klass->mask_cpuid_features) { - return klass->mask_cpuid_features(cg, feature, index, reg, value); + if (klass->adjust_cpuid_features) { + return klass->adjust_cpuid_features(cg, feature, index, reg, value); } else { return value; } diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 90a0dac4a1..0d47463431 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -574,7 +574,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, } if (current_machine->cgs) { - ret = x86_confidential_guest_mask_cpuid_features( + ret = x86_confidential_guest_adjust_cpuid_features( X86_CONFIDENTIAL_GUEST(current_machine->cgs), function, index, reg, ret); } diff --git a/target/i386/sev.c b/target/i386/sev.c index 7ee700d6a3..8b87b7cdec 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -947,7 +947,7 @@ out: } static uint32_t -sev_snp_mask_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, +sev_snp_adjust_cpuid_features(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, int reg, uint32_t value) { switch (feature) { @@ -2405,7 +2405,7 @@ sev_snp_guest_class_init(ObjectClass *oc, const void *data) klass->launch_finish = sev_snp_launch_finish; klass->launch_update_data = sev_snp_launch_update_data; klass->kvm_init = sev_snp_kvm_init; - x86_klass->mask_cpuid_features = sev_snp_mask_cpuid_features; + x86_klass->adjust_cpuid_features = sev_snp_adjust_cpuid_features; x86_klass->kvm_type = sev_snp_kvm_type; object_class_property_add(oc, "policy", "uint64", From 75ec6189f5c65cab210dd9f16cf4eef368038d45 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:50 -0400 Subject: [PATCH 1261/2760] i386/tdx: Implement adjust_cpuid_features() for TDX Maintain a TDX specific supported CPUID set, and use it to mask the common supported CPUID value of KVM. It can avoid newly added supported features (reported via KVM_GET_SUPPORTED_CPUID) for common VMs being falsely reported as supported for TDX. As the first step, initialize the TDX supported CPUID set with all the configurable CPUID bits. It's not complete because there are other CPUID bits are supported for TDX but not reported as directly configurable. E.g. the XFAM related bits, attribute related bits and fixed-1 bits. They will be handled in the future. Also, what matters are the CPUID bits related to QEMU's feature word. Only mask the CPUID leafs which are feature word leaf. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-45-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 16 ++++++++++++++++ target/i386/cpu.h | 1 + target/i386/kvm/kvm.c | 2 +- target/i386/kvm/kvm_i386.h | 1 + target/i386/kvm/tdx.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6a97d7549e..5aacb62f08 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1678,6 +1678,22 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, }; +bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg) +{ + FeatureWordInfo *wi; + FeatureWord w; + + for (w = 0; w < FEATURE_WORDS; w++) { + wi = &feature_word_info[w]; + if (wi->type == CPUID_FEATURE_WORD && wi->cpuid.eax == feature && + (!wi->cpuid.needs_ecx || wi->cpuid.ecx == index) && + wi->cpuid.reg == reg) { + return true; + } + } + return false; +} + typedef struct FeatureMask { FeatureWord index; uint64_t mask; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index ad0e3d8cdd..7ffcf91b01 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2502,6 +2502,7 @@ void cpu_set_apic_feature(CPUX86State *env); void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); bool cpu_has_x2apic_feature(CPUX86State *env); +bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg); static inline bool x86_has_cpuid_0x1f(X86CPU *cpu) { diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 0d47463431..cd87f5502a 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -394,7 +394,7 @@ static bool host_tsx_broken(void) /* Returns the value for a specific register on the cpuid entry */ -static uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg) +uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg) { uint32_t ret = 0; switch (reg) { diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index dc696cb723..484a1de84d 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -62,6 +62,7 @@ void kvm_update_msi_routes_all(void *private, bool global, struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid2 *cpuid, uint32_t function, uint32_t index); +uint32_t cpuid_entry_get_reg(struct kvm_cpuid_entry2 *entry, int reg); uint32_t kvm_x86_build_cpuid(CPUX86State *env, struct kvm_cpuid_entry2 *entries, uint32_t cpuid_i); #endif /* CONFIG_KVM */ diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 68ed3b9f98..e3b7ad6d14 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -45,6 +45,7 @@ static TdxGuest *tdx_guest; static struct kvm_tdx_capabilities *tdx_caps; +static struct kvm_cpuid2 *tdx_supported_cpuid; /* Valid after kvm_arch_init()->confidential_guest_kvm_init()->tdx_kvm_init() */ bool is_tdx_vm(void) @@ -366,6 +367,20 @@ static Notifier tdx_machine_done_notify = { .notify = tdx_finalize_vm, }; +static void tdx_setup_supported_cpuid(void) +{ + if (tdx_supported_cpuid) { + return; + } + + tdx_supported_cpuid = g_malloc0(sizeof(*tdx_supported_cpuid) + + KVM_MAX_CPUID_ENTRIES * sizeof(struct kvm_cpuid_entry2)); + + memcpy(tdx_supported_cpuid->entries, tdx_caps->cpuid.entries, + tdx_caps->cpuid.nent * sizeof(struct kvm_cpuid_entry2)); + tdx_supported_cpuid->nent = tdx_caps->cpuid.nent; +} + static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -403,6 +418,8 @@ static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) } } + tdx_setup_supported_cpuid(); + /* TDX relies on KVM_HC_MAP_GPA_RANGE to handle TDG.VP.VMCALL */ if (!kvm_enable_hypercall(BIT_ULL(KVM_HC_MAP_GPA_RANGE))) { return -EOPNOTSUPP; @@ -440,6 +457,22 @@ static void tdx_cpu_instance_init(X86ConfidentialGuest *cg, CPUState *cpu) x86cpu->enable_cpuid_0x1f = true; } +static uint32_t tdx_adjust_cpuid_features(X86ConfidentialGuest *cg, + uint32_t feature, uint32_t index, + int reg, uint32_t value) +{ + struct kvm_cpuid_entry2 *e; + + if (is_feature_word_cpuid(feature, index, reg)) { + e = cpuid_find_entry(tdx_supported_cpuid, feature, index); + if (e) { + value &= cpuid_entry_get_reg(e, reg); + } + } + + return value; +} + static int tdx_validate_attributes(TdxGuest *tdx, Error **errp) { if ((tdx->attributes & ~tdx_caps->supported_attrs)) { @@ -834,4 +867,5 @@ static void tdx_guest_class_init(ObjectClass *oc, const void *data) klass->kvm_init = tdx_kvm_init; x86_klass->kvm_type = tdx_kvm_type; x86_klass->cpu_instance_init = tdx_cpu_instance_init; + x86_klass->adjust_cpuid_features = tdx_adjust_cpuid_features; } From 0ba06e46d09b84a2cb97a268da5576aaca3a24ca Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:51 -0400 Subject: [PATCH 1262/2760] i386/tdx: Add TDX fixed1 bits to supported CPUIDs TDX architecture forcibly sets some CPUID bits for TD guest that VMM cannot disable it. They are fixed1 bits. Fixed1 bits are not covered by tdx_caps.cpuid (which only contains the directly configurable bits), while fixed1 bits are supported for TD guest obviously. Add fixed1 bits to tdx_supported_cpuid. Besides, set all the fixed1 bits to the initial set of KVM's support since KVM might not report them as supported. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-46-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 2 + target/i386/kvm/kvm_i386.h | 7 ++ target/i386/kvm/tdx.c | 134 +++++++++++++++++++++++++++++++++++++ target/i386/sev.c | 8 --- 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7ffcf91b01..342e4f2a57 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -920,6 +920,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); #define CPUID_7_0_EDX_FSRM (1U << 4) /* AVX512 Vector Pair Intersection to a Pair of Mask Registers */ #define CPUID_7_0_EDX_AVX512_VP2INTERSECT (1U << 8) + /* "md_clear" VERW clears CPU buffers */ +#define CPUID_7_0_EDX_MD_CLEAR (1U << 10) /* SERIALIZE instruction */ #define CPUID_7_0_EDX_SERIALIZE (1U << 14) /* TSX Suspend Load Address Tracking instruction */ diff --git a/target/i386/kvm/kvm_i386.h b/target/i386/kvm/kvm_i386.h index 484a1de84d..5f83e8850a 100644 --- a/target/i386/kvm/kvm_i386.h +++ b/target/i386/kvm/kvm_i386.h @@ -44,6 +44,13 @@ void kvm_request_xsave_components(X86CPU *cpu, uint64_t mask); #ifdef CONFIG_KVM +#include + +typedef struct KvmCpuidInfo { + struct kvm_cpuid2 cpuid; + struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; +} KvmCpuidInfo; + bool kvm_is_vm_type_supported(int type); bool kvm_has_adjust_clock_stable(void); bool kvm_has_exception_payload(void); diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e3b7ad6d14..9d92ff1484 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -367,6 +367,133 @@ static Notifier tdx_machine_done_notify = { .notify = tdx_finalize_vm, }; +/* + * Some CPUID bits change from fixed1 to configurable bits when TDX module + * supports TDX_FEATURES0.VE_REDUCTION. e.g., MCA/MCE/MTRR/CORE_CAPABILITY. + * + * To make QEMU work with all the versions of TDX module, keep the fixed1 bits + * here if they are ever fixed1 bits in any of the version though not fixed1 in + * the latest version. Otherwise, with the older version of TDX module, QEMU may + * treat the fixed1 bit as unsupported. + * + * For newer TDX module, it does no harm to keep them in tdx_fixed1_bits even + * though they changed to configurable bits. Because tdx_fixed1_bits is used to + * setup the supported bits. + */ +KvmCpuidInfo tdx_fixed1_bits = { + .cpuid.nent = 8, + .entries[0] = { + .function = 0x1, + .index = 0, + .ecx = CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | CPUID_EXT_DTES64 | + CPUID_EXT_DSCPL | CPUID_EXT_SSSE3 | CPUID_EXT_CX16 | + CPUID_EXT_PDCM | CPUID_EXT_PCID | CPUID_EXT_SSE41 | + CPUID_EXT_SSE42 | CPUID_EXT_X2APIC | CPUID_EXT_MOVBE | + CPUID_EXT_POPCNT | CPUID_EXT_AES | CPUID_EXT_XSAVE | + CPUID_EXT_RDRAND | CPUID_EXT_HYPERVISOR, + .edx = CPUID_FP87 | CPUID_VME | CPUID_DE | CPUID_PSE | CPUID_TSC | + CPUID_MSR | CPUID_PAE | CPUID_MCE | CPUID_CX8 | CPUID_APIC | + CPUID_SEP | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | + CPUID_PAT | CPUID_CLFLUSH | CPUID_DTS | CPUID_MMX | CPUID_FXSR | + CPUID_SSE | CPUID_SSE2, + }, + .entries[1] = { + .function = 0x6, + .index = 0, + .eax = CPUID_6_EAX_ARAT, + }, + .entries[2] = { + .function = 0x7, + .index = 0, + .flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX, + .ebx = CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_FDP_EXCPTN_ONLY | + CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_INVPCID | + CPUID_7_0_EBX_ZERO_FCS_FDS | CPUID_7_0_EBX_RDSEED | + CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_CLFLUSHOPT | + CPUID_7_0_EBX_CLWB | CPUID_7_0_EBX_SHA_NI, + .ecx = CPUID_7_0_ECX_BUS_LOCK_DETECT | CPUID_7_0_ECX_MOVDIRI | + CPUID_7_0_ECX_MOVDIR64B, + .edx = CPUID_7_0_EDX_MD_CLEAR | CPUID_7_0_EDX_SPEC_CTRL | + CPUID_7_0_EDX_STIBP | CPUID_7_0_EDX_FLUSH_L1D | + CPUID_7_0_EDX_ARCH_CAPABILITIES | CPUID_7_0_EDX_CORE_CAPABILITY | + CPUID_7_0_EDX_SPEC_CTRL_SSBD, + }, + .entries[3] = { + .function = 0x7, + .index = 2, + .flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX, + .edx = CPUID_7_2_EDX_PSFD | CPUID_7_2_EDX_IPRED_CTRL | + CPUID_7_2_EDX_RRSBA_CTRL | CPUID_7_2_EDX_BHI_CTRL, + }, + .entries[4] = { + .function = 0xD, + .index = 0, + .flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX, + .eax = XSTATE_FP_MASK | XSTATE_SSE_MASK, + }, + .entries[5] = { + .function = 0xD, + .index = 1, + .flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX, + .eax = CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC| + CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, + }, + .entries[6] = { + .function = 0x80000001, + .index = 0, + .ecx = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_3DNOWPREFETCH, + /* + * Strictly speaking, SYSCALL is not fixed1 bit since it depends on + * the CPU to be in 64-bit mode. But here fixed1 is used to serve the + * purpose of supported bits for TDX. In this sense, SYACALL is always + * supported. + */ + .edx = CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | CPUID_EXT2_PDPE1GB | + CPUID_EXT2_RDTSCP | CPUID_EXT2_LM, + }, + .entries[7] = { + .function = 0x80000007, + .index = 0, + .edx = CPUID_APM_INVTSC, + }, +}; + +static struct kvm_cpuid_entry2 *find_in_supported_entry(uint32_t function, + uint32_t index) +{ + struct kvm_cpuid_entry2 *e; + + e = cpuid_find_entry(tdx_supported_cpuid, function, index); + if (!e) { + if (tdx_supported_cpuid->nent >= KVM_MAX_CPUID_ENTRIES) { + error_report("tdx_supported_cpuid requries more space than %d entries", + KVM_MAX_CPUID_ENTRIES); + exit(1); + } + e = &tdx_supported_cpuid->entries[tdx_supported_cpuid->nent++]; + e->function = function; + e->index = index; + } + + return e; +} + +static void tdx_add_supported_cpuid_by_fixed1_bits(void) +{ + struct kvm_cpuid_entry2 *e, *e1; + int i; + + for (i = 0; i < tdx_fixed1_bits.cpuid.nent; i++) { + e = &tdx_fixed1_bits.entries[i]; + + e1 = find_in_supported_entry(e->function, e->index); + e1->eax |= e->eax; + e1->ebx |= e->ebx; + e1->ecx |= e->ecx; + e1->edx |= e->edx; + } +} + static void tdx_setup_supported_cpuid(void) { if (tdx_supported_cpuid) { @@ -379,6 +506,8 @@ static void tdx_setup_supported_cpuid(void) memcpy(tdx_supported_cpuid->entries, tdx_caps->cpuid.entries, tdx_caps->cpuid.nent * sizeof(struct kvm_cpuid_entry2)); tdx_supported_cpuid->nent = tdx_caps->cpuid.nent; + + tdx_add_supported_cpuid_by_fixed1_bits(); } static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) @@ -463,6 +592,11 @@ static uint32_t tdx_adjust_cpuid_features(X86ConfidentialGuest *cg, { struct kvm_cpuid_entry2 *e; + e = cpuid_find_entry(&tdx_fixed1_bits.cpuid, feature, index); + if (e) { + value |= cpuid_entry_get_reg(e, reg); + } + if (is_feature_word_cpuid(feature, index, reg)) { e = cpuid_find_entry(tdx_supported_cpuid, feature, index); if (e) { diff --git a/target/i386/sev.c b/target/i386/sev.c index 8b87b7cdec..adf787797e 100644 --- a/target/i386/sev.c +++ b/target/i386/sev.c @@ -212,14 +212,6 @@ static const char *const sev_fw_errlist[] = { #define SEV_FW_MAX_ERROR ARRAY_SIZE(sev_fw_errlist) -/* doesn't expose this, so re-use the max from kvm.c */ -#define KVM_MAX_CPUID_ENTRIES 100 - -typedef struct KvmCpuidInfo { - struct kvm_cpuid2 cpuid; - struct kvm_cpuid_entry2 entries[KVM_MAX_CPUID_ENTRIES]; -} KvmCpuidInfo; - #define SNP_CPUID_FUNCTION_MAXCOUNT 64 #define SNP_CPUID_FUNCTION_UNKNOWN 0xFFFFFFFF From 31df29c532a9ef473c6efd497950a620099bf1da Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:52 -0400 Subject: [PATCH 1263/2760] i386/tdx: Add supported CPUID bits related to TD Attributes For TDX, some CPUID feature bit is configured via TD attributes. They are not covered by tdx_caps.cpuid (which only contians the directly configurable CPUID bits), but they are actually supported when the related attributre bit is supported. Note, LASS and KeyLocker are not supported by KVM for TDX, nor does QEMU support it (see TDX_SUPPORTED_TD_ATTRS). They are defined in tdx_attrs_maps[] for the completeness of the existing TD Attribute bits that are related with CPUID features. Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250508150002.689633-47-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 4 +++ target/i386/kvm/tdx.c | 60 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 342e4f2a57..e50c57264d 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -899,6 +899,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); #define CPUID_7_0_ECX_LA57 (1U << 16) /* Read Processor ID */ #define CPUID_7_0_ECX_RDPID (1U << 22) +/* KeyLocker */ +#define CPUID_7_0_ECX_KeyLocker (1U << 23) /* Bus Lock Debug Exception */ #define CPUID_7_0_ECX_BUS_LOCK_DETECT (1U << 24) /* Cache Line Demote Instruction */ @@ -959,6 +961,8 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); #define CPUID_7_1_EAX_AVX_VNNI (1U << 4) /* AVX512 BFloat16 Instruction */ #define CPUID_7_1_EAX_AVX512_BF16 (1U << 5) +/* Linear address space separation */ +#define CPUID_7_1_EAX_LASS (1U << 6) /* CMPCCXADD Instructions */ #define CPUID_7_1_EAX_CMPCCXADD (1U << 7) /* Fast Zero REP MOVS */ diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 9d92ff1484..fa161661fa 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -458,6 +458,34 @@ KvmCpuidInfo tdx_fixed1_bits = { }, }; +typedef struct TdxAttrsMap { + uint32_t attr_index; + uint32_t cpuid_leaf; + uint32_t cpuid_subleaf; + int cpuid_reg; + uint32_t feat_mask; +} TdxAttrsMap; + +static TdxAttrsMap tdx_attrs_maps[] = { + {.attr_index = 27, + .cpuid_leaf = 7, + .cpuid_subleaf = 1, + .cpuid_reg = R_EAX, + .feat_mask = CPUID_7_1_EAX_LASS,}, + + {.attr_index = 30, + .cpuid_leaf = 7, + .cpuid_subleaf = 0, + .cpuid_reg = R_ECX, + .feat_mask = CPUID_7_0_ECX_PKS,}, + + {.attr_index = 31, + .cpuid_leaf = 7, + .cpuid_subleaf = 0, + .cpuid_reg = R_ECX, + .feat_mask = CPUID_7_0_ECX_KeyLocker,}, +}; + static struct kvm_cpuid_entry2 *find_in_supported_entry(uint32_t function, uint32_t index) { @@ -494,6 +522,37 @@ static void tdx_add_supported_cpuid_by_fixed1_bits(void) } } +static void tdx_add_supported_cpuid_by_attrs(void) +{ + struct kvm_cpuid_entry2 *e; + TdxAttrsMap *map; + int i; + + for (i = 0; i < ARRAY_SIZE(tdx_attrs_maps); i++) { + map = &tdx_attrs_maps[i]; + if (!((1ULL << map->attr_index) & tdx_caps->supported_attrs)) { + continue; + } + + e = find_in_supported_entry(map->cpuid_leaf, map->cpuid_subleaf); + + switch(map->cpuid_reg) { + case R_EAX: + e->eax |= map->feat_mask; + break; + case R_EBX: + e->ebx |= map->feat_mask; + break; + case R_ECX: + e->ecx |= map->feat_mask; + break; + case R_EDX: + e->edx |= map->feat_mask; + break; + } + } +} + static void tdx_setup_supported_cpuid(void) { if (tdx_supported_cpuid) { @@ -508,6 +567,7 @@ static void tdx_setup_supported_cpuid(void) tdx_supported_cpuid->nent = tdx_caps->cpuid.nent; tdx_add_supported_cpuid_by_fixed1_bits(); + tdx_add_supported_cpuid_by_attrs(); } static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) From 8c94c84cb9e0140b48acc9c9d404525ca7ef7457 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:53 -0400 Subject: [PATCH 1264/2760] i386/tdx: Add supported CPUID bits relates to XFAM Some CPUID bits are controlled by XFAM. They are not covered by tdx_caps.cpuid (which only contians the directly configurable bits), but they are actually supported when the related XFAM bit is supported. Add these XFAM controlled bits to TDX supported CPUID bits based on the supported_xfam. Besides, incorporate the supported_xfam into the supported CPUID leaf of 0xD. Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250508150002.689633-48-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 12 ------- target/i386/cpu.h | 16 ++++++++++ target/i386/kvm/tdx.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5aacb62f08..383c0b35d4 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1694,15 +1694,6 @@ bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg) return false; } -typedef struct FeatureMask { - FeatureWord index; - uint64_t mask; -} FeatureMask; - -typedef struct FeatureDep { - FeatureMask from, to; -} FeatureDep; - static FeatureDep feature_dependencies[] = { { .from = { FEAT_7_0_EDX, CPUID_7_0_EDX_ARCH_CAPABILITIES }, @@ -1871,9 +1862,6 @@ static const X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { }; #undef REGISTER -/* CPUID feature bits available in XSS */ -#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK) - ExtSaveArea x86_ext_save_areas[XSAVE_STATE_AREA_COUNT] = { [XSTATE_FP_BIT] = { /* x87 FP state component is always enabled if XSAVE is supported */ diff --git a/target/i386/cpu.h b/target/i386/cpu.h index e50c57264d..b38e691f1a 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -584,6 +584,7 @@ typedef enum X86Seg { #define XSTATE_OPMASK_BIT 5 #define XSTATE_ZMM_Hi256_BIT 6 #define XSTATE_Hi16_ZMM_BIT 7 +#define XSTATE_PT_BIT 8 #define XSTATE_PKRU_BIT 9 #define XSTATE_ARCH_LBR_BIT 15 #define XSTATE_XTILE_CFG_BIT 17 @@ -597,6 +598,7 @@ typedef enum X86Seg { #define XSTATE_OPMASK_MASK (1ULL << XSTATE_OPMASK_BIT) #define XSTATE_ZMM_Hi256_MASK (1ULL << XSTATE_ZMM_Hi256_BIT) #define XSTATE_Hi16_ZMM_MASK (1ULL << XSTATE_Hi16_ZMM_BIT) +#define XSTATE_PT_MASK (1ULL << XSTATE_PT_BIT) #define XSTATE_PKRU_MASK (1ULL << XSTATE_PKRU_BIT) #define XSTATE_ARCH_LBR_MASK (1ULL << XSTATE_ARCH_LBR_BIT) #define XSTATE_XTILE_CFG_MASK (1ULL << XSTATE_XTILE_CFG_BIT) @@ -619,6 +621,11 @@ typedef enum X86Seg { XSTATE_Hi16_ZMM_MASK | XSTATE_PKRU_MASK | \ XSTATE_XTILE_CFG_MASK | XSTATE_XTILE_DATA_MASK) +/* CPUID feature bits available in XSS */ +#define CPUID_XSTATE_XSS_MASK (XSTATE_ARCH_LBR_MASK) + +#define CPUID_XSTATE_MASK (CPUID_XSTATE_XCR0_MASK | CPUID_XSTATE_XSS_MASK) + /* CPUID feature words */ typedef enum FeatureWord { FEAT_1_EDX, /* CPUID[1].EDX */ @@ -667,6 +674,15 @@ typedef enum FeatureWord { FEATURE_WORDS, } FeatureWord; +typedef struct FeatureMask { + FeatureWord index; + uint64_t mask; +} FeatureMask; + +typedef struct FeatureDep { + FeatureMask from, to; +} FeatureDep; + typedef uint64_t FeatureWordArray[FEATURE_WORDS]; uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index fa161661fa..188c2242d5 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -23,6 +23,8 @@ #include +#include "cpu.h" +#include "cpu-internal.h" #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" @@ -486,6 +488,32 @@ static TdxAttrsMap tdx_attrs_maps[] = { .feat_mask = CPUID_7_0_ECX_KeyLocker,}, }; +typedef struct TdxXFAMDep { + int xfam_bit; + FeatureMask feat_mask; +} TdxXFAMDep; + +/* + * Note, only the CPUID bits whose virtualization type are "XFAM & Native" are + * defiend here. + * + * For those whose virtualization type are "XFAM & Configured & Native", they + * are reported as configurable bits. And they are not supported if not in the + * configureable bits list from KVM even if the corresponding XFAM bit is + * supported. + */ +TdxXFAMDep tdx_xfam_deps[] = { + { XSTATE_YMM_BIT, { FEAT_1_ECX, CPUID_EXT_FMA }}, + { XSTATE_YMM_BIT, { FEAT_7_0_EBX, CPUID_7_0_EBX_AVX2 }}, + { XSTATE_OPMASK_BIT, { FEAT_7_0_ECX, CPUID_7_0_ECX_AVX512_VBMI}}, + { XSTATE_OPMASK_BIT, { FEAT_7_0_EDX, CPUID_7_0_EDX_AVX512_FP16}}, + { XSTATE_PT_BIT, { FEAT_7_0_EBX, CPUID_7_0_EBX_INTEL_PT}}, + { XSTATE_PKRU_BIT, { FEAT_7_0_ECX, CPUID_7_0_ECX_PKU}}, + { XSTATE_XTILE_CFG_BIT, { FEAT_7_0_EDX, CPUID_7_0_EDX_AMX_BF16 }}, + { XSTATE_XTILE_CFG_BIT, { FEAT_7_0_EDX, CPUID_7_0_EDX_AMX_TILE }}, + { XSTATE_XTILE_CFG_BIT, { FEAT_7_0_EDX, CPUID_7_0_EDX_AMX_INT8 }}, +}; + static struct kvm_cpuid_entry2 *find_in_supported_entry(uint32_t function, uint32_t index) { @@ -553,6 +581,50 @@ static void tdx_add_supported_cpuid_by_attrs(void) } } +static void tdx_add_supported_cpuid_by_xfam(void) +{ + struct kvm_cpuid_entry2 *e; + int i; + + const TdxXFAMDep *xfam_dep; + const FeatureWordInfo *f; + for (i = 0; i < ARRAY_SIZE(tdx_xfam_deps); i++) { + xfam_dep = &tdx_xfam_deps[i]; + if (!((1ULL << xfam_dep->xfam_bit) & tdx_caps->supported_xfam)) { + continue; + } + + f = &feature_word_info[xfam_dep->feat_mask.index]; + if (f->type != CPUID_FEATURE_WORD) { + continue; + } + + e = find_in_supported_entry(f->cpuid.eax, f->cpuid.ecx); + switch(f->cpuid.reg) { + case R_EAX: + e->eax |= xfam_dep->feat_mask.mask; + break; + case R_EBX: + e->ebx |= xfam_dep->feat_mask.mask; + break; + case R_ECX: + e->ecx |= xfam_dep->feat_mask.mask; + break; + case R_EDX: + e->edx |= xfam_dep->feat_mask.mask; + break; + } + } + + e = find_in_supported_entry(0xd, 0); + e->eax |= (tdx_caps->supported_xfam & CPUID_XSTATE_XCR0_MASK); + e->edx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XCR0_MASK) >> 32; + + e = find_in_supported_entry(0xd, 1); + e->ecx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XSS_MASK); + e->edx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XSS_MASK) >> 32; +} + static void tdx_setup_supported_cpuid(void) { if (tdx_supported_cpuid) { @@ -568,6 +640,7 @@ static void tdx_setup_supported_cpuid(void) tdx_add_supported_cpuid_by_fixed1_bits(); tdx_add_supported_cpuid_by_attrs(); + tdx_add_supported_cpuid_by_xfam(); } static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) From 9f5771c57dbe92d46361afd992a5851c846d0322 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:54 -0400 Subject: [PATCH 1265/2760] i386/tdx: Add XFD to supported bit of TDX Just mark XFD as always supported for TDX. This simple solution relies on the fact KVM will report XFD as 0 when it's not supported by the hardware. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-49-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.h | 1 + target/i386/kvm/tdx.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index b38e691f1a..8a4b4217d0 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1122,6 +1122,7 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); #define CPUID_XSAVE_XSAVEC (1U << 1) #define CPUID_XSAVE_XGETBV1 (1U << 2) #define CPUID_XSAVE_XSAVES (1U << 3) +#define CPUID_XSAVE_XFD (1U << 4) #define CPUID_6_EAX_ARAT (1U << 2) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 188c2242d5..0f7f47c6da 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -621,6 +621,12 @@ static void tdx_add_supported_cpuid_by_xfam(void) e->edx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XCR0_MASK) >> 32; e = find_in_supported_entry(0xd, 1); + /* + * Mark XFD always support for TDX, it will be cleared finally in + * tdx_adjust_cpuid_features() if XFD is unavailable on the hardware + * because in this case the original data has it as 0. + */ + e->eax |= CPUID_XSAVE_XFD; e->ecx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XSS_MASK); e->edx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XSS_MASK) >> 32; } From 4d6e288a350a977b0fb0613db952087928ccd93e Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:55 -0400 Subject: [PATCH 1266/2760] i386/tdx: Define supported KVM features for TDX For TDX, only limited KVM PV features are supported. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-50-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 0f7f47c6da..e35983ad9b 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -32,6 +32,8 @@ #include "kvm_i386.h" #include "tdx.h" +#include "standard-headers/asm-x86/kvm_para.h" + #define TDX_MIN_TSC_FREQUENCY_KHZ (100 * 1000) #define TDX_MAX_TSC_FREQUENCY_KHZ (10 * 1000 * 1000) @@ -44,6 +46,14 @@ TDX_TD_ATTRIBUTES_PKS | \ TDX_TD_ATTRIBUTES_PERFMON) +#define TDX_SUPPORTED_KVM_FEATURES ((1U << KVM_FEATURE_NOP_IO_DELAY) | \ + (1U << KVM_FEATURE_PV_UNHALT) | \ + (1U << KVM_FEATURE_PV_TLB_FLUSH) | \ + (1U << KVM_FEATURE_PV_SEND_IPI) | \ + (1U << KVM_FEATURE_POLL_CONTROL) | \ + (1U << KVM_FEATURE_PV_SCHED_YIELD) | \ + (1U << KVM_FEATURE_MSI_EXT_DEST_ID)) + static TdxGuest *tdx_guest; static struct kvm_tdx_capabilities *tdx_caps; @@ -631,6 +641,14 @@ static void tdx_add_supported_cpuid_by_xfam(void) e->edx |= (tdx_caps->supported_xfam & CPUID_XSTATE_XSS_MASK) >> 32; } +static void tdx_add_supported_kvm_features(void) +{ + struct kvm_cpuid_entry2 *e; + + e = find_in_supported_entry(0x40000001, 0); + e->eax = TDX_SUPPORTED_KVM_FEATURES; +} + static void tdx_setup_supported_cpuid(void) { if (tdx_supported_cpuid) { @@ -647,6 +665,8 @@ static void tdx_setup_supported_cpuid(void) tdx_add_supported_cpuid_by_fixed1_bits(); tdx_add_supported_cpuid_by_attrs(); tdx_add_supported_cpuid_by_xfam(); + + tdx_add_supported_kvm_features(); } static int tdx_kvm_init(ConfidentialGuestSupport *cgs, Error **errp) From dc0b08b303ad34983b43936a4c978672e0f9a9d8 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:56 -0400 Subject: [PATCH 1267/2760] i386/cgs: Introduce x86_confidential_guest_check_features() To do cgs specific feature checking. Note the feature checking in x86_cpu_filter_features() is valid for non-cgs VMs. For cgs VMs like TDX, what features can be supported has more restrictions. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-51-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/confidential-guest.h | 13 +++++++++++++ target/i386/kvm/kvm.c | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/target/i386/confidential-guest.h b/target/i386/confidential-guest.h index 777d43cc96..48b88dbd31 100644 --- a/target/i386/confidential-guest.h +++ b/target/i386/confidential-guest.h @@ -42,6 +42,7 @@ struct X86ConfidentialGuestClass { void (*cpu_instance_init)(X86ConfidentialGuest *cg, CPUState *cpu); uint32_t (*adjust_cpuid_features)(X86ConfidentialGuest *cg, uint32_t feature, uint32_t index, int reg, uint32_t value); + int (*check_features)(X86ConfidentialGuest *cg, CPUState *cs); }; /** @@ -91,4 +92,16 @@ static inline int x86_confidential_guest_adjust_cpuid_features(X86ConfidentialGu } } +static inline int x86_confidential_guest_check_features(X86ConfidentialGuest *cg, + CPUState *cs) +{ + X86ConfidentialGuestClass *klass = X86_CONFIDENTIAL_GUEST_GET_CLASS(cg); + + if (klass->check_features) { + return klass->check_features(cg, cs); + } + + return 0; +} + #endif diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index cd87f5502a..a6bc089d02 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2093,6 +2093,14 @@ int kvm_arch_init_vcpu(CPUState *cs) int r; Error *local_err = NULL; + if (current_machine->cgs) { + r = x86_confidential_guest_check_features( + X86_CONFIDENTIAL_GUEST(current_machine->cgs), cs); + if (r < 0) { + return r; + } + } + memset(&cpuid_data, 0, sizeof(cpuid_data)); cpuid_i = 0; From 4a2fb19669bb41eee5b2fb8e5b5ba30e1daaeaf5 Mon Sep 17 00:00:00 2001 From: Lei Wang Date: Tue, 17 Dec 2024 07:39:31 -0500 Subject: [PATCH 1268/2760] i386: Remove unused parameter "uint32_t bit" in feature_word_description() Parameter "uint32_t bit" is not used in function feature_word_description(), so remove it. Signed-off-by: Lei Wang Reviewed-by: Igor Mammedov Reviewed-by: Xiaoyao Li Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20241217123932.948789-2-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 383c0b35d4..6258027ab1 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5771,7 +5771,7 @@ static const TypeInfo max_x86_cpu_type_info = { .class_init = max_x86_cpu_class_init, }; -static char *feature_word_description(FeatureWordInfo *f, uint32_t bit) +static char *feature_word_description(FeatureWordInfo *f) { assert(f->type == CPUID_FEATURE_WORD || f->type == MSR_FEATURE_WORD); @@ -5810,6 +5810,7 @@ static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, CPUX86State *env = &cpu->env; FeatureWordInfo *f = &feature_word_info[w]; int i; + g_autofree char *feat_word_str = feature_word_description(f); if (!cpu->force_features) { env->features[w] &= ~mask; @@ -5822,7 +5823,6 @@ static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, for (i = 0; i < 64; ++i) { if ((1ULL << i) & mask) { - g_autofree char *feat_word_str = feature_word_description(f, i); warn_report("%s: %s%s%s [bit %d]", verbose_prefix, feat_word_str, From adf25ad70f2f989e63c2cd3e9de4e38152d05e84 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Tue, 17 Dec 2024 07:39:32 -0500 Subject: [PATCH 1269/2760] target/i386: Print CPUID subleaf info for unsupported feature Some CPUID leaves have meaningful subleaf index. Print the subleaf info in feature_word_description for CPUID features. Signed-off-by: Xiaoyao Li Reviewed-by: Eduardo Habkost Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20241217123932.948789-3-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 6258027ab1..be3812973f 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5780,11 +5780,15 @@ static char *feature_word_description(FeatureWordInfo *f) { const char *reg = get_register_name_32(f->cpuid.reg); assert(reg); - return g_strdup_printf("CPUID.%02XH:%s", - f->cpuid.eax, reg); + if (!f->cpuid.needs_ecx) { + return g_strdup_printf("CPUID[eax=%02Xh].%s", f->cpuid.eax, reg); + } else { + return g_strdup_printf("CPUID[eax=%02Xh,ecx=%02Xh].%s", + f->cpuid.eax, f->cpuid.ecx, reg); + } } case MSR_FEATURE_WORD: - return g_strdup_printf("MSR(%02XH)", + return g_strdup_printf("MSR(%02Xh)", f->msr.index); } From e3d1a4a6d1d61cf5fbd0e4b389cfb3976093739f Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:57 -0400 Subject: [PATCH 1270/2760] i386/tdx: Fetch and validate CPUID of TD guest Use KVM_TDX_GET_CPUID to get the CPUIDs that are managed and enfored by TDX module for TD guest. Check QEMU's configuration against the fetched data. Print wanring message when 1. a feature is not supported but requested by QEMU or 2. QEMU doesn't want to expose a feature while it is enforced enabled. - If cpu->enforced_cpuid is not set, prints the warning message of both 1) and 2) and tweak QEMU's configuration. - If cpu->enforced_cpuid is set, quit if any case of 1) or 2). Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250508150002.689633-52-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 33 +++++++++++++- target/i386/cpu.h | 7 +++ target/i386/kvm/tdx.c | 101 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index be3812973f..34364cf96a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -5808,8 +5808,8 @@ static bool x86_cpu_have_filtered_features(X86CPU *cpu) return false; } -static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, - const char *verbose_prefix) +void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, + const char *verbose_prefix) { CPUX86State *env = &cpu->env; FeatureWordInfo *f = &feature_word_info[w]; @@ -5836,6 +5836,35 @@ static void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, } } +void mark_forced_on_features(X86CPU *cpu, FeatureWord w, uint64_t mask, + const char *verbose_prefix) +{ + CPUX86State *env = &cpu->env; + FeatureWordInfo *f = &feature_word_info[w]; + int i; + + if (!cpu->force_features) { + env->features[w] |= mask; + } + + cpu->forced_on_features[w] |= mask; + + if (!verbose_prefix) { + return; + } + + for (i = 0; i < 64; ++i) { + if ((1ULL << i) & mask) { + g_autofree char *feat_word_str = feature_word_description(f); + warn_report("%s: %s%s%s [bit %d]", + verbose_prefix, + feat_word_str, + f->feat_names[i] ? "." : "", + f->feat_names[i] ? f->feat_names[i] : "", i); + } + } +} + static void x86_cpuid_version_get_family(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 8a4b4217d0..22e82444ae 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -2215,6 +2215,9 @@ struct ArchCPU { /* Features that were filtered out because of missing host capabilities */ FeatureWordArray filtered_features; + /* Features that are forced enabled by underlying hypervisor, e.g., TDX */ + FeatureWordArray forced_on_features; + /* Enable PMU CPUID bits. This can't be enabled by default yet because * it doesn't have ABI stability guarantees, as it passes all PMU CPUID * bits returned by GET_SUPPORTED_CPUID (that depend on host CPU and kernel @@ -2526,6 +2529,10 @@ void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); bool cpu_has_x2apic_feature(CPUX86State *env); bool is_feature_word_cpuid(uint32_t feature, uint32_t index, int reg); +void mark_unavailable_features(X86CPU *cpu, FeatureWord w, uint64_t mask, + const char *verbose_prefix); +void mark_forced_on_features(X86CPU *cpu, FeatureWord w, uint64_t mask, + const char *verbose_prefix); static inline bool x86_has_cpuid_0x1f(X86CPU *cpu) { diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e35983ad9b..e474abf3a6 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -766,6 +766,106 @@ static uint32_t tdx_adjust_cpuid_features(X86ConfidentialGuest *cg, return value; } +static struct kvm_cpuid2 *tdx_fetch_cpuid(CPUState *cpu, int *ret) +{ + struct kvm_cpuid2 *fetch_cpuid; + int size = KVM_MAX_CPUID_ENTRIES; + Error *local_err = NULL; + int r; + + do { + error_free(local_err); + local_err = NULL; + + fetch_cpuid = g_malloc0(sizeof(*fetch_cpuid) + + sizeof(struct kvm_cpuid_entry2) * size); + fetch_cpuid->nent = size; + r = tdx_vcpu_ioctl(cpu, KVM_TDX_GET_CPUID, 0, fetch_cpuid, &local_err); + if (r == -E2BIG) { + g_free(fetch_cpuid); + size = fetch_cpuid->nent; + } + } while (r == -E2BIG); + + if (r < 0) { + error_report_err(local_err); + *ret = r; + return NULL; + } + + return fetch_cpuid; +} + +static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs) +{ + uint64_t actual, requested, unavailable, forced_on; + g_autofree struct kvm_cpuid2 *fetch_cpuid; + const char *forced_on_prefix = NULL; + const char *unav_prefix = NULL; + struct kvm_cpuid_entry2 *entry; + X86CPU *cpu = X86_CPU(cs); + CPUX86State *env = &cpu->env; + FeatureWordInfo *wi; + FeatureWord w; + bool mismatch = false; + int r; + + fetch_cpuid = tdx_fetch_cpuid(cs, &r); + if (!fetch_cpuid) { + return r; + } + + if (cpu->check_cpuid || cpu->enforce_cpuid) { + unav_prefix = "TDX doesn't support requested feature"; + forced_on_prefix = "TDX forcibly sets the feature"; + } + + for (w = 0; w < FEATURE_WORDS; w++) { + wi = &feature_word_info[w]; + actual = 0; + + switch (wi->type) { + case CPUID_FEATURE_WORD: + entry = cpuid_find_entry(fetch_cpuid, wi->cpuid.eax, wi->cpuid.ecx); + if (!entry) { + /* + * If KVM doesn't report it means it's totally configurable + * by QEMU + */ + continue; + } + + actual = cpuid_entry_get_reg(entry, wi->cpuid.reg); + break; + case MSR_FEATURE_WORD: + /* + * TODO: + * validate MSR features when KVM has interface report them. + */ + continue; + } + + requested = env->features[w]; + unavailable = requested & ~actual; + mark_unavailable_features(cpu, w, unavailable, unav_prefix); + if (unavailable) { + mismatch = true; + } + + forced_on = actual & ~requested; + mark_forced_on_features(cpu, w, forced_on, forced_on_prefix); + if (forced_on) { + mismatch = true; + } + } + + if (cpu->enforce_cpuid && mismatch) { + return -EINVAL; + } + + return 0; +} + static int tdx_validate_attributes(TdxGuest *tdx, Error **errp) { if ((tdx->attributes & ~tdx_caps->supported_attrs)) { @@ -1161,4 +1261,5 @@ static void tdx_guest_class_init(ObjectClass *oc, const void *data) x86_klass->kvm_type = tdx_kvm_type; x86_klass->cpu_instance_init = tdx_cpu_instance_init; x86_klass->adjust_cpuid_features = tdx_adjust_cpuid_features; + x86_klass->check_features = tdx_check_features; } From deb9db6fb789cfe80527b75983e86137589227a4 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:58 -0400 Subject: [PATCH 1271/2760] i386/tdx: Don't treat SYSCALL as unavailable On Intel CPU, the value of CPUID_EXT2_SYSCALL depends on the mode of the vcpu. It's 0 outside 64-bit mode and 1 in 64-bit mode. The initial state of TDX vcpu is 32-bit protected mode. At the time of calling KVM_TDX_GET_CPUID, vcpu hasn't started running so the value read is 0. In reality, 64-bit mode should always be supported. So mark CPUID_EXT2_SYSCALL always supported to avoid false warning. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-53-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index e474abf3a6..7629302991 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -845,6 +845,19 @@ static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs) continue; } + /* Fixup for special cases */ + switch (w) { + case FEAT_8000_0001_EDX: + /* + * Intel enumerates SYSCALL bit as 1 only when processor in 64-bit + * mode and before vcpu running it's not in 64-bit mode. + */ + actual |= CPUID_EXT2_SYSCALL; + break; + default: + break; + } + requested = env->features[w]; unavailable = requested & ~actual; mark_unavailable_features(cpu, w, unavailable, unav_prefix); From ea4867b911fc2f6d4c8bd50ec62f0dc0fa190fab Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 10:59:59 -0400 Subject: [PATCH 1272/2760] i386/tdx: Make invtsc default on Because it's fixed1 bit that enforced by TDX module. Signed-off-by: Xiaoyao Li Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-54-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/kvm/tdx.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index 7629302991..a55ab436ad 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -742,6 +742,9 @@ static void tdx_cpu_instance_init(X86ConfidentialGuest *cg, CPUState *cpu) object_property_set_bool(OBJECT(cpu), "pmu", false, &error_abort); + /* invtsc is fixed1 for TD guest */ + object_property_set_bool(OBJECT(cpu), "invtsc", true, &error_abort); + x86cpu->enable_cpuid_0x1f = true; } From 907ee7b67e50a7eea2768c66e3ad67c9aa4ffd3c Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 11:00:00 -0400 Subject: [PATCH 1273/2760] i386/tdx: Validate phys_bits against host value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For TDX guest, the phys_bits is not configurable and can only be host/native value. Validate phys_bits inside tdx_check_features(). Signed-off-by: Xiaoyao Li Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/20250508150002.689633-55-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- target/i386/host-cpu.c | 2 +- target/i386/host-cpu.h | 1 + target/i386/kvm/tdx.c | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/target/i386/host-cpu.c b/target/i386/host-cpu.c index a2d3830f5b..7512567298 100644 --- a/target/i386/host-cpu.c +++ b/target/i386/host-cpu.c @@ -15,7 +15,7 @@ #include "system/system.h" /* Note: Only safe for use on x86(-64) hosts */ -static uint32_t host_cpu_phys_bits(void) +uint32_t host_cpu_phys_bits(void) { uint32_t eax; uint32_t host_phys_bits; diff --git a/target/i386/host-cpu.h b/target/i386/host-cpu.h index 6a9bc918ba..b97ec01c9b 100644 --- a/target/i386/host-cpu.h +++ b/target/i386/host-cpu.h @@ -10,6 +10,7 @@ #ifndef HOST_CPU_H #define HOST_CPU_H +uint32_t host_cpu_phys_bits(void); void host_cpu_instance_init(X86CPU *cpu); void host_cpu_max_instance_init(X86CPU *cpu); bool host_cpu_realizefn(CPUState *cs, Error **errp); diff --git a/target/i386/kvm/tdx.c b/target/i386/kvm/tdx.c index a55ab436ad..0a21ae555c 100644 --- a/target/i386/kvm/tdx.c +++ b/target/i386/kvm/tdx.c @@ -25,6 +25,7 @@ #include "cpu.h" #include "cpu-internal.h" +#include "host-cpu.h" #include "hw/i386/e820_memory_layout.h" #include "hw/i386/tdvf.h" #include "hw/i386/x86.h" @@ -879,6 +880,13 @@ static int tdx_check_features(X86ConfidentialGuest *cg, CPUState *cs) return -EINVAL; } + if (cpu->phys_bits != host_cpu_phys_bits()) { + error_report("TDX requires guest CPU physical bits (%u) " + "to match host CPU physical bits (%u)", + cpu->phys_bits, host_cpu_phys_bits()); + return -EINVAL; + } + return 0; } From dc1424319311f86449c6825ceec2364ee645a363 Mon Sep 17 00:00:00 2001 From: Xiaoyao Li Date: Thu, 8 May 2025 11:00:01 -0400 Subject: [PATCH 1274/2760] docs: Add TDX documentation Add docs/system/i386/tdx.rst for TDX support, and add tdx in confidential-guest-support.rst Signed-off-by: Xiaoyao Li Link: https://lore.kernel.org/r/20250508150002.689633-56-xiaoyao.li@intel.com Signed-off-by: Paolo Bonzini --- docs/system/confidential-guest-support.rst | 1 + docs/system/i386/tdx.rst | 161 +++++++++++++++++++++ docs/system/target-i386.rst | 1 + 3 files changed, 163 insertions(+) create mode 100644 docs/system/i386/tdx.rst diff --git a/docs/system/confidential-guest-support.rst b/docs/system/confidential-guest-support.rst index 0c490dbda2..66129fbab6 100644 --- a/docs/system/confidential-guest-support.rst +++ b/docs/system/confidential-guest-support.rst @@ -38,6 +38,7 @@ Supported mechanisms Currently supported confidential guest mechanisms are: * AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`) +* Intel Trust Domain Extension (TDX) (see :doc:`i386/tdx`) * POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`) * s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`) diff --git a/docs/system/i386/tdx.rst b/docs/system/i386/tdx.rst new file mode 100644 index 0000000000..8131750b64 --- /dev/null +++ b/docs/system/i386/tdx.rst @@ -0,0 +1,161 @@ +Intel Trusted Domain eXtension (TDX) +==================================== + +Intel Trusted Domain eXtensions (TDX) refers to an Intel technology that extends +Virtual Machine Extensions (VMX) and Multi-Key Total Memory Encryption (MKTME) +with a new kind of virtual machine guest called a Trust Domain (TD). A TD runs +in a CPU mode that is designed to protect the confidentiality of its memory +contents and its CPU state from any other software, including the hosting +Virtual Machine Monitor (VMM), unless explicitly shared by the TD itself. + +Prerequisites +------------- + +To run TD, the physical machine needs to have TDX module loaded and initialized +while KVM hypervisor has TDX support and has TDX enabled. If those requirements +are met, the ``KVM_CAP_VM_TYPES`` will report the support of ``KVM_X86_TDX_VM``. + +Trust Domain Virtual Firmware (TDVF) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Trust Domain Virtual Firmware (TDVF) is required to provide TD services to boot +TD Guest OS. TDVF needs to be copied to guest private memory and measured before +the TD boots. + +KVM vcpu ioctl ``KVM_TDX_INIT_MEM_REGION`` can be used to populate the TDVF +content into its private memory. + +Since TDX doesn't support readonly memslot, TDVF cannot be mapped as pflash +device and it actually works as RAM. "-bios" option is chosen to load TDVF. + +OVMF is the opensource firmware that implements the TDVF support. Thus the +command line to specify and load TDVF is ``-bios OVMF.fd`` + +Feature Configuration +--------------------- + +Unlike non-TDX VM, the CPU features (enumerated by CPU or MSR) of a TD are not +under full control of VMM. VMM can only configure part of features of a TD on +``KVM_TDX_INIT_VM`` command of VM scope ``MEMORY_ENCRYPT_OP`` ioctl. + +The configurable features have three types: + +- Attributes: + - PKS (bit 30) controls whether Supervisor Protection Keys is exposed to TD, + which determines related CPUID bit and CR4 bit; + - PERFMON (bit 63) controls whether PMU is exposed to TD. + +- XSAVE related features (XFAM): + XFAM is a 64b mask, which has the same format as XCR0 or IA32_XSS MSR. It + determines the set of extended features available for use by the guest TD. + +- CPUID features: + Only some bits of some CPUID leaves are directly configurable by VMM. + +What features can be configured is reported via TDX capabilities. + +TDX capabilities +~~~~~~~~~~~~~~~~ + +The VM scope ``MEMORY_ENCRYPT_OP`` ioctl provides command ``KVM_TDX_CAPABILITIES`` +to get the TDX capabilities from KVM. It returns a data structure of +``struct kvm_tdx_capabilities``, which tells the supported configuration of +attributes, XFAM and CPUIDs. + +TD attributes +~~~~~~~~~~~~~ + +QEMU supports configuring raw 64-bit TD attributes directly via "attributes" +property of "tdx-guest" object. Note, it's users' responsibility to provide a +valid value because some bits may not supported by current QEMU or KVM yet. + +QEMU also supports the configuration of individual attribute bits that are +supported by it, via properties of "tdx-guest" object. +E.g., "sept-ve-disable" (bit 28). + +MSR based features +~~~~~~~~~~~~~~~~~~ + +Current KVM doesn't support MSR based feature (e.g., MSR_IA32_ARCH_CAPABILITIES) +configuration for TDX, and it's a future work to enable it in QEMU when KVM adds +support of it. + +Feature check +~~~~~~~~~~~~~ + +QEMU checks if the final (CPU) features, determined by given cpu model and +explicit feature adjustment of "+featureA/-featureB", can be supported or not. +It can produce feature not supported warning like + + "warning: host doesn't support requested feature: CPUID.07H:EBX.intel-pt [bit 25]" + +It can also produce warning like + + "warning: TDX forcibly sets the feature: CPUID.80000007H:EDX.invtsc [bit 8]" + +if the fixed-1 feature is requested to be disabled explicitly. This is newly +added to QEMU for TDX because TDX has fixed-1 features that are forcibly enabled +by TDX module and VMM cannot disable them. + +Launching a TD (TDX VM) +----------------------- + +To launch a TD, the necessary command line options are tdx-guest object and +split kernel-irqchip, as below: + +.. parsed-literal:: + + |qemu_system_x86| \\ + -accel kvm \\ + -cpu host \\ + -object tdx-guest,id=tdx0 \\ + -machine ...,confidential-guest-support=tdx0 \\ + -bios OVMF.fd \\ + +Restrictions +------------ + + - kernel-irqchip must be split; + + This is set by default for TDX guest if kernel-irqchip is left on its default + 'auto' setting. + + - No readonly support for private memory; + + - No SMM support: SMM support requires manipulating the guest register states + which is not allowed; + +Debugging +--------- + +Bit 0 of TD attributes, is DEBUG bit, which decides if the TD runs in off-TD +debug mode. When in off-TD debug mode, TD's VCPU state and private memory are +accessible via given SEAMCALLs. This requires KVM to expose APIs to invoke those +SEAMCALLs and corresonponding QEMU change. + +It's targeted as future work. + +TD attestation +-------------- + +In TD guest, the attestation process is used to verify the TDX guest +trustworthiness to other entities before provisioning secrets to the guest. + +TD attestation is initiated first by calling TDG.MR.REPORT inside TD to get the +REPORT. Then the REPORT data needs to be converted into a remotely verifiable +Quote by SGX Quoting Enclave (QE). + +It's a future work in QEMU to add support of TD attestation since it lacks +support in current KVM. + +Live Migration +-------------- + +Future work. + +References +---------- + +- `TDX Homepage `__ + +- `SGX QE `__ diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst index ab7af1a75d..43b09c79d6 100644 --- a/docs/system/target-i386.rst +++ b/docs/system/target-i386.rst @@ -31,6 +31,7 @@ Architectural features i386/kvm-pv i386/sgx i386/amd-memory-encryption + i386/tdx OS requirements ~~~~~~~~~~~~~~~ From 1297b285cc3ffbd06dc3208fbecdb2d582c535dc Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 26 May 2025 09:22:20 +0200 Subject: [PATCH 1275/2760] rust: make declaration of dependent crates more consistent Crates like "bilge" and "libc" can be shared by more than one directory, so declare them directly in rust/meson.build. While at it, make their variable names end with "_rs" and always add a subproject() statement (as that pinpoints the error better if the subproject is missing and cannot be downloaded). Reviewed-by: Zhao Liu Signed-off-by: Paolo Bonzini --- rust/hw/char/pl011/meson.build | 12 +++--------- rust/meson.build | 16 ++++++++++++++++ rust/qemu-api-macros/meson.build | 14 +++----------- rust/qemu-api/meson.build | 4 +--- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/rust/hw/char/pl011/meson.build b/rust/hw/char/pl011/meson.build index 547cca5a96..494b6c123c 100644 --- a/rust/hw/char/pl011/meson.build +++ b/rust/hw/char/pl011/meson.build @@ -1,17 +1,11 @@ -subproject('bilge-0.2-rs', required: true) -subproject('bilge-impl-0.2-rs', required: true) - -bilge_dep = dependency('bilge-0.2-rs') -bilge_impl_dep = dependency('bilge-impl-0.2-rs') - _libpl011_rs = static_library( 'pl011', files('src/lib.rs'), override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', dependencies: [ - bilge_dep, - bilge_impl_dep, + bilge_rs, + bilge_impl_rs, qemu_api, qemu_api_macros, ], @@ -21,6 +15,6 @@ rust_devices_ss.add(when: 'CONFIG_X_PL011_RUST', if_true: [declare_dependency( link_whole: [_libpl011_rs], # Putting proc macro crates in `dependencies` is necessary for Meson to find # them when compiling the root per-target static rust lib. - dependencies: [bilge_impl_dep, qemu_api_macros], + dependencies: [bilge_impl_rs, qemu_api_macros], variables: {'crate': 'pl011'}, )]) diff --git a/rust/meson.build b/rust/meson.build index 91e52b8fb8..1f0dcce7d0 100644 --- a/rust/meson.build +++ b/rust/meson.build @@ -1,3 +1,19 @@ +subproject('bilge-0.2-rs', required: true) +subproject('bilge-impl-0.2-rs', required: true) +subproject('libc-0.2-rs', required: true) + +bilge_rs = dependency('bilge-0.2-rs') +bilge_impl_rs = dependency('bilge-impl-0.2-rs') +libc_rs = dependency('libc-0.2-rs') + +subproject('proc-macro2-1-rs', required: true) +subproject('quote-1-rs', required: true) +subproject('syn-2-rs', required: true) + +quote_rs_native = dependency('quote-1-rs', native: true) +syn_rs_native = dependency('syn-2-rs', native: true) +proc_macro2_rs_native = dependency('proc-macro2-1-rs', native: true) + subdir('qemu-api-macros') subdir('qemu-api') diff --git a/rust/qemu-api-macros/meson.build b/rust/qemu-api-macros/meson.build index 6f94a4bb3c..8610ce1c84 100644 --- a/rust/qemu-api-macros/meson.build +++ b/rust/qemu-api-macros/meson.build @@ -1,11 +1,3 @@ -subproject('proc-macro2-1-rs', required: true) -subproject('quote-1-rs', required: true) -subproject('syn-2-rs', required: true) - -quote_dep = dependency('quote-1-rs', native: true) -syn_dep = dependency('syn-2-rs', native: true) -proc_macro2_dep = dependency('proc-macro2-1-rs', native: true) - _qemu_api_macros_rs = rust.proc_macro( 'qemu_api_macros', files('src/lib.rs'), @@ -16,9 +8,9 @@ _qemu_api_macros_rs = rust.proc_macro( '--cfg', 'feature="proc-macro"', ], dependencies: [ - proc_macro2_dep, - quote_dep, - syn_dep, + proc_macro2_rs_native, + quote_rs_native, + syn_rs_native, ], ) diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build index 1696df705b..1ea86b8bbf 100644 --- a/rust/qemu-api/meson.build +++ b/rust/qemu-api/meson.build @@ -2,8 +2,6 @@ _qemu_api_cfg = run_command(rustc_args, '--config-headers', config_host_h, '--features', files('Cargo.toml'), capture: true, check: true).stdout().strip().splitlines() -libc_dep = dependency('libc-0.2-rs') - # _qemu_api_cfg += ['--cfg', 'feature="allocator"'] if get_option('debug_mutex') _qemu_api_cfg += ['--cfg', 'feature="debug_cell"'] @@ -37,7 +35,7 @@ _qemu_api_rs = static_library( override_options: ['rust_std=2021', 'build.rust_std=2021'], rust_abi: 'rust', rust_args: _qemu_api_cfg, - dependencies: [libc_dep, qemu_api_macros], + dependencies: [libc_rs, qemu_api_macros], ) rust.test('rust-qemu-api-tests', _qemu_api_rs, From 397db937e85d7b9f5a6f0b30764786cef09d1ff3 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:57:59 -0500 Subject: [PATCH 1276/2760] target/i386: Update EPYC CPU model for Cache property, RAS, SVM feature bits Found that some of the cache properties are not set correctly for EPYC models. l1d_cache.no_invd_sharing should not be true. l1i_cache.no_invd_sharing should not be true. L2.self_init should be true. L2.inclusive should be true. L3.inclusive should not be true. L3.no_invd_sharing should be true. Fix the cache properties. Also add the missing RAS and SVM features bits on AMD EPYC CPU models. The SVM feature bits are used in nested guests. succor : Software uncorrectable error containment and recovery capability. overflow-recov : MCA overflow recovery support. lbrv : LBR virtualization tsc-scale : MSR based TSC rate control vmcb-clean : VMCB clean bits flushbyasid : Flush by ASID pause-filter : Pause intercept filter pfthreshold : PAUSE filter threshold v-vmsave-vmload : Virtualized VMLOAD and VMSAVE vgif : Virtualized GIF Signed-off-by: Babu Moger Reviewed-by: Maksim Davydov Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/515941861700d7066186c9600bc5d96a1741ef0c.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 34364cf96a..b6c63b892e 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2211,6 +2211,60 @@ static CPUCaches epyc_v4_cache_info = { }, }; +static CPUCaches epyc_v5_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + .type = DATA_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, + .level = 1, + .size = 64 * KiB, + .line_size = 64, + .associativity = 4, + .partitions = 1, + .sets = 256, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 8 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 8192, + .lines_per_tag = 1, + .self_init = true, + .no_invd_sharing = true, + .complex_indexing = false, + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, +}; + static const CPUCaches epyc_rome_cache_info = { .l1d_cache = &(CPUCacheInfo) { .type = DATA_CACHE, @@ -5238,6 +5292,25 @@ static const X86CPUDefinition builtin_x86_defs[] = { }, .cache_info = &epyc_v4_cache_info }, + { + .version = 5, + .props = (PropValue[]) { + { "overflow-recov", "on" }, + { "succor", "on" }, + { "lbrv", "on" }, + { "tsc-scale", "on" }, + { "vmcb-clean", "on" }, + { "flushbyasid", "on" }, + { "pause-filter", "on" }, + { "pfthreshold", "on" }, + { "v-vmsave-vmload", "on" }, + { "vgif", "on" }, + { "model-id", + "AMD EPYC-v5 Processor" }, + { /* end of list */ } + }, + .cache_info = &epyc_v5_cache_info + }, { /* end of list */ } } }, From 83d940e9700527ff080416ce2fa52ee1f4771d72 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:58:00 -0500 Subject: [PATCH 1277/2760] target/i386: Update EPYC-Rome CPU model for Cache property, RAS, SVM feature bits Found that some of the cache properties are not set correctly for EPYC models. l1d_cache.no_invd_sharing should not be true. l1i_cache.no_invd_sharing should not be true. L2.self_init should be true. L2.inclusive should be true. L3.inclusive should not be true. L3.no_invd_sharing should be true. Fix these cache properties. Also add the missing RAS and SVM features bits on AMD EPYC-Rome. The SVM feature bits are used in nested guests. succor : Software uncorrectable error containment and recovery capability. overflow-recov : MCA overflow recovery support. lbrv : LBR virtualization tsc-scale : MSR based TSC rate control vmcb-clean : VMCB clean bits flushbyasid : Flush by ASID pause-filter : Pause intercept filter pfthreshold : PAUSE filter threshold v-vmsave-vmload : Virtualized VMLOAD and VMSAVE vgif : Virtualized GIF Signed-off-by: Babu Moger Reviewed-by: Maksim Davydov Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/8265af72057b84c99ac3a02a5487e32759cc69b1.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index b6c63b892e..5b5324a35c 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2373,6 +2373,60 @@ static const CPUCaches epyc_rome_v3_cache_info = { }, }; +static const CPUCaches epyc_rome_v5_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + .type = DATA_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 16 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 16384, + .lines_per_tag = 1, + .self_init = true, + .no_invd_sharing = true, + .complex_indexing = false, + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, +}; + static const CPUCaches epyc_milan_cache_info = { .l1d_cache = &(CPUCacheInfo) { .type = DATA_CACHE, @@ -5449,6 +5503,25 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } }, }, + { + .version = 5, + .props = (PropValue[]) { + { "overflow-recov", "on" }, + { "succor", "on" }, + { "lbrv", "on" }, + { "tsc-scale", "on" }, + { "vmcb-clean", "on" }, + { "flushbyasid", "on" }, + { "pause-filter", "on" }, + { "pfthreshold", "on" }, + { "v-vmsave-vmload", "on" }, + { "vgif", "on" }, + { "model-id", + "AMD EPYC-Rome-v5 Processor" }, + { /* end of list */ } + }, + .cache_info = &epyc_rome_v5_cache_info + }, { /* end of list */ } } }, From fc014d9ba5b26b27401e0e88a4e1ef827c68fe64 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:58:01 -0500 Subject: [PATCH 1278/2760] target/i386: Update EPYC-Milan CPU model for Cache property, RAS, SVM feature bits Found that some of the cache properties are not set correctly for EPYC models. l1d_cache.no_invd_sharing should not be true. l1i_cache.no_invd_sharing should not be true. L2.self_init should be true. L2.inclusive should be true. L3.inclusive should not be true. L3.no_invd_sharing should be true. Fix these cache properties. Also add the missing RAS and SVM features bits on AMD EPYC-Milan model. The SVM feature bits are used in nested guests. succor : Software uncorrectable error containment and recovery capability. overflow-recov : MCA overflow recovery support. lbrv : LBR virtualization tsc-scale : MSR based TSC rate control vmcb-clean : VMCB clean bits flushbyasid : Flush by ASID pause-filter : Pause intercept filter pfthreshold : PAUSE filter threshold v-vmsave-vmload : Virtualized VMLOAD and VMSAVE vgif : Virtualized GIF Signed-off-by: Babu Moger Reviewed-by: Maksim Davydov Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/c619c0e09a9d5d496819ed48d69181d65f416891.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 5b5324a35c..d01a808e3a 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2535,6 +2535,60 @@ static const CPUCaches epyc_milan_v2_cache_info = { }, }; +static const CPUCaches epyc_milan_v3_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + .type = DATA_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 512 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 32 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 32768, + .lines_per_tag = 1, + .self_init = true, + .no_invd_sharing = true, + .complex_indexing = false, + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, +}; + static const CPUCaches epyc_genoa_cache_info = { .l1d_cache = &(CPUCacheInfo) { .type = DATA_CACHE, @@ -5597,6 +5651,25 @@ static const X86CPUDefinition builtin_x86_defs[] = { }, .cache_info = &epyc_milan_v2_cache_info }, + { + .version = 3, + .props = (PropValue[]) { + { "overflow-recov", "on" }, + { "succor", "on" }, + { "lbrv", "on" }, + { "tsc-scale", "on" }, + { "vmcb-clean", "on" }, + { "flushbyasid", "on" }, + { "pause-filter", "on" }, + { "pfthreshold", "on" }, + { "v-vmsave-vmload", "on" }, + { "vgif", "on" }, + { "model-id", + "AMD EPYC-Milan-v3 Processor" }, + { /* end of list */ } + }, + .cache_info = &epyc_milan_v3_cache_info + }, { /* end of list */ } } }, From dfd5b456108a75588ab094358ba5754787146d3d Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:58:02 -0500 Subject: [PATCH 1279/2760] target/i386: Add couple of feature bits in CPUID_Fn80000021_EAX Add CPUID bit indicates that a WRMSR to MSR_FS_BASE, MSR_GS_BASE, or MSR_KERNEL_GS_BASE is non-serializing amd PREFETCHI that the indicates support for IC prefetch. CPUID_Fn80000021_EAX Bit Feature description 20 Indicates support for IC prefetch. 1 FsGsKernelGsBaseNonSerializing. WRMSR to FS_BASE, GS_BASE and KernelGSbase are non-serializing. Link: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/57238.zip Signed-off-by: Babu Moger Reviewed-by: Maksim Davydov Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/a5f6283a59579b09ac345b3f21ecb3b3b2d92451.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 4 ++-- target/i386/cpu.h | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index d01a808e3a..0d1b907778 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -1253,12 +1253,12 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = { [FEAT_8000_0021_EAX] = { .type = CPUID_FEATURE_WORD, .feat_names = { - "no-nested-data-bp", NULL, "lfence-always-serializing", NULL, + "no-nested-data-bp", "fs-gs-base-ns", "lfence-always-serializing", NULL, NULL, NULL, "null-sel-clr-base", NULL, "auto-ibrs", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, + "prefetchi", NULL, NULL, NULL, "eraps", NULL, NULL, "sbpb", "ibpb-brtype", "srso-no", "srso-user-kernel-no", NULL, }, diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 22e82444ae..1146465c8c 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -1092,12 +1092,16 @@ uint64_t x86_cpu_get_supported_feature_word(X86CPU *cpu, FeatureWord w); /* Processor ignores nested data breakpoints */ #define CPUID_8000_0021_EAX_NO_NESTED_DATA_BP (1U << 0) +/* WRMSR to FS_BASE, GS_BASE, or KERNEL_GS_BASE is non-serializing */ +#define CPUID_8000_0021_EAX_FS_GS_BASE_NS (1U << 1) /* LFENCE is always serializing */ #define CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING (1U << 2) /* Null Selector Clears Base */ #define CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE (1U << 6) /* Automatic IBRS */ #define CPUID_8000_0021_EAX_AUTO_IBRS (1U << 8) +/* Indicates support for IC prefetch */ +#define CPUID_8000_0021_EAX_PREFETCHI (1U << 20) /* Enhanced Return Address Predictor Scurity */ #define CPUID_8000_0021_EAX_ERAPS (1U << 24) /* Selective Branch Predictor Barrier */ From abc92cc8488b5dbcc403b5be24d8092180605101 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:58:03 -0500 Subject: [PATCH 1280/2760] target/i386: Update EPYC-Genoa for Cache property, perfmon-v2, RAS and SVM feature bits Found that some of the cache properties are not set correctly for EPYC models. l1d_cache.no_invd_sharing should not be true. l1i_cache.no_invd_sharing should not be true. L2.self_init should be true. L2.inclusive should be true. L3.inclusive should not be true. L3.no_invd_sharing should be true. Fix these cache properties. Also add the missing RAS and SVM features bits on AMD EPYC-Genoa model. The SVM feature bits are used in nested guests. perfmon-v2 : Allow guests to make use of the PerfMonV2 features. succor : Software uncorrectable error containment and recovery capability. overflow-recov : MCA overflow recovery support. lbrv : LBR virtualization tsc-scale : MSR based TSC rate control vmcb-clean : VMCB clean bits flushbyasid : Flush by ASID pause-filter : Pause intercept filter pfthreshold : PAUSE filter threshold v-vmsave-vmload: Virtualized VMLOAD and VMSAVE vgif : Virtualized GIF fs-gs-base-ns : WRMSR to {FS,GS,KERNEL_GS}_BASE is non-serializing The feature details are available in APM listed below [1]. [1] AMD64 Architecture Programmer's Manual Volume 2: System Programming Publication # 24593 Revision 3.41. Link: https://bugzilla.kernel.org/show_bug.cgi?id=206537 Signed-off-by: Babu Moger Reviewed-by: Maksim Davydov Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/afe3f05d4116124fd5795f28fc23d7b396140313.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 0d1b907778..a656b3c664 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2643,6 +2643,59 @@ static const CPUCaches epyc_genoa_cache_info = { }, }; +static const CPUCaches epyc_genoa_v2_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + .type = DATA_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 1 * MiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 2048, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 32 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 32768, + .lines_per_tag = 1, + .self_init = true, + .no_invd_sharing = true, + .complex_indexing = false, + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, +}; /* The following VMX features are not supported by KVM and are left out in the * CPU definitions: * @@ -5744,6 +5797,31 @@ static const X86CPUDefinition builtin_x86_defs[] = { .xlevel = 0x80000022, .model_id = "AMD EPYC-Genoa Processor", .cache_info = &epyc_genoa_cache_info, + .versions = (X86CPUVersionDefinition[]) { + { .version = 1 }, + { + .version = 2, + .props = (PropValue[]) { + { "overflow-recov", "on" }, + { "succor", "on" }, + { "lbrv", "on" }, + { "tsc-scale", "on" }, + { "vmcb-clean", "on" }, + { "flushbyasid", "on" }, + { "pause-filter", "on" }, + { "pfthreshold", "on" }, + { "v-vmsave-vmload", "on" }, + { "vgif", "on" }, + { "fs-gs-base-ns", "on" }, + { "perfmon-v2", "on" }, + { "model-id", + "AMD EPYC-Genoa-v2 Processor" }, + { /* end of list */ } + }, + .cache_info = &epyc_genoa_v2_cache_info + }, + { /* end of list */ } + } }, { .name = "YongFeng", From 3771a4daa273ba17cb27309984413790d1df5651 Mon Sep 17 00:00:00 2001 From: Babu Moger Date: Thu, 8 May 2025 14:58:04 -0500 Subject: [PATCH 1281/2760] target/i386: Add support for EPYC-Turin model Add the support for AMD EPYC zen 5 processors (EPYC-Turin). Add the following new feature bits on top of the feature bits from the previous generation EPYC models. movdiri : Move Doubleword as Direct Store Instruction movdir64b : Move 64 Bytes as Direct Store Instruction avx512-vp2intersect : AVX512 Vector Pair Intersection to a Pair of Mask Register avx-vnni : AVX VNNI Instruction prefetchi : Indicates support for IC prefetch sbpb : Selective Branch Predictor Barrier ibpb-brtype : IBPB includes branch type prediction flushing srso-user-kernel-no : Not vulnerable to SRSO at the user-kernel boundary Link: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/57238.zip Link: https://www.amd.com/content/dam/amd/en/documents/corporate/cr/speculative-return-stack-overflow-whitepaper.pdf Signed-off-by: Babu Moger Reviewed-by: Zhao Liu Link: https://lore.kernel.org/r/b4fa7708a0e1453d2e9b8ec3dc881feb92eeca0b.1746734284.git.babu.moger@amd.com Signed-off-by: Paolo Bonzini --- target/i386/cpu.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/target/i386/cpu.c b/target/i386/cpu.c index a656b3c664..15439fdfa8 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -2696,6 +2696,61 @@ static const CPUCaches epyc_genoa_v2_cache_info = { .share_level = CPU_TOPOLOGY_LEVEL_DIE, }, }; + +static const CPUCaches epyc_turin_cache_info = { + .l1d_cache = &(CPUCacheInfo) { + .type = DATA_CACHE, + .level = 1, + .size = 48 * KiB, + .line_size = 64, + .associativity = 12, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l1i_cache = &(CPUCacheInfo) { + .type = INSTRUCTION_CACHE, + .level = 1, + .size = 32 * KiB, + .line_size = 64, + .associativity = 8, + .partitions = 1, + .sets = 64, + .lines_per_tag = 1, + .self_init = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l2_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 2, + .size = 1 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 1024, + .lines_per_tag = 1, + .self_init = true, + .inclusive = true, + .share_level = CPU_TOPOLOGY_LEVEL_CORE, + }, + .l3_cache = &(CPUCacheInfo) { + .type = UNIFIED_CACHE, + .level = 3, + .size = 32 * MiB, + .line_size = 64, + .associativity = 16, + .partitions = 1, + .sets = 32768, + .lines_per_tag = 1, + .self_init = true, + .no_invd_sharing = true, + .complex_indexing = false, + .share_level = CPU_TOPOLOGY_LEVEL_DIE, + }, +}; + /* The following VMX features are not supported by KVM and are left out in the * CPU definitions: * @@ -5959,6 +6014,89 @@ static const X86CPUDefinition builtin_x86_defs[] = { { /* end of list */ } } }, + { + .name = "EPYC-Turin", + .level = 0xd, + .vendor = CPUID_VENDOR_AMD, + .family = 26, + .model = 0, + .stepping = 0, + .features[FEAT_1_ECX] = + CPUID_EXT_RDRAND | CPUID_EXT_F16C | CPUID_EXT_AVX | + CPUID_EXT_XSAVE | CPUID_EXT_AES | CPUID_EXT_POPCNT | + CPUID_EXT_MOVBE | CPUID_EXT_SSE42 | CPUID_EXT_SSE41 | + CPUID_EXT_PCID | CPUID_EXT_CX16 | CPUID_EXT_FMA | + CPUID_EXT_SSSE3 | CPUID_EXT_MONITOR | CPUID_EXT_PCLMULQDQ | + CPUID_EXT_SSE3, + .features[FEAT_1_EDX] = + CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX | CPUID_CLFLUSH | + CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA | CPUID_PGE | + CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 | CPUID_MCE | + CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE | CPUID_DE | + CPUID_VME | CPUID_FP87, + .features[FEAT_6_EAX] = + CPUID_6_EAX_ARAT, + .features[FEAT_7_0_EBX] = + CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_AVX2 | + CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | + CPUID_7_0_EBX_INVPCID | CPUID_7_0_EBX_AVX512F | + CPUID_7_0_EBX_AVX512DQ | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX | + CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_AVX512IFMA | + CPUID_7_0_EBX_CLFLUSHOPT | CPUID_7_0_EBX_CLWB | + CPUID_7_0_EBX_AVX512CD | CPUID_7_0_EBX_SHA_NI | + CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512VL, + .features[FEAT_7_0_ECX] = + CPUID_7_0_ECX_AVX512_VBMI | CPUID_7_0_ECX_UMIP | CPUID_7_0_ECX_PKU | + CPUID_7_0_ECX_AVX512_VBMI2 | CPUID_7_0_ECX_GFNI | + CPUID_7_0_ECX_VAES | CPUID_7_0_ECX_VPCLMULQDQ | + CPUID_7_0_ECX_AVX512VNNI | CPUID_7_0_ECX_AVX512BITALG | + CPUID_7_0_ECX_AVX512_VPOPCNTDQ | CPUID_7_0_ECX_LA57 | + CPUID_7_0_ECX_RDPID | CPUID_7_0_ECX_MOVDIRI | + CPUID_7_0_ECX_MOVDIR64B, + .features[FEAT_7_0_EDX] = + CPUID_7_0_EDX_FSRM | CPUID_7_0_EDX_AVX512_VP2INTERSECT, + .features[FEAT_7_1_EAX] = + CPUID_7_1_EAX_AVX_VNNI | CPUID_7_1_EAX_AVX512_BF16, + .features[FEAT_8000_0001_ECX] = + CPUID_EXT3_OSVW | CPUID_EXT3_3DNOWPREFETCH | + CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM | + CPUID_EXT3_CR8LEG | CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM | + CPUID_EXT3_TOPOEXT | CPUID_EXT3_PERFCORE, + .features[FEAT_8000_0001_EDX] = + CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_PDPE1GB | + CPUID_EXT2_FFXSR | CPUID_EXT2_MMXEXT | CPUID_EXT2_NX | + CPUID_EXT2_SYSCALL, + .features[FEAT_8000_0007_EBX] = + CPUID_8000_0007_EBX_OVERFLOW_RECOV | CPUID_8000_0007_EBX_SUCCOR, + .features[FEAT_8000_0008_EBX] = + CPUID_8000_0008_EBX_CLZERO | CPUID_8000_0008_EBX_XSAVEERPTR | + CPUID_8000_0008_EBX_WBNOINVD | CPUID_8000_0008_EBX_IBPB | + CPUID_8000_0008_EBX_IBRS | CPUID_8000_0008_EBX_STIBP | + CPUID_8000_0008_EBX_STIBP_ALWAYS_ON | + CPUID_8000_0008_EBX_AMD_SSBD | CPUID_8000_0008_EBX_AMD_PSFD, + .features[FEAT_8000_0021_EAX] = + CPUID_8000_0021_EAX_NO_NESTED_DATA_BP | + CPUID_8000_0021_EAX_FS_GS_BASE_NS | + CPUID_8000_0021_EAX_LFENCE_ALWAYS_SERIALIZING | + CPUID_8000_0021_EAX_NULL_SEL_CLR_BASE | + CPUID_8000_0021_EAX_AUTO_IBRS | CPUID_8000_0021_EAX_PREFETCHI | + CPUID_8000_0021_EAX_SBPB | CPUID_8000_0021_EAX_IBPB_BRTYPE | + CPUID_8000_0021_EAX_SRSO_USER_KERNEL_NO, + .features[FEAT_8000_0022_EAX] = + CPUID_8000_0022_EAX_PERFMON_V2, + .features[FEAT_XSAVE] = + CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC | + CPUID_XSAVE_XGETBV1 | CPUID_XSAVE_XSAVES, + .features[FEAT_SVM] = + CPUID_SVM_NPT | CPUID_SVM_LBRV | CPUID_SVM_NRIPSAVE | + CPUID_SVM_TSCSCALE | CPUID_SVM_VMCBCLEAN | CPUID_SVM_FLUSHASID | + CPUID_SVM_PAUSEFILTER | CPUID_SVM_PFTHRESHOLD | + CPUID_SVM_V_VMSAVE_VMLOAD | CPUID_SVM_VGIF | + CPUID_SVM_VNMI | CPUID_SVM_SVME_ADDR_CHK, + .xlevel = 0x80000022, + .model_id = "AMD EPYC-Turin Processor", + .cache_info = &epyc_turin_cache_info, + }, }; /* From 9bd24d8d2756a0771b6677b02c7f9b603ef6afe9 Mon Sep 17 00:00:00 2001 From: Fiona Ebner Date: Mon, 26 May 2025 13:44:47 +0200 Subject: [PATCH 1282/2760] target/i386/tcg/helper-tcg: fix file references in comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 32cad1ffb8 ("include: Rename sysemu/ -> system/") renamed target/i386/tcg/sysemu => target/i386/tcg/system. Signed-off-by: Fiona Ebner Reviewed-by: Philippe Mathieu-Daudé Link: https://lore.kernel.org/r/20250526114447.1243840-1-f.ebner@proxmox.com Signed-off-by: Paolo Bonzini --- target/i386/tcg/helper-tcg.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/i386/tcg/helper-tcg.h b/target/i386/tcg/helper-tcg.h index 6b3f19855f..be011b06b7 100644 --- a/target/i386/tcg/helper-tcg.h +++ b/target/i386/tcg/helper-tcg.h @@ -97,7 +97,7 @@ static inline unsigned int compute_pf(uint8_t x) /* misc_helper.c */ void cpu_load_eflags(CPUX86State *env, int eflags, int update_mask); -/* sysemu/svm_helper.c */ +/* system/svm_helper.c */ #ifndef CONFIG_USER_ONLY G_NORETURN void cpu_vmexit(CPUX86State *nenv, uint32_t exit_code, uint64_t exit_info_1, uintptr_t retaddr); @@ -115,7 +115,7 @@ int exception_has_error_code(int intno); /* smm_helper.c */ void do_smm_enter(X86CPU *cpu); -/* sysemu/bpt_helper.c */ +/* system/bpt_helper.c */ bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update); /* From 638422f5bcdf2c7bdb401b987b134322c5d6bd4d Mon Sep 17 00:00:00 2001 From: Hao Wu Date: Thu, 29 May 2025 17:45:09 +0100 Subject: [PATCH 1283/2760] hw/arm: Add GMAC devices to NPCM8XX SoC The GMAC was originally created for the 8xx machine. During upstreaming both the GMAC and the 8XX we removed it so they would not depend on each other for the process, that connection should be added back in. Signed-off-by: Hao Wu Signed-off-by: Nabih Estefan Message-id: 20250508220718.735415-2-nabihestefan@google.com Reviewed-by: Tyrone Ting Signed-off-by: Peter Maydell --- hw/arm/npcm8xx.c | 54 ++++++++++++++++++++++++++++++++++++---- include/hw/arm/npcm8xx.h | 5 +++- 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c index d7ee306de7..d14bf55cd7 100644 --- a/hw/arm/npcm8xx.c +++ b/hw/arm/npcm8xx.c @@ -67,6 +67,9 @@ /* SDHCI Modules */ #define NPCM8XX_MMC_BA 0xf0842000 +/* PCS Module */ +#define NPCM8XX_PCS_BA 0xf0780000 + /* PSPI Modules */ #define NPCM8XX_PSPI_BA 0xf0201000 @@ -85,6 +88,10 @@ enum NPCM8xxInterrupt { NPCM8XX_ADC_IRQ = 0, NPCM8XX_PECI_IRQ = 6, NPCM8XX_KCS_HIB_IRQ = 9, + NPCM8XX_GMAC1_IRQ = 14, + NPCM8XX_GMAC2_IRQ, + NPCM8XX_GMAC3_IRQ, + NPCM8XX_GMAC4_IRQ, NPCM8XX_MMC_IRQ = 26, NPCM8XX_PSPI_IRQ = 28, NPCM8XX_TIMER0_IRQ = 32, /* Timer Module 0 */ @@ -260,6 +267,14 @@ static const hwaddr npcm8xx_smbus_addr[] = { 0xfff0a000, }; +/* Register base address for each GMAC Module */ +static const hwaddr npcm8xx_gmac_addr[] = { + 0xf0802000, + 0xf0804000, + 0xf0806000, + 0xf0808000, +}; + /* Register base address for each USB host EHCI registers */ static const hwaddr npcm8xx_ehci_addr[] = { 0xf0828100, @@ -444,6 +459,11 @@ static void npcm8xx_init(Object *obj) object_initialize_child(obj, "mft[*]", &s->mft[i], TYPE_NPCM7XX_MFT); } + for (i = 0; i < ARRAY_SIZE(s->gmac); i++) { + object_initialize_child(obj, "gmac[*]", &s->gmac[i], TYPE_NPCM_GMAC); + } + object_initialize_child(obj, "pcs", &s->pcs, TYPE_NPCM_PCS); + object_initialize_child(obj, "mmc", &s->mmc, TYPE_NPCM7XX_SDHCI); object_initialize_child(obj, "pspi", &s->pspi, TYPE_NPCM_PSPI); } @@ -668,6 +688,35 @@ static void npcm8xx_realize(DeviceState *dev, Error **errp) sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_MFT0_IRQ + i)); } + /* + * GMAC Modules. Cannot fail. + */ + QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm8xx_gmac_addr) != ARRAY_SIZE(s->gmac)); + for (i = 0; i < ARRAY_SIZE(s->gmac); i++) { + SysBusDevice *sbd = SYS_BUS_DEVICE(&s->gmac[i]); + + /* This is used to make sure that the NIC can create the device */ + qemu_configure_nic_device(DEVICE(sbd), false, NULL); + + /* + * The device exists regardless of whether it's connected to a QEMU + * netdev backend. So always instantiate it even if there is no + * backend. + */ + sysbus_realize(sbd, &error_abort); + sysbus_mmio_map(sbd, 0, npcm8xx_gmac_addr[i]); + /* + * N.B. The values for the second argument sysbus_connect_irq are + * chosen to match the registration order in npcm7xx_emc_realize. + */ + sysbus_connect_irq(sbd, 0, npcm8xx_irq(s, NPCM8XX_GMAC1_IRQ + i)); + } + /* + * GMAC Physical Coding Sublayer(PCS) Module. Cannot fail. + */ + sysbus_realize(SYS_BUS_DEVICE(&s->pcs), &error_abort); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->pcs), 0, NPCM8XX_PCS_BA); + /* * Flash Interface Unit (FIU). Can fail if incorrect number of chip selects * specified, but this is a programming error. @@ -741,12 +790,7 @@ static void npcm8xx_realize(DeviceState *dev, Error **errp) create_unimplemented_device("npcm8xx.ahbpci", 0xf0400000, 1 * MiB); create_unimplemented_device("npcm8xx.dap", 0xf0500000, 960 * KiB); create_unimplemented_device("npcm8xx.mcphy", 0xf05f0000, 64 * KiB); - create_unimplemented_device("npcm8xx.pcs", 0xf0780000, 256 * KiB); create_unimplemented_device("npcm8xx.tsgen", 0xf07fc000, 8 * KiB); - create_unimplemented_device("npcm8xx.gmac1", 0xf0802000, 8 * KiB); - create_unimplemented_device("npcm8xx.gmac2", 0xf0804000, 8 * KiB); - create_unimplemented_device("npcm8xx.gmac3", 0xf0806000, 8 * KiB); - create_unimplemented_device("npcm8xx.gmac4", 0xf0808000, 8 * KiB); create_unimplemented_device("npcm8xx.copctl", 0xf080c000, 4 * KiB); create_unimplemented_device("npcm8xx.tipctl", 0xf080d000, 4 * KiB); create_unimplemented_device("npcm8xx.rst", 0xf080e000, 4 * KiB); diff --git a/include/hw/arm/npcm8xx.h b/include/hw/arm/npcm8xx.h index 3436abff99..a8377db490 100644 --- a/include/hw/arm/npcm8xx.h +++ b/include/hw/arm/npcm8xx.h @@ -28,7 +28,8 @@ #include "hw/misc/npcm7xx_mft.h" #include "hw/misc/npcm7xx_pwm.h" #include "hw/misc/npcm7xx_rng.h" -#include "hw/net/npcm7xx_emc.h" +#include "hw/net/npcm_gmac.h" +#include "hw/net/npcm_pcs.h" #include "hw/nvram/npcm7xx_otp.h" #include "hw/sd/npcm7xx_sdhci.h" #include "hw/timer/npcm7xx_timer.h" @@ -99,6 +100,8 @@ struct NPCM8xxState { EHCISysBusState ehci[2]; OHCISysBusState ohci[2]; NPCM7xxFIUState fiu[3]; + NPCMGMACState gmac[4]; + NPCMPCSState pcs; NPCM7xxSDHCIState mmc; NPCMPSPIState pspi; }; From e7083b02f5628f0ec63d29f2208ca5d3e963e9a8 Mon Sep 17 00:00:00 2001 From: Nabih Estefan Date: Thu, 29 May 2025 17:45:09 +0100 Subject: [PATCH 1284/2760] tests/qtest: Migrate GMAC test from 7xx to 8xx For upstreaming we migrated this test to 7xx (since that was already upstream) move it back to 8xx where it can check the 4 GMACs since that is the board this test was originally created for. Signed-off-by: Nabih Estefan Message-id: 20250508220718.735415-3-nabihestefan@google.com Reviewed-by: Tyrone Ting Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- tests/qtest/meson.build | 6 ++- tests/qtest/npcm_gmac-test.c | 85 ++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 5 deletions(-) diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 43e5a86699..8ad849054f 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -208,9 +208,10 @@ qtests_npcm7xx = \ 'npcm7xx_sdhci-test', 'npcm7xx_smbus-test', 'npcm7xx_timer-test', - 'npcm7xx_watchdog_timer-test', - 'npcm_gmac-test'] + \ + 'npcm7xx_watchdog_timer-test'] + \ (slirp.found() ? ['npcm7xx_emc-test'] : []) +qtests_npcm8xx = \ + ['npcm_gmac-test'] qtests_aspeed = \ ['aspeed_gpio-test', 'aspeed_hace-test', @@ -259,6 +260,7 @@ qtests_aarch64 = \ (config_all_accel.has_key('CONFIG_TCG') and \ config_all_devices.has_key('CONFIG_TPM_TIS_I2C') ? ['tpm-tis-i2c-test'] : []) + \ (config_all_devices.has_key('CONFIG_ASPEED_SOC') ? qtests_aspeed64 : []) + \ + (config_all_devices.has_key('CONFIG_NPCM8XX') ? qtests_npcm8xx : []) + \ ['arm-cpu-features', 'numa-test', 'boot-serial-test', diff --git a/tests/qtest/npcm_gmac-test.c b/tests/qtest/npcm_gmac-test.c index c28b471ab2..1317da2cd7 100644 --- a/tests/qtest/npcm_gmac-test.c +++ b/tests/qtest/npcm_gmac-test.c @@ -36,7 +36,7 @@ typedef struct TestData { const GMACModule *module; } TestData; -/* Values extracted from hw/arm/npcm7xx.c */ +/* Values extracted from hw/arm/npcm8xx.c */ static const GMACModule gmac_module_list[] = { { .irq = 14, @@ -46,6 +46,14 @@ static const GMACModule gmac_module_list[] = { .irq = 15, .base_addr = 0xf0804000 }, + { + .irq = 16, + .base_addr = 0xf0806000 + }, + { + .irq = 17, + .base_addr = 0xf0808000 + } }; /* Returns the index of the GMAC module. */ @@ -174,18 +182,32 @@ static uint32_t gmac_read(QTestState *qts, const GMACModule *mod, return qtest_readl(qts, mod->base_addr + regno); } +static uint16_t pcs_read(QTestState *qts, const GMACModule *mod, + NPCMRegister regno) +{ + uint32_t write_value = (regno & 0x3ffe00) >> 9; + qtest_writel(qts, PCS_BASE_ADDRESS + NPCM_PCS_IND_AC_BA, write_value); + uint32_t read_offset = regno & 0x1ff; + return qtest_readl(qts, PCS_BASE_ADDRESS + read_offset); +} + /* Check that GMAC registers are reset to default value */ static void test_init(gconstpointer test_data) { const TestData *td = test_data; const GMACModule *mod = td->module; - QTestState *qts = qtest_init("-machine npcm750-evb"); + QTestState *qts = qtest_init("-machine npcm845-evb"); #define CHECK_REG32(regno, value) \ do { \ g_assert_cmphex(gmac_read(qts, mod, (regno)), ==, (value)); \ } while (0) +#define CHECK_REG_PCS(regno, value) \ + do { \ + g_assert_cmphex(pcs_read(qts, mod, (regno)), ==, (value)); \ + } while (0) + CHECK_REG32(NPCM_DMA_BUS_MODE, 0x00020100); CHECK_REG32(NPCM_DMA_XMT_POLL_DEMAND, 0); CHECK_REG32(NPCM_DMA_RCV_POLL_DEMAND, 0); @@ -235,6 +257,63 @@ static void test_init(gconstpointer test_data) CHECK_REG32(NPCM_GMAC_PTP_TAR, 0); CHECK_REG32(NPCM_GMAC_PTP_TTSR, 0); + if (mod->base_addr == 0xf0802000) { + CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID1, 0x699e); + CHECK_REG_PCS(NPCM_PCS_SR_CTL_ID2, 0); + CHECK_REG_PCS(NPCM_PCS_SR_CTL_STS, 0x8000); + + CHECK_REG_PCS(NPCM_PCS_SR_MII_CTRL, 0x1140); + CHECK_REG_PCS(NPCM_PCS_SR_MII_STS, 0x0109); + CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID1, 0x699e); + CHECK_REG_PCS(NPCM_PCS_SR_MII_DEV_ID2, 0x0ced0); + CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_ADV, 0x0020); + CHECK_REG_PCS(NPCM_PCS_SR_MII_LP_BABL, 0); + CHECK_REG_PCS(NPCM_PCS_SR_MII_AN_EXPN, 0); + CHECK_REG_PCS(NPCM_PCS_SR_MII_EXT_STS, 0xc000); + + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_ABL, 0x0003); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_LWR, 0x0038); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MAX_DLY_UPR, 0); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_LWR, 0x0038); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_TX_MIN_DLY_UPR, 0); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_LWR, 0x0058); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MAX_DLY_UPR, 0); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_LWR, 0x0048); + CHECK_REG_PCS(NPCM_PCS_SR_TIM_SYNC_RX_MIN_DLY_UPR, 0); + + CHECK_REG_PCS(NPCM_PCS_VR_MII_MMD_DIG_CTRL1, 0x2400); + CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_CTRL, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_AN_INTR_STS, 0x000a); + CHECK_REG_PCS(NPCM_PCS_VR_MII_TC, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_DBG_CTRL, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL0, 0x899c); + CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_TXTIMER, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_RXTIMER, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_LINK_TIMER_CTRL, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_EEE_MCTRL1, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_STS, 0x0010); + CHECK_REG_PCS(NPCM_PCS_VR_MII_ICG_ERRCNT1, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MISC_STS, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_RX_LSTS, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_BSTCTRL0, 0x00a); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_LVLCTRL0, 0x007f); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL0, 0x0001); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_GENCTRL1, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_TX_STS, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL0, 0x0100); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_GENCTRL1, 0x1100); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_RX_LOS_CTRL0, 0x000e); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL0, 0x0100); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_CTRL1, 0x0032); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MPLL_STS, 0x0001); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL2, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_LVL_CTRL, 0x0019); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL0, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_MP_MISC_CTRL1, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_CTRL2, 0); + CHECK_REG_PCS(NPCM_PCS_VR_MII_DIG_ERRCNT_SEL, 0); + } + qtest_quit(qts); } @@ -242,7 +321,7 @@ static void gmac_add_test(const char *name, const TestData* td, GTestDataFunc fn) { g_autofree char *full_name = g_strdup_printf( - "npcm7xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name); + "npcm8xx_gmac/gmac[%d]/%s", gmac_module_index(td->module), name); qtest_add_data_func(full_name, td, fn); } From e6bc01777e5a4b6ecf3414b21a2d7b4846bf4817 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 29 May 2025 17:45:10 +0100 Subject: [PATCH 1285/2760] hw/arm: Add missing psci_conduit to NPCM8XX SoC boot info Without psci_conduit, the Linux kernel crashes almost immediately. psci: probing for conduit method from DT. Internal error: Oops - Undefined instruction: 0000000002000000 [#1] PREEMPT SMP Fixes: ae0c4d1a1290 ("hw/arm: Add NPCM8XX SoC") Cc: qemu-stable@nongnu.org Cc: Hao Wu Cc: Peter Maydell Signed-off-by: Guenter Roeck Message-id: 20250315142050.3642741-1-linux@roeck-us.net Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/npcm8xx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/npcm8xx.c b/hw/arm/npcm8xx.c index d14bf55cd7..a276fea698 100644 --- a/hw/arm/npcm8xx.c +++ b/hw/arm/npcm8xx.c @@ -365,6 +365,7 @@ static struct arm_boot_info npcm8xx_binfo = { .secure_boot = false, .board_id = -1, .board_setup_addr = NPCM8XX_BOARD_SETUP_ADDR, + .psci_conduit = QEMU_PSCI_CONDUIT_SMC, }; void npcm8xx_load_kernel(MachineState *machine, NPCM8xxState *soc) From 0a233da8a02a6126140b9dbd3af29e6763a390b1 Mon Sep 17 00:00:00 2001 From: Souleymane Conte Date: Thu, 29 May 2025 17:45:10 +0100 Subject: [PATCH 1286/2760] docs/interop: convert text files to restructuredText buglink: https://gitlab.com/qemu-project/qemu/-/issues/527 Signed-off-by: Souleymane Conte Reviewed-by: Peter Maydell Reviewed-by: Eric Blake Message-id: 20250522092622.40869-1-conte.souleymane@gmail.com [PMM: switched a few more bits of formatting to monospaced; updated references to qcow2.txt in MAINTAINERS, qcow2-cache.txt and bitmaps.rst] Signed-off-by: Peter Maydell --- MAINTAINERS | 2 +- docs/interop/bitmaps.rst | 2 +- docs/interop/index.rst | 1 + docs/interop/{qcow2.txt => qcow2.rst} | 187 +++++++++++++++----------- docs/qcow2-cache.txt | 2 +- 5 files changed, 113 insertions(+), 81 deletions(-) rename docs/interop/{qcow2.txt => qcow2.rst} (89%) diff --git a/MAINTAINERS b/MAINTAINERS index e27d1458c5..8e68333623 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4130,7 +4130,7 @@ M: Hanna Reitz L: qemu-block@nongnu.org S: Supported F: block/qcow2* -F: docs/interop/qcow2.txt +F: docs/interop/qcow2.rst qcow M: Kevin Wolf diff --git a/docs/interop/bitmaps.rst b/docs/interop/bitmaps.rst index ddf8947d54..7536f0ba5c 100644 --- a/docs/interop/bitmaps.rst +++ b/docs/interop/bitmaps.rst @@ -97,7 +97,7 @@ time. - Persistent storage formats may impose their own requirements on bitmap names and namespaces. Presently, only qcow2 supports persistent bitmaps. See - docs/interop/qcow2.txt for more details on restrictions. Notably: + :doc:`qcow2` for more details on restrictions. Notably: - qcow2 bitmap names are limited to between 1 and 1023 bytes long. diff --git a/docs/interop/index.rst b/docs/interop/index.rst index 999e44eae1..4b951ae416 100644 --- a/docs/interop/index.rst +++ b/docs/interop/index.rst @@ -17,6 +17,7 @@ are useful for making QEMU interoperate with other software. nbd parallels prl-xml + qcow2 pr-helper qmp-spec qemu-ga diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.rst similarity index 89% rename from docs/interop/qcow2.txt rename to docs/interop/qcow2.rst index 2c4618375a..5948591107 100644 --- a/docs/interop/qcow2.txt +++ b/docs/interop/qcow2.rst @@ -1,6 +1,8 @@ -== General == +======================= +Qcow2 Image File Format +======================= -A qcow2 image file is organized in units of constant size, which are called +A ``qcow2`` image file is organized in units of constant size, which are called (host) clusters. A cluster is the unit in which all allocations are done, both for actual guest data and for image metadata. @@ -9,10 +11,10 @@ clusters of the same size. All numbers in qcow2 are stored in Big Endian byte order. +Header +------ -== Header == - -The first cluster of a qcow2 image contains the file header: +The first cluster of a qcow2 image contains the file header:: Byte 0 - 3: magic QCOW magic string ("QFI\xfb") @@ -38,7 +40,7 @@ The first cluster of a qcow2 image contains the file header: within a cluster (1 << cluster_bits is the cluster size). Must not be less than 9 (i.e. 512 byte clusters). - Note: qemu as of today has an implementation limit of 2 MB + Note: QEMU as of today has an implementation limit of 2 MB as the maximum cluster size and won't be able to open images with larger cluster sizes. @@ -48,7 +50,7 @@ The first cluster of a qcow2 image contains the file header: 24 - 31: size Virtual disk size in bytes. - Note: qemu has an implementation limit of 32 MB as + Note: QEMU has an implementation limit of 32 MB as the maximum L1 table size. With a 2 MB cluster size, it is unable to populate a virtual cluster beyond 2 EB (61 bits); with a 512 byte cluster @@ -87,7 +89,8 @@ The first cluster of a qcow2 image contains the file header: For version 2, the header is exactly 72 bytes in length, and finishes here. For version 3 or higher, the header length is at least 104 bytes, including -the next fields through header_length. +the next fields through ``header_length``. +:: 72 - 79: incompatible_features Bitmask of incompatible features. An implementation must @@ -185,7 +188,8 @@ the next fields through header_length. of 8. -=== Additional fields (version 3 and higher) === +Additional fields (version 3 and higher) +---------------------------------------- In general, these fields are optional and may be safely ignored by the software, as well as filled by zeros (which is equal to field absence), if software needs @@ -193,21 +197,25 @@ to set field B, but does not care about field A which precedes B. More formally, additional fields have the following compatibility rules: 1. If the value of the additional field must not be ignored for correct -handling of the file, it will be accompanied by a corresponding incompatible -feature bit. + handling of the file, it will be accompanied by a corresponding incompatible + feature bit. 2. If there are no unrecognized incompatible feature bits set, an unknown -additional field may be safely ignored other than preserving its value when -rewriting the image header. + additional field may be safely ignored other than preserving its value when + rewriting the image header. + +.. _ref_rules_3: 3. An explicit value of 0 will have the same behavior as when the field is not -present*, if not altered by a specific incompatible bit. + present*, if not altered by a specific incompatible bit. -*. A field is considered not present when header_length is less than or equal +(*) A field is considered not present when ``header_length`` is less than or equal to the field's offset. Also, all additional fields are not present for version 2. - 104: compression_type +:: + + 104: compression_type Defines the compression method used for compressed clusters. All compressed clusters in an image use the same compression @@ -219,8 +227,8 @@ version 2. or must be zero (which means deflate). Available compression type values: - 0: deflate - 1: zstd + - 0: deflate + - 1: zstd The deflate compression type is called "zlib" in QEMU. However, clusters with the @@ -228,19 +236,21 @@ version 2. 105 - 111: Padding, contents defined below. -=== Header padding === +Header padding +-------------- -@header_length must be a multiple of 8, which means that if the end of the last +``header_length`` must be a multiple of 8, which means that if the end of the last additional field is not aligned, some padding is needed. This padding must be zeroed, so that if some existing (or future) additional field will fall into -the padding, it will be interpreted accordingly to point [3.] of the previous +the padding, it will be interpreted accordingly to point `[3.] <#ref_rules_3>`_ of the previous paragraph, i.e. in the same manner as when this field is not present. -=== Header extensions === +Header extensions +----------------- Directly after the image header, optional sections called header extensions can -be stored. Each extension has a structure like the following: +be stored. Each extension has a structure like the following:: Byte 0 - 3: Header extension type: 0x00000000 - End of the header extension area @@ -270,17 +280,19 @@ data of compatible features that it doesn't support. Compatible features that need space for additional data can use a header extension. -== String header extensions == +String header extensions +------------------------ Some header extensions (such as the backing file format name and the external data file name) are just a single string. In this case, the header extension -length is the string length and the string is not '\0' terminated. (The header -extension padding can make it look like a string is '\0' terminated, but +length is the string length and the string is not ``\0`` terminated. (The header +extension padding can make it look like a string is ``\0`` terminated, but neither is padding always necessary nor is there a guarantee that zero bytes are used for padding.) -== Feature name table == +Feature name table +------------------ The feature name table is an optional header extension that contains the name for features used by the image. It can be used by applications that don't know @@ -288,7 +300,7 @@ the respective feature (e.g. because the feature was introduced only later) to display a useful error message. The number of entries in the feature name table is determined by the length of -the header extension data. Each entry look like this: +the header extension data. Each entry looks like this:: Byte 0: Type of feature (select feature bitmap) 0: Incompatible feature @@ -302,7 +314,8 @@ the header extension data. Each entry look like this: terminated if it has full length) -== Bitmaps extension == +Bitmaps extension +----------------- The bitmaps extension is an optional header extension. It provides the ability to store bitmaps related to a virtual disk. For now, there is only one bitmap @@ -310,9 +323,9 @@ type: the dirty tracking bitmap, which tracks virtual disk changes from some point in time. The data of the extension should be considered consistent only if the -corresponding auto-clear feature bit is set, see autoclear_features above. +corresponding auto-clear feature bit is set, see ``autoclear_features`` above. -The fields of the bitmaps extension are: +The fields of the bitmaps extension are:: Byte 0 - 3: nb_bitmaps The number of bitmaps contained in the image. Must be @@ -331,15 +344,17 @@ The fields of the bitmaps extension are: Offset into the image file at which the bitmap directory starts. Must be aligned to a cluster boundary. -== Full disk encryption header pointer == +Full disk encryption header pointer +----------------------------------- The full disk encryption header must be present if, and only if, the -'crypt_method' header requires metadata. Currently this is only true -of the 'LUKS' crypt method. The header extension must be absent for +``crypt_method`` header requires metadata. Currently this is only true +of the ``LUKS`` crypt method. The header extension must be absent for other methods. This header provides the offset at which the crypt method can store its additional data, as well as the length of such data. +:: Byte 0 - 7: Offset into the image file at which the encryption header starts in bytes. Must be aligned to a cluster @@ -357,10 +372,10 @@ The first 592 bytes of the header clusters will contain the LUKS partition header. This is then followed by the key material data areas. The size of the key material data areas is determined by the number of stripes in the key slot and key size. Refer to the LUKS format -specification ('docs/on-disk-format.pdf' in the cryptsetup source +specification (``docs/on-disk-format.pdf`` in the cryptsetup source package) for details of the LUKS partition header format. -In the LUKS partition header, the "payload-offset" field will be +In the LUKS partition header, the ``payload-offset`` field will be calculated as normal for the LUKS spec. ie the size of the LUKS header, plus key material regions, plus padding, relative to the start of the LUKS header. This offset value is not required to be @@ -369,11 +384,12 @@ context of qcow2, since the qcow2 file format itself defines where the real payload offset is, but none the less a valid payload offset should always be present. -In the LUKS key slots header, the "key-material-offset" is relative +In the LUKS key slots header, the ``key-material-offset`` is relative to the start of the LUKS header clusters in the qcow2 container, not the start of the qcow2 file. Logically the layout looks like +:: +-----------------------------+ | QCow2 header | @@ -405,7 +421,8 @@ Logically the layout looks like | | +-----------------------------+ -== Data encryption == +Data encryption +--------------- When an encryption method is requested in the header, the image payload data must be encrypted/decrypted on every write/read. The image headers @@ -413,7 +430,7 @@ and metadata are never encrypted. The algorithms used for encryption vary depending on the method - - AES: + - ``AES``: The AES cipher, in CBC mode, with 256 bit keys. @@ -425,7 +442,7 @@ The algorithms used for encryption vary depending on the method supported in the command line tools for the sake of back compatibility and data liberation. - - LUKS: + - ``LUKS``: The algorithms are specified in the LUKS header. @@ -433,7 +450,8 @@ The algorithms used for encryption vary depending on the method in the LUKS header, with the physical disk sector as the input tweak. -== Host cluster management == +Host cluster management +----------------------- qcow2 manages the allocation of host clusters by maintaining a reference count for each host cluster. A refcount of 0 means that the cluster is free, 1 means @@ -453,14 +471,15 @@ Although a large enough refcount table can reserve clusters past 64 PB large), note that some qcow2 metadata such as L1/L2 tables must point to clusters prior to that point. -Note: qemu has an implementation limit of 8 MB as the maximum refcount -table size. With a 2 MB cluster size and a default refcount_order of -4, it is unable to reference host resources beyond 2 EB (61 bits); in -the worst case, with a 512 cluster size and refcount_order of 6, it is -unable to access beyond 32 GB (35 bits). +.. note:: + QEMU has an implementation limit of 8 MB as the maximum refcount + table size. With a 2 MB cluster size and a default refcount_order of + 4, it is unable to reference host resources beyond 2 EB (61 bits); in + the worst case, with a 512 cluster size and refcount_order of 6, it is + unable to access beyond 32 GB (35 bits). Given an offset into the image file, the refcount of its cluster can be -obtained as follows: +obtained as follows:: refcount_block_entries = (cluster_size * 8 / refcount_bits) @@ -470,7 +489,7 @@ obtained as follows: refcount_block = load_cluster(refcount_table[refcount_table_index]); return refcount_block[refcount_block_index]; -Refcount table entry: +Refcount table entry:: Bit 0 - 8: Reserved (set to 0) @@ -482,14 +501,15 @@ Refcount table entry: been allocated. All refcounts managed by this refcount block are 0. -Refcount block entry (x = refcount_bits - 1): +Refcount block entry ``(x = refcount_bits - 1)``:: Bit 0 - x: Reference count of the cluster. If refcount_bits implies a sub-byte width, note that bit 0 means the least significant bit in this context. -== Cluster mapping == +Cluster mapping +--------------- Just as for refcounts, qcow2 uses a two-level structure for the mapping of guest clusters to host clusters. They are called L1 and L2 table. @@ -509,7 +529,7 @@ compressed clusters to reside below 512 TB (49 bits), and this limit cannot be relaxed without an incompatible layout change). Given an offset into the virtual disk, the offset into the image file can be -obtained as follows: +obtained as follows:: l2_entries = (cluster_size / sizeof(uint64_t)) [*] @@ -523,7 +543,7 @@ obtained as follows: [*] this changes if Extended L2 Entries are enabled, see next section -L1 table entry: +L1 table entry:: Bit 0 - 8: Reserved (set to 0) @@ -538,7 +558,7 @@ L1 table entry: refcount is exactly one. This information is only accurate in the active L1 table. -L2 table entry: +L2 table entry:: Bit 0 - 61: Cluster descriptor @@ -555,7 +575,7 @@ L2 table entry: mapping for guest cluster offsets), so this bit should be 1 for all allocated clusters. -Standard Cluster Descriptor: +Standard Cluster Descriptor:: Bit 0: If set to 1, the cluster reads as all zeros. The host cluster offset can be used to describe a preallocation, @@ -577,7 +597,7 @@ Standard Cluster Descriptor: 56 - 61: Reserved (set to 0) -Compressed Clusters Descriptor (x = 62 - (cluster_bits - 8)): +Compressed Clusters Descriptor ``(x = 62 - (cluster_bits - 8))``:: Bit 0 - x-1: Host cluster offset. This is usually _not_ aligned to a cluster or sector boundary! If cluster_bits is @@ -601,7 +621,8 @@ file (except if bit 0 in the Standard Cluster Descriptor is set). If there is no backing file or the backing file is smaller than the image, they shall read zeros for all parts that are not covered by the backing file. -== Extended L2 Entries == +Extended L2 Entries +------------------- An image uses Extended L2 Entries if bit 4 is set on the incompatible_features field of the header. @@ -615,6 +636,8 @@ subclusters so they are treated the same as in images without this feature. The size of an extended L2 entry is 128 bits so the number of entries per table is calculated using this formula: +.. code:: + l2_entries = (cluster_size / (2 * sizeof(uint64_t))) The first 64 bits have the same format as the standard L2 table entry described @@ -623,7 +646,7 @@ descriptor. The last 64 bits contain a subcluster allocation bitmap with this format: -Subcluster Allocation Bitmap (for standard clusters): +Subcluster Allocation Bitmap (for standard clusters):: Bit 0 - 31: Allocation status (one bit per subcluster) @@ -647,13 +670,14 @@ Subcluster Allocation Bitmap (for standard clusters): Bits are assigned starting from the least significant one (i.e. bit x is used for subcluster x - 32). -Subcluster Allocation Bitmap (for compressed clusters): +Subcluster Allocation Bitmap (for compressed clusters):: Bit 0 - 63: Reserved (set to 0) Compressed clusters don't have subclusters, so this field is not used. -== Snapshots == +Snapshots +--------- qcow2 supports internal snapshots. Their basic principle of operation is to switch the active L1 table, so that a different set of host clusters are @@ -672,7 +696,7 @@ in the image file, whose starting offset and length are given by the header fields snapshots_offset and nb_snapshots. The entries of the snapshot table have variable length, depending on the length of ID, name and extra data. -Snapshot table entry: +Snapshot table entry:: Byte 0 - 7: Offset into the image file at which the L1 table for the snapshot starts. Must be aligned to a cluster boundary. @@ -728,7 +752,8 @@ Snapshot table entry: next multiple of 8. -== Bitmaps == +Bitmaps +------- As mentioned above, the bitmaps extension provides the ability to store bitmaps related to a virtual disk. This section describes how these bitmaps are stored. @@ -739,20 +764,23 @@ each bitmap size is equal to the virtual disk size. Each bit of the bitmap is responsible for strictly defined range of the virtual disk. For bit number bit_nr the corresponding range (in bytes) will be: +.. code:: + [bit_nr * bitmap_granularity .. (bit_nr + 1) * bitmap_granularity - 1] Granularity is a property of the concrete bitmap, see below. -=== Bitmap directory === +Bitmap directory +---------------- Each bitmap saved in the image is described in a bitmap directory entry. The bitmap directory is a contiguous area in the image file, whose starting offset -and length are given by the header extension fields bitmap_directory_offset and -bitmap_directory_size. The entries of the bitmap directory have variable +and length are given by the header extension fields ``bitmap_directory_offset`` and +``bitmap_directory_size``. The entries of the bitmap directory have variable length, depending on the lengths of the bitmap name and extra data. -Structure of a bitmap directory entry: +Structure of a bitmap directory entry:: Byte 0 - 7: bitmap_table_offset Offset into the image file at which the bitmap table @@ -833,7 +861,8 @@ Structure of a bitmap directory entry: next multiple of 8. All bytes of the padding must be zero. -=== Bitmap table === +Bitmap table +------------ Each bitmap is stored using a one-level structure (as opposed to two-level structures like for refcounts and guest clusters mapping) for the mapping of @@ -843,7 +872,7 @@ Each bitmap table has a variable size (stored in the bitmap directory entry) and may use multiple clusters, however, it must be contiguous in the image file. -Structure of a bitmap table entry: +Structure of a bitmap table entry:: Bit 0: Reserved and must be zero if bits 9 - 55 are non-zero. If bits 9 - 55 are zero: @@ -860,11 +889,12 @@ Structure of a bitmap table entry: 56 - 63: Reserved and must be zero. -=== Bitmap data === +Bitmap data +----------- As noted above, bitmap data is stored in separate clusters, described by the bitmap table. Given an offset (in bytes) into the bitmap data, the offset into -the image file can be obtained as follows: +the image file can be obtained as follows:: image_offset(bitmap_data_offset) = bitmap_table[bitmap_data_offset / cluster_size] + @@ -875,7 +905,7 @@ above). Given an offset byte_nr into the virtual disk and the bitmap's granularity, the bit offset into the image file to the corresponding bit of the bitmap can be -calculated like this: +calculated like this:: bit_offset(byte_nr) = image_offset(byte_nr / granularity / 8) * 8 + @@ -886,21 +916,22 @@ last cluster of the bitmap data contains some unused tail bits. These bits must be zero. -=== Dirty tracking bitmaps === +Dirty tracking bitmaps +---------------------- -Bitmaps with 'type' field equal to one are dirty tracking bitmaps. +Bitmaps with ``type`` field equal to one are dirty tracking bitmaps. -When the virtual disk is in use dirty tracking bitmap may be 'enabled' or -'disabled'. While the bitmap is 'enabled', all writes to the virtual disk +When the virtual disk is in use dirty tracking bitmap may be ``enabled`` or +``disabled``. While the bitmap is ``enabled``, all writes to the virtual disk should be reflected in the bitmap. A set bit in the bitmap means that the corresponding range of the virtual disk (see above) was written to while the -bitmap was 'enabled'. An unset bit means that this range was not written to. +bitmap was ``enabled``. An unset bit means that this range was not written to. The software doesn't have to sync the bitmap in the image file with its -representation in RAM after each write or metadata change. Flag 'in_use' +representation in RAM after each write or metadata change. Flag ``in_use`` should be set while the bitmap is not synced. -In the image file the 'enabled' state is reflected by the 'auto' flag. If this -flag is set, the software must consider the bitmap as 'enabled' and start +In the image file the ``enabled`` state is reflected by the ``auto`` flag. If this +flag is set, the software must consider the bitmap as ``enabled`` and start tracking virtual disk changes to this bitmap from the first write to the virtual disk. If this flag is not set then the bitmap is disabled. diff --git a/docs/qcow2-cache.txt b/docs/qcow2-cache.txt index 5f763aa6bb..204a5741ad 100644 --- a/docs/qcow2-cache.txt +++ b/docs/qcow2-cache.txt @@ -15,7 +15,7 @@ not a straightforward operation. This document attempts to give an overview of the L2 and refcount caches, and how to configure them. -Please refer to the docs/interop/qcow2.txt file for an in-depth +Please refer to the docs/interop/qcow2.rst file for an in-depth technical description of the qcow2 file format. From 4f8599f20c4a54cefc626b50dc7392dd82b422f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:10 +0100 Subject: [PATCH 1287/2760] target/arm/tcg-stubs: compile file once (system) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-id: 20250513173928.77376-2-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index b404fa5486..e568dfb706 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -48,7 +48,7 @@ subdir('hvf') if 'CONFIG_TCG' in config_all_accel subdir('tcg') else - arm_ss.add(files('tcg-stubs.c')) + arm_common_system_ss.add(files('tcg-stubs.c')) endif target_arch += {'arm': arm_ss} From f1bcfa81d84c2a7401f6dcbf8fc1c7b26ec18213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:10 +0100 Subject: [PATCH 1288/2760] target/arm/hvf_arm: Avoid using poisoned CONFIG_HVF definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to allow non-target specific code to include "hvf_arm.h", define the stubs in hvf-stub.c. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Reviewed-by: Richard Henderson Message-id: 20250513173928.77376-3-philmd@linaro.org Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + target/arm/hvf-stub.c | 20 ++++++++++++++++++++ target/arm/hvf_arm.h | 16 ---------------- target/arm/meson.build | 1 + 4 files changed, 22 insertions(+), 16 deletions(-) create mode 100644 target/arm/hvf-stub.c diff --git a/MAINTAINERS b/MAINTAINERS index 8e68333623..973254fae7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -510,6 +510,7 @@ Apple Silicon HVF CPUs M: Alexander Graf S: Maintained F: target/arm/hvf/ +F: target/arm/hvf-stub.c X86 HVF CPUs M: Cameron Esfahani diff --git a/target/arm/hvf-stub.c b/target/arm/hvf-stub.c new file mode 100644 index 0000000000..ff137267a0 --- /dev/null +++ b/target/arm/hvf-stub.c @@ -0,0 +1,20 @@ +/* + * QEMU Hypervisor.framework (HVF) stubs for ARM + * + * Copyright (c) Linaro + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "hvf_arm.h" + +uint32_t hvf_arm_get_default_ipa_bit_size(void) +{ + g_assert_not_reached(); +} + +uint32_t hvf_arm_get_max_ipa_bit_size(void) +{ + g_assert_not_reached(); +} diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h index 26c717b382..7a44e09262 100644 --- a/target/arm/hvf_arm.h +++ b/target/arm/hvf_arm.h @@ -22,23 +22,7 @@ void hvf_arm_init_debug(void); void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu); -#ifdef CONFIG_HVF - uint32_t hvf_arm_get_default_ipa_bit_size(void); uint32_t hvf_arm_get_max_ipa_bit_size(void); -#else - -static inline uint32_t hvf_arm_get_default_ipa_bit_size(void) -{ - return 0; -} - -static inline uint32_t hvf_arm_get_max_ipa_bit_size(void) -{ - return 0; -} - -#endif - #endif diff --git a/target/arm/meson.build b/target/arm/meson.build index e568dfb706..2747f4b404 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -32,6 +32,7 @@ arm_common_system_ss.add(files('cpu.c'), capstone) arm_common_system_ss.add(when: 'TARGET_AARCH64', if_false: files( 'cpu32-stubs.c')) arm_common_system_ss.add(when: 'CONFIG_KVM', if_false: files('kvm-stub.c')) +arm_common_system_ss.add(when: 'CONFIG_HVF', if_false: files('hvf-stub.c')) arm_common_system_ss.add(files( 'arch_dump.c', 'arm-powerctl.c', From 54d1046f939c2c508a6b73531af83345306ecaa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:11 +0100 Subject: [PATCH 1289/2760] target/arm: Only link with zlib when TCG is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 538b764d341 ("target/arm: Move minor arithmetic helpers out of helper.c") we only use the zlib helpers under TCG. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20250513173928.77376-4-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/meson.build | 1 - target/arm/tcg/meson.build | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/target/arm/meson.build b/target/arm/meson.build index 2747f4b404..dcba4ef379 100644 --- a/target/arm/meson.build +++ b/target/arm/meson.build @@ -3,7 +3,6 @@ arm_common_ss = ss.source_set() arm_ss.add(files( 'gdbstub.c', )) -arm_ss.add(zlib) arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'cpu64.c', diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index 2d1502ba88..c59f0f03a1 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -56,6 +56,8 @@ arm_system_ss.add(files( arm_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c')) arm_user_ss.add(when: 'TARGET_AARCH64', if_false: files('cpu-v7m.c')) +arm_common_ss.add(zlib) + arm_common_ss.add(files( 'arith_helper.c', 'crypto_helper.c', From 982a42c773efc7767e33d618f0fe4fcaef716a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:11 +0100 Subject: [PATCH 1290/2760] target/arm/cpregs: Include missing 'target/arm/cpu.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPReadFn type definitions use the CPUARMState type, itself declared in "cpu.h". Include this file in order to avoid when refactoring headers: ../target/arm/cpregs.h:241:27: error: unknown type name 'CPUARMState' typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); ^ Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20250513173928.77376-5-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpregs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/cpregs.h b/target/arm/cpregs.h index 2183de8eda..c1a7ae3735 100644 --- a/target/arm/cpregs.h +++ b/target/arm/cpregs.h @@ -23,6 +23,7 @@ #include "hw/registerfields.h" #include "target/arm/kvm-consts.h" +#include "cpu.h" /* * ARMCPRegInfo type field bits: From c28900fbcdc36175a1fc81015e952133007ae864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:11 +0100 Subject: [PATCH 1291/2760] hw/arm/boot: Include missing 'system/memory.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit default_reset_secondary() uses address_space_stl_notdirty(), itself declared in "system/memory.h". Include this header in order to avoid when refactoring headers: ../hw/arm/boot.c:281:5: error: implicit declaration of function 'address_space_stl_notdirty' is invalid in C99 [-Werror,-Wimplicit-function-declaration] address_space_stl_notdirty(as, info->smp_bootreg_addr, ^ Reviewed-by: Richard Henderson Signed-off-by: Philippe Mathieu-Daudé Message-id: 20250513173928.77376-6-philmd@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index f94b940bc3..79afb51b8a 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -19,6 +19,7 @@ #include "system/kvm.h" #include "system/tcg.h" #include "system/system.h" +#include "system/memory.h" #include "system/numa.h" #include "hw/boards.h" #include "system/reset.h" From fe5aa1cfe22c71c80e544cf97741036cba0556d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:11 +0100 Subject: [PATCH 1292/2760] target/arm/cpu-features: Include missing 'cpu.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit "target/arm/cpu-features.h" dereferences the ARMISARegisters structure, which is defined in "cpu.h". Include the latter to avoid when refactoring unrelated headers: In file included from target/arm/internals.h:33: target/arm/cpu-features.h:45:54: error: unknown type name 'ARMISARegisters' 45 | static inline bool isar_feature_aa32_thumb_div(const ARMISARegisters *id) | ^ target/arm/cpu-features.h:47:12: error: use of undeclared identifier 'R_ID_ISAR0_DIVIDE_SHIFT' 47 | return FIELD_EX32(id->id_isar0, ID_ISAR0, DIVIDE) != 0; | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20250513173928.77376-7-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/cpu-features.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index 525e4cee12..4452e7c21e 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -22,6 +22,7 @@ #include "hw/registerfields.h" #include "qemu/host-utils.h" +#include "cpu.h" /* * Naming convention for isar_feature functions: From e0f224ec077d90c10288a4f73d01a264b0364e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:12 +0100 Subject: [PATCH 1293/2760] target/arm/qmp: Include missing 'cpu.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arm-qmp-cmds.c uses ARM_MAX_VQ, which is defined in "cpu.h". Include the latter to avoid when refactoring unrelated headers: target/arm/arm-qmp-cmds.c:83:19: error: use of undeclared identifier 'ARM_MAX_VQ' 83 | QEMU_BUILD_BUG_ON(ARM_MAX_VQ > 16); | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20250513173928.77376-8-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/arm-qmp-cmds.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/arm-qmp-cmds.c b/target/arm/arm-qmp-cmds.c index cca6b9722b..cefd235263 100644 --- a/target/arm/arm-qmp-cmds.c +++ b/target/arm/arm-qmp-cmds.c @@ -30,6 +30,7 @@ #include "qapi/qapi-commands-misc-arm.h" #include "qobject/qdict.h" #include "qom/qom-qobject.h" +#include "cpu.h" static GICCapability *gic_cap_new(int version) { From 3d28b2ce00e8b5e74e1f5cbba13cf306b8360762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:12 +0100 Subject: [PATCH 1294/2760] target/arm/kvm: Include missing 'cpu-qom.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARMCPU typedef is declared in "cpu-qom.h". Include it in order to avoid when refactoring unrelated headers: target/arm/kvm_arm.h:54:29: error: unknown type name 'ARMCPU' 54 | bool write_list_to_kvmstate(ARMCPU *cpu, int level); | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20250513173928.77376-9-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/kvm_arm.h | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/kvm_arm.h b/target/arm/kvm_arm.h index c4178d1327..7dc83caed5 100644 --- a/target/arm/kvm_arm.h +++ b/target/arm/kvm_arm.h @@ -12,6 +12,7 @@ #define QEMU_KVM_ARM_H #include "system/kvm.h" +#include "target/arm/cpu-qom.h" #define KVM_ARM_VGIC_V2 (1 << 0) #define KVM_ARM_VGIC_V3 (1 << 1) From c42300ef71ba103a9bf67ca64cb94d5d9b633175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Thu, 29 May 2025 17:45:12 +0100 Subject: [PATCH 1295/2760] target/arm/hvf: Include missing 'cpu-qom.h' header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARMCPU typedef is declared in "cpu-qom.h". Include it in order to avoid when refactoring unrelated headers: target/arm/hvf_arm.h:23:41: error: unknown type name 'ARMCPU' 23 | void hvf_arm_set_cpu_features_from_host(ARMCPU *cpu); | ^ Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Pierrick Bouvier Message-id: 20250513173928.77376-10-philmd@linaro.org Signed-off-by: Peter Maydell --- target/arm/hvf_arm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/hvf_arm.h b/target/arm/hvf_arm.h index 7a44e09262..ea82f2691d 100644 --- a/target/arm/hvf_arm.h +++ b/target/arm/hvf_arm.h @@ -11,7 +11,7 @@ #ifndef QEMU_HVF_ARM_H #define QEMU_HVF_ARM_H -#include "cpu.h" +#include "target/arm/cpu-qom.h" /** * hvf_arm_init_debug() - initialize guest debug capabilities From 96778e69a2e391e5dc99d2318e7830695c607795 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 29 May 2025 17:45:12 +0100 Subject: [PATCH 1296/2760] tests/functional: Add a test for the Stellaris arm machines The 2023 edition of the QEMU advent calendar featured an image that we can use to test whether the lm3s6965evb machine is basically still working. And for the lm3s811evb there is a small test kernel on github which can be used to check its UART. Signed-off-by: Thomas Huth Message-id: 20250519170242.520805-1-thuth@redhat.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- MAINTAINERS | 1 + tests/functional/meson.build | 1 + tests/functional/test_arm_stellaris.py | 48 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100755 tests/functional/test_arm_stellaris.py diff --git a/MAINTAINERS b/MAINTAINERS index 973254fae7..16af37986a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1004,6 +1004,7 @@ F: hw/display/ssd03* F: include/hw/input/gamepad.h F: include/hw/timer/stellaris-gptm.h F: docs/system/arm/stellaris.rst +F: tests/functional/test_arm_stellaris.py STM32L4x5 SoC Family M: Samuel Tardieu diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 52b4706cfe..557d59ddf4 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -137,6 +137,7 @@ tests_arm_system_thorough = [ 'arm_raspi2', 'arm_replay', 'arm_smdkc210', + 'arm_stellaris', 'arm_sx1', 'arm_vexpress', 'arm_virt', diff --git a/tests/functional/test_arm_stellaris.py b/tests/functional/test_arm_stellaris.py new file mode 100755 index 0000000000..cbd21cb1a0 --- /dev/null +++ b/tests/functional/test_arm_stellaris.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# +# Functional test that checks the serial console of the stellaris machines +# +# SPDX-License-Identifier: GPL-2.0-or-later + +from qemu_test import QemuSystemTest, Asset, exec_command_and_wait_for_pattern +from qemu_test import wait_for_console_pattern + + +class StellarisMachine(QemuSystemTest): + + ASSET_DAY22 = Asset( + 'https://www.qemu-advent-calendar.org/2023/download/day22.tar.gz', + 'ae3a63ef4b7a22c21bfc7fc0d85e402fe95e223308ed23ac854405016431ff51') + + def test_lm3s6965evb(self): + self.set_machine('lm3s6965evb') + kernel_path = self.archive_extract(self.ASSET_DAY22, + member='day22/day22.bin') + self.vm.set_console() + self.vm.add_args('-kernel', kernel_path) + self.vm.launch() + + wait_for_console_pattern(self, 'In a one horse open') + + ASSET_NOTMAIN = Asset( + 'https://github.com/Ahelion/QemuArmM4FDemoSw/raw/master/build/notmain.bin', + '6ceda031aa081a420fca2fca9e137fa681d6e3820d820ad1917736cb265e611a') + + def test_lm3s811evb(self): + self.set_machine('lm3s811evb') + kernel_path = self.ASSET_NOTMAIN.fetch() + + self.vm.set_console() + self.vm.add_args('-cpu', 'cortex-m4') + self.vm.add_args('-kernel', kernel_path) + self.vm.launch() + + # The test kernel emits an initial '!' and then waits for input. + # For each character that we send it responds with a certain + # other ASCII character. + wait_for_console_pattern(self, '!') + exec_command_and_wait_for_pattern(self, '789', 'cdf') + + +if __name__ == '__main__': + QemuSystemTest.main() From e86c1f967a323165d13bcadfad4b92d0d34cdb08 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 29 May 2025 17:45:13 +0100 Subject: [PATCH 1297/2760] hw/block: Drop unused nand.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nand.c device (TYPE_NAND) is an emulation of a NAND flash memory chip which was used by the old OMAP boards. No current QEMU board uses it, and although techically "-device nand,chip-id=0x6b" doesn't error out, it's not possible to usefully use it from the command line because the only interface it has is via calling C functions like nand_setpins() and nand_setio(). The "config OMAP" stanza (used only by the SX1 board) is the only thing that does "select NAND" to compile in this code, but the SX1 board doesn't actually use the NAND device. Remove the NAND device code entirely; this is effectively leftover cleanup from when we dropped the PXA boards and the OMAP boards other than the sx1. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Message-id: 20250522142859.3122389-1-peter.maydell@linaro.org --- hw/arm/Kconfig | 1 - hw/block/Kconfig | 3 - hw/block/meson.build | 1 - hw/block/nand.c | 835 --------------------------------------- include/hw/block/flash.h | 18 - 5 files changed, 858 deletions(-) delete mode 100644 hw/block/nand.c diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig index a55b44d7bd..f543d944c3 100644 --- a/hw/arm/Kconfig +++ b/hw/arm/Kconfig @@ -147,7 +147,6 @@ config OMAP bool select FRAMEBUFFER select I2C - select NAND select PFLASH_CFI01 select SD select SERIAL_MM diff --git a/hw/block/Kconfig b/hw/block/Kconfig index a898e04f03..737dbcdb3e 100644 --- a/hw/block/Kconfig +++ b/hw/block/Kconfig @@ -13,9 +13,6 @@ config FDC_SYSBUS config SSI_M25P80 bool -config NAND - bool - config PFLASH_CFI01 bool diff --git a/hw/block/meson.build b/hw/block/meson.build index 16a51bf8e2..655704471a 100644 --- a/hw/block/meson.build +++ b/hw/block/meson.build @@ -6,7 +6,6 @@ system_ss.add(files( system_ss.add(when: 'CONFIG_FDC', if_true: files('fdc.c')) system_ss.add(when: 'CONFIG_FDC_ISA', if_true: files('fdc-isa.c')) system_ss.add(when: 'CONFIG_FDC_SYSBUS', if_true: files('fdc-sysbus.c')) -system_ss.add(when: 'CONFIG_NAND', if_true: files('nand.c')) system_ss.add(when: 'CONFIG_PFLASH_CFI01', if_true: files('pflash_cfi01.c')) system_ss.add(when: 'CONFIG_PFLASH_CFI02', if_true: files('pflash_cfi02.c')) system_ss.add(when: 'CONFIG_SSI_M25P80', if_true: files('m25p80.c')) diff --git a/hw/block/nand.c b/hw/block/nand.c deleted file mode 100644 index c80bf78fe5..0000000000 --- a/hw/block/nand.c +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Flash NAND memory emulation. Based on "16M x 8 Bit NAND Flash - * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from - * Samsung Electronic. - * - * Copyright (c) 2006 Openedhand Ltd. - * Written by Andrzej Zaborowski - * - * Support for additional features based on "MT29F2G16ABCWP 2Gx16" - * datasheet from Micron Technology and "NAND02G-B2C" datasheet - * from ST Microelectronics. - * - * This code is licensed under the GNU GPL v2. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#ifndef NAND_IO - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "hw/qdev-properties.h" -#include "hw/qdev-properties-system.h" -#include "hw/block/flash.h" -#include "system/block-backend.h" -#include "migration/vmstate.h" -#include "qapi/error.h" -#include "qemu/error-report.h" -#include "qemu/module.h" -#include "qom/object.h" - -# define NAND_CMD_READ0 0x00 -# define NAND_CMD_READ1 0x01 -# define NAND_CMD_READ2 0x50 -# define NAND_CMD_LPREAD2 0x30 -# define NAND_CMD_NOSERIALREAD2 0x35 -# define NAND_CMD_RANDOMREAD1 0x05 -# define NAND_CMD_RANDOMREAD2 0xe0 -# define NAND_CMD_READID 0x90 -# define NAND_CMD_RESET 0xff -# define NAND_CMD_PAGEPROGRAM1 0x80 -# define NAND_CMD_PAGEPROGRAM2 0x10 -# define NAND_CMD_CACHEPROGRAM2 0x15 -# define NAND_CMD_BLOCKERASE1 0x60 -# define NAND_CMD_BLOCKERASE2 0xd0 -# define NAND_CMD_READSTATUS 0x70 -# define NAND_CMD_COPYBACKPRG1 0x85 - -# define NAND_IOSTATUS_ERROR (1 << 0) -# define NAND_IOSTATUS_PLANE0 (1 << 1) -# define NAND_IOSTATUS_PLANE1 (1 << 2) -# define NAND_IOSTATUS_PLANE2 (1 << 3) -# define NAND_IOSTATUS_PLANE3 (1 << 4) -# define NAND_IOSTATUS_READY (1 << 6) -# define NAND_IOSTATUS_UNPROTCT (1 << 7) - -# define MAX_PAGE 0x800 -# define MAX_OOB 0x40 - -typedef struct NANDFlashState NANDFlashState; -struct NANDFlashState { - DeviceState parent_obj; - - uint8_t manf_id, chip_id; - uint8_t buswidth; /* in BYTES */ - int size, pages; - int page_shift, oob_shift, erase_shift, addr_shift; - uint8_t *storage; - BlockBackend *blk; - int mem_oob; - - uint8_t cle, ale, ce, wp, gnd; - - uint8_t io[MAX_PAGE + MAX_OOB + 0x400]; - uint8_t *ioaddr; - int iolen; - - uint32_t cmd; - uint64_t addr; - int addrlen; - int status; - int offset; - - void (*blk_write)(NANDFlashState *s); - void (*blk_erase)(NANDFlashState *s); - /* - * Returns %true when block containing (@addr + @offset) is - * successfully loaded, otherwise %false. - */ - bool (*blk_load)(NANDFlashState *s, uint64_t addr, unsigned offset); - - uint32_t ioaddr_vmstate; -}; - -#define TYPE_NAND "nand" - -OBJECT_DECLARE_SIMPLE_TYPE(NANDFlashState, NAND) - -static void mem_and(uint8_t *dest, const uint8_t *src, size_t n) -{ - /* Like memcpy() but we logical-AND the data into the destination */ - int i; - for (i = 0; i < n; i++) { - dest[i] &= src[i]; - } -} - -# define NAND_NO_AUTOINCR 0x00000001 -# define NAND_BUSWIDTH_16 0x00000002 -# define NAND_NO_PADDING 0x00000004 -# define NAND_CACHEPRG 0x00000008 -# define NAND_COPYBACK 0x00000010 -# define NAND_IS_AND 0x00000020 -# define NAND_4PAGE_ARRAY 0x00000040 -# define NAND_NO_READRDY 0x00000100 -# define NAND_SAMSUNG_LP (NAND_NO_PADDING | NAND_COPYBACK) - -# define NAND_IO - -# define PAGE(addr) ((addr) >> ADDR_SHIFT) -# define PAGE_START(page) (PAGE(page) * (NAND_PAGE_SIZE + OOB_SIZE)) -# define PAGE_MASK ((1 << ADDR_SHIFT) - 1) -# define OOB_SHIFT (PAGE_SHIFT - 5) -# define OOB_SIZE (1 << OOB_SHIFT) -# define SECTOR(addr) ((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT)) -# define SECTOR_OFFSET(addr) ((addr) & ((511 >> PAGE_SHIFT) << 8)) - -# define NAND_PAGE_SIZE 256 -# define PAGE_SHIFT 8 -# define PAGE_SECTORS 1 -# define ADDR_SHIFT 8 -# include "nand.c" -# define NAND_PAGE_SIZE 512 -# define PAGE_SHIFT 9 -# define PAGE_SECTORS 1 -# define ADDR_SHIFT 8 -# include "nand.c" -# define NAND_PAGE_SIZE 2048 -# define PAGE_SHIFT 11 -# define PAGE_SECTORS 4 -# define ADDR_SHIFT 16 -# include "nand.c" - -/* Information based on Linux drivers/mtd/nand/raw/nand_ids.c */ -static const struct { - int size; - int width; - int page_shift; - int erase_shift; - uint32_t options; -} nand_flash_ids[0x100] = { - [0 ... 0xff] = { 0 }, - - [0x6b] = { 4, 8, 9, 4, 0 }, - [0xe3] = { 4, 8, 9, 4, 0 }, - [0xe5] = { 4, 8, 9, 4, 0 }, - [0xd6] = { 8, 8, 9, 4, 0 }, - [0xe6] = { 8, 8, 9, 4, 0 }, - - [0x33] = { 16, 8, 9, 5, 0 }, - [0x73] = { 16, 8, 9, 5, 0 }, - [0x43] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x53] = { 16, 16, 9, 5, NAND_BUSWIDTH_16 }, - - [0x35] = { 32, 8, 9, 5, 0 }, - [0x75] = { 32, 8, 9, 5, 0 }, - [0x45] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x55] = { 32, 16, 9, 5, NAND_BUSWIDTH_16 }, - - [0x36] = { 64, 8, 9, 5, 0 }, - [0x76] = { 64, 8, 9, 5, 0 }, - [0x46] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x56] = { 64, 16, 9, 5, NAND_BUSWIDTH_16 }, - - [0x78] = { 128, 8, 9, 5, 0 }, - [0x39] = { 128, 8, 9, 5, 0 }, - [0x79] = { 128, 8, 9, 5, 0 }, - [0x72] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x49] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x74] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, - [0x59] = { 128, 16, 9, 5, NAND_BUSWIDTH_16 }, - - [0x71] = { 256, 8, 9, 5, 0 }, - - /* - * These are the new chips with large page size. The pagesize and the - * erasesize is determined from the extended id bytes - */ -# define LP_OPTIONS (NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR) -# define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) - - /* 512 Megabit */ - [0xa2] = { 64, 8, 0, 0, LP_OPTIONS }, - [0xf2] = { 64, 8, 0, 0, LP_OPTIONS }, - [0xb2] = { 64, 16, 0, 0, LP_OPTIONS16 }, - [0xc2] = { 64, 16, 0, 0, LP_OPTIONS16 }, - - /* 1 Gigabit */ - [0xa1] = { 128, 8, 0, 0, LP_OPTIONS }, - [0xf1] = { 128, 8, 0, 0, LP_OPTIONS }, - [0xb1] = { 128, 16, 0, 0, LP_OPTIONS16 }, - [0xc1] = { 128, 16, 0, 0, LP_OPTIONS16 }, - - /* 2 Gigabit */ - [0xaa] = { 256, 8, 0, 0, LP_OPTIONS }, - [0xda] = { 256, 8, 0, 0, LP_OPTIONS }, - [0xba] = { 256, 16, 0, 0, LP_OPTIONS16 }, - [0xca] = { 256, 16, 0, 0, LP_OPTIONS16 }, - - /* 4 Gigabit */ - [0xac] = { 512, 8, 0, 0, LP_OPTIONS }, - [0xdc] = { 512, 8, 0, 0, LP_OPTIONS }, - [0xbc] = { 512, 16, 0, 0, LP_OPTIONS16 }, - [0xcc] = { 512, 16, 0, 0, LP_OPTIONS16 }, - - /* 8 Gigabit */ - [0xa3] = { 1024, 8, 0, 0, LP_OPTIONS }, - [0xd3] = { 1024, 8, 0, 0, LP_OPTIONS }, - [0xb3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, - [0xc3] = { 1024, 16, 0, 0, LP_OPTIONS16 }, - - /* 16 Gigabit */ - [0xa5] = { 2048, 8, 0, 0, LP_OPTIONS }, - [0xd5] = { 2048, 8, 0, 0, LP_OPTIONS }, - [0xb5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, - [0xc5] = { 2048, 16, 0, 0, LP_OPTIONS16 }, -}; - -static void nand_reset(DeviceState *dev) -{ - NANDFlashState *s = NAND(dev); - s->cmd = NAND_CMD_READ0; - s->addr = 0; - s->addrlen = 0; - s->iolen = 0; - s->offset = 0; - s->status &= NAND_IOSTATUS_UNPROTCT; - s->status |= NAND_IOSTATUS_READY; -} - -static inline void nand_pushio_byte(NANDFlashState *s, uint8_t value) -{ - s->ioaddr[s->iolen++] = value; - for (value = s->buswidth; --value;) { - s->ioaddr[s->iolen++] = 0; - } -} - -/* - * nand_load_block: Load block containing (s->addr + @offset). - * Returns length of data available at @offset in this block. - */ -static unsigned nand_load_block(NANDFlashState *s, unsigned offset) -{ - unsigned iolen; - - if (!s->blk_load(s, s->addr, offset)) { - return 0; - } - - iolen = (1 << s->page_shift); - if (s->gnd) { - iolen += 1 << s->oob_shift; - } - assert(offset <= iolen); - iolen -= offset; - - return iolen; -} - -static void nand_command(NANDFlashState *s) -{ - switch (s->cmd) { - case NAND_CMD_READ0: - s->iolen = 0; - break; - - case NAND_CMD_READID: - s->ioaddr = s->io; - s->iolen = 0; - nand_pushio_byte(s, s->manf_id); - nand_pushio_byte(s, s->chip_id); - nand_pushio_byte(s, 'Q'); /* Don't-care byte (often 0xa5) */ - if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { - /* Page Size, Block Size, Spare Size; bit 6 indicates - * 8 vs 16 bit width NAND. - */ - nand_pushio_byte(s, (s->buswidth == 2) ? 0x55 : 0x15); - } else { - nand_pushio_byte(s, 0xc0); /* Multi-plane */ - } - break; - - case NAND_CMD_RANDOMREAD2: - case NAND_CMD_NOSERIALREAD2: - if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)) - break; - s->iolen = nand_load_block(s, s->addr & ((1 << s->addr_shift) - 1)); - break; - - case NAND_CMD_RESET: - nand_reset(DEVICE(s)); - break; - - case NAND_CMD_PAGEPROGRAM1: - s->ioaddr = s->io; - s->iolen = 0; - break; - - case NAND_CMD_PAGEPROGRAM2: - if (s->wp) { - s->blk_write(s); - } - break; - - case NAND_CMD_BLOCKERASE1: - break; - - case NAND_CMD_BLOCKERASE2: - s->addr &= (1ull << s->addrlen * 8) - 1; - s->addr <<= nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP ? - 16 : 8; - - if (s->wp) { - s->blk_erase(s); - } - break; - - case NAND_CMD_READSTATUS: - s->ioaddr = s->io; - s->iolen = 0; - nand_pushio_byte(s, s->status); - break; - - default: - printf("%s: Unknown NAND command 0x%02x\n", __func__, s->cmd); - } -} - -static int nand_pre_save(void *opaque) -{ - NANDFlashState *s = NAND(opaque); - - s->ioaddr_vmstate = s->ioaddr - s->io; - - return 0; -} - -static int nand_post_load(void *opaque, int version_id) -{ - NANDFlashState *s = NAND(opaque); - - if (s->ioaddr_vmstate > sizeof(s->io)) { - return -EINVAL; - } - s->ioaddr = s->io + s->ioaddr_vmstate; - - return 0; -} - -static const VMStateDescription vmstate_nand = { - .name = "nand", - .version_id = 1, - .minimum_version_id = 1, - .pre_save = nand_pre_save, - .post_load = nand_post_load, - .fields = (const VMStateField[]) { - VMSTATE_UINT8(cle, NANDFlashState), - VMSTATE_UINT8(ale, NANDFlashState), - VMSTATE_UINT8(ce, NANDFlashState), - VMSTATE_UINT8(wp, NANDFlashState), - VMSTATE_UINT8(gnd, NANDFlashState), - VMSTATE_BUFFER(io, NANDFlashState), - VMSTATE_UINT32(ioaddr_vmstate, NANDFlashState), - VMSTATE_INT32(iolen, NANDFlashState), - VMSTATE_UINT32(cmd, NANDFlashState), - VMSTATE_UINT64(addr, NANDFlashState), - VMSTATE_INT32(addrlen, NANDFlashState), - VMSTATE_INT32(status, NANDFlashState), - VMSTATE_INT32(offset, NANDFlashState), - /* XXX: do we want to save s->storage too? */ - VMSTATE_END_OF_LIST() - } -}; - -static void nand_realize(DeviceState *dev, Error **errp) -{ - int pagesize; - NANDFlashState *s = NAND(dev); - int ret; - - - s->buswidth = nand_flash_ids[s->chip_id].width >> 3; - s->size = nand_flash_ids[s->chip_id].size << 20; - if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { - s->page_shift = 11; - s->erase_shift = 6; - } else { - s->page_shift = nand_flash_ids[s->chip_id].page_shift; - s->erase_shift = nand_flash_ids[s->chip_id].erase_shift; - } - - switch (1 << s->page_shift) { - case 256: - nand_init_256(s); - break; - case 512: - nand_init_512(s); - break; - case 2048: - nand_init_2048(s); - break; - default: - error_setg(errp, "Unsupported NAND block size %#x", - 1 << s->page_shift); - return; - } - - pagesize = 1 << s->oob_shift; - s->mem_oob = 1; - if (s->blk) { - if (!blk_supports_write_perm(s->blk)) { - error_setg(errp, "Can't use a read-only drive"); - return; - } - ret = blk_set_perm(s->blk, BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE, - BLK_PERM_ALL, errp); - if (ret < 0) { - return; - } - if (blk_getlength(s->blk) >= - (s->pages << s->page_shift) + (s->pages << s->oob_shift)) { - pagesize = 0; - s->mem_oob = 0; - } - } else { - pagesize += 1 << s->page_shift; - } - if (pagesize) { - s->storage = (uint8_t *) memset(g_malloc(s->pages * pagesize), - 0xff, s->pages * pagesize); - } - /* Give s->ioaddr a sane value in case we save state before it is used. */ - s->ioaddr = s->io; -} - -static const Property nand_properties[] = { - DEFINE_PROP_UINT8("manufacturer_id", NANDFlashState, manf_id, 0), - DEFINE_PROP_UINT8("chip_id", NANDFlashState, chip_id, 0), - DEFINE_PROP_DRIVE("drive", NANDFlashState, blk), -}; - -static void nand_class_init(ObjectClass *klass, const void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = nand_realize; - device_class_set_legacy_reset(dc, nand_reset); - dc->vmsd = &vmstate_nand; - device_class_set_props(dc, nand_properties); - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static const TypeInfo nand_info = { - .name = TYPE_NAND, - .parent = TYPE_DEVICE, - .instance_size = sizeof(NANDFlashState), - .class_init = nand_class_init, -}; - -static void nand_register_types(void) -{ - type_register_static(&nand_info); -} - -/* - * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins. Chip - * outputs are R/B and eight I/O pins. - * - * CE, WP and R/B are active low. - */ -void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale, - uint8_t ce, uint8_t wp, uint8_t gnd) -{ - NANDFlashState *s = NAND(dev); - - s->cle = cle; - s->ale = ale; - s->ce = ce; - s->wp = wp; - s->gnd = gnd; - if (wp) { - s->status |= NAND_IOSTATUS_UNPROTCT; - } else { - s->status &= ~NAND_IOSTATUS_UNPROTCT; - } -} - -void nand_getpins(DeviceState *dev, int *rb) -{ - *rb = 1; -} - -void nand_setio(DeviceState *dev, uint32_t value) -{ - int i; - NANDFlashState *s = NAND(dev); - - if (!s->ce && s->cle) { - if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) { - if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2) - return; - if (value == NAND_CMD_RANDOMREAD1) { - s->addr &= ~((1 << s->addr_shift) - 1); - s->addrlen = 0; - return; - } - } - if (value == NAND_CMD_READ0) { - s->offset = 0; - } else if (value == NAND_CMD_READ1) { - s->offset = 0x100; - value = NAND_CMD_READ0; - } else if (value == NAND_CMD_READ2) { - s->offset = 1 << s->page_shift; - value = NAND_CMD_READ0; - } - - s->cmd = value; - - if (s->cmd == NAND_CMD_READSTATUS || - s->cmd == NAND_CMD_PAGEPROGRAM2 || - s->cmd == NAND_CMD_BLOCKERASE1 || - s->cmd == NAND_CMD_BLOCKERASE2 || - s->cmd == NAND_CMD_NOSERIALREAD2 || - s->cmd == NAND_CMD_RANDOMREAD2 || - s->cmd == NAND_CMD_RESET) { - nand_command(s); - } - - if (s->cmd != NAND_CMD_RANDOMREAD2) { - s->addrlen = 0; - } - } - - if (s->ale) { - unsigned int shift = s->addrlen * 8; - uint64_t mask = ~(0xffull << shift); - uint64_t v = (uint64_t)value << shift; - - s->addr = (s->addr & mask) | v; - s->addrlen ++; - - switch (s->addrlen) { - case 1: - if (s->cmd == NAND_CMD_READID) { - nand_command(s); - } - break; - case 2: /* fix cache address as a byte address */ - s->addr <<= (s->buswidth - 1); - break; - case 3: - if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && - (s->cmd == NAND_CMD_READ0 || - s->cmd == NAND_CMD_PAGEPROGRAM1)) { - nand_command(s); - } - break; - case 4: - if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && - nand_flash_ids[s->chip_id].size < 256 && /* 1Gb or less */ - (s->cmd == NAND_CMD_READ0 || - s->cmd == NAND_CMD_PAGEPROGRAM1)) { - nand_command(s); - } - break; - case 5: - if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) && - nand_flash_ids[s->chip_id].size >= 256 && /* 2Gb or more */ - (s->cmd == NAND_CMD_READ0 || - s->cmd == NAND_CMD_PAGEPROGRAM1)) { - nand_command(s); - } - break; - default: - break; - } - } - - if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) { - if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift)) { - for (i = s->buswidth; i--; value >>= 8) { - s->io[s->iolen ++] = (uint8_t) (value & 0xff); - } - } - } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) { - if ((s->addr & ((1 << s->addr_shift) - 1)) < - (1 << s->page_shift) + (1 << s->oob_shift)) { - for (i = s->buswidth; i--; s->addr++, value >>= 8) { - s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = - (uint8_t) (value & 0xff); - } - } - } -} - -uint32_t nand_getio(DeviceState *dev) -{ - int offset; - uint32_t x = 0; - NANDFlashState *s = NAND(dev); - - /* Allow sequential reading */ - if (!s->iolen && s->cmd == NAND_CMD_READ0) { - offset = (int) (s->addr & ((1 << s->addr_shift) - 1)) + s->offset; - s->offset = 0; - s->iolen = nand_load_block(s, offset); - } - - if (s->ce || s->iolen <= 0) { - return 0; - } - - for (offset = s->buswidth; offset--;) { - x |= s->ioaddr[offset] << (offset << 3); - } - /* after receiving READ STATUS command all subsequent reads will - * return the status register value until another command is issued - */ - if (s->cmd != NAND_CMD_READSTATUS) { - s->addr += s->buswidth; - s->ioaddr += s->buswidth; - s->iolen -= s->buswidth; - } - return x; -} - -uint32_t nand_getbuswidth(DeviceState *dev) -{ - NANDFlashState *s = (NANDFlashState *) dev; - return s->buswidth << 3; -} - -DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id) -{ - DeviceState *dev; - - if (nand_flash_ids[chip_id].size == 0) { - hw_error("%s: Unsupported NAND chip ID.\n", __func__); - } - dev = qdev_new(TYPE_NAND); - qdev_prop_set_uint8(dev, "manufacturer_id", manf_id); - qdev_prop_set_uint8(dev, "chip_id", chip_id); - if (blk) { - qdev_prop_set_drive_err(dev, "drive", blk, &error_fatal); - } - - qdev_realize(dev, NULL, &error_fatal); - return dev; -} - -type_init(nand_register_types) - -#else - -/* Program a single page */ -static void glue(nand_blk_write_, NAND_PAGE_SIZE)(NANDFlashState *s) -{ - uint64_t off, page, sector, soff; - uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200]; - if (PAGE(s->addr) >= s->pages) - return; - - if (!s->blk) { - mem_and(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) + - s->offset, s->io, s->iolen); - } else if (s->mem_oob) { - sector = SECTOR(s->addr); - off = (s->addr & PAGE_MASK) + s->offset; - soff = SECTOR_OFFSET(s->addr); - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, - PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) { - printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); - return; - } - - mem_and(iobuf + (soff | off), s->io, MIN(s->iolen, NAND_PAGE_SIZE - off)); - if (off + s->iolen > NAND_PAGE_SIZE) { - page = PAGE(s->addr); - mem_and(s->storage + (page << OOB_SHIFT), s->io + NAND_PAGE_SIZE - off, - MIN(OOB_SIZE, off + s->iolen - NAND_PAGE_SIZE)); - } - - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, - PAGE_SECTORS << BDRV_SECTOR_BITS, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); - } - } else { - off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset; - sector = off >> 9; - soff = off & 0x1ff; - if (blk_pread(s->blk, sector << BDRV_SECTOR_BITS, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) { - printf("%s: read error in sector %" PRIu64 "\n", __func__, sector); - return; - } - - mem_and(iobuf + soff, s->io, s->iolen); - - if (blk_pwrite(s->blk, sector << BDRV_SECTOR_BITS, - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", __func__, sector); - } - } - s->offset = 0; -} - -/* Erase a single block */ -static void glue(nand_blk_erase_, NAND_PAGE_SIZE)(NANDFlashState *s) -{ - uint64_t i, page, addr; - uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, }; - addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1); - - if (PAGE(addr) >= s->pages) { - return; - } - - if (!s->blk) { - memset(s->storage + PAGE_START(addr), - 0xff, (NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift); - } else if (s->mem_oob) { - memset(s->storage + (PAGE(addr) << OOB_SHIFT), - 0xff, OOB_SIZE << s->erase_shift); - i = SECTOR(addr); - page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift))); - for (; i < page; i ++) - if (blk_pwrite(s->blk, i << BDRV_SECTOR_BITS, - BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", __func__, i); - } - } else { - addr = PAGE_START(addr); - page = addr >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, - BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: read error in sector %" PRIu64 "\n", __func__, page); - } - memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, - BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", __func__, page); - } - - memset(iobuf, 0xff, 0x200); - i = (addr & ~0x1ff) + 0x200; - for (addr += ((NAND_PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200; - i < addr; i += 0x200) { - if (blk_pwrite(s->blk, i, BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", - __func__, i >> 9); - } - } - - page = i >> 9; - if (blk_pread(s->blk, page << BDRV_SECTOR_BITS, - BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: read error in sector %" PRIu64 "\n", __func__, page); - } - memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1); - if (blk_pwrite(s->blk, page << BDRV_SECTOR_BITS, - BDRV_SECTOR_SIZE, iobuf, 0) < 0) { - printf("%s: write error in sector %" PRIu64 "\n", __func__, page); - } - } -} - -static bool glue(nand_blk_load_, NAND_PAGE_SIZE)(NANDFlashState *s, - uint64_t addr, unsigned offset) -{ - if (PAGE(addr) >= s->pages) { - return false; - } - - if (offset > NAND_PAGE_SIZE + OOB_SIZE) { - return false; - } - - if (s->blk) { - if (s->mem_oob) { - if (blk_pread(s->blk, SECTOR(addr) << BDRV_SECTOR_BITS, - PAGE_SECTORS << BDRV_SECTOR_BITS, s->io, 0) < 0) { - printf("%s: read error in sector %" PRIu64 "\n", - __func__, SECTOR(addr)); - } - memcpy(s->io + SECTOR_OFFSET(s->addr) + NAND_PAGE_SIZE, - s->storage + (PAGE(s->addr) << OOB_SHIFT), - OOB_SIZE); - s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset; - } else { - if (blk_pread(s->blk, PAGE_START(addr), - (PAGE_SECTORS + 2) << BDRV_SECTOR_BITS, s->io, 0) - < 0) { - printf("%s: read error in sector %" PRIu64 "\n", - __func__, PAGE_START(addr) >> 9); - } - s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset; - } - } else { - memcpy(s->io, s->storage + PAGE_START(s->addr) + - offset, NAND_PAGE_SIZE + OOB_SIZE - offset); - s->ioaddr = s->io; - } - - return true; -} - -static void glue(nand_init_, NAND_PAGE_SIZE)(NANDFlashState *s) -{ - s->oob_shift = PAGE_SHIFT - 5; - s->pages = s->size >> PAGE_SHIFT; - s->addr_shift = ADDR_SHIFT; - - s->blk_erase = glue(nand_blk_erase_, NAND_PAGE_SIZE); - s->blk_write = glue(nand_blk_write_, NAND_PAGE_SIZE); - s->blk_load = glue(nand_blk_load_, NAND_PAGE_SIZE); -} - -# undef NAND_PAGE_SIZE -# undef PAGE_SHIFT -# undef PAGE_SECTORS -# undef ADDR_SHIFT -#endif /* NAND_IO */ diff --git a/include/hw/block/flash.h b/include/hw/block/flash.h index 5fd67f5bb7..3671f0174d 100644 --- a/include/hw/block/flash.h +++ b/include/hw/block/flash.h @@ -44,24 +44,6 @@ PFlashCFI02 *pflash_cfi02_register(hwaddr base, uint16_t unlock_addr1, int be); -/* nand.c */ -DeviceState *nand_init(BlockBackend *blk, int manf_id, int chip_id); -void nand_setpins(DeviceState *dev, uint8_t cle, uint8_t ale, - uint8_t ce, uint8_t wp, uint8_t gnd); -void nand_getpins(DeviceState *dev, int *rb); -void nand_setio(DeviceState *dev, uint32_t value); -uint32_t nand_getio(DeviceState *dev); -uint32_t nand_getbuswidth(DeviceState *dev); - -#define NAND_MFR_TOSHIBA 0x98 -#define NAND_MFR_SAMSUNG 0xec -#define NAND_MFR_FUJITSU 0x04 -#define NAND_MFR_NATIONAL 0x8f -#define NAND_MFR_RENESAS 0x07 -#define NAND_MFR_STMICRO 0x20 -#define NAND_MFR_HYNIX 0xad -#define NAND_MFR_MICRON 0x2c - /* m25p80.c */ #define TYPE_M25P80 "m25p80-generic" From e2e360db7a55afd62e77577a965f6aa224132cef Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sat, 17 May 2025 23:11:52 +0300 Subject: [PATCH 1298/2760] io: Add helper for setting socket send buffer size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing reading and writing from qemu-nbd using a unix domain socket shows that the platform default send buffer size is too low, leading to poor performance and hight cpu usage. Add a helper for setting socket send buffer size to be used in NBD code. It can also be used in other contexts. We don't need a helper for receive buffer size since it is not used with unix domain sockets. This is documented for Linux, and not documented for macOS. Failing to set the socket buffer size is not a fatal error, but the caller may want to warn about the failure. Signed-off-by: Nir Soffer Message-ID: <20250517201154.88456-2-nirsof@gmail.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Eric Blake --- include/io/channel-socket.h | 13 +++++++++++++ io/channel-socket.c | 11 +++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/io/channel-socket.h b/include/io/channel-socket.h index ab15577d38..a88cf8b3a9 100644 --- a/include/io/channel-socket.h +++ b/include/io/channel-socket.h @@ -261,5 +261,18 @@ QIOChannelSocket * qio_channel_socket_accept(QIOChannelSocket *ioc, Error **errp); +/** + * qio_channel_socket_set_send_buffer: + * @ioc: the socket channel object + * @size: buffer size + * @errp: pointer to a NULL-initialized error object + * + * Set the underlying socket send buffer size. + * + * Retruns: 0 on success, or -1 on error. + */ +int qio_channel_socket_set_send_buffer(QIOChannelSocket *ioc, + size_t size, + Error **errp); #endif /* QIO_CHANNEL_SOCKET_H */ diff --git a/io/channel-socket.c b/io/channel-socket.c index 088b49ffdb..3b7ca924ff 100644 --- a/io/channel-socket.c +++ b/io/channel-socket.c @@ -78,6 +78,17 @@ qio_channel_socket_new(void) return sioc; } +int qio_channel_socket_set_send_buffer(QIOChannelSocket *ioc, + size_t size, + Error **errp) +{ + if (setsockopt(ioc->fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) < 0) { + error_setg_errno(errp, errno, "Unable to set socket send buffer size"); + return -1; + } + + return 0; +} static int qio_channel_socket_set_fd(QIOChannelSocket *sioc, From e9f4550b74a8a9774979a51caa4b1aaff9e1d055 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sat, 17 May 2025 23:11:53 +0300 Subject: [PATCH 1299/2760] nbd: Set unix socket send buffer on macOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS we need to increase unix socket buffers size on the client and server to get good performance. We set socket buffers on macOS after connecting or accepting a client connection. Testing shows that setting socket receive buffer size (SO_RCVBUF) has no effect on performance, so we set only the send buffer size (SO_SNDBUF). It seems to work like Linux but not documented. Testing shows that optimal buffer size is 512k to 4 MiB, depending on the test case. The difference is very small, so I chose 2 MiB. I tested reading from qemu-nbd and writing to qemu-nbd with qemu-img and computing a blkhash with nbdcopy and blksum. To focus on NBD communication and get less noisy results, I tested reading and writing to null-co driver. I added a read-pattern option to the null-co driver to return data full of 0xff: NULL="json:{'driver': 'raw', 'file': {'driver': 'null-co', 'size': '10g', 'read-pattern': 255}}" For testing buffer size I added an environment variable for setting the socket buffer size. Read from qemu-nbd via qemu-img convert. In this test buffer size of 2m is optimal (12.6 times faster). qemu-nbd -r -t -e 0 -f raw -k /tmp/nbd.sock "$NULL" & qemu-img convert -f raw -O raw -W -n "nbd+unix:///?socket=/tmp/nbd.sock" "$NULL" | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 13.361 | 2.653 | 5.702 | | 65536 | 2.283 | 0.204 | 1.318 | | 131072 | 1.673 | 0.062 | 1.008 | | 262144 | 1.592 | 0.053 | 0.952 | | 524288 | 1.496 | 0.049 | 0.887 | | 1048576 | 1.234 | 0.047 | 0.738 | | 2097152 | 1.060 | 0.080 | 0.602 | | 4194304 | 1.061 | 0.076 | 0.604 | Write to qemu-nbd with qemu-img convert. In this test buffer size of 2m is optimal (9.2 times faster). qemu-nbd -t -e 0 -f raw -k /tmp/nbd.sock "$NULL" & qemu-img convert -f raw -O raw -W -n "$NULL" "nbd+unix:///?socket=/tmp/nbd.sock" | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 8.063 | 2.522 | 4.184 | | 65536 | 1.472 | 0.430 | 0.867 | | 131072 | 1.071 | 0.297 | 0.654 | | 262144 | 1.012 | 0.239 | 0.587 | | 524288 | 0.970 | 0.201 | 0.514 | | 1048576 | 0.895 | 0.184 | 0.454 | | 2097152 | 0.877 | 0.174 | 0.440 | | 4194304 | 0.944 | 0.231 | 0.535 | Compute a blkhash with nbdcopy, using 4 NBD connections and 256k request size. In this test buffer size of 4m is optimal (5.1 times faster). qemu-nbd -r -t -e 0 -f raw -k /tmp/nbd.sock "$NULL" & nbdcopy --blkhash "nbd+unix:///?socket=/tmp/nbd.sock" null: | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 8.624 | 5.727 | 6.507 | | 65536 | 2.563 | 4.760 | 2.498 | | 131072 | 1.903 | 4.559 | 2.093 | | 262144 | 1.759 | 4.513 | 1.935 | | 524288 | 1.729 | 4.489 | 1.924 | | 1048576 | 1.696 | 4.479 | 1.884 | | 2097152 | 1.710 | 4.480 | 1.763 | | 4194304 | 1.687 | 4.479 | 1.712 | Compute a blkhash with blksum, using 1 NBD connection and 256k read size. In this test buffer size of 512k is optimal (10.3 times faster). qemu-nbd -r -t -e 0 -f raw -k /tmp/nbd.sock "$NULL" & blksum "nbd+unix:///?socket=/tmp/nbd.sock" | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 13.085 | 5.664 | 6.461 | | 65536 | 3.299 | 5.106 | 2.515 | | 131072 | 2.396 | 4.989 | 2.069 | | 262144 | 1.607 | 4.724 | 1.555 | | 524288 | 1.271 | 4.528 | 1.224 | | 1048576 | 1.294 | 4.565 | 1.333 | | 2097152 | 1.299 | 4.569 | 1.344 | | 4194304 | 1.291 | 4.559 | 1.327 | Signed-off-by: Nir Soffer Message-ID: <20250517201154.88456-3-nirsof@gmail.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Eric Blake --- nbd/client-connection.c | 3 +++ nbd/common.c | 25 +++++++++++++++++++++++++ nbd/nbd-internal.h | 5 +++++ nbd/server.c | 2 ++ 4 files changed, 35 insertions(+) diff --git a/nbd/client-connection.c b/nbd/client-connection.c index b11e266807..79ea97e4cc 100644 --- a/nbd/client-connection.c +++ b/nbd/client-connection.c @@ -31,6 +31,8 @@ #include "qapi/clone-visitor.h" #include "qemu/coroutine.h" +#include "nbd/nbd-internal.h" + struct NBDClientConnection { /* Initialization constants, never change */ SocketAddress *saddr; /* address to connect to */ @@ -140,6 +142,7 @@ static int nbd_connect(QIOChannelSocket *sioc, SocketAddress *addr, return ret; } + nbd_set_socket_send_buffer(sioc); qio_channel_set_delay(QIO_CHANNEL(sioc), false); if (!info) { diff --git a/nbd/common.c b/nbd/common.c index 589a748cfe..9436e9d1d1 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -18,6 +18,9 @@ #include "qemu/osdep.h" #include "trace.h" +#include "io/channel-socket.h" +#include "qapi/error.h" +#include "qemu/units.h" #include "nbd-internal.h" /* Discard length bytes from channel. Return -errno on failure and 0 on @@ -264,3 +267,25 @@ const char *nbd_mode_lookup(NBDMode mode) return ""; } } + +/* + * Testing shows that 2m send buffer is optimal. Changing the receive buffer + * size has no effect on performance. + */ +#if defined(__APPLE__) +#define UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE (2 * MiB) +#endif + +void nbd_set_socket_send_buffer(QIOChannelSocket *sioc) +{ +#ifdef UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE + if (sioc->localAddr.ss_family == AF_UNIX) { + size_t size = UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE; + Error *errp = NULL; + + if (qio_channel_socket_set_send_buffer(sioc, size, &errp) < 0) { + warn_report_err(errp); + } + } +#endif /* UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE */ +} diff --git a/nbd/nbd-internal.h b/nbd/nbd-internal.h index 715d92d6ef..6bafeef5dd 100644 --- a/nbd/nbd-internal.h +++ b/nbd/nbd-internal.h @@ -74,4 +74,9 @@ static inline int nbd_write(QIOChannel *ioc, const void *buffer, size_t size, int nbd_drop(QIOChannel *ioc, size_t size, Error **errp); +/* nbd_set_socket_send_buffer + * Set the socket send buffer size for optimal performance. + */ +void nbd_set_socket_send_buffer(QIOChannelSocket *sioc); + #endif diff --git a/nbd/server.c b/nbd/server.c index 2076fb2666..d242be9811 100644 --- a/nbd/server.c +++ b/nbd/server.c @@ -3291,6 +3291,8 @@ void nbd_client_new(QIOChannelSocket *sioc, client->close_fn = close_fn; client->owner = owner; + nbd_set_socket_send_buffer(sioc); + co = qemu_coroutine_create(nbd_co_client_start, client); qemu_coroutine_enter(co); } From 479ec8106185d0e88d65539df5e940c781a82c53 Mon Sep 17 00:00:00 2001 From: Nir Soffer Date: Sat, 17 May 2025 23:11:54 +0300 Subject: [PATCH 1300/2760] nbd: Set unix socket send buffer on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Like macOS we have similar issue on Linux. For TCP socket the send buffer size is 2626560 bytes (~2.5 MiB) and we get good performance. However for unix socket the default and maximum buffer size is 212992 bytes (208 KiB) and we see poor performance when using one NBD connection, up to 4 times slower than macOS on the same machine. Tracing shows that for every 2 MiB payload (qemu uses 2 MiB io size), we do 1 recvmsg call with TCP socket, and 10 recvmsg calls with unix socket. Fixing this issue requires changing the maximum send buffer size (the receive buffer size is ignored). This can be done using: $ cat /etc/sysctl.d/net-mem-max.conf net.core.wmem_max = 2097152 $ sudo sysctl -p /etc/sysctl.d/net-mem-max.conf With this we can set the socket buffer size to 2 MiB. With the defaults the value requested by qemu is clipped to the maximum size and has no effect. I tested on 2 machines: - Fedora 42 VM on MacBook Pro M2 Max - Dell PowerEdge R640 (Intel(R) Xeon(R) Gold 6230 CPU @ 2.10GHz) On the older Dell machine we see very little improvement, up to 1.03 higher throughput. On the M2 machine we see up to 2.67 times higher throughput. The following results are from the M2 machine. Reading from qemu-nbd with qemu-img convert. In this test buffer size of 4m is optimal (2.28 times faster). | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 4.292 | 0.243 | 1.604 | | 524288 | 2.167 | 0.058 | 1.288 | | 1048576 | 2.041 | 0.060 | 1.238 | | 2097152 | 1.884 | 0.060 | 1.191 | | 4194304 | 1.881 | 0.054 | 1.196 | Writing to qemu-nbd with qemu-img convert. In this test buffer size of 1m is optimal (2.67 times faster). | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 3.113 | 0.334 | 1.094 | | 524288 | 1.173 | 0.179 | 0.654 | | 1048576 | 1.164 | 0.164 | 0.670 | | 2097152 | 1.227 | 0.197 | 0.663 | | 4194304 | 1.227 | 0.198 | 0.666 | Computing a blkhash with nbdcopy. In this test buffer size of 512k is optimal (1.19 times faster). | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 2.140 | 4.483 | 2.681 | | 524288 | 1.794 | 4.467 | 2.572 | | 1048576 | 1.807 | 4.447 | 2.644 | | 2097152 | 1.822 | 4.461 | 2.698 | | 4194304 | 1.827 | 4.465 | 2.700 | Computing a blkhash with blksum. In this test buffer size of 4m is optimal (2.65 times faster). | buffer size | time | user | system | |-------------|---------|---------|---------| | default | 3.582 | 4.595 | 2.392 | | 524288 | 1.499 | 4.384 | 1.482 | | 1048576 | 1.377 | 4.381 | 1.345 | | 2097152 | 1.388 | 4.389 | 1.354 | | 4194304 | 1.352 | 4.395 | 1.302 | Signed-off-by: Nir Soffer Message-ID: <20250517201154.88456-4-nirsof@gmail.com> Reviewed-by: Daniel P. Berrangé Signed-off-by: Eric Blake --- nbd/common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nbd/common.c b/nbd/common.c index 9436e9d1d1..2a133a66c3 100644 --- a/nbd/common.c +++ b/nbd/common.c @@ -271,8 +271,9 @@ const char *nbd_mode_lookup(NBDMode mode) /* * Testing shows that 2m send buffer is optimal. Changing the receive buffer * size has no effect on performance. + * On Linux we need to increase net.core.wmem_max to make this effective. */ -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__linux__) #define UNIX_STREAM_SOCKET_SEND_BUFFER_SIZE (2 * MiB) #endif From d2b3e32bf7395c710ba44585520d837f6330fa70 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 23 May 2025 11:27:21 -0500 Subject: [PATCH 1301/2760] iotests: Use disk_usage in more places Commit be9bac07 added a utility disk_usage function, but there are a couple of other tests that could also use it. Signed-off-by: Eric Blake Message-ID: <20250523163041.2548675-6-eblake@redhat.com> Reviewed-by: Fiona Ebner Tested-by: Fiona Ebner --- tests/qemu-iotests/125 | 2 +- tests/qemu-iotests/308 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/125 b/tests/qemu-iotests/125 index 46279d6b38..708e7c5ba2 100755 --- a/tests/qemu-iotests/125 +++ b/tests/qemu-iotests/125 @@ -35,7 +35,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 get_image_size_on_host() { - echo $(($(stat -c '%b * %B' "$TEST_IMG_FILE"))) + disk_usage "$TEST_IMG_FILE" } # get standard environment and filters diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index ea81dc496a..437a9014da 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -290,7 +290,7 @@ echo '--- Try growing non-growable export ---' # Get the current size so we can write beyond the EOF orig_len=$(get_proto_len "$EXT_MP" "$TEST_IMG") -orig_disk_usage=$(stat -c '%b' "$TEST_IMG") +orig_disk_usage=$(disk_usage "$TEST_IMG") # Should fail (exports are non-growable by default) # (Note that qemu-io can never write beyond the EOF, so we have to use @@ -312,7 +312,7 @@ else echo 'OK: Post-truncate image size is as expected' fi -new_disk_usage=$(stat -c '%b' "$TEST_IMG") +new_disk_usage=$(disk_usage "$TEST_IMG") if [ "$new_disk_usage" -gt "$orig_disk_usage" ]; then echo 'OK: Disk usage grew with fallocate' else From ed1c336119c084159575ae9d4fd9171bd500f7e4 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 23 May 2025 11:27:22 -0500 Subject: [PATCH 1302/2760] iotests: Improve mirror-sparse on ext4 and xfs Fiona reported that an ext4 filesystem on top of LVM can sometimes report over-allocation to du (based on the heuristics the filesystem is making while observing the contents being mirrored); even though the contents and actual size matched, about 50% of the time the size reported by disk_usage was too large by 4k, failing the test. In auditing other iotests, this is a common problem we've had to deal with. Meanwhile, Markus reported that an xfs filesystem reports disk usage at a default granularity of 1M (so the sparse file occupies 3M, since it has just over 2M data). Reported-by: Fiona Ebner Reported-by: Markus Armbruster Fixes: c0ddcb2c ("tests: Add iotest mirror-sparse for recent patches") Signed-off-by: Eric Blake Reviewed-by: Fiona Ebner Tested-by: Fiona Ebner Message-ID: <20250523163041.2548675-7-eblake@redhat.com> [eblake: Also fix xfs issue] Signed-off-by: Eric Blake --- tests/qemu-iotests/tests/mirror-sparse | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/qemu-iotests/tests/mirror-sparse b/tests/qemu-iotests/tests/mirror-sparse index 8c52a4e244..11418c0871 100755 --- a/tests/qemu-iotests/tests/mirror-sparse +++ b/tests/qemu-iotests/tests/mirror-sparse @@ -96,13 +96,15 @@ _send_qemu_cmd $h1 '{"execute": "blockdev-del", "arguments": {"node-name": "dst"}}' 'return' \ | _filter_block_job_offset | _filter_block_job_len $QEMU_IMG compare -U -f $IMGFMT -F raw $TEST_IMG.base $TEST_IMG +# Some filesystems can fudge allocations for various reasons; rather +# than expecting precise 2M and 20M images, it is better to allow for slop. result=$(disk_usage $TEST_IMG) -if test $result -lt $((3*1024*1024)); then +if test $result -lt $((4*1024*1024)); then actual=sparse -elif test $result = $((20*1024*1024)); then +elif test $result -gt $((19*1024*1024)); then actual=full else - actual=unknown + actual="unexpected size ($result)" fi echo "Destination is $actual; expected $expected" } From c49dda7254d43d9e1d4da59c55f02055ba7c4c1b Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Fri, 23 May 2025 11:27:23 -0500 Subject: [PATCH 1303/2760] iotests: Filter out ZFS in several tests Fiona reported that ZFS makes sparse file testing awkward, since: - it has asynchronous allocation (not even 'fsync $file' makes du see the desired size; it takes the slower 'fsync -f $file' which is not appropriate for the tests) - for tests of fully allocated files, ZFS with compression enabled still reports smaller disk usage Add a new _require_disk_usage that quickly probes whether an attempt to create a sparse 5M file shows as less than 1M usage, while the same file with -o preallocation=full shows as more than 4M usage without sync, which should filter out ZFS behavior. Then use it in various affected tests. This does not add the new filter on all tests that Fiona is seeing ZFS failures on, but only those where I could quickly spot that there is at least one place where the test depends on the output of 'du -b' or 'stat -c %b'. Reported-by: Fiona Ebner Signed-off-by: Eric Blake Message-ID: <20250523163041.2548675-8-eblake@redhat.com> Reviewed-by: Fiona Ebner Tested-by: Fiona Ebner --- tests/qemu-iotests/106 | 1 + tests/qemu-iotests/175 | 1 + tests/qemu-iotests/221 | 1 + tests/qemu-iotests/253 | 1 + tests/qemu-iotests/308 | 1 + tests/qemu-iotests/common.rc | 30 +++++++++++++++++++++ tests/qemu-iotests/tests/mirror-sparse | 1 + tests/qemu-iotests/tests/write-zeroes-unmap | 1 + 8 files changed, 37 insertions(+) diff --git a/tests/qemu-iotests/106 b/tests/qemu-iotests/106 index ae0fc46691..55548439aa 100755 --- a/tests/qemu-iotests/106 +++ b/tests/qemu-iotests/106 @@ -40,6 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15 _supported_fmt raw _supported_proto file fuse _supported_os Linux +_require_disk_usage # in kB CREATION_SIZE=128 diff --git a/tests/qemu-iotests/175 b/tests/qemu-iotests/175 index f74f053b71..bbbf550a5a 100755 --- a/tests/qemu-iotests/175 +++ b/tests/qemu-iotests/175 @@ -77,6 +77,7 @@ _supported_os Linux _default_cache_mode none _supported_cache_modes none directsync +_require_disk_usage size=$((1 * 1024 * 1024)) diff --git a/tests/qemu-iotests/221 b/tests/qemu-iotests/221 index c463fd4b11..eba00b80ad 100755 --- a/tests/qemu-iotests/221 +++ b/tests/qemu-iotests/221 @@ -41,6 +41,7 @@ _supported_os Linux _default_cache_mode writeback _supported_cache_modes writeback writethrough unsafe +_require_disk_usage echo echo "=== Check mapping of unaligned raw image ===" diff --git a/tests/qemu-iotests/253 b/tests/qemu-iotests/253 index 35039d20a8..6da85e6a11 100755 --- a/tests/qemu-iotests/253 +++ b/tests/qemu-iotests/253 @@ -41,6 +41,7 @@ _supported_os Linux _default_cache_mode none _supported_cache_modes none directsync +_require_disk_usage echo echo "=== Check mapping of unaligned raw image ===" diff --git a/tests/qemu-iotests/308 b/tests/qemu-iotests/308 index 437a9014da..6eced3aefb 100755 --- a/tests/qemu-iotests/308 +++ b/tests/qemu-iotests/308 @@ -51,6 +51,7 @@ _unsupported_fmt vpc _supported_proto file # We create the FUSE export manually _supported_os Linux # We need /dev/urandom +_require_disk_usage # $1: Export ID # $2: Options (beyond the node-name and ID) diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc index 237f746af8..e977cb4eb6 100644 --- a/tests/qemu-iotests/common.rc +++ b/tests/qemu-iotests/common.rc @@ -996,6 +996,36 @@ _require_large_file() rm "$FILENAME" } +# Check whether disk_usage can be reliably used. +_require_disk_usage() +{ + local unusable=false + # ZFS triggers known failures on this front; it does not immediately + # allocate files, and then aggressively compresses writes even when full + # allocation was requested. + if [ -z "$TEST_IMG_FILE" ]; then + FILENAME="$TEST_IMG" + else + FILENAME="$TEST_IMG_FILE" + fi + if [ -e "FILENAME" ]; then + echo "unwilling to overwrite existing file" + exit 1 + fi + $QEMU_IMG create -f raw "$FILENAME" 5M > /dev/null + if [ $(disk_usage "$FILENAME") -gt $((1024*1024)) ]; then + unusable=true + fi + $QEMU_IMG create -f raw -o preallocation=full "$FILENAME" 5M > /dev/null + if [ $(disk_usage "$FILENAME") -lt $((4*1024*1024)) ]; then + unusable=true + fi + rm -f "$FILENAME" + if $unusable; then + _notrun "file system on $TEST_DIR does not handle sparse files nicely" + fi +} + # Check that a set of devices is available in the QEMU binary # _require_devices() diff --git a/tests/qemu-iotests/tests/mirror-sparse b/tests/qemu-iotests/tests/mirror-sparse index 11418c0871..cfcaa600ab 100755 --- a/tests/qemu-iotests/tests/mirror-sparse +++ b/tests/qemu-iotests/tests/mirror-sparse @@ -40,6 +40,7 @@ cd .. _supported_fmt qcow2 raw # Format of the source. dst is always raw file _supported_proto file _supported_os Linux +_require_disk_usage echo echo "=== Initial image setup ===" diff --git a/tests/qemu-iotests/tests/write-zeroes-unmap b/tests/qemu-iotests/tests/write-zeroes-unmap index 7cfeeaf839..f90fb8e8d2 100755 --- a/tests/qemu-iotests/tests/write-zeroes-unmap +++ b/tests/qemu-iotests/tests/write-zeroes-unmap @@ -32,6 +32,7 @@ cd .. _supported_fmt raw _supported_proto file _supported_os Linux +_require_disk_usage create_test_image() { _make_test_img -f $IMGFMT 1m From e1c9c801023d556d317256a414562634b1fe8b13 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 May 2025 16:51:12 +0200 Subject: [PATCH 1304/2760] tests/functional/test_sparc64_tuxrun: Explicitly set the 'sun4u' machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use self.set_machine() to set the machine instead of relying on the default machine of the binary. This way the test can be skipped in case the machine has not been compiled into the QEMU binary. Reviewed-by: Alex Bennée Tested-by: Alex Bennée Signed-off-by: Thomas Huth Message-ID: <20250521145112.142222-1-thuth@redhat.com> --- tests/functional/test_sparc64_tuxrun.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/test_sparc64_tuxrun.py b/tests/functional/test_sparc64_tuxrun.py index 3be08d6102..0d7b43dd74 100755 --- a/tests/functional/test_sparc64_tuxrun.py +++ b/tests/functional/test_sparc64_tuxrun.py @@ -24,6 +24,7 @@ class TuxRunSparc64Test(TuxRunBaselineTest): '479c3dc104c82b68be55e2c0c5c38cd473d0b37ad4badccde4775bb88ce34611') def test_sparc64(self): + self.set_machine('sun4u') self.root='sda' self.wait_for_shutdown=False self.common_tuxrun(kernel_asset=self.ASSET_SPARC64_KERNEL, From 644ded5c814055feb4d3a546628ccd28102f7acb Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 22 May 2025 10:02:08 +0200 Subject: [PATCH 1305/2760] tests/functional/test_mips_malta: Re-enable the check for the PCI host bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The problem with the PCI bridge has been fixed in commit e5894fd6f411c1 ("hw/pci-host/gt64120: Fix endianness handling"), so we can enable the corresponding test again. Reviewed-by: Alex Bennée Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250522080208.205489-1-thuth@redhat.com> --- tests/functional/test_mips_malta.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/functional/test_mips_malta.py b/tests/functional/test_mips_malta.py index 89b9556f30..30279f0ff2 100755 --- a/tests/functional/test_mips_malta.py +++ b/tests/functional/test_mips_malta.py @@ -80,10 +80,8 @@ def mips_check_wheezy(test, kernel_path, image_path, kernel_command_line, exec_command_and_wait_for_pattern(test, 'cat /proc/devices', 'usb') exec_command_and_wait_for_pattern(test, 'cat /proc/ioports', ' : piix4_smbus') - # lspci for the host bridge does not work on big endian targets: - # https://gitlab.com/qemu-project/qemu/-/issues/2826 - # exec_command_and_wait_for_pattern(test, 'lspci -d 11ab:4620', - # 'GT-64120') + exec_command_and_wait_for_pattern(test, 'lspci -d 11ab:4620', + 'GT-64120') exec_command_and_wait_for_pattern(test, 'cat /sys/bus/i2c/devices/i2c-0/name', 'SMBus PIIX4 adapter') From 9f7cf938efc6016f7ce323b064c2f3f46360c751 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 21 May 2025 16:37:32 +0200 Subject: [PATCH 1306/2760] tests/functional/test_mem_addr_space: Use set_machine() to select the machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using self.set_machine() the tests get properly skipped in case the machine has not been compiled into the QEMU binary, e.g. when "configure" has been run with "--without-default-devices". Reviewed-by: Philippe Mathieu-Daudé Reviewed-by: Richard Henderson Signed-off-by: Thomas Huth Message-ID: <20250521143732.140711-1-thuth@redhat.com> --- tests/functional/test_mem_addr_space.py | 63 +++++++++++++------------ 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/tests/functional/test_mem_addr_space.py b/tests/functional/test_mem_addr_space.py index 2d9d31efb5..61b4a190b4 100755 --- a/tests/functional/test_mem_addr_space.py +++ b/tests/functional/test_mem_addr_space.py @@ -58,8 +58,8 @@ class MemAddrCheck(QemuSystemTest): should start fine. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=59.6G', + self.set_machine('q35') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=59.6G', '-cpu', 'pentium,pse36=on', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -76,8 +76,8 @@ class MemAddrCheck(QemuSystemTest): with pse36 above. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=59.6G', + self.set_machine('q35') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=59.6G', '-cpu', 'pentium,pae=on', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -93,8 +93,8 @@ class MemAddrCheck(QemuSystemTest): same options as the failing case above with pse36 cpu feature. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + self.set_machine('q35') + self.vm.add_args('-m', '512,slots=1,maxmem=59.5G', '-cpu', 'pentium,pse36=on', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -111,8 +111,8 @@ class MemAddrCheck(QemuSystemTest): with the same options as the case above. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + self.set_machine('q35') + self.vm.add_args('-m', '512,slots=1,maxmem=59.5G', '-cpu', 'pentium,pae=on', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -128,8 +128,8 @@ class MemAddrCheck(QemuSystemTest): with pse36 ON. """ self.ensure_64bit_binary() - self.vm.add_args('-machine', 'q35', '-m', - '512,slots=1,maxmem=59.5G', + self.set_machine('q35') + self.vm.add_args('-m', '512,slots=1,maxmem=59.5G', '-cpu', 'pentium2', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -148,8 +148,8 @@ class MemAddrCheck(QemuSystemTest): above 4 GiB due to the PCI hole and simplicity. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'q35', '-m', - '512,slots=1,maxmem=4G', + self.set_machine('q35') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=4G', '-cpu', 'pentium', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -176,8 +176,8 @@ class MemAddrCheck(QemuSystemTest): make QEMU fail with the error message. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m', - '512,slots=1,maxmem=988G', + self.set_machine('pc-q35-7.0') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=988G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -197,8 +197,8 @@ class MemAddrCheck(QemuSystemTest): than 988 GiB). """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=976G', + self.set_machine('pc-q35-7.1') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=976G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -214,8 +214,8 @@ class MemAddrCheck(QemuSystemTest): successfully start when maxmem is < 988G. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.0', '-m', - '512,slots=1,maxmem=987.5G', + self.set_machine('pc-q35-7.0') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=987.5G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -231,8 +231,8 @@ class MemAddrCheck(QemuSystemTest): successfully start when maxmem is < 976G. """ self.ensure_64bit_binary() - self.vm.add_args('-S', '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=975.5G', + self.set_machine('pc-q35-7.1') + self.vm.add_args('-S', '-m', '512,slots=1,maxmem=975.5G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -249,9 +249,9 @@ class MemAddrCheck(QemuSystemTest): "above_4G" memory starts at 4G. """ self.ensure_64bit_binary() + self.set_machine('pc-q35-7.1') self.vm.add_args('-S', '-cpu', 'Skylake-Server', - '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=976G', + '-m', '512,slots=1,maxmem=976G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -274,9 +274,9 @@ class MemAddrCheck(QemuSystemTest): fail to start. """ self.ensure_64bit_binary() + self.set_machine('pc-q35-7.1') self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41', - '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=992G', + '-m', '512,slots=1,maxmem=992G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -293,9 +293,9 @@ class MemAddrCheck(QemuSystemTest): QEMU should start fine. """ self.ensure_64bit_binary() + self.set_machine('pc-q35-7.1') self.vm.add_args('-S', '-cpu', 'EPYC-v4,phys-bits=41', - '-machine', 'pc-q35-7.1', '-m', - '512,slots=1,maxmem=990G', + '-m', '512,slots=1,maxmem=990G', '-display', 'none', '-object', 'memory-backend-ram,id=mem1,size=1G', '-device', 'pc-dimm,id=vm0,memdev=mem1') @@ -314,12 +314,12 @@ class MemAddrCheck(QemuSystemTest): alignment constraints with 40 bits (1 TiB) of processor physical bits. """ self.ensure_64bit_binary() + self.set_machine('q35') self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40', - '-machine', 'q35,cxl=on', '-m', - '512,slots=1,maxmem=987G', + '-m', '512,slots=1,maxmem=987G', '-display', 'none', '-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1', - '-M', 'cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=1G') + '-M', 'cxl=on,cxl-fmw.0.targets.0=cxl.1,cxl-fmw.0.size=1G') self.vm.set_qmp_monitor(enabled=False) self.vm.launch() self.vm.wait() @@ -333,9 +333,10 @@ class MemAddrCheck(QemuSystemTest): with cxl enabled. """ self.ensure_64bit_binary() + self.set_machine('q35') self.vm.add_args('-S', '-cpu', 'Skylake-Server,phys-bits=40', - '-machine', 'q35,cxl=on', '-m', - '512,slots=1,maxmem=987G', + '-machine', 'cxl=on', + '-m', '512,slots=1,maxmem=987G', '-display', 'none', '-device', 'pxb-cxl,bus_nr=12,bus=pcie.0,id=cxl.1') self.vm.set_qmp_monitor(enabled=False) From 141ec228deb7f94fb713c4d7ce0276e088e59f15 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 May 2025 15:20:16 +0200 Subject: [PATCH 1307/2760] hw/microblaze: Add endianness property to the petalogix_s3adsp1800 machine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the microblaze target can now handle both endianness, big and little, we should provide a config knob for the user to select the desired endianness. Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250515132019.569365-2-thuth@redhat.com> --- hw/microblaze/petalogix_s3adsp1800_mmu.c | 42 +++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/hw/microblaze/petalogix_s3adsp1800_mmu.c b/hw/microblaze/petalogix_s3adsp1800_mmu.c index 032f6f70ea..e8d0ddfdf8 100644 --- a/hw/microblaze/petalogix_s3adsp1800_mmu.c +++ b/hw/microblaze/petalogix_s3adsp1800_mmu.c @@ -58,9 +58,20 @@ #define TYPE_PETALOGIX_S3ADSP1800_MACHINE \ MACHINE_TYPE_NAME("petalogix-s3adsp1800") +struct S3Adsp1800MachineState { + MachineState parent_class; + + EndianMode endianness; +}; + +OBJECT_DECLARE_TYPE(S3Adsp1800MachineState, MachineClass, + PETALOGIX_S3ADSP1800_MACHINE) + + static void petalogix_s3adsp1800_init(MachineState *machine) { + S3Adsp1800MachineState *psms = PETALOGIX_S3ADSP1800_MACHINE(machine); ram_addr_t ram_size = machine->ram_size; DeviceState *dev; MicroBlazeCPU *cpu; @@ -71,13 +82,12 @@ petalogix_s3adsp1800_init(MachineState *machine) MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32]; MemoryRegion *sysmem = get_system_memory(); - EndianMode endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG - : ENDIAN_MODE_LITTLE; + EndianMode endianness = psms->endianness; cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); object_property_set_str(OBJECT(cpu), "version", "7.10.d", &error_abort); object_property_set_bool(OBJECT(cpu), "little-endian", - !TARGET_BIG_ENDIAN, &error_abort); + endianness == ENDIAN_MODE_LITTLE, &error_abort); qdev_realize(DEVICE(cpu), NULL, &error_abort); /* Attach emulated BRAM through the LMB. */ @@ -135,20 +145,41 @@ petalogix_s3adsp1800_init(MachineState *machine) create_unimplemented_device("xps_gpio", GPIO_BASEADDR, 0x10000); - microblaze_load_kernel(cpu, !TARGET_BIG_ENDIAN, ddr_base, ram_size, - machine->initrd_filename, + microblaze_load_kernel(cpu, endianness == ENDIAN_MODE_LITTLE, ddr_base, + ram_size, machine->initrd_filename, BINARY_DEVICE_TREE_FILE, NULL); } +static int machine_get_endianness(Object *obj, Error **errp G_GNUC_UNUSED) +{ + S3Adsp1800MachineState *ms = PETALOGIX_S3ADSP1800_MACHINE(obj); + return ms->endianness; +} + +static void machine_set_endianness(Object *obj, int endianness, Error **errp) +{ + S3Adsp1800MachineState *ms = PETALOGIX_S3ADSP1800_MACHINE(obj); + ms->endianness = endianness; +} + static void petalogix_s3adsp1800_machine_class_init(ObjectClass *oc, const void *data) { MachineClass *mc = MACHINE_CLASS(oc); + ObjectProperty *prop; mc->desc = "PetaLogix linux refdesign for xilinx Spartan 3ADSP1800"; mc->init = petalogix_s3adsp1800_init; mc->is_default = true; + + prop = object_class_property_add_enum(oc, "endianness", "EndianMode", + &EndianMode_lookup, + machine_get_endianness, + machine_set_endianness); + object_property_set_default_str(prop, TARGET_BIG_ENDIAN ? "big" : "little"); + object_class_property_set_description(oc, "endianness", + "Defines whether the machine runs in big or little endian mode"); } static const TypeInfo petalogix_s3adsp1800_machine_types[] = { @@ -156,6 +187,7 @@ static const TypeInfo petalogix_s3adsp1800_machine_types[] = { .name = TYPE_PETALOGIX_S3ADSP1800_MACHINE, .parent = TYPE_MACHINE, .class_init = petalogix_s3adsp1800_machine_class_init, + .instance_size = sizeof(S3Adsp1800MachineState), }, }; From 6c5477558490cf76dc6d521fe906a2bfbc96ee27 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 May 2025 15:20:17 +0200 Subject: [PATCH 1308/2760] tests/functional: Test both microblaze s3adsp1800 endianness variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that the endianness of the petalogix-s3adsp1800 can be configured, we should test that the cross-endianness also works as expected, thus test the big endian variant on the little endian target and vice versa. (based on an original idea from Philippe Mathieu-Daudé) Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250515132019.569365-3-thuth@redhat.com> --- tests/functional/test_microblaze_s3adsp1800.py | 18 +++++++++++++----- .../functional/test_microblazeel_s3adsp1800.py | 6 +++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/functional/test_microblaze_s3adsp1800.py b/tests/functional/test_microblaze_s3adsp1800.py index c93fa14232..f093b162c0 100755 --- a/tests/functional/test_microblaze_s3adsp1800.py +++ b/tests/functional/test_microblaze_s3adsp1800.py @@ -25,12 +25,14 @@ class MicroblazeMachine(QemuSystemTest): ('http://www.qemu-advent-calendar.org/2023/download/day13.tar.gz'), 'b9b3d43c5dd79db88ada495cc6e0d1f591153fe41355e925d791fbf44de50c22') - def do_ballerina_be_test(self, machine): - self.set_machine(machine) + def do_ballerina_be_test(self, force_endianness=False): + self.set_machine('petalogix-s3adsp1800') self.archive_extract(self.ASSET_IMAGE_BE) self.vm.set_console() self.vm.add_args('-kernel', self.scratch_file('day17', 'ballerina.bin')) + if force_endianness: + self.vm.add_args('-M', 'endianness=big') self.vm.launch() wait_for_console_pattern(self, 'This architecture does not have ' 'kernel memory protection') @@ -39,12 +41,14 @@ class MicroblazeMachine(QemuSystemTest): # message, that's why we don't test for a later string here. This # needs some investigation by a microblaze wizard one day... - def do_xmaton_le_test(self, machine): + def do_xmaton_le_test(self, force_endianness=False): self.require_netdev('user') - self.set_machine(machine) + self.set_machine('petalogix-s3adsp1800') self.archive_extract(self.ASSET_IMAGE_LE) self.vm.set_console() self.vm.add_args('-kernel', self.scratch_file('day13', 'xmaton.bin')) + if force_endianness: + self.vm.add_args('-M', 'endianness=little') tftproot = self.scratch_file('day13') self.vm.add_args('-nic', f'user,tftp={tftproot}') self.vm.launch() @@ -59,9 +63,13 @@ class MicroblazeMachine(QemuSystemTest): class MicroblazeBigEndianMachine(MicroblazeMachine): ASSET_IMAGE_BE = MicroblazeMachine.ASSET_IMAGE_BE + ASSET_IMAGE_LE = MicroblazeMachine.ASSET_IMAGE_LE def test_microblaze_s3adsp1800_legacy_be(self): - self.do_ballerina_be_test('petalogix-s3adsp1800') + self.do_ballerina_be_test() + + def test_microblaze_s3adsp1800_legacy_le(self): + self.do_xmaton_le_test(force_endianness=True) if __name__ == '__main__': diff --git a/tests/functional/test_microblazeel_s3adsp1800.py b/tests/functional/test_microblazeel_s3adsp1800.py index ab59941d57..915902d48b 100755 --- a/tests/functional/test_microblazeel_s3adsp1800.py +++ b/tests/functional/test_microblazeel_s3adsp1800.py @@ -13,9 +13,13 @@ from test_microblaze_s3adsp1800 import MicroblazeMachine class MicroblazeLittleEndianMachine(MicroblazeMachine): ASSET_IMAGE_LE = MicroblazeMachine.ASSET_IMAGE_LE + ASSET_IMAGE_BE = MicroblazeMachine.ASSET_IMAGE_BE def test_microblaze_s3adsp1800_legacy_le(self): - self.do_xmaton_le_test('petalogix-s3adsp1800') + self.do_xmaton_le_test() + + def test_microblaze_s3adsp1800_legacy_be(self): + self.do_ballerina_be_test(force_endianness=True) if __name__ == '__main__': From 0e259fa5a13a3d0ff65aa4199b1e03832e51e1b2 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 May 2025 15:20:18 +0200 Subject: [PATCH 1309/2760] hw/microblaze: Remove the big-endian variants of ml605 and xlnx-zynqmp-pmu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both machines were added with little-endian in mind only (the "endianness" CPU property was hard-wired to "true", see commits 133d23b3ad1 and a88bbb006a52), so the variants that showed up on the big endian target likely never worked. We deprecated these non-working machine variants two releases ago, and so far nobody complained, so it should be fine now to disable them. Hard-wire the machines to little endian now. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250515132019.569365-4-thuth@redhat.com> --- docs/about/deprecated.rst | 6 ------ docs/about/removed-features.rst | 9 +++++++++ hw/microblaze/petalogix_ml605_mmu.c | 15 ++++----------- hw/microblaze/xlnx-zynqmp-pmu.c | 7 +------ 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 4715d1ede5..863779ae78 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -315,12 +315,6 @@ deprecated; use the new name ``dtb-randomness`` instead. The new name better reflects the way this property affects all random data within the device tree blob, not just the ``kaslr-seed`` node. -Big-Endian variants of MicroBlaze ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` machines (since 9.2) -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Both ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` were added for little endian -CPUs. Big endian support is not tested. - Mips ``mipssim`` machine (since 10.0) ''''''''''''''''''''''''''''''''''''' diff --git a/docs/about/removed-features.rst b/docs/about/removed-features.rst index 4819cb4665..d7c2113fc3 100644 --- a/docs/about/removed-features.rst +++ b/docs/about/removed-features.rst @@ -1091,6 +1091,15 @@ This machine was removed because PPC 405 CPU have no known users, firmware images are not available, OpenWRT dropped support in 2019, U-Boot in 2017, and Linux in 2024. +Big-Endian variants of ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` machines (removed in 10.1) +''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' + +Both the MicroBlaze ``petalogix-ml605`` and ``xlnx-zynqmp-pmu`` machines +were added for little endian CPUs. Big endian support was never tested +and likely never worked. Starting with QEMU v10.1, the machines are now +only available as little-endian machines. + + linux-user mode CPUs -------------------- diff --git a/hw/microblaze/petalogix_ml605_mmu.c b/hw/microblaze/petalogix_ml605_mmu.c index bea6b689fd..6e923c49cf 100644 --- a/hw/microblaze/petalogix_ml605_mmu.c +++ b/hw/microblaze/petalogix_ml605_mmu.c @@ -80,8 +80,6 @@ petalogix_ml605_init(MachineState *machine) MemoryRegion *phys_lmb_bram = g_new(MemoryRegion, 1); MemoryRegion *phys_ram = g_new(MemoryRegion, 1); qemu_irq irq[32]; - EndianMode endianness = TARGET_BIG_ENDIAN ? ENDIAN_MODE_BIG - : ENDIAN_MODE_LITTLE; /* init CPUs */ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU)); @@ -113,7 +111,7 @@ petalogix_ml605_init(MachineState *machine) dev = qdev_new("xlnx.xps-intc"); - qdev_prop_set_enum(dev, "endianness", endianness); + qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE); qdev_prop_set_uint32(dev, "kind-of-intr", 1 << TIMER_IRQ); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR); @@ -129,7 +127,7 @@ petalogix_ml605_init(MachineState *machine) /* 2 timers at irq 2 @ 100 Mhz. */ dev = qdev_new("xlnx.xps-timer"); - qdev_prop_set_enum(dev, "endianness", endianness); + qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE); qdev_prop_set_uint32(dev, "one-timer-only", 0); qdev_prop_set_uint32(dev, "clock-frequency", 100 * 1000000); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); @@ -177,7 +175,7 @@ petalogix_ml605_init(MachineState *machine) SSIBus *spi; dev = qdev_new("xlnx.xps-spi"); - qdev_prop_set_enum(dev, "endianness", endianness); + qdev_prop_set_enum(dev, "endianness", ENDIAN_MODE_LITTLE); qdev_prop_set_uint8(dev, "num-ss-bits", NUM_SPI_FLASHES); busdev = SYS_BUS_DEVICE(dev); sysbus_realize_and_unref(busdev, &error_fatal); @@ -218,12 +216,7 @@ petalogix_ml605_init(MachineState *machine) static void petalogix_ml605_machine_init(MachineClass *mc) { - if (TARGET_BIG_ENDIAN) { - mc->desc = "PetaLogix linux refdesign for xilinx ml605 (big endian)"; - mc->deprecation_reason = "big endian support is not tested"; - } else { - mc->desc = "PetaLogix linux refdesign for xilinx ml605 (little endian)"; - } + mc->desc = "PetaLogix linux refdesign for xilinx ml605 (little endian)"; mc->init = petalogix_ml605_init; } diff --git a/hw/microblaze/xlnx-zynqmp-pmu.c b/hw/microblaze/xlnx-zynqmp-pmu.c index ed40b5f2e0..e909802bb7 100644 --- a/hw/microblaze/xlnx-zynqmp-pmu.c +++ b/hw/microblaze/xlnx-zynqmp-pmu.c @@ -181,12 +181,7 @@ static void xlnx_zynqmp_pmu_init(MachineState *machine) static void xlnx_zynqmp_pmu_machine_init(MachineClass *mc) { - if (TARGET_BIG_ENDIAN) { - mc->desc = "Xilinx ZynqMP PMU machine (big endian)"; - mc->deprecation_reason = "big endian support is not tested"; - } else { - mc->desc = "Xilinx ZynqMP PMU machine (little endian)"; - } + mc->desc = "Xilinx ZynqMP PMU machine (little endian)"; mc->init = xlnx_zynqmp_pmu_init; } From 225e9e230efd5ae509b12fd191a8de6287f934ef Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Thu, 15 May 2025 15:20:19 +0200 Subject: [PATCH 1310/2760] docs: Deprecate the qemu-system-microblazeel binary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The (former big-endian only) binary qemu-system-microblaze can handle both endiannesses nowadays, so we don't need the separate qemu-system-microblazeel binary for little endian anymore. Let's deprecate it to avoid unnecessary compilation and test time in the future. Reviewed-by: Richard Henderson Reviewed-by: Philippe Mathieu-Daudé Signed-off-by: Thomas Huth Message-ID: <20250515132019.569365-5-thuth@redhat.com> --- docs/about/deprecated.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/about/deprecated.rst b/docs/about/deprecated.rst index 863779ae78..42037131de 100644 --- a/docs/about/deprecated.rst +++ b/docs/about/deprecated.rst @@ -345,6 +345,19 @@ machine must ensure that they're setting the ``spike`` machine in the command line (``-M spike``). +System emulator binaries +------------------------ + +``qemu-system-microblazeel`` (since 10.1) +''''''''''''''''''''''''''''''''''''''''' + +The ``qemu-system-microblaze`` binary can emulate little-endian machines +now, too, so the separate binary ``qemu-system-microblazeel`` (with the +``el`` suffix) for little-endian targets is not required anymore. The +``petalogix-s3adsp1800`` machine can now be switched to little endian by +setting its ``endianness`` property to ``little``. + + Backend options --------------- From 07a2adeebbe522b6e1c5706db2bdba0b05d0b2ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:30 +0200 Subject: [PATCH 1311/2760] hw/i386/pc: Remove deprecated pc-q35-2.4 and pc-i440fx-2.4 machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These machines has been supported for a period of more than 6 years. According to our versioned machine support policy (see commit ce80c4fa6ff "docs: document special exception for machine type deprecation & removal") they can now be removed. Remove the qtest in test-x86-cpuid-compat.c file. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-2-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/i386/pc_piix.c | 13 ------------- hw/i386/pc_q35.c | 13 ------------- tests/qtest/test-x86-cpuid-compat.c | 14 -------------- 3 files changed, 40 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0dce512f18..04213b45b4 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -791,19 +791,6 @@ static void pc_i440fx_machine_2_5_options(MachineClass *m) DEFINE_I440FX_MACHINE(2, 5); -static void pc_i440fx_machine_2_4_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - - pc_i440fx_machine_2_5_options(m); - m->hw_version = "2.4.0"; - pcmc->broken_reserved_end = true; - compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len); - compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len); -} - -DEFINE_I440FX_MACHINE(2, 4); - #ifdef CONFIG_ISAPC static void isapc_machine_options(MachineClass *m) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index c538b3d05b..47e1260241 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -685,16 +685,3 @@ static void pc_q35_machine_2_5_options(MachineClass *m) } DEFINE_Q35_MACHINE(2, 5); - -static void pc_q35_machine_2_4_options(MachineClass *m) -{ - PCMachineClass *pcmc = PC_MACHINE_CLASS(m); - - pc_q35_machine_2_5_options(m); - m->hw_version = "2.4.0"; - pcmc->broken_reserved_end = true; - compat_props_add(m->compat_props, hw_compat_2_4, hw_compat_2_4_len); - compat_props_add(m->compat_props, pc_compat_2_4, pc_compat_2_4_len); -} - -DEFINE_Q35_MACHINE(2, 4); diff --git a/tests/qtest/test-x86-cpuid-compat.c b/tests/qtest/test-x86-cpuid-compat.c index c9de47bb26..456e2af665 100644 --- a/tests/qtest/test-x86-cpuid-compat.c +++ b/tests/qtest/test-x86-cpuid-compat.c @@ -365,20 +365,6 @@ int main(int argc, char **argv) "level", 10); } - /* - * xlevel doesn't have any feature that triggers auto-level - * code on old machine-types. Just check that the compat code - * is working correctly: - */ - if (qtest_has_machine("pc-i440fx-2.4")) { - add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-off", - "SandyBridge", NULL, "pc-i440fx-2.4", - "xlevel", 0x80000008); - add_cpuid_test("x86/cpuid/xlevel-compat/pc-i440fx-2.4/npt-on", - "SandyBridge", "svm=on,npt=on", "pc-i440fx-2.4", - "xlevel", 0x80000008); - } - /* Test feature parsing */ add_feature_test("x86/cpuid/features/plus", "486", "+arat", From 8b1c560937467d0d96c1d0948e99f86ce188c0bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:31 +0200 Subject: [PATCH 1312/2760] hw/i386/pc: Remove PCMachineClass::broken_reserved_end field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCMachineClass::broken_reserved_end field was only used by the pc-q35-2.4 and pc-i440fx-2.4 machines, which got removed. Remove it and simplify pc_memory_init(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-3-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/i386/pc.c | 13 +++++-------- include/hw/i386/pc.h | 1 - 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 70656157ca..c8bb4a3ee4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -999,14 +999,13 @@ void pc_memory_init(PCMachineState *pcms, if (machine->device_memory) { uint64_t *val = g_malloc(sizeof(*val)); - uint64_t res_mem_end = machine->device_memory->base; - - if (!pcmc->broken_reserved_end) { - res_mem_end += memory_region_size(&machine->device_memory->mr); - } + uint64_t res_mem_end; if (pcms->cxl_devices_state.is_enabled) { res_mem_end = cxl_resv_end; + } else { + res_mem_end = machine->device_memory->base + + memory_region_size(&machine->device_memory->mr); } *val = cpu_to_le64(ROUND_UP(res_mem_end, 1 * GiB)); fw_cfg_add_file(fw_cfg, "etc/reserved-memory-end", val, sizeof(*val)); @@ -1044,9 +1043,7 @@ uint64_t pc_pci_hole64_start(void) hole64_start = pc_get_cxl_range_end(pcms); } else if (pcmc->has_reserved_memory && (ms->ram_size < ms->maxram_size)) { pc_get_device_memory_range(pcms, &hole64_start, &size); - if (!pcmc->broken_reserved_end) { - hole64_start += size; - } + hole64_start += size; } else { hole64_start = pc_above_4g_end(pcms); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 9563674e2d..f4a874b17f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -107,7 +107,6 @@ struct PCMachineClass { /* RAM / address space compat: */ bool gigabyte_align; bool has_reserved_memory; - bool broken_reserved_end; bool enforce_amd_1tb_hole; bool isa_bios_alias; From 4c82e7b34b1bf35d97e026196f5bf10ea916512c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:32 +0200 Subject: [PATCH 1313/2760] hw/i386/pc: Remove pc_compat_2_4[] array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pc_compat_2_4[] array was only used by the pc-q35-2.4 and pc-i440fx-2.4 machines, which got removed. Remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-4-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/i386/pc.c | 19 ------------------- include/hw/i386/pc.h | 3 --- 2 files changed, 22 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index c8bb4a3ee4..2b46714a5a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -262,25 +262,6 @@ const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6); GlobalProperty pc_compat_2_5[] = {}; const size_t pc_compat_2_5_len = G_N_ELEMENTS(pc_compat_2_5); -GlobalProperty pc_compat_2_4[] = { - PC_CPU_MODEL_IDS("2.4.0") - { "Haswell-" TYPE_X86_CPU, "abm", "off" }, - { "Haswell-noTSX-" TYPE_X86_CPU, "abm", "off" }, - { "Broadwell-" TYPE_X86_CPU, "abm", "off" }, - { "Broadwell-noTSX-" TYPE_X86_CPU, "abm", "off" }, - { "host" "-" TYPE_X86_CPU, "host-cache-info", "on" }, - { TYPE_X86_CPU, "check", "off" }, - { "qemu64" "-" TYPE_X86_CPU, "sse4a", "on" }, - { "qemu64" "-" TYPE_X86_CPU, "abm", "on" }, - { "qemu64" "-" TYPE_X86_CPU, "popcnt", "on" }, - { "qemu32" "-" TYPE_X86_CPU, "popcnt", "on" }, - { "Opteron_G2" "-" TYPE_X86_CPU, "rdtscp", "on" }, - { "Opteron_G3" "-" TYPE_X86_CPU, "rdtscp", "on" }, - { "Opteron_G4" "-" TYPE_X86_CPU, "rdtscp", "on" }, - { "Opteron_G5" "-" TYPE_X86_CPU, "rdtscp", "on", } -}; -const size_t pc_compat_2_4_len = G_N_ELEMENTS(pc_compat_2_4); - /* * @PC_FW_DATA: * Size of the chunk of memory at the top of RAM for the BIOS ACPI tables diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index f4a874b17f..b34aa25fdc 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -301,9 +301,6 @@ extern const size_t pc_compat_2_6_len; extern GlobalProperty pc_compat_2_5[]; extern const size_t pc_compat_2_5_len; -extern GlobalProperty pc_compat_2_4[]; -extern const size_t pc_compat_2_4_len; - #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, \ const void *data) \ From 60ce3f67bea0a782a58cf4f71840e8d20ef8ddfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:34 +0200 Subject: [PATCH 1314/2760] hw/core/machine: Remove hw_compat_2_4[] array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hw_compat_2_4[] array was only used by the pc-q35-2.4 and pc-i440fx-2.4 machines, which got removed. Remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-6-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/core/machine.c | 9 --------- include/hw/boards.h | 3 --- 2 files changed, 12 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index c3f3a5020d..15cd2bc3c4 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -294,15 +294,6 @@ GlobalProperty hw_compat_2_5[] = { }; const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5); -GlobalProperty hw_compat_2_4[] = { - { "e1000", "extra_mac_registers", "off" }, - { "virtio-pci", "x-disable-pcie", "on" }, - { "virtio-pci", "migrate-extra", "off" }, - { "fw_cfg_mem", "dma_enabled", "off" }, - { "fw_cfg_io", "dma_enabled", "off" } -}; -const size_t hw_compat_2_4_len = G_N_ELEMENTS(hw_compat_2_4); - MachineState *current_machine; static char *machine_get_kernel(Object *obj, Error **errp) diff --git a/include/hw/boards.h b/include/hw/boards.h index a7b1fcffae..03e7cbeae8 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -866,7 +866,4 @@ extern const size_t hw_compat_2_6_len; extern GlobalProperty hw_compat_2_5[]; extern const size_t hw_compat_2_5_len; -extern GlobalProperty hw_compat_2_4[]; -extern const size_t hw_compat_2_4_len; - #endif From 0bf8727696267a79658998d844a96e35e0353602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:35 +0200 Subject: [PATCH 1315/2760] hw/net/e1000: Remove unused E1000_FLAG_MAC flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit E1000_FLAG_MAC was only used by the hw_compat_2_4[] array, via the 'extra_mac_registers=off' property. We removed all machines using that array, lets remove all the code around E1000_FLAG_MAC, including the MAC_ACCESS_FLAG_NEEDED enum, similarly to commit fa4ec9ffda7 ("e1000: remove old compatibility code"). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Message-ID: <20250512083948.39294-7-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/net/e1000.c | 93 ++++++++++++++++++++++---------------------------- 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/hw/net/e1000.c b/hw/net/e1000.c index cba4999e6d..a80a7b0cdb 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -127,10 +127,8 @@ struct E1000State_st { QEMUTimer *flush_queue_timer; /* Compatibility flags for migration to/from qemu 1.3.0 and older */ -#define E1000_FLAG_MAC_BIT 2 #define E1000_FLAG_TSO_BIT 3 #define E1000_FLAG_VET_BIT 4 -#define E1000_FLAG_MAC (1 << E1000_FLAG_MAC_BIT) #define E1000_FLAG_TSO (1 << E1000_FLAG_TSO_BIT) #define E1000_FLAG_VET (1 << E1000_FLAG_VET_BIT) @@ -1212,52 +1210,51 @@ enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) }; enum { MAC_ACCESS_PARTIAL = 1, MAC_ACCESS_FLAG_NEEDED = 2 }; -#define markflag(x) ((E1000_FLAG_##x << 2) | MAC_ACCESS_FLAG_NEEDED) /* In the array below the meaning of the bits is: [f|f|f|f|f|f|n|p] * f - flag bits (up to 6 possible flags) * n - flag needed - * p - partially implenented */ + * p - partially implemented */ static const uint8_t mac_reg_access[0x8000] = { - [IPAV] = markflag(MAC), [WUC] = markflag(MAC), - [IP6AT] = markflag(MAC), [IP4AT] = markflag(MAC), - [FFVT] = markflag(MAC), [WUPM] = markflag(MAC), - [ECOL] = markflag(MAC), [MCC] = markflag(MAC), - [DC] = markflag(MAC), [TNCRS] = markflag(MAC), - [RLEC] = markflag(MAC), [XONRXC] = markflag(MAC), - [XOFFTXC] = markflag(MAC), [RFC] = markflag(MAC), - [TSCTFC] = markflag(MAC), [MGTPRC] = markflag(MAC), - [WUS] = markflag(MAC), [AIT] = markflag(MAC), - [FFLT] = markflag(MAC), [FFMT] = markflag(MAC), - [SCC] = markflag(MAC), [FCRUC] = markflag(MAC), - [LATECOL] = markflag(MAC), [COLC] = markflag(MAC), - [SEQEC] = markflag(MAC), [CEXTERR] = markflag(MAC), - [XONTXC] = markflag(MAC), [XOFFRXC] = markflag(MAC), - [RJC] = markflag(MAC), [RNBC] = markflag(MAC), - [MGTPDC] = markflag(MAC), [MGTPTC] = markflag(MAC), - [RUC] = markflag(MAC), [ROC] = markflag(MAC), - [GORCL] = markflag(MAC), [GORCH] = markflag(MAC), - [GOTCL] = markflag(MAC), [GOTCH] = markflag(MAC), - [BPRC] = markflag(MAC), [MPRC] = markflag(MAC), - [TSCTC] = markflag(MAC), [PRC64] = markflag(MAC), - [PRC127] = markflag(MAC), [PRC255] = markflag(MAC), - [PRC511] = markflag(MAC), [PRC1023] = markflag(MAC), - [PRC1522] = markflag(MAC), [PTC64] = markflag(MAC), - [PTC127] = markflag(MAC), [PTC255] = markflag(MAC), - [PTC511] = markflag(MAC), [PTC1023] = markflag(MAC), - [PTC1522] = markflag(MAC), [MPTC] = markflag(MAC), - [BPTC] = markflag(MAC), + [IPAV] = MAC_ACCESS_FLAG_NEEDED, [WUC] = MAC_ACCESS_FLAG_NEEDED, + [IP6AT] = MAC_ACCESS_FLAG_NEEDED, [IP4AT] = MAC_ACCESS_FLAG_NEEDED, + [FFVT] = MAC_ACCESS_FLAG_NEEDED, [WUPM] = MAC_ACCESS_FLAG_NEEDED, + [ECOL] = MAC_ACCESS_FLAG_NEEDED, [MCC] = MAC_ACCESS_FLAG_NEEDED, + [DC] = MAC_ACCESS_FLAG_NEEDED, [TNCRS] = MAC_ACCESS_FLAG_NEEDED, + [RLEC] = MAC_ACCESS_FLAG_NEEDED, [XONRXC] = MAC_ACCESS_FLAG_NEEDED, + [XOFFTXC] = MAC_ACCESS_FLAG_NEEDED, [RFC] = MAC_ACCESS_FLAG_NEEDED, + [TSCTFC] = MAC_ACCESS_FLAG_NEEDED, [MGTPRC] = MAC_ACCESS_FLAG_NEEDED, + [WUS] = MAC_ACCESS_FLAG_NEEDED, [AIT] = MAC_ACCESS_FLAG_NEEDED, + [FFLT] = MAC_ACCESS_FLAG_NEEDED, [FFMT] = MAC_ACCESS_FLAG_NEEDED, + [SCC] = MAC_ACCESS_FLAG_NEEDED, [FCRUC] = MAC_ACCESS_FLAG_NEEDED, + [LATECOL] = MAC_ACCESS_FLAG_NEEDED, [COLC] = MAC_ACCESS_FLAG_NEEDED, + [SEQEC] = MAC_ACCESS_FLAG_NEEDED, [CEXTERR] = MAC_ACCESS_FLAG_NEEDED, + [XONTXC] = MAC_ACCESS_FLAG_NEEDED, [XOFFRXC] = MAC_ACCESS_FLAG_NEEDED, + [RJC] = MAC_ACCESS_FLAG_NEEDED, [RNBC] = MAC_ACCESS_FLAG_NEEDED, + [MGTPDC] = MAC_ACCESS_FLAG_NEEDED, [MGTPTC] = MAC_ACCESS_FLAG_NEEDED, + [RUC] = MAC_ACCESS_FLAG_NEEDED, [ROC] = MAC_ACCESS_FLAG_NEEDED, + [GORCL] = MAC_ACCESS_FLAG_NEEDED, [GORCH] = MAC_ACCESS_FLAG_NEEDED, + [GOTCL] = MAC_ACCESS_FLAG_NEEDED, [GOTCH] = MAC_ACCESS_FLAG_NEEDED, + [BPRC] = MAC_ACCESS_FLAG_NEEDED, [MPRC] = MAC_ACCESS_FLAG_NEEDED, + [TSCTC] = MAC_ACCESS_FLAG_NEEDED, [PRC64] = MAC_ACCESS_FLAG_NEEDED, + [PRC127] = MAC_ACCESS_FLAG_NEEDED, [PRC255] = MAC_ACCESS_FLAG_NEEDED, + [PRC511] = MAC_ACCESS_FLAG_NEEDED, [PRC1023] = MAC_ACCESS_FLAG_NEEDED, + [PRC1522] = MAC_ACCESS_FLAG_NEEDED, [PTC64] = MAC_ACCESS_FLAG_NEEDED, + [PTC127] = MAC_ACCESS_FLAG_NEEDED, [PTC255] = MAC_ACCESS_FLAG_NEEDED, + [PTC511] = MAC_ACCESS_FLAG_NEEDED, [PTC1023] = MAC_ACCESS_FLAG_NEEDED, + [PTC1522] = MAC_ACCESS_FLAG_NEEDED, [MPTC] = MAC_ACCESS_FLAG_NEEDED, + [BPTC] = MAC_ACCESS_FLAG_NEEDED, - [TDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [TDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFH] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFT] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFHS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFTS] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [RDFPC] = markflag(MAC) | MAC_ACCESS_PARTIAL, - [PBM] = markflag(MAC) | MAC_ACCESS_PARTIAL, + [TDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [TDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFH] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFT] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFHS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFTS] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [RDFPC] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, + [PBM] = MAC_ACCESS_FLAG_NEEDED | MAC_ACCESS_PARTIAL, }; static void @@ -1419,13 +1416,6 @@ static int e1000_tx_tso_post_load(void *opaque, int version_id) return 0; } -static bool e1000_full_mac_needed(void *opaque) -{ - E1000State *s = opaque; - - return chkflag(MAC); -} - static bool e1000_tso_state_needed(void *opaque) { E1000State *s = opaque; @@ -1451,7 +1441,6 @@ static const VMStateDescription vmstate_e1000_full_mac_state = { .name = "e1000/full_mac_state", .version_id = 1, .minimum_version_id = 1, - .needed = e1000_full_mac_needed, .fields = (const VMStateField[]) { VMSTATE_UINT32_ARRAY(mac_reg, E1000State, 0x8000), VMSTATE_END_OF_LIST() @@ -1679,8 +1668,6 @@ static void pci_e1000_realize(PCIDevice *pci_dev, Error **errp) static const Property e1000_properties[] = { DEFINE_NIC_PROPERTIES(E1000State, conf), - DEFINE_PROP_BIT("extra_mac_registers", E1000State, - compat_flags, E1000_FLAG_MAC_BIT, true), DEFINE_PROP_BIT("migrate_tso_props", E1000State, compat_flags, E1000_FLAG_TSO_BIT, true), DEFINE_PROP_BIT("init-vet", E1000State, From fce42ccb51f115156d41eb3c8bd04bddf4a0ca8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:36 +0200 Subject: [PATCH 1316/2760] hw/virtio/virtio-pci: Remove VIRTIO_PCI_FLAG_MIGRATE_EXTRA definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIRTIO_PCI_FLAG_MIGRATE_EXTRA was only used by the hw_compat_2_4[] array, via the 'migrate-extra=true' property. We removed all machines using that array, lets remove all the code around VIRTIO_PCI_FLAG_MIGRATE_EXTRA. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Message-ID: <20250512083948.39294-8-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/virtio/virtio-pci.c | 6 +----- include/hw/virtio/virtio-pci.h | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9b48aa8c3e..f52fac663c 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -146,9 +146,7 @@ static const VMStateDescription vmstate_virtio_pci = { static bool virtio_pci_has_extra_state(DeviceState *d) { - VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - - return proxy->flags & VIRTIO_PCI_FLAG_MIGRATE_EXTRA; + return true; } static void virtio_pci_save_extra_state(DeviceState *d, QEMUFile *f) @@ -2363,8 +2361,6 @@ static void virtio_pci_bus_reset_hold(Object *obj, ResetType type) static const Property virtio_pci_properties[] = { DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), - DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true), DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index 1dbc3851b0..eb22ed0a1d 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -32,7 +32,6 @@ DECLARE_OBJ_CHECKERS(VirtioPCIBusState, VirtioPCIBusClass, enum { VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, - VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, @@ -57,9 +56,6 @@ enum { /* virtio version flags */ #define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT) -/* migrate extra state */ -#define VIRTIO_PCI_FLAG_MIGRATE_EXTRA (1 << VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT) - /* have pio notification for modern device ? */ #define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \ (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT) From 47d9e81f0ab44b59e99f4e87fe5409851e670de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:37 +0200 Subject: [PATCH 1317/2760] hw/virtio/virtio-pci: Remove VIRTIO_PCI_FLAG_DISABLE_PCIE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VIRTIO_PCI_FLAG_DISABLE_PCIE was only used by the hw_compat_2_4[] array, via the 'x-disable-pcie=false' property. We removed all machines using that array, lets remove all the code around VIRTIO_PCI_FLAG_DISABLE_PCIE (see commit 9a4c0e220d8 for similar VIRTIO_PCI_FLAG_* enum removal). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-9-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/virtio/virtio-pci.c | 5 +---- include/hw/virtio/virtio-pci.h | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index f52fac663c..e62ae1e5e0 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2363,8 +2363,6 @@ static const Property virtio_pci_properties[] = { VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false), DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, false), - DEFINE_PROP_BIT("x-disable-pcie", VirtIOPCIProxy, flags, - VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, false), DEFINE_PROP_BIT("page-per-vq", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, false), DEFINE_PROP_BOOL("x-ignore-backend-features", VirtIOPCIProxy, @@ -2393,8 +2391,7 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp) VirtIOPCIProxy *proxy = VIRTIO_PCI(qdev); PCIDevice *pci_dev = &proxy->pci_dev; - if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) && - virtio_pci_modern(proxy)) { + if (virtio_pci_modern(proxy)) { pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; } diff --git a/include/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h index eb22ed0a1d..eab5394898 100644 --- a/include/hw/virtio/virtio-pci.h +++ b/include/hw/virtio/virtio-pci.h @@ -33,7 +33,6 @@ enum { VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT, - VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT, VIRTIO_PCI_FLAG_PAGE_PER_VQ_BIT, VIRTIO_PCI_FLAG_ATS_BIT, VIRTIO_PCI_FLAG_INIT_DEVERR_BIT, @@ -53,9 +52,6 @@ enum { * vcpu thread using ioeventfd for some devices. */ #define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT) -/* virtio version flags */ -#define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT) - /* have pio notification for modern device ? */ #define VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY \ (1 << VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT) From ff63280a81144500726f1899b0ae374e692e1f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:38 +0200 Subject: [PATCH 1318/2760] hw/i386/pc: Remove deprecated pc-q35-2.5 and pc-i440fx-2.5 machines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These machines has been supported for a period of more than 6 years. According to our versioned machine support policy (see commit ce80c4fa6ff "docs: document special exception for machine type deprecation & removal") they can now be removed. Remove the now unused empty pc_compat_2_5[] array. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-10-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/i386/pc.c | 3 --- hw/i386/pc_piix.c | 13 ------------- hw/i386/pc_q35.c | 13 ------------- include/hw/i386/pc.h | 3 --- 4 files changed, 32 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 2b46714a5a..cb375aabdc 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -259,9 +259,6 @@ GlobalProperty pc_compat_2_6[] = { }; const size_t pc_compat_2_6_len = G_N_ELEMENTS(pc_compat_2_6); -GlobalProperty pc_compat_2_5[] = {}; -const size_t pc_compat_2_5_len = G_N_ELEMENTS(pc_compat_2_5); - /* * @PC_FW_DATA: * Size of the chunk of memory at the top of RAM for the BIOS ACPI tables diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 04213b45b4..7a62bb0650 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -778,19 +778,6 @@ static void pc_i440fx_machine_2_6_options(MachineClass *m) DEFINE_I440FX_MACHINE(2, 6); -static void pc_i440fx_machine_2_5_options(MachineClass *m) -{ - X86MachineClass *x86mc = X86_MACHINE_CLASS(m); - - pc_i440fx_machine_2_6_options(m); - x86mc->save_tsc_khz = false; - m->legacy_fw_cfg_order = 1; - compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len); - compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len); -} - -DEFINE_I440FX_MACHINE(2, 5); - #ifdef CONFIG_ISAPC static void isapc_machine_options(MachineClass *m) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 47e1260241..33211b1876 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -672,16 +672,3 @@ static void pc_q35_machine_2_6_options(MachineClass *m) } DEFINE_Q35_MACHINE(2, 6); - -static void pc_q35_machine_2_5_options(MachineClass *m) -{ - X86MachineClass *x86mc = X86_MACHINE_CLASS(m); - - pc_q35_machine_2_6_options(m); - x86mc->save_tsc_khz = false; - m->legacy_fw_cfg_order = 1; - compat_props_add(m->compat_props, hw_compat_2_5, hw_compat_2_5_len); - compat_props_add(m->compat_props, pc_compat_2_5, pc_compat_2_5_len); -} - -DEFINE_Q35_MACHINE(2, 5); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index b34aa25fdc..79b72c54dd 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -298,9 +298,6 @@ extern const size_t pc_compat_2_7_len; extern GlobalProperty pc_compat_2_6[]; extern const size_t pc_compat_2_6_len; -extern GlobalProperty pc_compat_2_5[]; -extern const size_t pc_compat_2_5_len; - #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, \ const void *data) \ From 42cbccfcb0635257721aa6a0e55cb80e85756ecf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:39 +0200 Subject: [PATCH 1319/2760] hw/i386/x86: Remove X86MachineClass::save_tsc_khz field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The X86MachineClass::save_tsc_khz boolean was only used by the pc-q35-2.5 and pc-i440fx-2.5 machines, which got removed. Remove it and simplify tsc_khz_needed(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-11-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/i386/x86.c | 1 - include/hw/i386/x86.h | 5 ----- target/i386/machine.c | 5 ++--- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/hw/i386/x86.c b/hw/i386/x86.c index e2d0409299..f80533df1c 100644 --- a/hw/i386/x86.c +++ b/hw/i386/x86.c @@ -382,7 +382,6 @@ static void x86_machine_class_init(ObjectClass *oc, const void *data) mc->get_default_cpu_node_id = x86_get_default_cpu_node_id; mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids; mc->kvm_type = x86_kvm_type; - x86mc->save_tsc_khz = true; x86mc->fwcfg_dma_enabled = true; nc->nmi_monitor_handler = x86_nmi; diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h index 258b1343a1..fc460b82f8 100644 --- a/include/hw/i386/x86.h +++ b/include/hw/i386/x86.h @@ -27,13 +27,8 @@ #include "qom/object.h" struct X86MachineClass { - /*< private >*/ MachineClass parent; - /*< public >*/ - - /* TSC rate migration: */ - bool save_tsc_khz; /* use DMA capable linuxboot option rom */ bool fwcfg_dma_enabled; /* CPU and apic information: */ diff --git a/target/i386/machine.c b/target/i386/machine.c index 6cb561c632..dd2dac1d44 100644 --- a/target/i386/machine.c +++ b/target/i386/machine.c @@ -1060,9 +1060,8 @@ static bool tsc_khz_needed(void *opaque) { X86CPU *cpu = opaque; CPUX86State *env = &cpu->env; - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - X86MachineClass *x86mc = X86_MACHINE_CLASS(mc); - return env->tsc_khz && x86mc->save_tsc_khz; + + return env->tsc_khz; } static const VMStateDescription vmstate_tsc_khz = { From 6160ce208419e6e218db644433528aaa5d4f5024 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:40 +0200 Subject: [PATCH 1320/2760] hw/nvram/fw_cfg: Remove legacy FW_CFG_ORDER_OVERRIDE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MachineClass::legacy_fw_cfg_order boolean was only used by the pc-q35-2.5 and pc-i440fx-2.5 machines, which got removed. Remove it along with: - FW_CFG_ORDER_OVERRIDE_* definitions - fw_cfg_set_order_override() - fw_cfg_reset_order_override() - fw_cfg_order[] - rom_set_order_override() - rom_reset_order_override() Simplify CLI and pc_vga_init() / pc_nic_init(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-12-philmd@linaro.org> [thuth: Fix error from check_patch.pl wrt to an empty "for" loop] Signed-off-by: Thomas Huth --- hw/core/loader.c | 14 ----- hw/i386/pc.c | 7 +-- hw/nvram/fw_cfg.c | 110 +++----------------------------------- include/hw/boards.h | 3 +- include/hw/loader.h | 2 - include/hw/nvram/fw_cfg.h | 10 ---- system/vl.c | 5 -- 7 files changed, 10 insertions(+), 141 deletions(-) diff --git a/hw/core/loader.c b/hw/core/loader.c index b792a54bb0..e7056ba4bd 100644 --- a/hw/core/loader.c +++ b/hw/core/loader.c @@ -1333,20 +1333,6 @@ void rom_set_fw(FWCfgState *f) fw_cfg = f; } -void rom_set_order_override(int order) -{ - if (!fw_cfg) - return; - fw_cfg_set_order_override(fw_cfg, order); -} - -void rom_reset_order_override(void) -{ - if (!fw_cfg) - return; - fw_cfg_reset_order_override(fw_cfg); -} - void rom_transaction_begin(void) { Rom *rom; diff --git a/hw/i386/pc.c b/hw/i386/pc.c index cb375aabdc..49632b69d2 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1033,7 +1033,6 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; - rom_set_order_override(FW_CFG_ORDER_OVERRIDE_VGA); if (pci_bus) { PCIDevice *pcidev = pci_vga_init(pci_bus); dev = pcidev ? &pcidev->qdev : NULL; @@ -1041,7 +1040,7 @@ DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) ISADevice *isadev = isa_vga_init(isa_bus); dev = isadev ? DEVICE(isadev) : NULL; } - rom_reset_order_override(); + return dev; } @@ -1231,8 +1230,6 @@ void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) bool default_is_ne2k = g_str_equal(mc->default_nic, TYPE_ISA_NE2000); NICInfo *nd; - rom_set_order_override(FW_CFG_ORDER_OVERRIDE_NIC); - while ((nd = qemu_find_nic_info(TYPE_ISA_NE2000, default_is_ne2k, NULL))) { pc_init_ne2k_isa(isa_bus, nd, &error_fatal); } @@ -1241,8 +1238,6 @@ void pc_nic_init(PCMachineClass *pcmc, ISABus *isa_bus, PCIBus *pci_bus) if (pci_bus) { pci_init_nic_devices(pci_bus, mc->default_nic); } - - rom_reset_order_override(); } void pc_i8259_create(ISABus *isa_bus, qemu_irq *i8259_irqs) diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index 237b9f7d1f..aa24050493 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -817,62 +817,6 @@ void fw_cfg_modify_i64(FWCfgState *s, uint16_t key, uint64_t value) g_free(old); } -void fw_cfg_set_order_override(FWCfgState *s, int order) -{ - assert(s->fw_cfg_order_override == 0); - s->fw_cfg_order_override = order; -} - -void fw_cfg_reset_order_override(FWCfgState *s) -{ - assert(s->fw_cfg_order_override != 0); - s->fw_cfg_order_override = 0; -} - -/* - * This is the legacy order list. For legacy systems, files are in - * the fw_cfg in the order defined below, by the "order" value. Note - * that some entries (VGA ROMs, NIC option ROMS, etc.) go into a - * specific area, but there may be more than one and they occur in the - * order that the user specifies them on the command line. Those are - * handled in a special manner, using the order override above. - * - * For non-legacy, the files are sorted by filename to avoid this kind - * of complexity in the future. - * - * This is only for x86, other arches don't implement versioning so - * they won't set legacy mode. - */ -static struct { - const char *name; - int order; -} fw_cfg_order[] = { - { "etc/boot-menu-wait", 10 }, - { "bootsplash.jpg", 11 }, - { "bootsplash.bmp", 12 }, - { "etc/boot-fail-wait", 15 }, - { "etc/smbios/smbios-tables", 20 }, - { "etc/smbios/smbios-anchor", 30 }, - { "etc/e820", 40 }, - { "etc/reserved-memory-end", 50 }, - { "genroms/kvmvapic.bin", 55 }, - { "genroms/linuxboot.bin", 60 }, - { }, /* VGA ROMs from pc_vga_init come here, 70. */ - { }, /* NIC option ROMs from pc_nic_init come here, 80. */ - { "etc/system-states", 90 }, - { }, /* User ROMs come here, 100. */ - { }, /* Device FW comes here, 110. */ - { "etc/extra-pci-roots", 120 }, - { "etc/acpi/tables", 130 }, - { "etc/table-loader", 140 }, - { "etc/tpm/log", 150 }, - { "etc/acpi/rsdp", 160 }, - { "bootorder", 170 }, - { "etc/msr_feature_control", 180 }, - -#define FW_CFG_ORDER_OVERRIDE_LAST 200 -}; - /* * Any sub-page size update to these table MRs will be lost during migration, * as we use aligned size in ram_load_precopy() -> qemu_ram_resize() path. @@ -890,29 +834,6 @@ static void fw_cfg_acpi_mr_save(FWCfgState *s, const char *filename, size_t len) } } -static int get_fw_cfg_order(FWCfgState *s, const char *name) -{ - int i; - - if (s->fw_cfg_order_override > 0) { - return s->fw_cfg_order_override; - } - - for (i = 0; i < ARRAY_SIZE(fw_cfg_order); i++) { - if (fw_cfg_order[i].name == NULL) { - continue; - } - - if (strcmp(name, fw_cfg_order[i].name) == 0) { - return fw_cfg_order[i].order; - } - } - - /* Stick unknown stuff at the end. */ - warn_report("Unknown firmware file in legacy mode: %s", name); - return FW_CFG_ORDER_OVERRIDE_LAST; -} - void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, FWCfgCallback select_cb, FWCfgWriteCallback write_cb, @@ -921,7 +842,6 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, { int i, index, count; size_t dsize; - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); int order = 0; if (!s->files) { @@ -933,22 +853,11 @@ void fw_cfg_add_file_callback(FWCfgState *s, const char *filename, count = be32_to_cpu(s->files->count); assert(count < fw_cfg_file_slots(s)); - /* Find the insertion point. */ - if (mc->legacy_fw_cfg_order) { - /* - * Sort by order. For files with the same order, we keep them - * in the sequence in which they were added. - */ - order = get_fw_cfg_order(s, filename); - for (index = count; - index > 0 && order < s->entry_order[index - 1]; - index--); - } else { - /* Sort by file name. */ - for (index = count; - index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0; - index--); - } + /* Find the insertion point, sorting by file name. */ + for (index = count; + index > 0 && strcmp(filename, s->files->f[index - 1].name) < 0; + index--) + ; /* * Move all the entries from the index point and after down one @@ -1058,7 +967,6 @@ bool fw_cfg_add_file_from_generator(FWCfgState *s, static void fw_cfg_machine_reset(void *opaque) { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); FWCfgState *s = opaque; void *ptr; size_t len; @@ -1068,11 +976,9 @@ static void fw_cfg_machine_reset(void *opaque) ptr = fw_cfg_modify_file(s, "bootorder", (uint8_t *)buf, len); g_free(ptr); - if (!mc->legacy_fw_cfg_order) { - buf = get_boot_devices_lchs_list(&len); - ptr = fw_cfg_modify_file(s, "bios-geometry", (uint8_t *)buf, len); - g_free(ptr); - } + buf = get_boot_devices_lchs_list(&len); + ptr = fw_cfg_modify_file(s, "bios-geometry", (uint8_t *)buf, len); + g_free(ptr); } static void fw_cfg_machine_ready(struct Notifier *n, void *data) diff --git a/include/hw/boards.h b/include/hw/boards.h index 03e7cbeae8..ab900dacab 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -286,8 +286,7 @@ struct MachineClass { no_parallel:1, no_floppy:1, no_cdrom:1, - pci_allow_0_address:1, - legacy_fw_cfg_order:1; + pci_allow_0_address:1; bool auto_create_sdcard; bool is_default; const char *default_machine_opts; diff --git a/include/hw/loader.h b/include/hw/loader.h index d280dc33e9..c96b5e141c 100644 --- a/include/hw/loader.h +++ b/include/hw/loader.h @@ -270,8 +270,6 @@ int rom_add_elf_program(const char *name, GMappedFile *mapped_file, void *data, AddressSpace *as); int rom_check_and_register_reset(void); void rom_set_fw(FWCfgState *f); -void rom_set_order_override(int order); -void rom_reset_order_override(void); /** * rom_transaction_begin: diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index 47578ccc7f..d41b9328fd 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -42,14 +42,6 @@ struct FWCfgDataGeneratorClass { typedef struct fw_cfg_file FWCfgFile; -#define FW_CFG_ORDER_OVERRIDE_VGA 70 -#define FW_CFG_ORDER_OVERRIDE_NIC 80 -#define FW_CFG_ORDER_OVERRIDE_USER 100 -#define FW_CFG_ORDER_OVERRIDE_DEVICE 110 - -void fw_cfg_set_order_override(FWCfgState *fw_cfg, int order); -void fw_cfg_reset_order_override(FWCfgState *fw_cfg); - typedef struct FWCfgFiles { uint32_t count; FWCfgFile f[]; @@ -75,8 +67,6 @@ struct FWCfgState { uint32_t cur_offset; Notifier machine_ready; - int fw_cfg_order_override; - bool dma_enabled; dma_addr_t dma_addr; AddressSpace *dma_as; diff --git a/system/vl.c b/system/vl.c index fd402b8ff8..3b7057e6c6 100644 --- a/system/vl.c +++ b/system/vl.c @@ -1192,10 +1192,7 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) return -1; } } - /* For legacy, keep user files in a specific global order. */ - fw_cfg_set_order_override(fw_cfg, FW_CFG_ORDER_OVERRIDE_USER); fw_cfg_add_file(fw_cfg, name, buf, size); - fw_cfg_reset_order_override(fw_cfg); return 0; } @@ -2745,7 +2742,6 @@ static void qemu_create_cli_devices(void) } /* init generic devices */ - rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE); qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, &error_fatal); QTAILQ_FOREACH(opt, &device_opts, next) { @@ -2756,7 +2752,6 @@ static void qemu_create_cli_devices(void) assert(ret_data == NULL); /* error_fatal aborts */ loc_pop(&opt->loc); } - rom_reset_order_override(); } static bool qemu_machine_creation_done(Error **errp) From 667e170d2cf033033dfd6656f871c41871107ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:41 +0200 Subject: [PATCH 1321/2760] hw/core/machine: Remove hw_compat_2_5[] array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hw_compat_2_5[] array was only used by the pc-q35-2.5 and pc-i440fx-2.5 machines, which got removed. Remove it. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-13-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/core/machine.c | 9 --------- include/hw/boards.h | 3 --- 2 files changed, 12 deletions(-) diff --git a/hw/core/machine.c b/hw/core/machine.c index 15cd2bc3c4..e869821b22 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -285,15 +285,6 @@ GlobalProperty hw_compat_2_6[] = { }; const size_t hw_compat_2_6_len = G_N_ELEMENTS(hw_compat_2_6); -GlobalProperty hw_compat_2_5[] = { - { "isa-fdc", "fallback", "144" }, - { "pvscsi", "x-old-pci-configuration", "on" }, - { "pvscsi", "x-disable-pcie", "on" }, - { "vmxnet3", "x-old-msi-offsets", "on" }, - { "vmxnet3", "x-disable-pcie", "on" }, -}; -const size_t hw_compat_2_5_len = G_N_ELEMENTS(hw_compat_2_5); - MachineState *current_machine; static char *machine_get_kernel(Object *obj, Error **errp) diff --git a/include/hw/boards.h b/include/hw/boards.h index ab900dacab..f424b2b505 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -862,7 +862,4 @@ extern const size_t hw_compat_2_7_len; extern GlobalProperty hw_compat_2_6[]; extern const size_t hw_compat_2_6_len; -extern GlobalProperty hw_compat_2_5[]; -extern const size_t hw_compat_2_5_len; - #endif From 16c04166ae71c78ec36a9e2914c46c2289a58503 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:43 +0200 Subject: [PATCH 1322/2760] hw/scsi/vmw_pvscsi: Remove PVSCSI_COMPAT_OLD_PCI_CONFIGURATION definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PVSCSI_COMPAT_OLD_PCI_CONFIGURATION was only used by the hw_compat_2_5[] array, via the 'x-old-pci-configuration=on' property. We removed all machines using that array, lets remove all the code around PVSCSI_COMPAT_OLD_PCI_CONFIGURATION. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-15-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/scsi/vmw_pvscsi.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index d5825b6786..34de59a7cf 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -69,17 +69,11 @@ OBJECT_DECLARE_TYPE(PVSCSIState, PVSCSIClass, PVSCSI) /* Compatibility flags for migration */ -#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT 0 -#define PVSCSI_COMPAT_OLD_PCI_CONFIGURATION \ - (1 << PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT) #define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1 #define PVSCSI_COMPAT_DISABLE_PCIE \ (1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT) -#define PVSCSI_USE_OLD_PCI_CONFIGURATION(s) \ - ((s)->compat_flags & PVSCSI_COMPAT_OLD_PCI_CONFIGURATION) -#define PVSCSI_MSI_OFFSET(s) \ - (PVSCSI_USE_OLD_PCI_CONFIGURATION(s) ? 0x50 : 0x7c) +#define PVSCSI_MSI_OFFSET (0x7c) #define PVSCSI_EXP_EP_OFFSET (0x40) typedef struct PVSCSIRingInfo { @@ -1110,7 +1104,7 @@ pvscsi_init_msi(PVSCSIState *s) int res; PCIDevice *d = PCI_DEVICE(s); - res = msi_init(d, PVSCSI_MSI_OFFSET(s), PVSCSI_MSIX_NUM_VECTORS, + res = msi_init(d, PVSCSI_MSI_OFFSET, PVSCSI_MSIX_NUM_VECTORS, PVSCSI_USE_64BIT, PVSCSI_PER_VECTOR_MASK, NULL); if (res < 0) { trace_pvscsi_init_msi_fail(res); @@ -1158,15 +1152,11 @@ pvscsi_realizefn(PCIDevice *pci_dev, Error **errp) trace_pvscsi_state("init"); /* PCI subsystem ID, subsystem vendor ID, revision */ - if (PVSCSI_USE_OLD_PCI_CONFIGURATION(s)) { - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, 0x1000); - } else { - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, - PCI_VENDOR_ID_VMWARE); - pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, - PCI_DEVICE_ID_VMWARE_PVSCSI); - pci_config_set_revision(pci_dev->config, 0x2); - } + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_VENDOR_ID, + PCI_VENDOR_ID_VMWARE); + pci_set_word(pci_dev->config + PCI_SUBSYSTEM_ID, + PCI_DEVICE_ID_VMWARE_PVSCSI); + pci_config_set_revision(pci_dev->config, 0x2); /* PCI latency timer = 255 */ pci_dev->config[PCI_LATENCY_TIMER] = 0xff; @@ -1298,8 +1288,6 @@ static const VMStateDescription vmstate_pvscsi = { static const Property pvscsi_properties[] = { DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1), - DEFINE_PROP_BIT("x-old-pci-configuration", PVSCSIState, compat_flags, - PVSCSI_COMPAT_OLD_PCI_CONFIGURATION_BIT, false), DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags, PVSCSI_COMPAT_DISABLE_PCIE_BIT, false), }; From 404b27b739aa6f2c53fbed58101719564f614aac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:44 +0200 Subject: [PATCH 1323/2760] hw/scsi/vmw_pvscsi: Remove PVSCSI_COMPAT_DISABLE_PCIE_BIT definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PVSCSI_COMPAT_DISABLE_PCIE_BIT was only used by the hw_compat_2_5[] array, via the 'x-disable-pcie=on' property. We removed all machines using that array, lets remove all the code around PVSCSI_COMPAT_DISABLE_PCIE_BIT, including the now unused PVSCSIState::compat_flags field. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Thomas Huth Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-16-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/scsi/vmw_pvscsi.c | 30 +----------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 34de59a7cf..e163023d14 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -68,11 +68,6 @@ struct PVSCSIClass { OBJECT_DECLARE_TYPE(PVSCSIState, PVSCSIClass, PVSCSI) -/* Compatibility flags for migration */ -#define PVSCSI_COMPAT_DISABLE_PCIE_BIT 1 -#define PVSCSI_COMPAT_DISABLE_PCIE \ - (1 << PVSCSI_COMPAT_DISABLE_PCIE_BIT) - #define PVSCSI_MSI_OFFSET (0x7c) #define PVSCSI_EXP_EP_OFFSET (0x40) @@ -123,8 +118,6 @@ struct PVSCSIState { uint8_t msi_used; /* For migration compatibility */ PVSCSIRingInfo rings; /* Data transfer rings manager */ uint32_t resetting; /* Reset in progress */ - - uint32_t compat_flags; }; typedef struct PVSCSIRequest { @@ -1224,21 +1217,8 @@ pvscsi_post_load(void *opaque, int version_id) return 0; } -static bool pvscsi_vmstate_need_pcie_device(void *opaque) -{ - PVSCSIState *s = PVSCSI(opaque); - - return !(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE); -} - -static bool pvscsi_vmstate_test_pci_device(void *opaque, int version_id) -{ - return !pvscsi_vmstate_need_pcie_device(opaque); -} - static const VMStateDescription vmstate_pvscsi_pcie_device = { .name = "pvscsi/pcie", - .needed = pvscsi_vmstate_need_pcie_device, .fields = (const VMStateField[]) { VMSTATE_PCI_DEVICE(parent_obj, PVSCSIState), VMSTATE_END_OF_LIST() @@ -1252,9 +1232,6 @@ static const VMStateDescription vmstate_pvscsi = { .pre_save = pvscsi_pre_save, .post_load = pvscsi_post_load, .fields = (const VMStateField[]) { - VMSTATE_STRUCT_TEST(parent_obj, PVSCSIState, - pvscsi_vmstate_test_pci_device, 0, - vmstate_pci_device, PCIDevice), VMSTATE_UINT8(msi_used, PVSCSIState), VMSTATE_UINT32(resetting, PVSCSIState), VMSTATE_UINT64(reg_interrupt_status, PVSCSIState), @@ -1288,19 +1265,14 @@ static const VMStateDescription vmstate_pvscsi = { static const Property pvscsi_properties[] = { DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1), - DEFINE_PROP_BIT("x-disable-pcie", PVSCSIState, compat_flags, - PVSCSI_COMPAT_DISABLE_PCIE_BIT, false), }; static void pvscsi_realize(DeviceState *qdev, Error **errp) { PVSCSIClass *pvs_c = PVSCSI_GET_CLASS(qdev); PCIDevice *pci_dev = PCI_DEVICE(qdev); - PVSCSIState *s = PVSCSI(qdev); - if (!(s->compat_flags & PVSCSI_COMPAT_DISABLE_PCIE)) { - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - } + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; pvs_c->parent_dc_realize(qdev, errp); } From 3763d16370f1505faada6909bd92ebe3a242b1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:45 +0200 Subject: [PATCH 1324/2760] hw/scsi/vmw_pvscsi: Convert DeviceRealize -> InstanceInit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify replacing pvscsi_realize() by pvscsi_instance_init(), removing the need for device_class_set_parent_realize(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-17-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/scsi/vmw_pvscsi.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index e163023d14..7c98b1b8ea 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1267,21 +1267,15 @@ static const Property pvscsi_properties[] = { DEFINE_PROP_UINT8("use_msg", PVSCSIState, use_msg, 1), }; -static void pvscsi_realize(DeviceState *qdev, Error **errp) +static void pvscsi_instance_init(Object *obj) { - PVSCSIClass *pvs_c = PVSCSI_GET_CLASS(qdev); - PCIDevice *pci_dev = PCI_DEVICE(qdev); - - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - - pvs_c->parent_dc_realize(qdev, errp); + PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS; } static void pvscsi_class_init(ObjectClass *klass, const void *data) { DeviceClass *dc = DEVICE_CLASS(klass); PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - PVSCSIClass *pvs_k = PVSCSI_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); k->realize = pvscsi_realizefn; @@ -1290,8 +1284,6 @@ static void pvscsi_class_init(ObjectClass *klass, const void *data) k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; k->class_id = PCI_CLASS_STORAGE_SCSI; k->subsystem_id = 0x1000; - device_class_set_parent_realize(dc, pvscsi_realize, - &pvs_k->parent_dc_realize); device_class_set_legacy_reset(dc, pvscsi_reset); dc->vmsd = &vmstate_pvscsi; device_class_set_props(dc, pvscsi_properties); @@ -1306,6 +1298,7 @@ static const TypeInfo pvscsi_info = { .class_size = sizeof(PVSCSIClass), .instance_size = sizeof(PVSCSIState), .class_init = pvscsi_class_init, + .instance_init = pvscsi_instance_init, .interfaces = (const InterfaceInfo[]) { { TYPE_HOTPLUG_HANDLER }, { INTERFACE_PCIE_DEVICE }, From 2531dfde0ac447b0d70a83c8a02f72e584b9c534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:46 +0200 Subject: [PATCH 1325/2760] hw/net/vmxnet3: Remove VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS was only used by the hw_compat_2_5[] array, via the 'x-old-msi-offsets=on' property. We removed all machines using that array, lets remove all the code around VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-18-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/net/vmxnet3.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 83d942af17..3cf5d71f47 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -42,18 +42,13 @@ #define VMXNET3_MSIX_BAR_SIZE 0x2000 /* Compatibility flags for migration */ -#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT 0 -#define VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS \ - (1 << VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT) #define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1 #define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \ (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT) #define VMXNET3_EXP_EP_OFFSET (0x48) -#define VMXNET3_MSI_OFFSET(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x50 : 0x84) -#define VMXNET3_MSIX_OFFSET(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0 : 0x9c) +#define VMXNET3_MSI_OFFSET (0x84) +#define VMXNET3_MSIX_OFFSET (0x9c) #define VMXNET3_DSN_OFFSET (0x100) #define VMXNET3_BAR0_IDX (0) @@ -61,8 +56,7 @@ #define VMXNET3_MSIX_BAR_IDX (2) #define VMXNET3_OFF_MSIX_TABLE (0x000) -#define VMXNET3_OFF_MSIX_PBA(s) \ - ((s)->compat_flags & VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS ? 0x800 : 0x1000) +#define VMXNET3_OFF_MSIX_PBA (0x1000) /* Link speed in Mbps should be shifted by 16 */ #define VMXNET3_LINK_SPEED (1000 << 16) @@ -2122,8 +2116,8 @@ vmxnet3_init_msix(VMXNET3State *s) &s->msix_bar, VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_TABLE, &s->msix_bar, - VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA(s), - VMXNET3_MSIX_OFFSET(s), NULL); + VMXNET3_MSIX_BAR_IDX, VMXNET3_OFF_MSIX_PBA, + VMXNET3_MSIX_OFFSET, NULL); if (0 > res) { VMW_WRPRN("Failed to initialize MSI-X, error %d", res); @@ -2221,7 +2215,7 @@ static void vmxnet3_pci_realize(PCIDevice *pci_dev, Error **errp) /* Interrupt pin A */ pci_dev->config[PCI_INTERRUPT_PIN] = 0x01; - ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET(s), VMXNET3_MAX_NMSIX_INTRS, + ret = msi_init(pci_dev, VMXNET3_MSI_OFFSET, VMXNET3_MAX_NMSIX_INTRS, VMXNET3_USE_64BIT, VMXNET3_PER_VECTOR_MASK, NULL); /* Any error other than -ENOTSUP(board's MSI support is broken) * is a programming error. Fall back to INTx silently on -ENOTSUP */ @@ -2472,8 +2466,6 @@ static const VMStateDescription vmstate_vmxnet3 = { static const Property vmxnet3_properties[] = { DEFINE_NIC_PROPERTIES(VMXNET3State, conf), - DEFINE_PROP_BIT("x-old-msi-offsets", VMXNET3State, compat_flags, - VMXNET3_COMPAT_FLAG_OLD_MSI_OFFSETS_BIT, false), DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags, VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false), }; From 2db72323f2370ca69ba331f17c9a6bbd1f3bb118 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:47 +0200 Subject: [PATCH 1326/2760] hw/net/vmxnet3: Remove VMXNET3_COMPAT_FLAG_DISABLE_PCIE definition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VMXNET3_COMPAT_FLAG_DISABLE_PCIE was only used by the hw_compat_2_5[] array, via the 'x-disable-pcie=on' property. We removed all machines using that array, lets remove all the code around VMXNET3_COMPAT_FLAG_DISABLE_PCIE. Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-19-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/net/vmxnet3.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index 3cf5d71f47..d080fe9b38 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -41,11 +41,6 @@ #define PCI_DEVICE_ID_VMWARE_VMXNET3_REVISION 0x1 #define VMXNET3_MSIX_BAR_SIZE 0x2000 -/* Compatibility flags for migration */ -#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT 1 -#define VMXNET3_COMPAT_FLAG_DISABLE_PCIE \ - (1 << VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT) - #define VMXNET3_EXP_EP_OFFSET (0x48) #define VMXNET3_MSI_OFFSET (0x84) #define VMXNET3_MSIX_OFFSET (0x9c) @@ -2466,8 +2461,6 @@ static const VMStateDescription vmstate_vmxnet3 = { static const Property vmxnet3_properties[] = { DEFINE_NIC_PROPERTIES(VMXNET3State, conf), - DEFINE_PROP_BIT("x-disable-pcie", VMXNET3State, compat_flags, - VMXNET3_COMPAT_FLAG_DISABLE_PCIE_BIT, false), }; static void vmxnet3_realize(DeviceState *qdev, Error **errp) @@ -2476,9 +2469,7 @@ static void vmxnet3_realize(DeviceState *qdev, Error **errp) PCIDevice *pci_dev = PCI_DEVICE(qdev); VMXNET3State *s = VMXNET3(qdev); - if (!(s->compat_flags & VMXNET3_COMPAT_FLAG_DISABLE_PCIE)) { - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - } + pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; vc->parent_dc_realize(qdev, errp); } From c4eb3f10a3573392c297f2124a81af9041300ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Mon, 12 May 2025 10:39:48 +0200 Subject: [PATCH 1327/2760] hw/net/vmxnet3: Merge DeviceRealize in InstanceInit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify merging vmxnet3_realize() within vmxnet3_instance_init(), removing the need for device_class_set_parent_realize(). Signed-off-by: Philippe Mathieu-Daudé Reviewed-by: Daniel P. Berrangé Reviewed-by: Zhao Liu Reviewed-by: Xiaoyao Li Message-ID: <20250512083948.39294-20-philmd@linaro.org> Signed-off-by: Thomas Huth --- hw/net/vmxnet3.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c index d080fe9b38..7c0ca56b7c 100644 --- a/hw/net/vmxnet3.c +++ b/hw/net/vmxnet3.c @@ -2238,6 +2238,7 @@ static void vmxnet3_instance_init(Object *obj) device_add_bootindex_property(obj, &s->conf.bootindex, "bootindex", "/ethernet-phy@0", DEVICE(obj)); + PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS; } static void vmxnet3_pci_uninit(PCIDevice *pci_dev) @@ -2463,22 +2464,10 @@ static const Property vmxnet3_properties[] = { DEFINE_NIC_PROPERTIES(VMXNET3State, conf), }; -static void vmxnet3_realize(DeviceState *qdev, Error **errp) -{ - VMXNET3Class *vc = VMXNET3_DEVICE_GET_CLASS(qdev); - PCIDevice *pci_dev = PCI_DEVICE(qdev); - VMXNET3State *s = VMXNET3(qdev); - - pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS; - - vc->parent_dc_realize(qdev, errp); -} - static void vmxnet3_class_init(ObjectClass *class, const void *data) { DeviceClass *dc = DEVICE_CLASS(class); PCIDeviceClass *c = PCI_DEVICE_CLASS(class); - VMXNET3Class *vc = VMXNET3_DEVICE_CLASS(class); c->realize = vmxnet3_pci_realize; c->exit = vmxnet3_pci_uninit; @@ -2489,8 +2478,6 @@ static void vmxnet3_class_init(ObjectClass *class, const void *data) c->class_id = PCI_CLASS_NETWORK_ETHERNET; c->subsystem_vendor_id = PCI_VENDOR_ID_VMWARE; c->subsystem_id = PCI_DEVICE_ID_VMWARE_VMXNET3; - device_class_set_parent_realize(dc, vmxnet3_realize, - &vc->parent_dc_realize); dc->desc = "VMWare Paravirtualized Ethernet v3"; device_class_set_legacy_reset(dc, vmxnet3_qdev_reset); dc->vmsd = &vmstate_vmxnet3; From 5c54a367265ec19ed94a535cd15d178c16b8cae0 Mon Sep 17 00:00:00 2001 From: Matheus Tavares Bernardino Date: Mon, 26 May 2025 10:20:55 -0700 Subject: [PATCH 1328/2760] tests/unit/test-util-sockets: fix mem-leak on error object The test fails with --enable-asan as the error struct is never freed. In the case where the test expects a success but it fails, let's also report the error for debugging (it will be freed internally). Fixes 316e8ee8d6 ("util/qemu-sockets: Refactor inet_parse() to use QemuOpts") Signed-off-by: Matheus Tavares Bernardino Reviewed-by: Juraj Marcin Message-ID: <518d94c7db20060b2a086cf55ee9bffab992a907.1748280011.git.matheus.bernardino@oss.qualcomm.com> Signed-off-by: Thomas Huth --- tests/unit/test-util-sockets.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/unit/test-util-sockets.c b/tests/unit/test-util-sockets.c index 8492f4d68f..ee66d727c3 100644 --- a/tests/unit/test-util-sockets.c +++ b/tests/unit/test-util-sockets.c @@ -341,8 +341,12 @@ static void inet_parse_test_helper(const char *str, int rc = inet_parse(&addr, str, &error); if (success) { + if (error) { + error_report_err(error); + } g_assert_cmpint(rc, ==, 0); } else { + error_free(error); g_assert_cmpint(rc, <, 0); } if (exp_addr != NULL) { From ac8fc4ccacd8a77d8d56dc3990bfb221c1f48fcd Mon Sep 17 00:00:00 2001 From: Yuri Benditovich Date: Thu, 15 May 2025 09:32:37 +0300 Subject: [PATCH 1329/2760] virtio: check for validity of indirect descriptors virtio processes indirect descriptors even if the respected feature VIRTIO_RING_F_INDIRECT_DESC was not negotiated. If qemu is used with reduced set of features to emulate the hardware device that does not support indirect descriptors, the will probably trigger problematic flows on the hardware setup but do not reveal the mistake on qemu. Add LOG_GUEST_ERROR for such case. This will issue logs with '-d guest_errors' in the command line Signed-off-by: Yuri Benditovich Message-Id: <20250515063237.808293-1-yuri.benditovich@daynix.com> Signed-off-by: Yuri Benditovich --- hw/virtio/virtio.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 2e98cecf64..5534251e01 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -205,6 +205,15 @@ static const char *virtio_id_to_name(uint16_t device_id) return name; } +static void virtio_check_indirect_feature(VirtIODevice *vdev) +{ + if (!virtio_vdev_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) { + qemu_log_mask(LOG_GUEST_ERROR, + "Device %s: indirect_desc was not negotiated!\n", + vdev->name); + } +} + /* Called within call_rcu(). */ static void virtio_free_region_cache(VRingMemoryRegionCaches *caches) { @@ -1733,6 +1742,7 @@ static void *virtqueue_split_pop(VirtQueue *vq, size_t sz) virtio_error(vdev, "Invalid size for indirect buffer table"); goto done; } + virtio_check_indirect_feature(vdev); /* loop over the indirect descriptor table */ len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as, @@ -1870,6 +1880,7 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz) virtio_error(vdev, "Invalid size for indirect buffer table"); goto done; } + virtio_check_indirect_feature(vdev); /* loop over the indirect descriptor table */ len = address_space_cache_init(&indirect_desc_cache, vdev->dma_as, From 31753d5a336fbb4e9246397f4b90b6f611f27f22 Mon Sep 17 00:00:00 2001 From: Sairaj Kodilkar Date: Fri, 16 May 2025 15:35:34 +0530 Subject: [PATCH 1330/2760] hw/i386/amd_iommu: Fix device setup failure when PT is on. Commit c1f46999ef506 ("amd_iommu: Add support for pass though mode") introduces the support for "pt" flag by enabling nodma memory when "pt=off". This allowed VFIO devices to successfully register notifiers by using nodma region. But, This also broke things when guest is booted with the iommu=nopt because, devices bypass the IOMMU and use untranslated addresses (IOVA) to perform DMA reads/writes to the nodma memory region, ultimately resulting in a failure to setup the devices in the guest. Fix the above issue by always enabling the amdvi_dev_as->iommu memory region. But this will once again cause VFIO devices to fail while registering the notifiers with AMD IOMMU memory region. Fixes: c1f46999ef506 ("amd_iommu: Add support for pass though mode") Signed-off-by: Sairaj Kodilkar Reviewed-by: Vasant Hegde Message-Id: <20250516100535.4980-2-sarunkod@amd.com> Fixes: c1f46999ef506 ("amd_iommu: Add support for pass though mode") Signed-off-by: Sairaj Kodilkar Reviewed-by: Vasant Hegde --- hw/i386/amd_iommu.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 0775c8f3bb..17379db52a 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1426,7 +1426,6 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) AMDVIState *s = opaque; AMDVIAddressSpace **iommu_as, *amdvi_dev_as; int bus_num = pci_bus_num(bus); - X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s); iommu_as = s->address_spaces[bus_num]; @@ -1486,15 +1485,8 @@ static AddressSpace *amdvi_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) AMDVI_INT_ADDR_FIRST, &amdvi_dev_as->iommu_ir, 1); - if (!x86_iommu->pt_supported) { - memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false); - memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), - true); - } else { - memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), - false); - memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, true); - } + memory_region_set_enabled(&amdvi_dev_as->iommu_nodma, false); + memory_region_set_enabled(MEMORY_REGION(&amdvi_dev_as->iommu), true); } return &iommu_as[devfn]->as; } From 0f178860df3489a9d3c19a5f7f024e6aa6c26515 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Fri, 16 May 2025 15:35:35 +0530 Subject: [PATCH 1331/2760] hw/i386/amd_iommu: Fix xtsup when vcpus < 255 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If vCPUs > 255 then x86 common code (x86_cpus_init()) call kvm_enable_x2apic(). But if vCPUs <= 255 then the common code won't calls kvm_enable_x2apic(). This is because commit 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") removed the call to kvm_enable_x2apic when xtsup is "on", which break things when guest is booted with x2apic mode and there are <= 255 vCPUs. Fix this by adding back kvm_enable_x2apic() call when xtsup=on. Fixes: 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") Reported-by: Alejandro Jimenez Tested-by: Tested-by: Alejandro Jimenez Cc: Philippe Mathieu-Daudé Cc: Joao Martins Signed-off-by: Vasant Hegde Signed-off-by: Sairaj Kodilkar Message-Id: <20250516100535.4980-3-sarunkod@amd.com> Fixes: 8c6619f3e692 ("hw/i386/amd_iommu: Simplify non-KVM checks on XTSup feature") Reported-by: Alejandro Jimenez Tested-by: Tested-by: Alejandro Jimenez Cc: Philippe Mathieu-Daudé Cc: Joao Martins Signed-off-by: Vasant Hegde Signed-off-by: Sairaj Kodilkar --- hw/i386/amd_iommu.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hw/i386/amd_iommu.c b/hw/i386/amd_iommu.c index 17379db52a..963aa2450c 100644 --- a/hw/i386/amd_iommu.c +++ b/hw/i386/amd_iommu.c @@ -1715,6 +1715,14 @@ static void amdvi_sysbus_realize(DeviceState *dev, Error **errp) exit(EXIT_FAILURE); } + if (s->xtsup) { + if (kvm_irqchip_is_split() && !kvm_enable_x2apic()) { + error_report("AMD IOMMU xtsup=on requires x2APIC support on " + "the KVM side"); + exit(EXIT_FAILURE); + } + } + pci_setup_iommu(bus, &amdvi_iommu_ops, s); amdvi_init(s); } From a8d178e1492a1a803898501a84829ac517ae2fb0 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:51 +0000 Subject: [PATCH 1332/2760] pcie: Add helper to declare PASID capability for a pcie device Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-2-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 25 +++++++++++++++++++++++++ include/hw/pci/pcie.h | 6 +++++- include/hw/pci/pcie_regs.h | 5 +++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 1b12db6fa2..4f935ff420 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1214,3 +1214,28 @@ void pcie_acs_reset(PCIDevice *dev) pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0); } } + +/* PASID */ +void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, + bool exec_perm, bool priv_mod) +{ + static const uint16_t control_reg_rw_mask = 0x07; + uint16_t capability_reg; + + assert(pasid_width <= PCI_EXT_CAP_PASID_MAX_WIDTH); + + pcie_add_capability(dev, PCI_EXT_CAP_ID_PASID, PCI_PASID_VER, offset, + PCI_EXT_CAP_PASID_SIZEOF); + + capability_reg = ((uint16_t)pasid_width) << PCI_PASID_CAP_WIDTH_SHIFT; + capability_reg |= exec_perm ? PCI_PASID_CAP_EXEC : 0; + capability_reg |= priv_mod ? PCI_PASID_CAP_PRIV : 0; + pci_set_word(dev->config + offset + PCI_PASID_CAP, capability_reg); + + /* Everything is disabled by default */ + pci_set_word(dev->config + offset + PCI_PASID_CTRL, 0); + + pci_set_word(dev->wmask + offset + PCI_PASID_CTRL, control_reg_rw_mask); + + dev->exp.pasid_cap = offset; +} diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 70a5de09de..fe82e0a915 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -70,8 +70,9 @@ struct PCIExpressDevice { uint16_t aer_cap; PCIEAERLog aer_log; - /* Offset of ATS capability in config space */ + /* Offset of ATS and PASID capabilities in config space */ uint16_t ats_cap; + uint16_t pasid_cap; /* ACS */ uint16_t acs_cap; @@ -150,4 +151,7 @@ void pcie_cap_slot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp); + +void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, + bool exec_perm, bool priv_mod); #endif /* QEMU_PCIE_H */ diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h index 9d3b6868dc..4d9cf4a29c 100644 --- a/include/hw/pci/pcie_regs.h +++ b/include/hw/pci/pcie_regs.h @@ -86,6 +86,11 @@ typedef enum PCIExpLinkWidth { #define PCI_ARI_VER 1 #define PCI_ARI_SIZEOF 8 +/* PASID */ +#define PCI_PASID_VER 1 +#define PCI_EXT_CAP_PASID_MAX_WIDTH 20 +#define PCI_PASID_CAP_WIDTH_SHIFT 8 + /* AER */ #define PCI_ERR_VER 2 #define PCI_ERR_SIZEOF 0x48 From 1e82e8a828cf18a8abfeca7295322db91879de04 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:51 +0000 Subject: [PATCH 1333/2760] pcie: Helper functions to check if PASID is enabled pasid_enabled checks whether the capability is present or not. If so, we read the configuration space to get the status of the feature (enabled or not). Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-3-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 9 +++++++++ include/hw/pci/pcie.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 4f935ff420..db9756d861 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1239,3 +1239,12 @@ void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, dev->exp.pasid_cap = offset; } + +bool pcie_pasid_enabled(const PCIDevice *dev) +{ + if (!pci_is_express(dev) || !dev->exp.pasid_cap) { + return false; + } + return (pci_get_word(dev->config + dev->exp.pasid_cap + PCI_PASID_CTRL) & + PCI_PASID_CTRL_ENABLE) != 0; +} diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index fe82e0a915..dff98ff2c6 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -154,4 +154,6 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, bool exec_perm, bool priv_mod); + +bool pcie_pasid_enabled(const PCIDevice *dev); #endif /* QEMU_PCIE_H */ From 6a3ae6a2440dead9dd8e3f84152dc53a5214c48d Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:52 +0000 Subject: [PATCH 1334/2760] pcie: Helper function to check if ATS is enabled ats_enabled checks whether the capability is present or not. If so, we read the configuration space to get the status of the feature (enabled or not). Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-4-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 9 +++++++++ include/hw/pci/pcie.h | 1 + 2 files changed, 10 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index db9756d861..36de709801 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1248,3 +1248,12 @@ bool pcie_pasid_enabled(const PCIDevice *dev) return (pci_get_word(dev->config + dev->exp.pasid_cap + PCI_PASID_CTRL) & PCI_PASID_CTRL_ENABLE) != 0; } + +bool pcie_ats_enabled(const PCIDevice *dev) +{ + if (!pci_is_express(dev) || !dev->exp.ats_cap) { + return false; + } + return (pci_get_word(dev->config + dev->exp.ats_cap + PCI_ATS_CTRL) & + PCI_ATS_CTRL_ENABLE) != 0; +} diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index dff98ff2c6..497d0bc2d2 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -156,4 +156,5 @@ void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, bool exec_perm, bool priv_mod); bool pcie_pasid_enabled(const PCIDevice *dev); +bool pcie_ats_enabled(const PCIDevice *dev); #endif /* QEMU_PCIE_H */ From dcad6cb2abf4ffc4f911041d0547c4b54c2f92e2 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:54 +0000 Subject: [PATCH 1335/2760] pcie: Add a helper to declare the PRI capability for a pcie device Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-5-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 26 ++++++++++++++++++++++++++ include/hw/pci/pcie.h | 5 ++++- include/hw/pci/pcie_regs.h | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 36de709801..542172b3fa 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1240,6 +1240,32 @@ void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, dev->exp.pasid_cap = offset; } +/* PRI */ +void pcie_pri_init(PCIDevice *dev, uint16_t offset, uint32_t outstanding_pr_cap, + bool prg_response_pasid_req) +{ + static const uint16_t control_reg_rw_mask = 0x3; + static const uint16_t status_reg_rw1_mask = 0x3; + static const uint32_t pr_alloc_reg_rw_mask = 0xffffffff; + uint16_t status_reg; + + status_reg = prg_response_pasid_req ? PCI_PRI_STATUS_PASID : 0; + status_reg |= PCI_PRI_STATUS_STOPPED; /* Stopped by default */ + + pcie_add_capability(dev, PCI_EXT_CAP_ID_PRI, PCI_PRI_VER, offset, + PCI_EXT_CAP_PRI_SIZEOF); + /* Disabled by default */ + + pci_set_word(dev->config + offset + PCI_PRI_STATUS, status_reg); + pci_set_long(dev->config + offset + PCI_PRI_MAX_REQ, outstanding_pr_cap); + + pci_set_word(dev->wmask + offset + PCI_PRI_CTRL, control_reg_rw_mask); + pci_set_word(dev->w1cmask + offset + PCI_PRI_STATUS, status_reg_rw1_mask); + pci_set_long(dev->wmask + offset + PCI_PRI_ALLOC_REQ, pr_alloc_reg_rw_mask); + + dev->exp.pri_cap = offset; +} + bool pcie_pasid_enabled(const PCIDevice *dev) { if (!pci_is_express(dev) || !dev->exp.pasid_cap) { diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 497d0bc2d2..17f06cd5d6 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -70,9 +70,10 @@ struct PCIExpressDevice { uint16_t aer_cap; PCIEAERLog aer_log; - /* Offset of ATS and PASID capabilities in config space */ + /* Offset of ATS, PRI and PASID capabilities in config space */ uint16_t ats_cap; uint16_t pasid_cap; + uint16_t pri_cap; /* ACS */ uint16_t acs_cap; @@ -154,6 +155,8 @@ void pcie_cap_slot_unplug_request_cb(HotplugHandler *hotplug_dev, void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, bool exec_perm, bool priv_mod); +void pcie_pri_init(PCIDevice *dev, uint16_t offset, uint32_t outstanding_pr_cap, + bool prg_response_pasid_req); bool pcie_pasid_enabled(const PCIDevice *dev); bool pcie_ats_enabled(const PCIDevice *dev); diff --git a/include/hw/pci/pcie_regs.h b/include/hw/pci/pcie_regs.h index 4d9cf4a29c..33a22229fe 100644 --- a/include/hw/pci/pcie_regs.h +++ b/include/hw/pci/pcie_regs.h @@ -91,6 +91,9 @@ typedef enum PCIExpLinkWidth { #define PCI_EXT_CAP_PASID_MAX_WIDTH 20 #define PCI_PASID_CAP_WIDTH_SHIFT 8 +/* PRI */ +#define PCI_PRI_VER 1 + /* AER */ #define PCI_ERR_VER 2 #define PCI_ERR_SIZEOF 0x48 From 5be8cf79188a2a1c73d16f3a8b458d909ac976f4 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:57 +0000 Subject: [PATCH 1336/2760] pcie: Helper functions to check to check if PRI is enabled pri_enabled can be used to check whether the capability is present and enabled on a PCIe device Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-6-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pcie.c | 9 +++++++++ include/hw/pci/pcie.h | 1 + 2 files changed, 10 insertions(+) diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 542172b3fa..eaeb68894e 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1266,6 +1266,15 @@ void pcie_pri_init(PCIDevice *dev, uint16_t offset, uint32_t outstanding_pr_cap, dev->exp.pri_cap = offset; } +bool pcie_pri_enabled(const PCIDevice *dev) +{ + if (!pci_is_express(dev) || !dev->exp.pri_cap) { + return false; + } + return (pci_get_word(dev->config + dev->exp.pri_cap + PCI_PRI_CTRL) & + PCI_PRI_CTRL_ENABLE) != 0; +} + bool pcie_pasid_enabled(const PCIDevice *dev) { if (!pci_is_express(dev) || !dev->exp.pasid_cap) { diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index 17f06cd5d6..ff6ce08e13 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -158,6 +158,7 @@ void pcie_pasid_init(PCIDevice *dev, uint16_t offset, uint8_t pasid_width, void pcie_pri_init(PCIDevice *dev, uint16_t offset, uint32_t outstanding_pr_cap, bool prg_response_pasid_req); +bool pcie_pri_enabled(const PCIDevice *dev); bool pcie_pasid_enabled(const PCIDevice *dev); bool pcie_ats_enabled(const PCIDevice *dev); #endif /* QEMU_PCIE_H */ From 8ff9e1def0ef3388333b6cc639c9f958f97ebe05 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:58 +0000 Subject: [PATCH 1337/2760] pci: Cache the bus mastering status in the device The cached is_master value is necessary to know if a device is allowed to issue ATS/PRI requests or not as these operations do not go through the master_enable memory region. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-7-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 23 +++++++++++++---------- include/hw/pci/pci_device.h | 1 + 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index f5ab510697..1114ba8529 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -128,6 +128,12 @@ static GSequence *pci_acpi_index_list(void) return used_acpi_index_list; } +static void pci_set_master(PCIDevice *d, bool enable) +{ + memory_region_set_enabled(&d->bus_master_enable_region, enable); + d->is_master = enable; /* cache the status */ +} + static void pci_init_bus_master(PCIDevice *pci_dev) { AddressSpace *dma_as = pci_device_iommu_address_space(pci_dev); @@ -135,7 +141,7 @@ static void pci_init_bus_master(PCIDevice *pci_dev) memory_region_init_alias(&pci_dev->bus_master_enable_region, OBJECT(pci_dev), "bus master", dma_as->root, 0, memory_region_size(dma_as->root)); - memory_region_set_enabled(&pci_dev->bus_master_enable_region, false); + pci_set_master(pci_dev, false); memory_region_add_subregion(&pci_dev->bus_master_container_region, 0, &pci_dev->bus_master_enable_region); } @@ -804,9 +810,8 @@ static int get_pci_config_device(QEMUFile *f, void *pv, size_t size, pci_bridge_update_mappings(PCI_BRIDGE(s)); } - memory_region_set_enabled(&s->bus_master_enable_region, - pci_get_word(s->config + PCI_COMMAND) - & PCI_COMMAND_MASTER); + pci_set_master(s, pci_get_word(s->config + PCI_COMMAND) + & PCI_COMMAND_MASTER); g_free(config); return 0; @@ -1787,9 +1792,8 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val_in, int if (ranges_overlap(addr, l, PCI_COMMAND, 2)) { pci_update_irq_disabled(d, was_irq_disabled); - memory_region_set_enabled(&d->bus_master_enable_region, - (pci_get_word(d->config + PCI_COMMAND) - & PCI_COMMAND_MASTER) && d->enabled); + pci_set_master(d, (pci_get_word(d->config + PCI_COMMAND) & + PCI_COMMAND_MASTER) && d->enabled); } msi_write_config(d, addr, val_in, l); @@ -3100,9 +3104,8 @@ void pci_set_enabled(PCIDevice *d, bool state) d->enabled = state; pci_update_mappings(d); - memory_region_set_enabled(&d->bus_master_enable_region, - (pci_get_word(d->config + PCI_COMMAND) - & PCI_COMMAND_MASTER) && d->enabled); + pci_set_master(d, (pci_get_word(d->config + PCI_COMMAND) + & PCI_COMMAND_MASTER) && d->enabled); if (qdev_is_realized(&d->qdev)) { pci_device_reset(d); } diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h index e41d95b0b0..eee0338568 100644 --- a/include/hw/pci/pci_device.h +++ b/include/hw/pci/pci_device.h @@ -90,6 +90,7 @@ struct PCIDevice { char name[64]; PCIIORegion io_regions[PCI_NUM_REGIONS]; AddressSpace bus_master_as; + bool is_master; MemoryRegion bus_master_container_region; MemoryRegion bus_master_enable_region; From 042cbc9aec7caca639dcb1a8a996406a7c572706 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:18:59 +0000 Subject: [PATCH 1338/2760] pci: Add an API to get IOMMU's min page size and virtual address width This kind of information is needed by devices implementing ATS in order to initialize their translation cache. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-8-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 17 +++++++++++++++++ include/hw/pci/pci.h | 26 ++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 1114ba8529..fc4954ac81 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2970,6 +2970,23 @@ void pci_device_unset_iommu_device(PCIDevice *dev) } } +int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, + uint32_t *min_page_size) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->get_iotlb_info) { + iommu_bus->iommu_ops->get_iotlb_info(iommu_bus->iommu_opaque, + addr_width, min_page_size); + return 0; + } + + return -ENODEV; +} + void pci_setup_iommu(PCIBus *bus, const PCIIOMMUOps *ops, void *opaque) { /* diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index c2fe6caa2c..d67ffe12db 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -429,6 +429,19 @@ typedef struct PCIIOMMUOps { * @devfn: device and function number of the PCI device. */ void (*unset_iommu_device)(PCIBus *bus, void *opaque, int devfn); + /** + * @get_iotlb_info: get properties required to initialize a device IOTLB. + * + * Callback required if devices are allowed to cache translations. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @addr_width: the address width of the IOMMU (output parameter). + * + * @min_page_size: the page size of the IOMMU (output parameter). + */ + void (*get_iotlb_info)(void *opaque, uint8_t *addr_width, + uint32_t *min_page_size); } PCIIOMMUOps; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); @@ -436,6 +449,19 @@ bool pci_device_set_iommu_device(PCIDevice *dev, HostIOMMUDevice *hiod, Error **errp); void pci_device_unset_iommu_device(PCIDevice *dev); +/** + * pci_iommu_get_iotlb_info: get properties required to initialize a + * device IOTLB. + * + * Returns 0 on success, or a negative errno otherwise. + * + * @dev: the device that wants to get the information. + * @addr_width: the address width of the IOMMU (output parameter). + * @min_page_size: the page size of the IOMMU (output parameter). + */ +int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, + uint32_t *min_page_size); + /** * pci_setup_iommu: Initialize specific IOMMU handlers for a PCIBus * From 7e94e45296d68982d448ae57e195efcf8f66649e Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:19:00 +0000 Subject: [PATCH 1339/2760] memory: Store user data pointer in the IOMMU notifiers This will help developers of ATS-capable devices to track a state. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-9-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/system/memory.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/system/memory.h b/include/system/memory.h index fbbf4cf911..fc35a0dcad 100644 --- a/include/system/memory.h +++ b/include/system/memory.h @@ -183,6 +183,7 @@ struct IOMMUNotifier { hwaddr start; hwaddr end; int iommu_idx; + void *opaque; QLIST_ENTRY(IOMMUNotifier) node; }; typedef struct IOMMUNotifier IOMMUNotifier; From a849ff5d6fa9d263beaecd6421fff8e21d2591c8 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:19:01 +0000 Subject: [PATCH 1340/2760] pci: Add a pci-level initialization function for IOMMU notifiers This is meant to be used by ATS-capable devices. Signed-off-by: Clement Mathieu--Drif Message-Id: <20250520071823.764266-10-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 17 +++++++++++++++++ include/hw/pci/pci.h | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index fc4954ac81..dfa5a0259e 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2939,6 +2939,23 @@ AddressSpace *pci_device_iommu_address_space(PCIDevice *dev) return &address_space_memory; } +int pci_iommu_init_iotlb_notifier(PCIDevice *dev, IOMMUNotifier *n, + IOMMUNotify fn, void *opaque) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->init_iotlb_notifier) { + iommu_bus->iommu_ops->init_iotlb_notifier(bus, iommu_bus->iommu_opaque, + devfn, n, fn, opaque); + return 0; + } + + return -ENODEV; +} + bool pci_device_set_iommu_device(PCIDevice *dev, HostIOMMUDevice *hiod, Error **errp) { diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index d67ffe12db..f3016fd76f 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -442,6 +442,26 @@ typedef struct PCIIOMMUOps { */ void (*get_iotlb_info)(void *opaque, uint8_t *addr_width, uint32_t *min_page_size); + /** + * @init_iotlb_notifier: initialize an IOMMU notifier. + * + * Optional callback. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @n: the notifier to be initialized. + * + * @fn: the callback to be installed. + * + * @user_opaque: a user pointer that can be used to track a state. + */ + void (*init_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn, + IOMMUNotifier *n, IOMMUNotify fn, + void *user_opaque); } PCIIOMMUOps; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); @@ -462,6 +482,19 @@ void pci_device_unset_iommu_device(PCIDevice *dev); int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, uint32_t *min_page_size); +/** + * pci_iommu_init_iotlb_notifier: initialize an IOMMU notifier. + * + * This function is used by devices before registering an IOTLB notifier. + * + * @dev: the device. + * @n: the notifier to be initialized. + * @fn: the callback to be installed. + * @opaque: a user pointer that can be used to track a state. + */ +int pci_iommu_init_iotlb_notifier(PCIDevice *dev, IOMMUNotifier *n, + IOMMUNotify fn, void *opaque); + /** * pci_setup_iommu: Initialize specific IOMMU handlers for a PCIBus * From e9b457500adb023229a08ece3a8d7f5866dd360e Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:19:03 +0000 Subject: [PATCH 1341/2760] pci: Add a pci-level API for ATS Devices implementing ATS can send translation requests using pci_ats_request_translation. The invalidation events are sent back to the device using the iommu notifier managed with pci_iommu_register_iotlb_notifier / pci_iommu_unregister_iotlb_notifier. Signed-off-by: Clement Mathieu--Drif Co-authored-by: Ethan Milon Message-Id: <20250520071823.764266-11-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 81 ++++++++++++++++++++++++++++ include/hw/pci/pci.h | 126 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index dfa5a0259e..0c63cb4bbe 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2987,6 +2987,87 @@ void pci_device_unset_iommu_device(PCIDevice *dev) } } +ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid, + bool priv_req, bool exec_req, + hwaddr addr, size_t length, + bool no_write, IOMMUTLBEntry *result, + size_t result_length, + uint32_t *err_count) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if (!dev->is_master || + ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) { + return -EPERM; + } + + if (result_length == 0) { + return -ENOSPC; + } + + if (!pcie_ats_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->ats_request_translation) { + return iommu_bus->iommu_ops->ats_request_translation(bus, + iommu_bus->iommu_opaque, + devfn, pasid, priv_req, + exec_req, addr, length, + no_write, result, + result_length, err_count); + } + + return -ENODEV; +} + +int pci_iommu_register_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->register_iotlb_notifier) { + iommu_bus->iommu_ops->register_iotlb_notifier(bus, + iommu_bus->iommu_opaque, devfn, + pasid, n); + return 0; + } + + return -ENODEV; +} + +int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->unregister_iotlb_notifier) { + iommu_bus->iommu_ops->unregister_iotlb_notifier(bus, + iommu_bus->iommu_opaque, + devfn, pasid, n); + return 0; + } + + return -ENODEV; +} + int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, uint32_t *min_page_size) { diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index f3016fd76f..5d72607ed5 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -462,6 +462,80 @@ typedef struct PCIIOMMUOps { void (*init_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn, IOMMUNotifier *n, IOMMUNotify fn, void *user_opaque); + /** + * @register_iotlb_notifier: setup an IOTLB invalidation notifier. + * + * Callback required if devices are allowed to cache translations. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to watch. + * + * @n: the notifier to register. + */ + void (*register_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid, IOMMUNotifier *n); + /** + * @unregister_iotlb_notifier: remove an IOTLB invalidation notifier. + * + * Callback required if devices are allowed to cache translations. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to stop watching. + * + * @n: the notifier to unregister. + */ + void (*unregister_iotlb_notifier)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid, IOMMUNotifier *n); + /** + * @ats_request_translation: issue an ATS request. + * + * Callback required if devices are allowed to use the address + * translation service. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to use for the request. + * + * @priv_req: privileged mode bit (PASID TLP). + * + * @exec_req: execute request bit (PASID TLP). + * + * @addr: start address of the memory range to be translated. + * + * @length: length of the memory range in bytes. + * + * @no_write: request a read-only translation (if supported). + * + * @result: buffer in which the TLB entries will be stored. + * + * @result_length: result buffer length. + * + * @err_count: number of untranslated subregions. + * + * Returns: the number of translations stored in the result buffer, or + * -ENOMEM if the buffer is not large enough. + */ + ssize_t (*ats_request_translation)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid, bool priv_req, + bool exec_req, hwaddr addr, + size_t length, bool no_write, + IOMMUTLBEntry *result, + size_t result_length, + uint32_t *err_count); } PCIIOMMUOps; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); @@ -495,6 +569,58 @@ int pci_iommu_get_iotlb_info(PCIDevice *dev, uint8_t *addr_width, int pci_iommu_init_iotlb_notifier(PCIDevice *dev, IOMMUNotifier *n, IOMMUNotify fn, void *opaque); +/** + * pci_ats_request_translation: perform an ATS request. + * + * Returns the number of translations stored in @result in case of success, + * a negative error code otherwise. + * -ENOMEM is returned when the result buffer is not large enough to store + * all the translations. + * + * @dev: the ATS-capable PCI device. + * @pasid: the pasid of the address space in which the translation will be done. + * @priv_req: privileged mode bit (PASID TLP). + * @exec_req: execute request bit (PASID TLP). + * @addr: start address of the memory range to be translated. + * @length: length of the memory range in bytes. + * @no_write: request a read-only translation (if supported). + * @result: buffer in which the TLB entries will be stored. + * @result_length: result buffer length. + * @err_count: number of untranslated subregions. + */ +ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid, + bool priv_req, bool exec_req, + hwaddr addr, size_t length, + bool no_write, IOMMUTLBEntry *result, + size_t result_length, + uint32_t *err_count); + +/** + * pci_iommu_register_iotlb_notifier: register a notifier for changes to + * IOMMU translation entries in a specific address space. + * + * Returns 0 on success, or a negative errno otherwise. + * + * @dev: the device that wants to get notified. + * @pasid: the pasid of the address space to track. + * @n: the notifier to register. + */ +int pci_iommu_register_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n); + +/** + * pci_iommu_unregister_iotlb_notifier: unregister a notifier that has been + * registerd with pci_iommu_register_iotlb_notifier. + * + * Returns 0 on success, or a negative errno otherwise. + * + * @dev: the device that wants to stop notifications. + * @pasid: the pasid of the address space to stop tracking. + * @n: the notifier to unregister. + */ +int pci_iommu_unregister_iotlb_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUNotifier *n); + /** * pci_setup_iommu: Initialize specific IOMMU handlers for a PCIBus * From f0f37daf8e67c7208641aec5e238197279ca7331 Mon Sep 17 00:00:00 2001 From: CLEMENT MATHIEU--DRIF Date: Tue, 20 May 2025 07:19:04 +0000 Subject: [PATCH 1342/2760] pci: Add a PCI-level API for PRI A device can send a PRI request to the IOMMU using pci_pri_request_page. The PRI response is sent back using the notifier managed with pci_pri_register_notifier and pci_pri_unregister_notifier. Signed-off-by: Clement Mathieu--Drif Co-authored-by: Ethan Milon Message-Id: <20250520071823.764266-12-clement.mathieu--drif@eviden.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 66 ++++++++++++++++++++++ include/hw/pci/pci.h | 130 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 0c63cb4bbe..c6b5768f3a 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -2987,6 +2987,72 @@ void pci_device_unset_iommu_device(PCIDevice *dev) } } +int pci_pri_request_page(PCIDevice *dev, uint32_t pasid, bool priv_req, + bool exec_req, hwaddr addr, bool lpig, + uint16_t prgi, bool is_read, bool is_write) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if (!dev->is_master || + ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) { + return -EPERM; + } + + if (!pcie_pri_enabled(dev)) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->pri_request_page) { + return iommu_bus->iommu_ops->pri_request_page(bus, + iommu_bus->iommu_opaque, + devfn, pasid, priv_req, + exec_req, addr, lpig, prgi, + is_read, is_write); + } + + return -ENODEV; +} + +int pci_pri_register_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUPRINotifier *notifier) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + if (!dev->is_master || + ((pasid != PCI_NO_PASID) && !pcie_pasid_enabled(dev))) { + return -EPERM; + } + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->pri_register_notifier) { + iommu_bus->iommu_ops->pri_register_notifier(bus, + iommu_bus->iommu_opaque, + devfn, pasid, notifier); + return 0; + } + + return -ENODEV; +} + +void pci_pri_unregister_notifier(PCIDevice *dev, uint32_t pasid) +{ + PCIBus *bus; + PCIBus *iommu_bus; + int devfn; + + pci_device_get_iommu_bus_devfn(dev, &bus, &iommu_bus, &devfn); + if (iommu_bus && iommu_bus->iommu_ops->pri_unregister_notifier) { + iommu_bus->iommu_ops->pri_unregister_notifier(bus, + iommu_bus->iommu_opaque, + devfn, pasid); + } +} + ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid, bool priv_req, bool exec_req, hwaddr addr, size_t length, diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 5d72607ed5..a6854dad2b 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -375,6 +375,28 @@ void pci_bus_get_w64_range(PCIBus *bus, Range *range); void pci_device_deassert_intx(PCIDevice *dev); +/* Page Request Interface */ +typedef enum { + IOMMU_PRI_RESP_SUCCESS, + IOMMU_PRI_RESP_INVALID_REQUEST, + IOMMU_PRI_RESP_FAILURE, +} IOMMUPRIResponseCode; + +typedef struct IOMMUPRIResponse { + IOMMUPRIResponseCode response_code; + uint16_t prgi; +} IOMMUPRIResponse; + +struct IOMMUPRINotifier; + +typedef void (*IOMMUPRINotify)(struct IOMMUPRINotifier *notifier, + IOMMUPRIResponse *response); + +typedef struct IOMMUPRINotifier { + IOMMUPRINotify notify; +} IOMMUPRINotifier; + +#define PCI_PRI_PRGI_MASK 0x1ffU /** * struct PCIIOMMUOps: callbacks structure for specific IOMMU handlers @@ -536,6 +558,72 @@ typedef struct PCIIOMMUOps { IOMMUTLBEntry *result, size_t result_length, uint32_t *err_count); + /** + * @pri_register_notifier: setup the PRI completion callback. + * + * Callback required if devices are allowed to use the page request + * interface. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to track. + * + * @notifier: the notifier to register. + */ + void (*pri_register_notifier)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid, IOMMUPRINotifier *notifier); + /** + * @pri_unregister_notifier: remove the PRI completion callback. + * + * Callback required if devices are allowed to use the page request + * interface. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to stop tracking. + */ + void (*pri_unregister_notifier)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid); + /** + * @pri_request_page: issue a PRI request. + * + * Callback required if devices are allowed to use the page request + * interface. + * + * @bus: the #PCIBus of the PCI device. + * + * @opaque: the data passed to pci_setup_iommu(). + * + * @devfn: device and function number of the PCI device. + * + * @pasid: the pasid of the address space to use for the request. + * + * @priv_req: privileged mode bit (PASID TLP). + * + * @exec_req: execute request bit (PASID TLP). + * + * @addr: untranslated address of the requested page. + * + * @lpig: last page in group. + * + * @prgi: page request group index. + * + * @is_read: request read access. + * + * @is_write: request write access. + */ + int (*pri_request_page)(PCIBus *bus, void *opaque, int devfn, + uint32_t pasid, bool priv_req, bool exec_req, + hwaddr addr, bool lpig, uint16_t prgi, bool is_read, + bool is_write); } PCIIOMMUOps; AddressSpace *pci_device_iommu_address_space(PCIDevice *dev); @@ -595,6 +683,48 @@ ssize_t pci_ats_request_translation(PCIDevice *dev, uint32_t pasid, size_t result_length, uint32_t *err_count); +/** + * pci_pri_request_page: perform a PRI request. + * + * Returns 0 if the PRI request has been sent to the guest OS, + * an error code otherwise. + * + * @dev: the PRI-capable PCI device. + * @pasid: the pasid of the address space in which the translation will be done. + * @priv_req: privileged mode bit (PASID TLP). + * @exec_req: execute request bit (PASID TLP). + * @addr: untranslated address of the requested page. + * @lpig: last page in group. + * @prgi: page request group index. + * @is_read: request read access. + * @is_write: request write access. + */ +int pci_pri_request_page(PCIDevice *dev, uint32_t pasid, bool priv_req, + bool exec_req, hwaddr addr, bool lpig, + uint16_t prgi, bool is_read, bool is_write); + +/** + * pci_pri_register_notifier: register the PRI callback for a given address + * space. + * + * Returns 0 on success, an error code otherwise. + * + * @dev: the PRI-capable PCI device. + * @pasid: the pasid of the address space to track. + * @notifier: the notifier to register. + */ +int pci_pri_register_notifier(PCIDevice *dev, uint32_t pasid, + IOMMUPRINotifier *notifier); + +/** + * pci_pri_unregister_notifier: remove the PRI callback from a given address + * space. + * + * @dev: the PRI-capable PCI device. + * @pasid: the pasid of the address space to stop tracking. + */ +void pci_pri_unregister_notifier(PCIDevice *dev, uint32_t pasid); + /** * pci_iommu_register_iotlb_notifier: register a notifier for changes to * IOMMU translation entries in a specific address space. From 75d4680c55498d6cf4f89b31e52d97f90d7fc46e Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 20 May 2025 21:01:51 +0800 Subject: [PATCH 1343/2760] uefi-test-tools:: Add LoongArch64 support Add support to build bios-tables-test iso image for LoongArch system. Signed-off-by: Bibo Mao Acked-by: Gerd Hoffmann Message-Id: <20250520130158.767083-2-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/uefi-test-tools/Makefile | 5 +++-- .../UefiTestToolsPkg/UefiTestToolsPkg.dsc | 6 +++++- tests/uefi-test-tools/uefi-test-build.config | 10 ++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/uefi-test-tools/Makefile b/tests/uefi-test-tools/Makefile index f4eaebd8ff..8ee6fb3571 100644 --- a/tests/uefi-test-tools/Makefile +++ b/tests/uefi-test-tools/Makefile @@ -12,7 +12,7 @@ edk2_dir := ../../roms/edk2 images_dir := ../data/uefi-boot-images -emulation_targets := arm aarch64 i386 x86_64 riscv64 +emulation_targets := arm aarch64 i386 x86_64 riscv64 loongarch64 uefi_binaries := bios-tables-test intermediate_suffixes := .efi .fat .iso.raw @@ -56,7 +56,8 @@ Build/%.iso.raw: Build/%.fat # stripped from, the argument. map_arm_to_uefi = $(subst arm,ARM,$(1)) map_aarch64_to_uefi = $(subst aarch64,AA64,$(call map_arm_to_uefi,$(1))) -map_riscv64_to_uefi = $(subst riscv64,RISCV64,$(call map_aarch64_to_uefi,$(1))) +map_loongarch64_to_uefi = $(subst loongarch64,LOONGARCH64,$(call map_aarch64_to_uefi,$(1))) +map_riscv64_to_uefi = $(subst riscv64,RISCV64,$(call map_loongarch64_to_uefi,$(1))) map_i386_to_uefi = $(subst i386,IA32,$(call map_riscv64_to_uefi,$(1))) map_x86_64_to_uefi = $(subst x86_64,X64,$(call map_i386_to_uefi,$(1))) map_to_uefi = $(subst .,,$(call map_x86_64_to_uefi,$(1))) diff --git a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc index 0902fd3c73..facf8df1fa 100644 --- a/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc +++ b/tests/uefi-test-tools/UefiTestToolsPkg/UefiTestToolsPkg.dsc @@ -19,7 +19,7 @@ PLATFORM_VERSION = 0.1 PLATFORM_NAME = UefiTestTools SKUID_IDENTIFIER = DEFAULT - SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64|RISCV64 + SUPPORTED_ARCHITECTURES = ARM|AARCH64|IA32|X64|RISCV64|LOONGARCH64 BUILD_TARGETS = DEBUG [BuildOptions.IA32] @@ -65,6 +65,10 @@ [LibraryClasses.RISCV64] BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf +[LibraryClasses.LOONGARCH64] + BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf + StackCheckLib|MdePkg/Library/StackCheckLibNull/StackCheckLibNull.inf + [PcdsFixedAtBuild] gEfiMdePkgTokenSpaceGuid.PcdDebugPrintErrorLevel|0x8040004F gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x2F diff --git a/tests/uefi-test-tools/uefi-test-build.config b/tests/uefi-test-tools/uefi-test-build.config index a4c61fc97a..8bf4826634 100644 --- a/tests/uefi-test-tools/uefi-test-build.config +++ b/tests/uefi-test-tools/uefi-test-build.config @@ -21,6 +21,16 @@ dest = ./Build arch = AARCH64 cpy1 = AARCH64/BiosTablesTest.efi bios-tables-test.aarch64.efi +#################################################################################### +# loongarch64 + +[build.loongarch64] +conf = UefiTestToolsPkg/UefiTestToolsPkg.dsc +plat = UefiTestTools +dest = ./Build +arch = LOONGARCH64 +cpy1 = LOONGARCH64/BiosTablesTest.efi bios-tables-test.loongarch64.efi + #################################################################################### # riscv64 From 0265723eba8a612d8a94d190cef988cf8d616862 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 20 May 2025 21:01:52 +0800 Subject: [PATCH 1344/2760] tests/data/uefi-boot-images: Add ISO image for LoongArch system To test ACPI tables, edk2 needs to be booted with a disk image having EFI partition. This image is created using UefiTestToolsPkg. The image is generated with the following command: make -f tests/uefi-test-tools/Makefile Signed-off-by: Bibo Mao Acked-by: Gerd Hoffmann Message-Id: <20250520130158.767083-3-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- .../bios-tables-test.loongarch64.iso.qcow2 | Bin 0 -> 12800 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2 diff --git a/tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2 b/tests/data/uefi-boot-images/bios-tables-test.loongarch64.iso.qcow2 new file mode 100644 index 0000000000000000000000000000000000000000..18daee0c52fcc703a0645dbcdc598aa1f101d96b GIT binary patch literal 12800 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 q*e2oa Date: Tue, 20 May 2025 21:01:53 +0800 Subject: [PATCH 1345/2760] tests/qtest/bios-tables-test: Use MiB macro rather hardcode value Replace 1024 * 1024 with MiB macro. Signed-off-by: Bibo Mao Message-Id: <20250520130158.767083-4-maobibo@loongson.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- tests/qtest/bios-tables-test.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/qtest/bios-tables-test.c b/tests/qtest/bios-tables-test.c index 0a333ec435..0b2bdf9d0d 100644 --- a/tests/qtest/bios-tables-test.c +++ b/tests/qtest/bios-tables-test.c @@ -1622,7 +1622,7 @@ static void test_acpi_aarch64_virt_tcg_memhp(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 256ULL * 1024 * 1024, + .scan_len = 256ULL * MiB, }; data.variant = ".memhp"; @@ -1717,7 +1717,7 @@ static void test_acpi_riscv64_virt_tcg_numamem(void) .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2", .ram_start = 0x80000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; data.variant = ".numamem"; @@ -1743,7 +1743,7 @@ static void test_acpi_aarch64_virt_tcg_numamem(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; data.variant = ".numamem"; @@ -1765,7 +1765,7 @@ static void test_acpi_aarch64_virt_tcg_pxb(void) .uefi_fl1 = "pc-bios/edk2-aarch64-code.fd", .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; /* * While using -cdrom, the cdrom would auto plugged into pxb-pcie, @@ -1841,7 +1841,7 @@ static void test_acpi_aarch64_virt_tcg_acpi_hmat(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; data.variant = ".acpihmatvirt"; @@ -2095,7 +2095,7 @@ static void test_acpi_riscv64_virt_tcg(void) .uefi_fl2 = "pc-bios/edk2-riscv-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.riscv64.iso.qcow2", .ram_start = 0x80000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; /* @@ -2117,7 +2117,7 @@ static void test_acpi_aarch64_virt_tcg(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; data.smbios_cpu_max_speed = 2900; @@ -2138,7 +2138,7 @@ static void test_acpi_aarch64_virt_tcg_topology(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; test_acpi_one("-cpu cortex-a57 " @@ -2223,7 +2223,7 @@ static void test_acpi_aarch64_virt_viot(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; test_acpi_one("-cpu cortex-a57 " @@ -2407,7 +2407,7 @@ static void test_acpi_aarch64_virt_oem_fields(void) .uefi_fl2 = "pc-bios/edk2-arm-vars.fd", .cd = "tests/data/uefi-boot-images/bios-tables-test.aarch64.iso.qcow2", .ram_start = 0x40000000ULL, - .scan_len = 128ULL * 1024 * 1024, + .scan_len = 128ULL * MiB, }; char *args; From a9403bfcd93025df7b1924d0cf34fbc408955b33 Mon Sep 17 00:00:00 2001 From: Huaitong Han Date: Thu, 22 May 2025 18:05:48 +0800 Subject: [PATCH 1346/2760] vhost: Don't set vring call if guest notifier is unused The vring call fd is set even when the guest does not use MSI-X (e.g., in the case of virtio PMD), leading to unnecessary CPU overhead for processing interrupts. The commit 96a3d98d2c("vhost: don't set vring call if no vector") optimized the case where MSI-X is enabled but the queue vector is unset. However, there's an additional case where the guest uses INTx and the INTx_DISABLED bit in the PCI config is set, meaning that no interrupt notifier will actually be used. In such cases, the vring call fd should also be cleared to avoid redundant interrupt handling. Fixes: 96a3d98d2c("vhost: don't set vring call if no vector") Reported-by: Zhiyuan Yuan Signed-off-by: Jidong Xia Signed-off-by: Huaitong Han Message-Id: <20250522100548.212740-1-hanht2@chinatelecom.cn> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 2 +- hw/virtio/virtio-pci.c | 7 ++++++- include/hw/pci/pci.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index c6b5768f3a..9b4bf48439 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -1730,7 +1730,7 @@ static void pci_update_mappings(PCIDevice *d) pci_update_vga(d); } -static inline int pci_irq_disabled(PCIDevice *d) +int pci_irq_disabled(PCIDevice *d) { return pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE; } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 9b48aa8c3e..7e309d1d49 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -1215,7 +1215,12 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, static bool virtio_pci_query_guest_notifiers(DeviceState *d) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - return msix_enabled(&proxy->pci_dev); + + if (msix_enabled(&proxy->pci_dev)) { + return true; + } else { + return pci_irq_disabled(&proxy->pci_dev); + } } static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index a6854dad2b..35d59d7672 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -983,6 +983,7 @@ void lsi53c8xx_handle_legacy_cmdline(DeviceState *lsi_dev); qemu_irq pci_allocate_irq(PCIDevice *pci_dev); void pci_set_irq(PCIDevice *pci_dev, int level); +int pci_irq_disabled(PCIDevice *d); static inline void pci_irq_assert(PCIDevice *pci_dev) { From 55cf1d4f10160e37440d9e727a160ac1141bbb53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:33 -0400 Subject: [PATCH 1347/2760] vdpa: check for iova tree initialized at net_client_start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To map the guest memory while it is migrating we need to create the iova_tree, as long as the destination uses x-svq=on. Checking to not override it. The function vhost_vdpa_net_client_stop clear it if the device is stopped. If the guest starts the device again, the iova tree is recreated by vhost_vdpa_net_data_start_first or vhost_vdpa_net_cvq_start if needed, so old behavior is kept. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-2-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- net/vhost-vdpa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index 7ca8b46eee..decb826868 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -366,7 +366,9 @@ static void vhost_vdpa_net_data_start_first(VhostVDPAState *s) migration_add_notifier(&s->migration_state, vdpa_net_migration_state_notifier); - if (v->shadow_vqs_enabled) { + + /* iova_tree may be initialized by vhost_vdpa_net_load_setup */ + if (v->shadow_vqs_enabled && !v->shared->iova_tree) { v->shared->iova_tree = vhost_iova_tree_new(v->shared->iova_range.first, v->shared->iova_range.last); } From 3312e6c8c9aa8f32019f14c74d209db17b9306eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:34 -0400 Subject: [PATCH 1348/2760] vdpa: reorder vhost_vdpa_set_backend_cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It will be used directly by vhost_vdpa_init. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-3-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 60 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 1ab2c11fa8..6b242ca56a 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -594,6 +594,36 @@ static void vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v) v->shadow_vqs = g_steal_pointer(&shadow_vqs); } +static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) +{ + struct vhost_vdpa *v = dev->opaque; + + uint64_t features; + uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | + 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | + 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID | + 0x1ULL << VHOST_BACKEND_F_SUSPEND; + int r; + + if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { + return -EFAULT; + } + + features &= f; + + if (vhost_vdpa_first_dev(dev)) { + r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); + if (r) { + return -EFAULT; + } + } + + dev->backend_cap = features; + v->shared->backend_cap = features; + + return 0; +} + static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) { struct vhost_vdpa *v = opaque; @@ -841,36 +871,6 @@ static int vhost_vdpa_set_features(struct vhost_dev *dev, return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); } -static int vhost_vdpa_set_backend_cap(struct vhost_dev *dev) -{ - struct vhost_vdpa *v = dev->opaque; - - uint64_t features; - uint64_t f = 0x1ULL << VHOST_BACKEND_F_IOTLB_MSG_V2 | - 0x1ULL << VHOST_BACKEND_F_IOTLB_BATCH | - 0x1ULL << VHOST_BACKEND_F_IOTLB_ASID | - 0x1ULL << VHOST_BACKEND_F_SUSPEND; - int r; - - if (vhost_vdpa_call(dev, VHOST_GET_BACKEND_FEATURES, &features)) { - return -EFAULT; - } - - features &= f; - - if (vhost_vdpa_first_dev(dev)) { - r = vhost_vdpa_call(dev, VHOST_SET_BACKEND_FEATURES, &features); - if (r) { - return -EFAULT; - } - } - - dev->backend_cap = features; - v->shared->backend_cap = features; - - return 0; -} - static int vhost_vdpa_get_device_id(struct vhost_dev *dev, uint32_t *device_id) { From 32f0c7ce4c948b2e275dca3cf7fa2a00677b9c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:35 -0400 Subject: [PATCH 1349/2760] vdpa: set backend capabilities at vhost_vdpa_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend does not reset them until the vdpa file descriptor is closed so there is no harm in doing it only once. This allows the destination of a live migration to premap memory in batches, using VHOST_BACKEND_F_IOTLB_BATCH. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-4-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 6b242ca56a..e9826ede2c 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -634,6 +634,12 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) v->dev = dev; dev->opaque = opaque ; v->shared->listener = vhost_vdpa_memory_listener; + + ret = vhost_vdpa_set_backend_cap(dev); + if (unlikely(ret != 0)) { + return ret; + } + vhost_vdpa_init_svq(dev, v); error_propagate(&dev->migration_blocker, v->migration_blocker); @@ -1563,7 +1569,6 @@ const VhostOps vdpa_ops = { .vhost_set_vring_kick = vhost_vdpa_set_vring_kick, .vhost_set_vring_call = vhost_vdpa_set_vring_call, .vhost_get_features = vhost_vdpa_get_features, - .vhost_set_backend_cap = vhost_vdpa_set_backend_cap, .vhost_set_owner = vhost_vdpa_set_owner, .vhost_set_vring_endian = NULL, .vhost_backend_memslots_limit = vhost_vdpa_memslots_limit, From be2e5fbefa7c1f8243bf6db2486b950b1ab19b72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:36 -0400 Subject: [PATCH 1350/2760] vdpa: add listener_registered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check if the listener has been registered or not, so it needs to be registered again at start. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-5-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 7 ++++++- include/hw/virtio/vhost-vdpa.h | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index e9826ede2c..450f68f117 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -1379,7 +1379,10 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) "IOMMU and try again"); return -1; } - memory_listener_register(&v->shared->listener, dev->vdev->dma_as); + if (!v->shared->listener_registered) { + memory_listener_register(&v->shared->listener, dev->vdev->dma_as); + v->shared->listener_registered = true; + } return vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); } @@ -1399,6 +1402,8 @@ static void vhost_vdpa_reset_status(struct vhost_dev *dev) vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER); memory_listener_unregister(&v->shared->listener); + v->shared->listener_registered = false; + } static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index 0a9575b469..221840987e 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -51,6 +51,12 @@ typedef struct vhost_vdpa_shared { bool iotlb_batch_begin_sent; + /* + * The memory listener has been registered, so DMA maps have been sent to + * the device. + */ + bool listener_registered; + /* Vdpa must send shadow addresses as IOTLB key for data queues, not GPA */ bool shadow_data; From 9344dcbd004f951155c020d01c1bdc881e0451c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:37 -0400 Subject: [PATCH 1351/2760] vdpa: reorder listener assignment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit f6fe3e333f ("vdpa: move memory listener to vhost_vdpa_shared") this piece of code repeatedly assign shared->listener members. This was not a problem as it was not used until device start. However next patches move the listener registration to this vhost_vdpa_init function. When the listener is registered it is added to an embedded linked list, so setting its members again will cause memory corruption to the linked list node. Do the right thing and only set it in the first vdpa device. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-6-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index 450f68f117..de834f2ebd 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -633,7 +633,6 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) v->dev = dev; dev->opaque = opaque ; - v->shared->listener = vhost_vdpa_memory_listener; ret = vhost_vdpa_set_backend_cap(dev); if (unlikely(ret != 0)) { @@ -675,6 +674,7 @@ static int vhost_vdpa_init(struct vhost_dev *dev, void *opaque, Error **errp) vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER); + v->shared->listener = vhost_vdpa_memory_listener; return 0; } From a400720365ea86602044b78dd8654911d0fe3977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:38 -0400 Subject: [PATCH 1352/2760] vdpa: move iova_tree allocation to net_vhost_vdpa_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As we are moving to keep the mapping through all the vdpa device life instead of resetting it at VirtIO reset, we need to move all its dependencies to the initialization too. In particular devices with x-svq=on need a valid iova_tree from the beginning. Simplify the code also consolidating the two creation points: the first data vq in case of SVQ active and CVQ start in case only CVQ uses it. Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Suggested-by: Si-Wei Liu Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-7-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/virtio/vhost-vdpa.h | 16 ++++++++++++++- net/vhost-vdpa.c | 36 +++------------------------------- 2 files changed, 18 insertions(+), 34 deletions(-) diff --git a/include/hw/virtio/vhost-vdpa.h b/include/hw/virtio/vhost-vdpa.h index 221840987e..449bf5c840 100644 --- a/include/hw/virtio/vhost-vdpa.h +++ b/include/hw/virtio/vhost-vdpa.h @@ -43,7 +43,21 @@ typedef struct vhost_vdpa_shared { struct vhost_vdpa_iova_range iova_range; QLIST_HEAD(, vdpa_iommu) iommu_list; - /* IOVA mapping used by the Shadow Virtqueue */ + /* + * IOVA mapping used by the Shadow Virtqueue + * + * It is shared among all ASID for simplicity, whether CVQ shares ASID with + * guest or not: + * - Memory listener need access to guest's memory addresses allocated in + * the IOVA tree. + * - There should be plenty of IOVA address space for both ASID not to + * worry about collisions between them. Guest's translations are still + * validated with virtio virtqueue_pop so there is no risk for the guest + * to access memory that it shouldn't. + * + * To allocate a iova tree per ASID is doable but it complicates the code + * and it is not worth it for the moment. + */ VhostIOVATree *iova_tree; /* Copy of backend features */ diff --git a/net/vhost-vdpa.c b/net/vhost-vdpa.c index decb826868..58d738945d 100644 --- a/net/vhost-vdpa.c +++ b/net/vhost-vdpa.c @@ -235,6 +235,7 @@ static void vhost_vdpa_cleanup(NetClientState *nc) return; } qemu_close(s->vhost_vdpa.shared->device_fd); + g_clear_pointer(&s->vhost_vdpa.shared->iova_tree, vhost_iova_tree_delete); g_free(s->vhost_vdpa.shared); } @@ -362,16 +363,8 @@ static int vdpa_net_migration_state_notifier(NotifierWithReturn *notifier, static void vhost_vdpa_net_data_start_first(VhostVDPAState *s) { - struct vhost_vdpa *v = &s->vhost_vdpa; - migration_add_notifier(&s->migration_state, vdpa_net_migration_state_notifier); - - /* iova_tree may be initialized by vhost_vdpa_net_load_setup */ - if (v->shadow_vqs_enabled && !v->shared->iova_tree) { - v->shared->iova_tree = vhost_iova_tree_new(v->shared->iova_range.first, - v->shared->iova_range.last); - } } static int vhost_vdpa_net_data_start(NetClientState *nc) @@ -418,19 +411,12 @@ static int vhost_vdpa_net_data_load(NetClientState *nc) static void vhost_vdpa_net_client_stop(NetClientState *nc) { VhostVDPAState *s = DO_UPCAST(VhostVDPAState, nc, nc); - struct vhost_dev *dev; assert(nc->info->type == NET_CLIENT_DRIVER_VHOST_VDPA); if (s->vhost_vdpa.index == 0) { migration_remove_notifier(&s->migration_state); } - - dev = s->vhost_vdpa.dev; - if (dev->vq_index + dev->nvqs == dev->vq_index_end) { - g_clear_pointer(&s->vhost_vdpa.shared->iova_tree, - vhost_iova_tree_delete); - } } static NetClientInfo net_vhost_vdpa_info = { @@ -602,24 +588,6 @@ out: return 0; } - /* - * If other vhost_vdpa already have an iova_tree, reuse it for simplicity, - * whether CVQ shares ASID with guest or not, because: - * - Memory listener need access to guest's memory addresses allocated in - * the IOVA tree. - * - There should be plenty of IOVA address space for both ASID not to - * worry about collisions between them. Guest's translations are still - * validated with virtio virtqueue_pop so there is no risk for the guest - * to access memory that it shouldn't. - * - * To allocate a iova tree per ASID is doable but it complicates the code - * and it is not worth it for the moment. - */ - if (!v->shared->iova_tree) { - v->shared->iova_tree = vhost_iova_tree_new(v->shared->iova_range.first, - v->shared->iova_range.last); - } - r = vhost_vdpa_cvq_map_buf(&s->vhost_vdpa, s->cvq_cmd_out_buffer, vhost_vdpa_net_cvq_cmd_page_len(), false); if (unlikely(r < 0)) { @@ -1728,6 +1696,8 @@ static NetClientState *net_vhost_vdpa_init(NetClientState *peer, s->vhost_vdpa.shared->device_fd = vdpa_device_fd; s->vhost_vdpa.shared->iova_range = iova_range; s->vhost_vdpa.shared->shadow_data = svq; + s->vhost_vdpa.shared->iova_tree = vhost_iova_tree_new(iova_range.first, + iova_range.last); } else if (!is_datapath) { s->cvq_cmd_out_buffer = mmap(NULL, vhost_vdpa_net_cvq_cmd_page_len(), PROT_READ | PROT_WRITE, From 494c50dcc0995ae6eb526d2848c33cbf910ab218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eugenio=20P=C3=A9rez?= Date: Thu, 22 May 2025 10:58:39 -0400 Subject: [PATCH 1353/2760] vdpa: move memory listener register to vhost_vdpa_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Current memory operations like pinning may take a lot of time at the destination. Currently they are done after the source of the migration is stopped, and before the workload is resumed at the destination. This is a period where neigher traffic can flow, nor the VM workload can continue (downtime). We can do better as we know the memory layout of the guest RAM at the destination from the moment that all devices are initializaed. So moving that operation allows QEMU to communicate the kernel the maps while the workload is still running in the source, so Linux can start mapping them. As a small drawback, there is a time in the initialization where QEMU cannot respond to QMP etc. By some testing, this time is about 0.2seconds. This may be further reduced (or increased) depending on the vdpa driver and the platform hardware, and it is dominated by the cost of memory pinning. This matches the time that we move out of the called downtime window. The downtime is measured as the elapsed trace time between the last vhost_vdpa_suspend on the source and the last vhost_vdpa_set_vring_enable_one on the destination. In other words, from "guest CPUs freeze" to the instant the final Rx/Tx queue-pair is able to start moving data. Using ConnectX-6 Dx (MLX5) NICs in vhost-vDPA mode with 8 queue-pairs, the series reduces guest-visible downtime during back-to-back live migrations by more than half: - 39G VM: 4.72s -> 2.09s (-2.63s, ~56% improvement) - 128G VM: 14.72s -> 5.83s (-8.89s, ~60% improvement) Tested-by: Lei Yang Reviewed-by: Si-Wei Liu Acked-by: Jason Wang Signed-off-by: Eugenio Pérez Signed-off-by: Jonah Palmer Message-Id: <20250522145839.59974-8-jonah.palmer@oracle.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/virtio/vhost-vdpa.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/hw/virtio/vhost-vdpa.c b/hw/virtio/vhost-vdpa.c index de834f2ebd..e20da95f30 100644 --- a/hw/virtio/vhost-vdpa.c +++ b/hw/virtio/vhost-vdpa.c @@ -894,8 +894,14 @@ static int vhost_vdpa_reset_device(struct vhost_dev *dev) ret = vhost_vdpa_call(dev, VHOST_VDPA_SET_STATUS, &status); trace_vhost_vdpa_reset_device(dev); + if (ret) { + return ret; + } + + memory_listener_unregister(&v->shared->listener); + v->shared->listener_registered = false; v->suspended = false; - return ret; + return 0; } static int vhost_vdpa_get_vq_index(struct vhost_dev *dev, int idx) @@ -1379,6 +1385,11 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) "IOMMU and try again"); return -1; } + if (v->shared->listener_registered && + dev->vdev->dma_as != v->shared->listener.address_space) { + memory_listener_unregister(&v->shared->listener); + v->shared->listener_registered = false; + } if (!v->shared->listener_registered) { memory_listener_register(&v->shared->listener, dev->vdev->dma_as); v->shared->listener_registered = true; @@ -1392,8 +1403,6 @@ static int vhost_vdpa_dev_start(struct vhost_dev *dev, bool started) static void vhost_vdpa_reset_status(struct vhost_dev *dev) { - struct vhost_vdpa *v = dev->opaque; - if (!vhost_vdpa_last_dev(dev)) { return; } @@ -1401,9 +1410,6 @@ static void vhost_vdpa_reset_status(struct vhost_dev *dev) vhost_vdpa_reset_device(dev); vhost_vdpa_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE | VIRTIO_CONFIG_S_DRIVER); - memory_listener_unregister(&v->shared->listener); - v->shared->listener_registered = false; - } static int vhost_vdpa_set_log_base(struct vhost_dev *dev, uint64_t base, @@ -1537,12 +1543,27 @@ static int vhost_vdpa_get_features(struct vhost_dev *dev, static int vhost_vdpa_set_owner(struct vhost_dev *dev) { + int r; + struct vhost_vdpa *v; + if (!vhost_vdpa_first_dev(dev)) { return 0; } trace_vhost_vdpa_set_owner(dev); - return vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL); + r = vhost_vdpa_call(dev, VHOST_SET_OWNER, NULL); + if (unlikely(r < 0)) { + return r; + } + + /* + * Being optimistic and listening address space memory. If the device + * uses vIOMMU, it is changed at vhost_vdpa_dev_start. + */ + v = dev->opaque; + memory_listener_register(&v->shared->listener, &address_space_memory); + v->shared->listener_registered = true; + return 0; } static int vhost_vdpa_vq_get_addr(struct vhost_dev *dev, From 0b006153b7ec66505cb2d231235aa19ca5d2ce37 Mon Sep 17 00:00:00 2001 From: Bernhard Beschow Date: Mon, 26 May 2025 22:38:20 +0200 Subject: [PATCH 1354/2760] hw/i386/pc_piix: Fix RTC ISA IRQ wiring of isapc machine Commit 56b1f50e3c10 ("hw/i386/pc: Wire RTC ISA IRQs in south bridges") attempted to refactor RTC IRQ wiring which was previously done in pc_basic_device_init() but forgot about the isapc machine. Fix this by wiring in the code section dedicated exclusively to the isapc machine. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2961 Fixes: 56b1f50e3c10 ("hw/i386/pc: Wire RTC ISA IRQs in south bridges") cc: qemu-stable Signed-off-by: Bernhard Beschow Reviewed-by: Mark Cave-Ayland Message-Id: <20250526203820.1853-1-shentey@gmail.com> Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 0dce512f18..6b6359ef65 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -285,6 +285,8 @@ static void pc_init1(MachineState *machine, const char *pci_type) pcms->idebus[0] = qdev_get_child_bus(dev, "ide.0"); pcms->idebus[1] = qdev_get_child_bus(dev, "ide.1"); } else { + uint32_t irq; + isa_bus = isa_bus_new(NULL, system_memory, system_io, &error_abort); isa_bus_register_input_irqs(isa_bus, x86ms->gsi); @@ -292,6 +294,9 @@ static void pc_init1(MachineState *machine, const char *pci_type) x86ms->rtc = isa_new(TYPE_MC146818_RTC); qdev_prop_set_int32(DEVICE(x86ms->rtc), "base_year", 2000); isa_realize_and_unref(x86ms->rtc, isa_bus, &error_fatal); + irq = object_property_get_uint(OBJECT(x86ms->rtc), "irq", + &error_fatal); + isa_connect_gpio_out(ISA_DEVICE(x86ms->rtc), 0, irq); i8257_dma_init(OBJECT(machine), isa_bus, 0); pcms->hpet_enabled = false; From ffcfb0faaa95fc6ca007f7dd989e390dacf936ca Mon Sep 17 00:00:00 2001 From: Tanish Desai Date: Wed, 28 May 2025 19:25:28 +0000 Subject: [PATCH 1355/2760] trace/simple: seperate hot paths of tracing fucntions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change improves performance by moving the hot path of the trace_vhost_commit()(or any other trace function) logic to the header file. Previously, even when the trace event was disabled, the function call chain:- trace_vhost_commit()(Or any other trace function) → _nocheck__trace_vhost_commit() → _simple_trace_vhost_commit() incurred a significant function prologue overhead before checking the trace state. Disassembly of _simple_trace_vhost_commit() (from the .c file) showed that 11 out of the first 14 instructions were prologue-related, including: 0x10 stp x29, x30, [sp, #-64]! Prologue: allocates 64-byte frame and saves old FP (x29) & LR (x30) 0x14 adrp x3, trace_events_enabled_count Prologue: computes page-base of the trace-enable counter 0x18 adrp x2, __stack_chk_guard Important (maybe prolog don't know?)(stack-protector): starts up the stack-canary load 0x1c mov x29, sp Prologue: sets new frame pointer 0x20 ldr x3, [x3] Prologue: loads the actual trace-enabled count 0x24 stp x19, x20, [sp, #16] Prologue: spills callee-saved regs used by this function (x19, x20) 0x28 and w20, w0, #0xff Tracepoint setup: extracts the low-8 bits of arg0 as the “event boolean” 0x2c ldr x2, [x2] Prologue (cont’d): completes loading of the stack-canary value 0x30 and w19, w1, #0xff Tracepoint setup: extracts low-8 bits of arg1 0x34 ldr w0, [x3] Important: loads the current trace-enabled flag from memory 0x38 ldr x1, [x2] Prologue (cont’d): reads the canary 0x3c str x1, [sp, #56] Prologue (cont’d): writes the canary into the new frame 0x40 mov x1, #0 Prologue (cont’d): zeroes out x1 for the upcoming branch test 0x44 cbnz w0, 0x88 Important: if tracing is disabled (w0==0) skip the heavy path entirely The trace-enabled check happens after the prologue. This is wasteful when tracing is disabled, which is often the case in production. To optimize this: _nocheck__trace_vhost_commit() is now fully inlined in the .h file with the hot path.It checks trace_event_get_state() before calling into _simple_trace_vhost_commit(), which remains in .c. This avoids calling into the .c function altogether when the tracepoint is disabled, thereby skipping unnecessary prologue instructions. This results in better performance by removing redundant instructions in the tracing fast path. Signed-off-by: Tanish Desai Message-id: 20250528192528.3968-1-tanishdesai37@gmail.com Signed-off-by: Stefan Hajnoczi --- scripts/tracetool/backend/simple.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py index a74d61fcd6..2688d4b64b 100644 --- a/scripts/tracetool/backend/simple.py +++ b/scripts/tracetool/backend/simple.py @@ -36,8 +36,17 @@ def generate_h_begin(events, group): def generate_h(event, group): - out(' _simple_%(api)s(%(args)s);', + event_id = 'TRACE_' + event.name.upper() + if "vcpu" in event.properties: + # already checked on the generic format code + cond = "true" + else: + cond = "trace_event_get_state(%s)" % event_id + out(' if (%(cond)s) {', + ' _simple_%(api)s(%(args)s);', + ' }', api=event.api(), + cond=cond, args=", ".join(event.args.names())) @@ -72,22 +81,10 @@ def generate_c(event, group): if len(event.args) == 0: sizestr = '0' - event_id = 'TRACE_' + event.name.upper() - if "vcpu" in event.properties: - # already checked on the generic format code - cond = "true" - else: - cond = "trace_event_get_state(%s)" % event_id - out('', - ' if (!%(cond)s) {', - ' return;', - ' }', - '', ' if (trace_record_start(&rec, %(event_obj)s.id, %(size_str)s)) {', ' return; /* Trace Buffer Full, Event Dropped ! */', ' }', - cond=cond, event_obj=event.api(event.QEMU_EVENT), size_str=sizestr) From 5e203f73c22786c73214d48a6d1abcb4ae9a3be3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:04 +0200 Subject: [PATCH 1356/2760] qapi: Tidy up run-together sentences in doc comments Fixes: a937b6aa739f (qapi: Reformat doc comments to conform to current conventions) Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-2-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/acpi.json | 2 +- qapi/block-core.json | 14 +++++++------- qapi/crypto.json | 18 +++++++++--------- qapi/machine.json | 4 ++-- qapi/migration.json | 18 +++++++++--------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/qapi/acpi.json b/qapi/acpi.json index 045dab6228..2d53b82365 100644 --- a/qapi/acpi.json +++ b/qapi/acpi.json @@ -80,7 +80,7 @@ ## # @ACPIOSTInfo: # -# OSPM Status Indication for a device For description of possible +# OSPM Status Indication for a device. For description of possible # values of @source and @status fields see "_OST (OSPM Status # Indication)" chapter of ACPI5.0 spec. # diff --git a/qapi/block-core.json b/qapi/block-core.json index b4115113d4..29d7c1c2c9 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2667,7 +2667,7 @@ # @iops-total-max: I/O operations burst # # @iops-total-max-length: length of the iops-total-max burst period, -# in seconds It must only be set if @iops-total-max is set as +# in seconds. It must only be set if @iops-total-max is set as # well. # # @iops-read: limit read operations per second @@ -2675,14 +2675,14 @@ # @iops-read-max: I/O operations read burst # # @iops-read-max-length: length of the iops-read-max burst period, in -# seconds It must only be set if @iops-read-max is set as well. +# seconds. It must only be set if @iops-read-max is set as well. # # @iops-write: limit write operations per second # # @iops-write-max: I/O operations write burst # # @iops-write-max-length: length of the iops-write-max burst period, -# in seconds It must only be set if @iops-write-max is set as +# in seconds. It must only be set if @iops-write-max is set as # well. # # @bps-total: limit total bytes per second @@ -2697,14 +2697,14 @@ # @bps-read-max: total bytes read burst # # @bps-read-max-length: length of the bps-read-max burst period, in -# seconds It must only be set if @bps-read-max is set as well. +# seconds. It must only be set if @bps-read-max is set as well. # # @bps-write: limit write bytes per second # # @bps-write-max: total bytes write burst # # @bps-write-max-length: length of the bps-write-max burst period, in -# seconds It must only be set if @bps-write-max is set as well. +# seconds. It must only be set if @bps-write-max is set as well. # # @iops-size: when limiting by iops max size of an I/O in bytes # @@ -5580,7 +5580,7 @@ # @x-blockdev-amend: # # Starts a job to amend format specific options of an existing open -# block device The job is automatically finalized, but a manual +# block device. The job is automatically finalized, but a manual # job-dismiss is required. # # @job-id: Identifier for the newly created job. @@ -5589,7 +5589,7 @@ # # @options: Options (driver specific) # -# @force: Allow unsafe operations, format specific For luks that +# @force: Allow unsafe operations, format specific. For luks that # allows erase of the last active keyslot (permanent loss of # data), and replacement of an active keyslot (possible loss of # data if IO error happens) diff --git a/qapi/crypto.json b/qapi/crypto.json index c9d967d782..fc7e294966 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -202,19 +202,19 @@ # # The options that apply to LUKS encryption format initialization # -# @cipher-alg: the cipher algorithm for data encryption Currently +# @cipher-alg: the cipher algorithm for data encryption. Currently # defaults to 'aes-256'. # -# @cipher-mode: the cipher mode for data encryption Currently defaults -# to 'xts' +# @cipher-mode: the cipher mode for data encryption. Currently +# defaults to 'xts' # -# @ivgen-alg: the initialization vector generator Currently defaults +# @ivgen-alg: the initialization vector generator. Currently defaults # to 'plain64' # -# @ivgen-hash-alg: the initialization vector generator hash Currently -# defaults to 'sha256' +# @ivgen-hash-alg: the initialization vector generator hash. +# Currently defaults to 'sha256' # -# @hash-alg: the master key hash algorithm Currently defaults to +# @hash-alg: the master key hash algorithm. Currently defaults to # 'sha256' # # @iter-time: number of milliseconds to spend in PBKDF passphrase @@ -370,11 +370,11 @@ # @new-secret: The ID of a QCryptoSecret object providing the password # to be written into added active keyslots # -# @old-secret: Optional (for deactivation only) If given will +# @old-secret: Optional (for deactivation only). If given will # deactivate all keyslots that match password located in # QCryptoSecret with this ID # -# @iter-time: Optional (for activation only) Number of milliseconds to +# @iter-time: Optional (for activation only). Number of milliseconds to # spend in PBKDF passphrase processing for the newly activated # keyslot. Currently defaults to 2000. # diff --git a/qapi/machine.json b/qapi/machine.json index 5373e1368c..0af2e1e0bb 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1160,7 +1160,7 @@ # # Information about the guest balloon device. # -# @actual: the logical size of the VM in bytes Formula used: +# @actual: the logical size of the VM in bytes. Formula used: # logical_vm_size = vm_ram_size - balloon_size # # Since: 0.14 @@ -1199,7 +1199,7 @@ # is equivalent to the @actual field return by the 'query-balloon' # command # -# @actual: the logical size of the VM in bytes Formula used: +# @actual: the logical size of the VM in bytes. Formula used: # logical_vm_size = vm_ram_size - balloon_size # # .. note:: This event is rate-limited. diff --git a/qapi/migration.json b/qapi/migration.json index 41826bde45..f5a6b35de4 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -760,9 +760,9 @@ # auto-converge detects that migration is not making progress. # The default value is 10. (Since 2.7) # -# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage At -# the tail stage of throttling, the Guest is very sensitive to CPU -# percentage while the @cpu-throttle -increment is excessive +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage. +# At the tail stage of throttling, the Guest is very sensitive to +# CPU percentage while the @cpu-throttle -increment is excessive # usually at tail stage. If this parameter is true, we will # compute the ideal CPU percentage used by the Guest, which may # exactly make the dirty rate match the dirty rate threshold. @@ -941,9 +941,9 @@ # auto-converge detects that migration is not making progress. # The default value is 10. (Since 2.7) # -# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage At -# the tail stage of throttling, the Guest is very sensitive to CPU -# percentage while the @cpu-throttle -increment is excessive +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage. +# At the tail stage of throttling, the Guest is very sensitive to +# CPU percentage while the @cpu-throttle -increment is excessive # usually at tail stage. If this parameter is true, we will # compute the ideal CPU percentage used by the Guest, which may # exactly make the dirty rate match the dirty rate threshold. @@ -1155,9 +1155,9 @@ # auto-converge detects that migration is not making progress. # (Since 2.7) # -# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage At -# the tail stage of throttling, the Guest is very sensitive to CPU -# percentage while the @cpu-throttle -increment is excessive +# @cpu-throttle-tailslow: Make CPU throttling slower at tail stage. +# At the tail stage of throttling, the Guest is very sensitive to +# CPU percentage while the @cpu-throttle -increment is excessive # usually at tail stage. If this parameter is true, we will # compute the ideal CPU percentage used by the Guest, which may # exactly make the dirty rate match the dirty rate threshold. From 69d68fb34e1d96f60addfd50c9c654eb8c0584e0 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:05 +0200 Subject: [PATCH 1357/2760] qapi: Tidy up whitespace in doc comments Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-3-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 16 ++++++++-------- qapi/block-export.json | 4 ++-- qapi/char.json | 2 +- qapi/crypto.json | 3 ++- qapi/job.json | 8 ++++---- qapi/machine.json | 2 +- qapi/migration.json | 12 ++++++------ qapi/qom.json | 2 +- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 29d7c1c2c9..13223df9b4 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -488,7 +488,7 @@ # # @active: true if the backend is active; typical cases for inactive backends # are on the migration source instance after migration completes and on the -# destination before it completes. (since: 10.0) +# destination before it completes. (since: 10.0) # # @encrypted: true if the backing device is encrypted # @@ -3030,10 +3030,10 @@ # state. Completing the job in any other state is an error. # # This is supported only for drive mirroring, where it also switches -# the device to write to the target path only. Note that drive +# the device to write to the target path only. Note that drive # mirroring includes drive-mirror, blockdev-mirror and block-commit # job (only in case of "active commit", when the node being commited -# is used by the guest). The ability to complete is signaled with a +# is used by the guest). The ability to complete is signaled with a # BLOCK_JOB_READY event. # # This command completes an active background block operation @@ -3068,10 +3068,10 @@ # # Deletes a job that is in the CONCLUDED state. This command only # needs to be run explicitly for jobs that don't have automatic -# dismiss enabled. In turn, automatic dismiss may be enabled only +# dismiss enabled. In turn, automatic dismiss may be enabled only # for jobs that have @auto-dismiss option, which are drive-backup, # blockdev-backup, drive-mirror, blockdev-mirror, block-commit and -# block-stream. @auto-dismiss is enabled by default for these +# block-stream. @auto-dismiss is enabled by default for these # jobs. # # This command will refuse to operate on any job that has not yet @@ -4737,7 +4737,7 @@ # @active: whether the block node should be activated (default: true). # Having inactive block nodes is useful primarily for migration because it # allows opening an image on the destination while the source is still -# holding locks for it. (Since 10.0) +# holding locks for it. (Since 10.0) # # @read-only: whether the block device should be read-only (default: # false). Note that some block drivers support only read-only @@ -4999,14 +4999,14 @@ ## # @blockdev-set-active: # -# Activate or inactivate a block device. Use this to manage the handover of +# Activate or inactivate a block device. Use this to manage the handover of # block devices on migration with qemu-storage-daemon. # # Activating a node automatically activates all of its child nodes first. # Inactivating a node automatically inactivates any of its child nodes that are # not in use by a still active node. # -# @node-name: Name of the graph node to activate or inactivate. By default, all +# @node-name: Name of the graph node to activate or inactivate. By default, all # nodes are affected by the operation. # # @active: true if the nodes should be active when the command returns success, diff --git a/qapi/block-export.json b/qapi/block-export.json index c783e01a53..04190b503c 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -373,9 +373,9 @@ # (since: 5.2) # # @allow-inactive: If true, the export allows the exported node to be inactive. -# If it is created for an inactive block node, the node remains inactive. If +# If it is created for an inactive block node, the node remains inactive. If # the export type doesn't support running on an inactive node, an error is -# returned. If false, inactive block nodes are automatically activated before +# returned. If false, inactive block nodes are automatically activated before # creating the export and trying to inactivate them later fails. # (since: 10.0; default: false) # diff --git a/qapi/char.json b/qapi/char.json index 447c10b91a..f79216e4d2 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -274,7 +274,7 @@ # @reconnect: For a client socket, if a socket is disconnected, then # attempt a reconnect after the given number of seconds. Setting # this to zero disables this function. The use of this member is -# deprecated, use @reconnect-ms instead. (default: 0) (Since: 2.2) +# deprecated, use @reconnect-ms instead. (default: 0) (Since: 2.2) # # @reconnect-ms: For a client socket, if a socket is disconnected, # then attempt a reconnect after the given number of milliseconds. diff --git a/qapi/crypto.json b/qapi/crypto.json index fc7e294966..9ec6301e18 100644 --- a/qapi/crypto.json +++ b/qapi/crypto.json @@ -55,7 +55,8 @@ # @sha512: SHA-512. (since 2.7) # # @ripemd160: RIPEMD-160. (since 2.7) -# @sm3: SM3. (since 9.2.0) +# +# @sm3: SM3. (since 9.2.0) # # Since: 2.6 ## diff --git a/qapi/job.json b/qapi/job.json index b03f80bc84..c53c96cce8 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -191,10 +191,10 @@ # state. Completing the job in any other state is an error. # # This is supported only for drive mirroring, where it also switches -# the device to write to the target path only. Note that drive +# the device to write to the target path only. Note that drive # mirroring includes drive-mirror, blockdev-mirror and block-commit # job (only in case of "active commit", when the node being commited -# is used by the guest). The ability to complete is signaled with a +# is used by the guest). The ability to complete is signaled with a # BLOCK_JOB_READY event. # # This command completes an active background block operation @@ -216,10 +216,10 @@ # # Deletes a job that is in the CONCLUDED state. This command only # needs to be run explicitly for jobs that don't have automatic -# dismiss enabled. In turn, automatic dismiss may be enabled only +# dismiss enabled. In turn, automatic dismiss may be enabled only # for jobs that have @auto-dismiss option, which are drive-backup, # blockdev-backup, drive-mirror, blockdev-mirror, block-commit and -# block-stream. @auto-dismiss is enabled by default for these +# block-stream. @auto-dismiss is enabled by default for these # jobs. # # This command will refuse to operate on any job that has not yet diff --git a/qapi/machine.json b/qapi/machine.json index 0af2e1e0bb..069e87d16a 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -694,7 +694,7 @@ # Structure of HMAT (Heterogeneous Memory Attribute Table) # # For more information about @HmatLBDataType, see chapter 5.2.27.4: -# Table 5-146: Field "Data Type" of ACPI 6.3 spec. +# Table 5-146: Field "Data Type" of ACPI 6.3 spec. # # @access-latency: access latency (nanoseconds) # diff --git a/qapi/migration.json b/qapi/migration.json index f5a6b35de4..7c7b09c341 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -842,9 +842,9 @@ # more CPU. Defaults to 1. (Since 5.0) # # @multifd-qatzip-level: Set the compression level to be used in live -# migration. The level is an integer between 1 and 9, where 1 means +# migration. The level is an integer between 1 and 9, where 1 means # the best compression speed, and 9 means the best compression -# ratio which will consume more CPU. Defaults to 1. (Since 9.2) +# ratio which will consume more CPU. Defaults to 1. (Since 9.2) # # @multifd-zstd-level: Set the compression level to be used in live # migration, the compression level is an integer between 0 and 20, @@ -1023,9 +1023,9 @@ # more CPU. Defaults to 1. (Since 5.0) # # @multifd-qatzip-level: Set the compression level to be used in live -# migration. The level is an integer between 1 and 9, where 1 means +# migration. The level is an integer between 1 and 9, where 1 means # the best compression speed, and 9 means the best compression -# ratio which will consume more CPU. Defaults to 1. (Since 9.2) +# ratio which will consume more CPU. Defaults to 1. (Since 9.2) # # @multifd-zstd-level: Set the compression level to be used in live # migration, the compression level is an integer between 0 and 20, @@ -1233,9 +1233,9 @@ # more CPU. Defaults to 1. (Since 5.0) # # @multifd-qatzip-level: Set the compression level to be used in live -# migration. The level is an integer between 1 and 9, where 1 means +# migration. The level is an integer between 1 and 9, where 1 means # the best compression speed, and 9 means the best compression -# ratio which will consume more CPU. Defaults to 1. (Since 9.2) +# ratio which will consume more CPU. Defaults to 1. (Since 9.2) # # @multifd-zstd-level: Set the compression level to be used in live # migration, the compression level is an integer between 0 and 20, diff --git a/qapi/qom.json b/qapi/qom.json index 45cd47508b..3e8debf78c 100644 --- a/qapi/qom.json +++ b/qapi/qom.json @@ -870,7 +870,7 @@ # information read from devices and switches in conjunction with # link characteristics read from PCIe Configuration space. # To get the full path latency from CPU to CXL attached DRAM -# CXL device: Add the latency from CPU to Generic Port (from +# CXL device: Add the latency from CPU to Generic Port (from # HMAT indexed via the node ID in this SRAT structure) to # that for CXL bus links, the latency across intermediate switches # and from the EP port to the actual memory. Bandwidth is more From 73aaba61a07c4bb4cd683a450a47504274ea1274 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:06 +0200 Subject: [PATCH 1358/2760] qapi: Move (since X.Y) to end of description By convention, we put (since X.Y) at the end of the description. Move the ones that somehow ended up in the middle of the description to the end. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-4-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 18 +++++++++--------- qapi/net.json | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 13223df9b4..0700bd3d46 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1322,8 +1322,8 @@ # @incremental: only copy data described by the dirty bitmap. # (since: 2.4) # -# @bitmap: only copy data described by the dirty bitmap. (since: 4.2) -# Behavior on completion is determined by the BitmapSyncMode. +# @bitmap: only copy data described by the dirty bitmap. Behavior on +# completion is determined by the BitmapSyncMode. (since: 4.2) # # Since: 1.3 ## @@ -3415,8 +3415,8 @@ # Driver specific block device options for LUKS. # # @key-secret: the ID of a QCryptoSecret object providing the -# decryption key (since 2.6). Mandatory except when doing a -# metadata-only probe of the image. +# decryption key. Mandatory except when doing a metadata-only +# probe of the image. (since 2.6) # # @header: block device holding a detached LUKS header. (since 9.0) # @@ -4724,11 +4724,11 @@ # # @driver: block driver name # -# @node-name: the node name of the new node (Since 2.0). This option -# is required on the top level of blockdev-add. Valid node names -# start with an alphabetic character and may contain only -# alphanumeric characters, '-', '.' and '_'. Their maximum length -# is 31 characters. +# @node-name: the node name of the new node. This option is required +# on the top level of blockdev-add. Valid node names start with +# an alphabetic character and may contain only alphanumeric +# characters, '-', '.' and '_'. Their maximum length is 31 +# characters. (Since 2.0) # # @discard: discard-related options (default: ignore) # diff --git a/qapi/net.json b/qapi/net.json index 310cc4fd19..e670efd6b0 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -150,9 +150,9 @@ # @domainname: guest-visible domain name of the virtual nameserver # (since 3.0) # -# @ipv6-prefix: IPv6 network prefix (default is fec0::) (since 2.6). -# The network prefix is given in the usual hexadecimal IPv6 -# address notation. +# @ipv6-prefix: IPv6 network prefix (default is fec0::). The network +# prefix is given in the usual hexadecimal IPv6 address notation. +# (since 2.6) # # @ipv6-prefixlen: IPv6 network prefix length (default is 64) (since # 2.6) From c1a6aa1d443e17e1902417ee2e531394eaf4c2d4 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:07 +0200 Subject: [PATCH 1359/2760] qapi: Avoid breaking lines within (since X.Y) Easier on the eyes and for grep. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-5-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 56 ++++++++++++++++++++++---------------------- qapi/introspect.json | 4 ++-- qapi/job.json | 12 +++++----- qapi/machine.json | 4 ++-- qapi/migration.json | 36 ++++++++++++++-------------- qapi/net.json | 12 +++++----- qapi/run-state.json | 4 ++-- qapi/ui.json | 4 ++-- 8 files changed, 66 insertions(+), 66 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 0700bd3d46..cc48fc7122 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -31,8 +31,8 @@ # @icount: Current instruction count. Appears when execution # record/replay is enabled. Used for "time-traveling" to match # the moment in the recorded execution with the snapshots. This -# counter may be obtained through @query-replay command (since -# 5.2) +# counter may be obtained through @query-replay command +# (since 5.2) # # Since: 1.3 ## @@ -510,11 +510,11 @@ # # @bps_max: total throughput limit during bursts, in bytes (Since 1.7) # -# @bps_rd_max: read throughput limit during bursts, in bytes (Since -# 1.7) +# @bps_rd_max: read throughput limit during bursts, in bytes +# (Since 1.7) # -# @bps_wr_max: write throughput limit during bursts, in bytes (Since -# 1.7) +# @bps_wr_max: write throughput limit during bursts, in bytes +# (Since 1.7) # # @iops_max: total I/O operations per second during bursts, in bytes # (Since 1.7) @@ -951,11 +951,11 @@ # @unmap_operations: The number of unmap operations performed by the # device (Since 4.2) # -# @rd_total_time_ns: Total time spent on reads in nanoseconds (since -# 0.15). +# @rd_total_time_ns: Total time spent on reads in nanoseconds +# (since 0.15) # -# @wr_total_time_ns: Total time spent on writes in nanoseconds (since -# 0.15). +# @wr_total_time_ns: Total time spent on writes in nanoseconds +# (since 0.15) # # @zone_append_total_time_ns: Total time spent on zone append writes # in nanoseconds (since 8.1) @@ -1502,15 +1502,15 @@ # # @device: the name of the device to take a snapshot of. # -# @node-name: graph node name to generate the snapshot from (Since -# 2.0) +# @node-name: graph node name to generate the snapshot from +# (Since 2.0) # # @snapshot-file: the target of the new overlay image. If the file # exists, or if it is a device, the overlay will be created in the # existing file/device. Otherwise, a new file will be created. # -# @snapshot-node-name: the graph node name of the new image (Since -# 2.0) +# @snapshot-node-name: the graph node name of the new image +# (Since 2.0) # # @format: the format of the overlay image, default is 'qcow2'. # @@ -1785,8 +1785,8 @@ # If top == base, that is an error. If top has no overlays on top of # it, or if it is in use by a writer, the job will not be completed by # itself. The user needs to complete the job with the -# block-job-complete command after getting the ready event. (Since -# 2.0) +# block-job-complete command after getting the ready event. +# (Since 2.0) # # If the base image is smaller than top, then the base image will be # resized to be the same size as top. If top is smaller than the base @@ -2169,8 +2169,8 @@ # @format: the format of the new destination, default is to probe if # @mode is 'existing', else the format of the source # -# @node-name: the new block driver state node name in the graph (Since -# 2.1) +# @node-name: the new block driver state node name in the graph +# (Since 2.1) # # @replaces: with sync=full graph node name to be replaced by the new # image when a whole image copy is done. This can be used to @@ -2593,11 +2593,11 @@ # # @bps_max: total throughput limit during bursts, in bytes (Since 1.7) # -# @bps_rd_max: read throughput limit during bursts, in bytes (Since -# 1.7) +# @bps_rd_max: read throughput limit during bursts, in bytes +# (Since 1.7) # -# @bps_wr_max: write throughput limit during bursts, in bytes (Since -# 1.7) +# @bps_wr_max: write throughput limit during bursts, in bytes +# (Since 1.7) # # @iops_max: total I/O operations per second during bursts, in bytes # (Since 1.7) @@ -3655,8 +3655,8 @@ # this feature. (since 2.5) # # @encrypt: Image decryption options. Mandatory for encrypted images, -# except when doing a metadata-only probe of the image. (since -# 2.10) +# except when doing a metadata-only probe of the image. +# (since 2.10) # # @data-file: reference to or definition of the external data file. # This may only be specified for images that require an external @@ -4326,8 +4326,8 @@ # @user: Ceph id name. # # @auth-client-required: Acceptable authentication modes. This maps -# to Ceph configuration option "auth_client_required". (Since -# 3.0) +# to Ceph configuration option "auth_client_required". +# (Since 3.0) # # @key-secret: ID of a QCryptoSecret object providing a key for cephx # authentication. This maps to Ceph configuration option "key". @@ -4581,8 +4581,8 @@ # error. During the first @reconnect-delay seconds, all requests # are paused and will be rerun on a successful reconnect. After # that time, any delayed requests and all future requests before a -# successful reconnect will immediately fail. Default 0 (Since -# 4.2) +# successful reconnect will immediately fail. Default 0 +# (Since 4.2) # # @open-timeout: In seconds. If zero, the nbd driver tries the # connection only once, and fails to open if the connection fails. diff --git a/qapi/introspect.json b/qapi/introspect.json index 01bb242947..95724ee2d2 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -154,8 +154,8 @@ # # Additional SchemaInfo members for meta-type 'enum'. # -# @members: the enum type's members, in no particular order (since -# 6.2). +# @members: the enum type's members, in no particular order. +# (since 6.2) # # @values: the enumeration type's member names, in no particular # order. Redundant with @members. Just for backward diff --git a/qapi/job.json b/qapi/job.json index c53c96cce8..9ddba537db 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -20,14 +20,14 @@ # # @create: image creation job type, see "blockdev-create" (since 3.0) # -# @amend: image options amend job type, see "x-blockdev-amend" (since -# 5.1) +# @amend: image options amend job type, see "x-blockdev-amend" +# (since 5.1) # -# @snapshot-load: snapshot load job type, see "snapshot-load" (since -# 6.0) +# @snapshot-load: snapshot load job type, see "snapshot-load" +# (since 6.0) # -# @snapshot-save: snapshot save job type, see "snapshot-save" (since -# 6.0) +# @snapshot-save: snapshot save job type, see "snapshot-save" +# (since 6.0) # # @snapshot-delete: snapshot delete job type, see "snapshot-delete" # (since 6.0) diff --git a/qapi/machine.json b/qapi/machine.json index 069e87d16a..5eb67fc4e9 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -182,8 +182,8 @@ # @default-cpu-type: default CPU model typename if none is requested # via the -cpu argument. (since 4.2) # -# @default-ram-id: the default ID of initial RAM memory backend (since -# 5.2) +# @default-ram-id: the default ID of initial RAM memory backend +# (since 5.2) # # @acpi: machine type supports ACPI (since 8.0) # diff --git a/qapi/migration.json b/qapi/migration.json index 7c7b09c341..7d1ec06605 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -57,8 +57,8 @@ # # @dirty-sync-missed-zero-copy: Number of times dirty RAM # synchronization could not avoid copying dirty pages. This is -# between 0 and @dirty-sync-count * @multifd-channels. (since -# 7.1) +# between 0 and @dirty-sync-count * @multifd-channels. +# (since 7.1) # # Since: 0.14 ## @@ -137,16 +137,16 @@ # # @active: in the process of doing migration. # -# @postcopy-active: like active, but now in postcopy mode. (since -# 2.5) +# @postcopy-active: like active, but now in postcopy mode. +# (since 2.5) # # @postcopy-paused: during postcopy but paused. (since 3.0) # # @postcopy-recover-setup: setup phase for a postcopy recovery # process, preparing for a recovery phase to start. (since 9.1) # -# @postcopy-recover: trying to recover from a paused postcopy. (since -# 3.0) +# @postcopy-recover: trying to recover from a paused postcopy. +# (since 3.0) # # @completed: migration is finished. # @@ -422,8 +422,8 @@ # for precopy. (since 2.10) # # @pause-before-switchover: Pause outgoing migration before -# serialising device state and before disabling block IO (since -# 2.11) +# serialising device state and before disabling block IO +# (since 2.11) # # @multifd: Use more than one fd for migration (since 4.0) # @@ -697,8 +697,8 @@ # @alias: An alias name for migration (for example the bitmap name on # the opposite site). # -# @transform: Allows the modification of the migrated bitmap. (since -# 6.0) +# @transform: Allows the modification of the migrated bitmap. +# (since 6.0) # # Since: 5.2 ## @@ -770,8 +770,8 @@ # specified by @cpu-throttle-increment and the one generated by # ideal CPU percentage. Therefore, it is compatible to # traditional throttling, meanwhile the throttle increment won't -# be excessive at tail stage. The default value is false. (Since -# 5.1) +# be excessive at tail stage. The default value is false. +# (Since 5.1) # # @tls-creds: ID of the 'tls-creds' object that provides credentials # for establishing a TLS connection over the migration data @@ -951,8 +951,8 @@ # specified by @cpu-throttle-increment and the one generated by # ideal CPU percentage. Therefore, it is compatible to # traditional throttling, meanwhile the throttle increment won't -# be excessive at tail stage. The default value is false. (Since -# 5.1) +# be excessive at tail stage. The default value is false. +# (Since 5.1) # # @tls-creds: ID of the 'tls-creds' object that provides credentials # for establishing a TLS connection over the migration data @@ -1148,8 +1148,8 @@ # percentage. The default value is 50. (Since 5.0) # # @cpu-throttle-initial: Initial percentage of time guest cpus are -# throttled when migration auto-converge is activated. (Since -# 2.7) +# throttled when migration auto-converge is activated. +# (Since 2.7) # # @cpu-throttle-increment: throttle percentage increase each time # auto-converge detects that migration is not making progress. @@ -1165,8 +1165,8 @@ # specified by @cpu-throttle-increment and the one generated by # ideal CPU percentage. Therefore, it is compatible to # traditional throttling, meanwhile the throttle increment won't -# be excessive at tail stage. The default value is false. (Since -# 5.1) +# be excessive at tail stage. The default value is false. +# (Since 5.1) # # @tls-creds: ID of the 'tls-creds' object that provides credentials # for establishing a TLS connection over the migration data diff --git a/qapi/net.json b/qapi/net.json index e670efd6b0..97ea183981 100644 --- a/qapi/net.json +++ b/qapi/net.json @@ -154,8 +154,8 @@ # prefix is given in the usual hexadecimal IPv6 address notation. # (since 2.6) # -# @ipv6-prefixlen: IPv6 network prefix length (default is 64) (since -# 2.6) +# @ipv6-prefixlen: IPv6 network prefix length (default is 64) +# (since 2.6) # # @ipv6-host: guest-visible IPv6 address of the host (since 2.6) # @@ -387,8 +387,8 @@ # # @hubid: hub identifier number # -# @netdev: used to connect hub to a netdev instead of a device (since -# 2.12) +# @netdev: used to connect hub to a netdev instead of a device +# (since 2.12) # # Since: 1.2 ## @@ -510,8 +510,8 @@ # @queues: number of queues to be created for multiqueue vhost-vdpa # (default: 1) # -# @x-svq: Start device with (experimental) shadow virtqueue. (Since -# 7.1) (default: false) +# @x-svq: Start device with (experimental) shadow virtqueue. +# (Since 7.1) (default: false) # # Features: # diff --git a/qapi/run-state.json b/qapi/run-state.json index ee11adc508..ebfeb669ab 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -365,8 +365,8 @@ # @shutdown: Shutdown the VM and exit, according to the shutdown # action # -# @exit-failure: Shutdown the VM and exit with nonzero status (since -# 7.1) +# @exit-failure: Shutdown the VM and exit with nonzero status +# (since 7.1) # # Since: 6.0 ## diff --git a/qapi/ui.json b/qapi/ui.json index 3d0c853c9a..7cfedb3914 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -175,8 +175,8 @@ # @filename: the path of a new file to store the image # # @device: ID of the display device that should be dumped. If this -# parameter is missing, the primary display will be used. (Since -# 2.12) +# parameter is missing, the primary display will be used. +# (Since 2.12) # # @head: head to use in case the device supports multiple heads. If # this parameter is missing, head #0 will be used. Also note that From 2e2309b6be074a2087afc3aedabcee722fcd512f Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:08 +0200 Subject: [PATCH 1360/2760] qapi: Drop a problematic (Since: 2.11) from query-hotpluggable-cpus There is a (Since: 2.11) in a query-hotpluggable-cpus example. Versioning information ought to be in the command description, not examples. The command description is basically empty (there is a TODO about it). What exactly didn't work before 2.11 is not quite clear from the documentation. The example was added in commit 4dc3b151882 (s390x: implement query-hotpluggable-cpus), which suggests the command failed for the s390x target until then. This was almost eight years ago, and I doubt anyone still cares about this detail. Simply delete the problematic (Since: 2.11). Cc: David Hildenbrand Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-6-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/machine.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/machine.json b/qapi/machine.json index 5eb67fc4e9..230b9b20dd 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1089,7 +1089,7 @@ # :annotated: # # For s390x-virtio-ccw machine type started with -# ``-smp 1,maxcpus=2 -cpu qemu`` (Since: 2.11):: +# ``-smp 1,maxcpus=2 -cpu qemu``:: # # -> { "execute": "query-hotpluggable-cpus" } # <- {"return": [ From 6263225492bad6d0f3a4feea13cd949b977fb3c3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:09 +0200 Subject: [PATCH 1361/2760] qapi: Correct spelling of QEMU in doc comments Improve awkward phrasing in migrate-incoming While there. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-7-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/audio.json | 8 ++++---- qapi/block-core.json | 10 +++++----- qapi/block-export.json | 2 +- qapi/char.json | 6 +++--- qapi/introspect.json | 4 ++-- qapi/migration.json | 8 ++++---- qapi/run-state.json | 6 +++--- qapi/transaction.json | 2 +- qapi/uefi.json | 2 +- qapi/ui.json | 4 ++-- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/qapi/audio.json b/qapi/audio.json index 8de4430578..16de231f6d 100644 --- a/qapi/audio.json +++ b/qapi/audio.json @@ -309,9 +309,9 @@ # # @name: name of the sink/source to use # -# @stream-name: name of the PulseAudio stream created by qemu. Can be +# @stream-name: name of the PulseAudio stream created by QEMU. Can be # used to identify the stream in PulseAudio when you create -# multiple PulseAudio devices or run multiple qemu instances +# multiple PulseAudio devices or run multiple QEMU instances # (default: audiodev's id, since 4.2) # # @latency: latency you want PulseAudio to achieve in microseconds @@ -353,9 +353,9 @@ # # @name: name of the sink/source to use # -# @stream-name: name of the PipeWire stream created by qemu. Can be +# @stream-name: name of the PipeWire stream created by QEMU. Can be # used to identify the stream in PipeWire when you create multiple -# PipeWire devices or run multiple qemu instances (default: +# PipeWire devices or run multiple QEMU instances (default: # audiodev's id) # # @latency: latency you want PipeWire to achieve in microseconds diff --git a/qapi/block-core.json b/qapi/block-core.json index cc48fc7122..b6447e847e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -2030,7 +2030,7 @@ # # @id: Block graph node identifier. This @id is generated only for # x-debug-query-block-graph and does not relate to any other -# identifiers in Qemu. +# identifiers in QEMU. # # @type: Type of graph node. Can be one of block-backend, block-job # or block-driver-state. @@ -2794,7 +2794,7 @@ # The node that receives the data is called the top image, can be # located in any part of the chain (but always above the base image; # see below) and can be specified using its device or node name. -# Earlier qemu versions only allowed 'device' to name the top level +# Earlier QEMU versions only allowed 'device' to name the top level # node; presence of the 'base-node' parameter during introspection can # be used as a witness of the enhanced semantics of 'device'. # @@ -3196,7 +3196,7 @@ # # Selects the AIO backend to handle I/O requests # -# @threads: Use qemu's thread pool +# @threads: Use QEMU's thread pool # # @native: Use native AIO backend (only Linux and Windows) # @@ -5157,10 +5157,10 @@ ## # @BlockdevQcow2Version: # -# @v2: The original QCOW2 format as introduced in qemu 0.10 (version +# @v2: The original QCOW2 format as introduced in QEMU 0.10 (version # 2) # -# @v3: The extended QCOW2 format as introduced in qemu 1.1 (version 3) +# @v3: The extended QCOW2 format as introduced in QEMU 1.1 (version 3) # # Since: 2.12 ## diff --git a/qapi/block-export.json b/qapi/block-export.json index 04190b503c..ed4deb54db 100644 --- a/qapi/block-export.json +++ b/qapi/block-export.json @@ -169,7 +169,7 @@ # @growable: Whether writes beyond the EOF should grow the block node # accordingly. (default: false) # -# @allow-other: If this is off, only qemu's user is allowed access to +# @allow-other: If this is off, only QEMU's user is allowed access to # this export. That cannot be changed even with chmod or chown. # Enabling this option will allow other users access to the export # with the FUSE mount option "allow_other". Note that using diff --git a/qapi/char.json b/qapi/char.json index f79216e4d2..df6e325e2e 100644 --- a/qapi/char.json +++ b/qapi/char.json @@ -351,7 +351,7 @@ # Configuration info for stdio chardevs. # # @signal: Allow signals (such as SIGINT triggered by ^C) be delivered -# to qemu. Default: true. +# to QEMU. Default: true. # # Since: 1.5 ## @@ -443,7 +443,7 @@ ## # @ChardevQemuVDAgent: # -# Configuration info for qemu vdagent implementation. +# Configuration info for QEMU vdagent implementation. # # @mouse: enable/disable mouse, default is enabled. # @@ -656,7 +656,7 @@ ## # @ChardevQemuVDAgentWrapper: # -# @data: Configuration info for qemu vdagent implementation +# @data: Configuration info for QEMU vdagent implementation # # Since: 6.1 ## diff --git a/qapi/introspect.json b/qapi/introspect.json index 95724ee2d2..e9e0297282 100644 --- a/qapi/introspect.json +++ b/qapi/introspect.json @@ -26,9 +26,9 @@ # the QAPI schema. # # Furthermore, while we strive to keep the QMP wire format -# backwards-compatible across qemu versions, the introspection output +# backwards-compatible across QEMU versions, the introspection output # is not guaranteed to have the same stability. For example, one -# version of qemu may list an object member as an optional +# version of QEMU may list an object member as an optional # non-variant, while another lists the same member only through the # object's variants; or the type of a member may change from a generic # string into a specific enum or from one specific type into an diff --git a/qapi/migration.json b/qapi/migration.json index 7d1ec06605..84edcf81e4 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -415,7 +415,7 @@ # on secondary side, this process is called COarse-Grain LOck # Stepping (COLO) for Non-stop Service. (since 2.8) # -# @release-ram: if enabled, qemu will free the migrated ram pages on +# @release-ram: if enabled, QEMU will free the migrated ram pages on # the source during postcopy-ram migration. (since 2.9) # # @return-path: If enabled, migration will use the return path even @@ -1500,7 +1500,7 @@ ## # @x-colo-lost-heartbeat: # -# Tell qemu that heartbeat is lost, request it to do takeover +# Tell QEMU that heartbeat is lost, request it to do takeover # procedures. If this command is sent to the PVM, the Primary side # will exit COLO mode. If sent to the Secondary, the Secondary side # will run failover work, then takes over server operation to become @@ -1729,8 +1729,8 @@ ## # @migrate-incoming: # -# Start an incoming migration, the qemu must have been started with -# -incoming defer +# Start an incoming migration. QEMU must have been started with +# -incoming defer. # # @uri: The Uniform Resource Identifier identifying the source or # address to listen on diff --git a/qapi/run-state.json b/qapi/run-state.json index ebfeb669ab..fcc00c805b 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -135,19 +135,19 @@ ## # @SHUTDOWN: # -# Emitted when the virtual machine has shut down, indicating that qemu +# Emitted when the virtual machine has shut down, indicating that QEMU # is about to exit. # # @guest: If true, the shutdown was triggered by a guest request (such # as a guest-initiated ACPI shutdown request or other # hardware-specific action) rather than a host request (such as -# sending qemu a SIGINT). (since 2.10) +# sending QEMU a SIGINT). (since 2.10) # # @reason: The @ShutdownCause which resulted in the SHUTDOWN. # (since 4.0) # # .. note:: If the command-line option ``-no-shutdown`` has been -# specified, qemu will not exit, and a STOP event will eventually +# specified, QEMU will not exit, and a STOP event will eventually # follow the SHUTDOWN event. # # Since: 0.12 diff --git a/qapi/transaction.json b/qapi/transaction.json index 021e383496..5c3394919e 100644 --- a/qapi/transaction.json +++ b/qapi/transaction.json @@ -223,7 +223,7 @@ # exists, the request will be rejected. Only some image formats # support it, for example, qcow2, and rbd, # -# On failure, qemu will try delete the newly created internal snapshot +# On failure, QEMU will try delete the newly created internal snapshot # in the transaction. When an I/O error occurs during deletion, the # user needs to fix it later with qemu-img or other command. # diff --git a/qapi/uefi.json b/qapi/uefi.json index bdfcabe1df..6592183d6c 100644 --- a/qapi/uefi.json +++ b/qapi/uefi.json @@ -5,7 +5,7 @@ ## # = UEFI Variable Store # -# The qemu efi variable store implementation (hw/uefi/) uses this to +# The QEMU efi variable store implementation (hw/uefi/) uses this to # store non-volatile variables in json format on disk. # # This is an existing format already supported by (at least) two other diff --git a/qapi/ui.json b/qapi/ui.json index 7cfedb3914..514fa159b1 100644 --- a/qapi/ui.json +++ b/qapi/ui.json @@ -1526,12 +1526,12 @@ # # Display (user interface) options. # -# @type: Which DisplayType qemu should use. +# @type: Which DisplayType QEMU should use. # # @full-screen: Start user interface in fullscreen mode # (default: off). # -# @window-close: Allow to quit qemu with window close button +# @window-close: Allow to quit QEMU with window close button # (default: on). # # @show-cursor: Force showing the mouse cursor (default: off). From 83691fa0698d658781a9ce81d4b8775d34ba6a8e Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:10 +0200 Subject: [PATCH 1362/2760] qapi: Fix capitalization in doc comments Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-8-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 6 +++--- qapi/block.json | 2 +- qapi/cryptodev.json | 2 +- qapi/cxl.json | 2 +- qapi/machine.json | 2 +- qapi/misc-i386.json | 2 +- qapi/run-state.json | 2 +- qapi/transaction.json | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index b6447e847e..f0faca1054 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1337,7 +1337,7 @@ # bitmap when used for data copy operations. # # @on-success: The bitmap is only synced when the operation is -# successful. This is the behavior always used for 'INCREMENTAL' +# successful. This is the behavior always used for incremental # backups. # # @never: The bitmap is never synchronized with the operation, and is @@ -1589,7 +1589,7 @@ # # @bitmap-mode: Specifies the type of data the bitmap should contain # after the operation concludes. Must be present if a bitmap was -# provided, Must NOT be present otherwise. (Since 4.2) +# provided, must NOT be present otherwise. (Since 4.2) # # @compress: true to compress data, if the target format supports it. # (default: false) (since 2.8) @@ -1840,7 +1840,7 @@ # @speed: the maximum speed, in bytes per second # # @on-error: the action to take on an error. 'ignore' means that the -# request should be retried. (default: report; Since: 5.0) +# request should be retried. (default: report; since: 5.0) # # @filter-node-name: the node name that should be assigned to the # filter driver that the commit job inserts into the graph above diff --git a/qapi/block.json b/qapi/block.json index f5374bd86c..1490a1a17f 100644 --- a/qapi/block.json +++ b/qapi/block.json @@ -48,7 +48,7 @@ ## # @FloppyDriveType: # -# Type of Floppy drive to be emulated by the Floppy Disk Controller. +# Type of floppy drive to be emulated by the Floppy Disk Controller. # # @144: 1.44MB 3.5" drive # diff --git a/qapi/cryptodev.json b/qapi/cryptodev.json index 28b97eb3da..b13db26403 100644 --- a/qapi/cryptodev.json +++ b/qapi/cryptodev.json @@ -15,7 +15,7 @@ # # @sym: symmetric encryption # -# @asym: asymmetric Encryption +# @asym: asymmetric encryption # # Since: 8.0 ## diff --git a/qapi/cxl.json b/qapi/cxl.json index dd947d3bbc..8f2e9237b1 100644 --- a/qapi/cxl.json +++ b/qapi/cxl.json @@ -117,7 +117,7 @@ # @nibble-mask: Identifies one or more nibbles that the error affects # # @bank-group: Bank group of the memory event location, incorporating -# a number of Banks. +# a number of banks. # # @bank: Bank of the memory event location. A single bank is accessed # per read or write of the memory. diff --git a/qapi/machine.json b/qapi/machine.json index 230b9b20dd..0650b8de71 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -811,7 +811,7 @@ # # @policy: the write policy, none/write-back/write-through. # -# @line: the cache Line size in bytes. +# @line: the cache line size in bytes. # # Since: 5.0 ## diff --git a/qapi/misc-i386.json b/qapi/misc-i386.json index 3b5346425a..5fefa0a484 100644 --- a/qapi/misc-i386.json +++ b/qapi/misc-i386.json @@ -195,7 +195,7 @@ # # @cbitpos: C-bit location in page table entry # -# @reduced-phys-bits: Number of physical Address bit reduction when +# @reduced-phys-bits: Number of physical address bit reduction when # SEV is enabled # # Since: 2.12 diff --git a/qapi/run-state.json b/qapi/run-state.json index fcc00c805b..fd09beb35c 100644 --- a/qapi/run-state.json +++ b/qapi/run-state.json @@ -62,7 +62,7 @@ ## # @ShutdownCause: # -# An enumeration of reasons for a Shutdown. +# An enumeration of reasons for a shutdown. # # @none: No shutdown request pending # diff --git a/qapi/transaction.json b/qapi/transaction.json index 5c3394919e..9d9e7af26c 100644 --- a/qapi/transaction.json +++ b/qapi/transaction.json @@ -21,7 +21,7 @@ ## # @ActionCompletionMode: # -# An enumeration of Transactional completion modes. +# An enumeration of transactional completion modes. # # @individual: Do not attempt to cancel any other Actions if any # Actions fail after the Transaction request succeeds. All From 188b31ad425c4122363a3af47343e0d3228687f8 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:11 +0200 Subject: [PATCH 1363/2760] qapi: Use proper markup instead of CAPS for emphasis in doc comments Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-9-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 2 +- qapi/dump.json | 6 +++--- qapi/migration.json | 26 +++++++++++++------------- qapi/misc.json | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index f0faca1054..7b0548dc2e 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1589,7 +1589,7 @@ # # @bitmap-mode: Specifies the type of data the bitmap should contain # after the operation concludes. Must be present if a bitmap was -# provided, must NOT be present otherwise. (Since 4.2) +# provided, must **not** be present otherwise. (Since 4.2) # # @compress: true to compress data, if the target format supports it. # (default: false) (since 2.8) diff --git a/qapi/dump.json b/qapi/dump.json index f2835c0b47..d0ba1f0596 100644 --- a/qapi/dump.json +++ b/qapi/dump.json @@ -54,9 +54,9 @@ # @paging: if true, do paging to get guest's memory mapping. This # allows using gdb to process the core file. # -# IMPORTANT: this option can make QEMU allocate several gigabytes -# of RAM. This can happen for a large guest, or a malicious guest -# pretending to be large. +# **Important**: this option can make QEMU allocate several +# gigabytes of RAM. This can happen for a large guest, or a +# malicious guest pretending to be large. # # Also, paging=true has the following limitations: # diff --git a/qapi/migration.json b/qapi/migration.json index 84edcf81e4..4963f6ca12 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -407,7 +407,7 @@ # @postcopy-ram: Start executing on the migration target before all of # RAM has been migrated, pulling the remaining pages along as # needed. The capacity must have the same setting on both source -# and target or migration will not even start. NOTE: If the +# and target or migration will not even start. **Note:** if the # migration fails during postcopy the VM will fail. (since 2.6) # # @x-colo: If enabled, migration will never end, and the state of the @@ -801,10 +801,10 @@ # (Since 2.8) # # @avail-switchover-bandwidth: to set the available bandwidth that -# migration can use during switchover phase. NOTE! This does not -# limit the bandwidth during switchover, but only for calculations -# when making decisions to switchover. By default, this value is -# zero, which means QEMU will estimate the bandwidth +# migration can use during switchover phase. **Note:** this does +# not limit the bandwidth during switchover, but only for +# calculations when making decisions to switchover. By default, +# this value is zero, which means QEMU will estimate the bandwidth # automatically. This can be set when the estimated value is not # accurate, while the user is able to guarantee such bandwidth is # available when switching over. When specified correctly, this @@ -982,10 +982,10 @@ # (Since 2.8) # # @avail-switchover-bandwidth: to set the available bandwidth that -# migration can use during switchover phase. NOTE! This does not -# limit the bandwidth during switchover, but only for calculations -# when making decisions to switchover. By default, this value is -# zero, which means QEMU will estimate the bandwidth +# migration can use during switchover phase. **Note:** this does +# not limit the bandwidth during switchover, but only for +# calculations when making decisions to switchover. By default, +# this value is zero, which means QEMU will estimate the bandwidth # automatically. This can be set when the estimated value is not # accurate, while the user is able to guarantee such bandwidth is # available when switching over. When specified correctly, this @@ -1192,10 +1192,10 @@ # (Since 2.8) # # @avail-switchover-bandwidth: to set the available bandwidth that -# migration can use during switchover phase. NOTE! This does not -# limit the bandwidth during switchover, but only for calculations -# when making decisions to switchover. By default, this value is -# zero, which means QEMU will estimate the bandwidth +# migration can use during switchover phase. **Note:** this does +# not limit the bandwidth during switchover, but only for +# calculations when making decisions to switchover. By default, +# this value is zero, which means QEMU will estimate the bandwidth # automatically. This can be set when the estimated value is not # accurate, while the user is able to guarantee such bandwidth is # available when switching over. When specified correctly, this diff --git a/qapi/misc.json b/qapi/misc.json index dcf9f7df5b..4b9e601cfa 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -222,8 +222,8 @@ # .. note:: This command only exists as a stop-gap. Its use is highly # discouraged. The semantics of this command are not guaranteed: # this means that command names, arguments and responses can change -# or be removed at ANY time. Applications that rely on long term -# stability guarantees should NOT use this command. +# or be removed at **any** time. Applications that rely on long +# term stability guarantees should **not** use this command. # # Known limitations: # From 51acba6fad54099dad5ba6d0ab2392d9b93ae284 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:12 +0200 Subject: [PATCH 1364/2760] qapi: Spell JSON null correctly in blockdev-reopen documentation The doc comment misspells JSON null as NULL. Fix that. Cc: Kevin Wolf Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-10-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 7b0548dc2e..f8f89ee2d7 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -4947,7 +4947,7 @@ # 3) A reference to a different node: the current child is replaced # with the specified one. # -# 4) NULL: the current child (if any) is detached. +# 4) null: the current child (if any) is detached. # # Options (1) and (2) are supported in all cases. Option (3) is # supported for @file and @backing, and option (4) for @backing only. From 5ca6400cadecc2556ad0852780896eb94bdf4018 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:13 +0200 Subject: [PATCH 1365/2760] qapi: Refer to job-FOO instead of deprecated block-job-FOO in docs We deprecated several block-job-FOO commands in commit b836bf2ab68 (qapi/block-core: deprecate some block-job- APIs). Update the doc comments to refer to their replacements instead. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-11-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 57 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index f8f89ee2d7..6e5b90d5df 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1606,16 +1606,16 @@ # copy-before-write jobs; defaults to break-guest-write. (Since 10.1) # # @auto-finalize: When false, this job will wait in a PENDING state -# after it has finished its work, waiting for @block-job-finalize -# before making any block graph changes. When true, this job will +# after it has finished its work, waiting for @job-finalize before +# making any block graph changes. When true, this job will # automatically perform its abort or commit actions. Defaults to # true. (Since 2.12) # # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits -# @block-job-dismiss. When true, this job will automatically -# disappear from the query list without user intervention. -# Defaults to true. (Since 2.12) +# @job-dismiss. When true, this job will automatically disappear +# from the query list without user intervention. Defaults to +# true. (Since 2.12) # # @filter-node-name: the node name that should be assigned to the # filter driver that the backup job inserts into the graph above @@ -1785,8 +1785,7 @@ # If top == base, that is an error. If top has no overlays on top of # it, or if it is in use by a writer, the job will not be completed by # itself. The user needs to complete the job with the -# block-job-complete command after getting the ready event. -# (Since 2.0) +# job-complete command after getting the ready event. (Since 2.0) # # If the base image is smaller than top, then the base image will be # resized to be the same size as top. If top is smaller than the base @@ -1848,16 +1847,16 @@ # autogenerated. (Since: 2.9) # # @auto-finalize: When false, this job will wait in a PENDING state -# after it has finished its work, waiting for @block-job-finalize -# before making any block graph changes. When true, this job will +# after it has finished its work, waiting for @job-finalize before +# making any block graph changes. When true, this job will # automatically perform its abort or commit actions. Defaults to # true. (Since 3.1) # # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits -# @block-job-dismiss. When true, this job will automatically -# disappear from the query list without user intervention. -# Defaults to true. (Since 3.1) +# @job-dismiss. When true, this job will automatically disappear +# from the query list without user intervention. Defaults to +# true. (Since 3.1) # # Features: # @@ -2212,16 +2211,16 @@ # 'background' (Since: 3.0) # # @auto-finalize: When false, this job will wait in a PENDING state -# after it has finished its work, waiting for @block-job-finalize -# before making any block graph changes. When true, this job will +# after it has finished its work, waiting for @job-finalize before +# making any block graph changes. When true, this job will # automatically perform its abort or commit actions. Defaults to # true. (Since 3.1) # # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits -# @block-job-dismiss. When true, this job will automatically -# disappear from the query list without user intervention. -# Defaults to true. (Since 3.1) +# @job-dismiss. When true, this job will automatically disappear +# from the query list without user intervention. Defaults to +# true. (Since 3.1) # # Since: 1.3 ## @@ -2531,16 +2530,16 @@ # 'background' (Since: 3.0) # # @auto-finalize: When false, this job will wait in a PENDING state -# after it has finished its work, waiting for @block-job-finalize -# before making any block graph changes. When true, this job will +# after it has finished its work, waiting for @job-finalize before +# making any block graph changes. When true, this job will # automatically perform its abort or commit actions. Defaults to # true. (Since 3.1) # # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits -# @block-job-dismiss. When true, this job will automatically -# disappear from the query list without user intervention. -# Defaults to true. (Since 3.1) +# @job-dismiss. When true, this job will automatically disappear +# from the query list without user intervention. Defaults to +# true. (Since 3.1) # # @target-is-zero: Assume the destination reads as all zeroes before # the mirror started. Setting this to true can speed up the @@ -2859,16 +2858,16 @@ # autogenerated. (Since: 6.0) # # @auto-finalize: When false, this job will wait in a PENDING state -# after it has finished its work, waiting for @block-job-finalize -# before making any block graph changes. When true, this job will +# after it has finished its work, waiting for @job-finalize before +# making any block graph changes. When true, this job will # automatically perform its abort or commit actions. Defaults to # true. (Since 3.1) # # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits -# @block-job-dismiss. When true, this job will automatically -# disappear from the query list without user intervention. -# Defaults to true. (Since 3.1) +# @job-dismiss. When true, this job will automatically disappear +# from the query list without user intervention. Defaults to +# true. (Since 3.1) # # Errors: # - If @device does not exist, DeviceNotFound. @@ -3077,7 +3076,7 @@ # This command will refuse to operate on any job that has not yet # reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that # make use of the BLOCK_JOB_READY event, block-job-cancel or -# block-job-complete will still need to be used as appropriate. +# job-complete will still need to be used as appropriate. # # @id: The job identifier. # @@ -5866,7 +5865,7 @@ # @BLOCK_JOB_PENDING: # # Emitted when a block job is awaiting explicit authorization to -# finalize graph changes via @block-job-finalize. If this job is part +# finalize graph changes via @job-finalize. If this job is part # of a transaction, it will not emit this event until the transaction # has converged first. # From 901eb8b2d8a14a0378d1c59fe37733366d4da16c Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:14 +0200 Subject: [PATCH 1366/2760] qapi: Mention both job-cancel and block-job-cancel in doc comments Several doc comments mention block-job-cancel where the more generic job-cancel would also work. Adjust them to mention both. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-12-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index 6e5b90d5df..ad6de151c8 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1894,7 +1894,7 @@ # The status of ongoing drive-backup operations can be checked with # query-block-jobs where the BlockJobInfo.type field has the value # 'backup'. The operation can be stopped before it has completed -# using the block-job-cancel command. +# using the job-cancel or block-job-cancel command. # # Features: # @@ -1925,7 +1925,7 @@ # The status of ongoing blockdev-backup operations can be checked with # query-block-jobs where the BlockJobInfo.type field has the value # 'backup'. The operation can be stopped before it has completed -# using the block-job-cancel command. +# using the job-cancel or block-job-cancel command. # # Errors: # - If @device is not a valid block device, DeviceNotFound @@ -2788,7 +2788,7 @@ # immediately once streaming has started. The status of ongoing block # streaming operations can be checked with query-block-jobs. The # operation can be stopped before it has completed using the -# block-job-cancel command. +# job-cancel or block-job-cancel command. # # The node that receives the data is called the top image, can be # located in any part of the chain (but always above the base image; @@ -3075,8 +3075,8 @@ # # This command will refuse to operate on any job that has not yet # reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that -# make use of the BLOCK_JOB_READY event, block-job-cancel or -# job-complete will still need to be used as appropriate. +# make use of the BLOCK_JOB_READY event, job-cancel, block-job-cancel +# or job-complete will still need to be used as appropriate. # # @id: The job identifier. # From feeb08c260171e8a15236d20f2978c68aae4f569 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:15 +0200 Subject: [PATCH 1367/2760] qapi: Tidy up references to job state CONCLUDED When talking about the job state machine, we refer to the states like READY, ABORTING, CONCLUDED, and so forth. Except in two places, where we use JOB_STATUS_CONCLUDED. Replace by CONCLUDED for consistency. We should arguably use the JobStatus enum values instead. Left for another day. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-13-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 6 +++--- qapi/job.json | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index ad6de151c8..da390f85ac 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -3074,9 +3074,9 @@ # jobs. # # This command will refuse to operate on any job that has not yet -# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that -# make use of the BLOCK_JOB_READY event, job-cancel, block-job-cancel -# or job-complete will still need to be used as appropriate. +# reached its terminal state, CONCLUDED. For jobs that make use of +# the BLOCK_JOB_READY event, job-cancel, block-job-cancel or +# job-complete will still need to be used as appropriate. # # @id: The job identifier. # diff --git a/qapi/job.json b/qapi/job.json index 9ddba537db..441cd7772b 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -223,9 +223,9 @@ # jobs. # # This command will refuse to operate on any job that has not yet -# reached its terminal state, JOB_STATUS_CONCLUDED. For jobs that -# make use of JOB_READY event, job-cancel or job-complete will still -# need to be used as appropriate. +# reached its terminal state, CONCLUDED. For jobs that make use of +# the JOB_READY event, job-cancel or job-complete will still need to +# be used as appropriate. # # @id: The job identifier. # From 8fa2020647041e9f01bc308589bb7fa00355ac9b Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Tue, 27 May 2025 09:39:16 +0200 Subject: [PATCH 1368/2760] qapi: Improve documentation around job state @concluded We use "the query list" in a few places. It's not entirely obvious what that means. It's actually the output of query-jobs or query-block-jobs. Documentation of @auto-dismiss talks about the job disappearing from the query list when it reaches state @concluded. This is less than precise. The job doesn't merely disappear from the query list, it disappears, period. Documentation of JobStatus @concluded explains "the job will remain in the query list until it is dismissed". Again less than precise. It remains in state @concluded until dismissed. Rephrase without use of "the query list" for clarity and precision. Signed-off-by: Markus Armbruster Message-ID: <20250527073916.1243024-14-armbru@redhat.com> Reviewed-by: Eric Blake --- qapi/block-core.json | 19 +++++++------------ qapi/job.json | 2 +- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/qapi/block-core.json b/qapi/block-core.json index da390f85ac..1df6644f0d 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1417,8 +1417,8 @@ # @auto-finalize: Job will finalize itself when PENDING, moving to the # CONCLUDED state. (since 2.12) # -# @auto-dismiss: Job will dismiss itself when CONCLUDED, moving to the -# NULL state and disappearing from the query list. (since 2.12) +# @auto-dismiss: Job will dismiss itself when CONCLUDED, and +# disappear. (since 2.12) # # @error: Error information if the job did not complete successfully. # Not set if the job completed successfully. (since 2.12.1) @@ -1614,8 +1614,7 @@ # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits # @job-dismiss. When true, this job will automatically disappear -# from the query list without user intervention. Defaults to -# true. (Since 2.12) +# without user intervention. Defaults to true. (Since 2.12) # # @filter-node-name: the node name that should be assigned to the # filter driver that the backup job inserts into the graph above @@ -1855,8 +1854,7 @@ # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits # @job-dismiss. When true, this job will automatically disappear -# from the query list without user intervention. Defaults to -# true. (Since 3.1) +# without user intervention. Defaults to true. (Since 3.1) # # Features: # @@ -2219,8 +2217,7 @@ # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits # @job-dismiss. When true, this job will automatically disappear -# from the query list without user intervention. Defaults to -# true. (Since 3.1) +# without user intervention. Defaults to true. (Since 3.1) # # Since: 1.3 ## @@ -2538,8 +2535,7 @@ # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits # @job-dismiss. When true, this job will automatically disappear -# from the query list without user intervention. Defaults to -# true. (Since 3.1) +# without user intervention. Defaults to true. (Since 3.1) # # @target-is-zero: Assume the destination reads as all zeroes before # the mirror started. Setting this to true can speed up the @@ -2866,8 +2862,7 @@ # @auto-dismiss: When false, this job will wait in a CONCLUDED state # after it has completely ceased all work, and awaits # @job-dismiss. When true, this job will automatically disappear -# from the query list without user intervention. Defaults to -# true. (Since 3.1) +# without user intervention. Defaults to true. (Since 3.1) # # Errors: # - If @device does not exist, DeviceNotFound. diff --git a/qapi/job.json b/qapi/job.json index 441cd7772b..126fa5ce60 100644 --- a/qapi/job.json +++ b/qapi/job.json @@ -74,7 +74,7 @@ # process. # # @concluded: The job has finished all work. If auto-dismiss was set -# to false, the job will remain in the query list until it is +# to false, the job will remain in this state until it is # dismissed via @job-dismiss. # # @null: The job is in the process of being dismantled. This state From b652d512855997ec89c78aa540aceadd5af13724 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 11 Dec 2024 18:14:19 +0100 Subject: [PATCH 1369/2760] rust: bindings: allow ptr_offset_with_cast This is produced by recent versions of bindgen: warning: use of `offset` with a `usize` casted to an `isize` --> /builds/bonzini/qemu/rust/target/debug/build/qemu_api-35cb647f4db404b8/out/bindings.inc.rs:39:21 | 39 | let byte = *(core::ptr::addr_of!((*this).storage) as *const u8).offset(byte_index as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(core::ptr::addr_of!((*this).storage) as *const u8).add(byte_index)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast = note: `#[warn(clippy::ptr_offset_with_cast)]` on by default warning: use of `offset` with a `usize` casted to an `isize` --> /builds/bonzini/qemu/rust/target/debug/build/qemu_api-35cb647f4db404b8/out/bindings.inc.rs:68:13 | 68 | (core::ptr::addr_of_mut!((*this).storage) as *mut u8).offset(byte_index as isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(core::ptr::addr_of_mut!((*this).storage) as *mut u8).add(byte_index)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast This seems to be new in bindgen 0.71.0, possibly related to bindgen commit 33006185b7878 ("Add raw_ref_macros feature", 2024-11-22). Signed-off-by: Paolo Bonzini --- rust/qemu-api/src/bindings.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rust/qemu-api/src/bindings.rs b/rust/qemu-api/src/bindings.rs index 3c1d297581..057de4b646 100644 --- a/rust/qemu-api/src/bindings.rs +++ b/rust/qemu-api/src/bindings.rs @@ -11,6 +11,7 @@ clippy::restriction, clippy::style, clippy::missing_const_for_fn, + clippy::ptr_offset_with_cast, clippy::useless_transmute, clippy::missing_safety_doc )] From 0074a471477d56723bd6fd044b78c30ff5958f56 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 29 Apr 2025 10:43:16 +0200 Subject: [PATCH 1370/2760] meson: update to version 1.8.1 This adds several improvements to Rust support, including native clippy and rustdoc targets, the "objects" keyword, and running doctests. Require it only when Rust support is requested, to avoid putting a strict requirement on all build platforms for the sake of an experimental feature. Signed-off-by: Paolo Bonzini --- configure | 8 ++++++++ python/scripts/vendor.py | 4 ++-- python/wheels/meson-1.5.0-py3-none-any.whl | Bin 959846 -> 0 bytes python/wheels/meson-1.8.1-py3-none-any.whl | Bin 0 -> 1013001 bytes pythondeps.toml | 2 +- tests/lcitool/mappings.yml | 6 +++++- 6 files changed, 16 insertions(+), 4 deletions(-) delete mode 100644 python/wheels/meson-1.5.0-py3-none-any.whl create mode 100644 python/wheels/meson-1.8.1-py3-none-any.whl diff --git a/configure b/configure index 2ce8d29fac..74b3865e51 100755 --- a/configure +++ b/configure @@ -1178,6 +1178,14 @@ fi ########################################## # detect rust triple +meson_version=$($meson --version) +if test "$rust" != disabled && ! version_ge "$meson_version" 1.8.1; then + if test "$rust" = enabled; then + error_exit "Rust support needs Meson 1.8.1 or newer" + fi + echo "Rust needs Meson 1.8.1, disabling" 2>&1 + rust=disabled +fi if test "$rust" != disabled && has "$rustc" && $rustc -vV > "${TMPDIR1}/${TMPB}.out"; then rust_host_triple=$(sed -n 's/^host: //p' "${TMPDIR1}/${TMPB}.out") else diff --git a/python/scripts/vendor.py b/python/scripts/vendor.py index 0405e910b4..b47db00743 100755 --- a/python/scripts/vendor.py +++ b/python/scripts/vendor.py @@ -41,8 +41,8 @@ def main() -> int: parser.parse_args() packages = { - "meson==1.5.0": - "52b34f4903b882df52ad0d533146d4b992c018ea77399f825579737672ae7b20", + "meson==1.8.1": + "374bbf71247e629475fc10b0bd2ef66fc418c2d8f4890572f74de0f97d0d42da", } vendor_dir = Path(__file__, "..", "..", "wheels").resolve() diff --git a/python/wheels/meson-1.5.0-py3-none-any.whl b/python/wheels/meson-1.5.0-py3-none-any.whl deleted file mode 100644 index c7edeb37ade47cb8b6275cc7dfe6681d957a1dee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 959846 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Ê&+``xSf5TeD({id|(c8gI5=A5{3Pxl38@ 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/x$W^Ppb9o++tC-$XwwP=bd?REQya6xP%xbDJF1g z-c^e{D1NYbzZmyA({8q)%C#RKd|jj!KdaNFHRid`9fpO1XBO6^7cNQQFYR~XQ8D_y z%4lW{w-octE|xg{9zu#?47|V8M z_HB~j=Z#oterKNIC$5tmeLG)wZhU=Vx0{ooqq`*cU;ACz>g`|NDos$xdsO-M0AF9X zhQR~|al=o`EiK>vatY$wn4;1CRhWNri`gUl$R}wX(VYLjxt~|LWLat3;qYwlB$MFA z>&!Jfx+~I;%l@{$WxayugFwrJV*=aPZctY!n2~X1E6=jUY3n*nLuEPlO8#Kq%5^lx zOMLDI*chyBCD*&2fQN_u4; z9&Gz`>HVVqzl>jWCPl(ht5v%ceXjm1Uvlc~JDH2je)4YGqNtl?Vs`rAg=UE)A^(#=6k1ew)fPO7y9t+Dw`SnJgU&iAt|bH{}hHk_#`|6Rf?=zG(y3Z2bplmtK+C^07(aA7=-Z?7+uI-IK z!?)ga-_K_`RkuD(E9D3go-oZ_>f%eSE~nIeO^TM@_kGR^_sVA+eE4#ww0{}D;U&52 zVFh<2_uf9p^=Z!`dui5H9uwyXaL4>+Zj11pz#YIvQ{q$j_ADiKBXxzzIIO1+!ueX*-uK=Ug`h5`QqD^rjO^JO^umwO6yA1Pm2lvk3HLU z=|u#0=f=ASYHz;zpHw(y&A$y>SG2x2IA4EeUpuGELa$9f4Oir?d~jn^|BH?1SM;y? z_3m5~=PJd!X;}xwA70+ixM%J2?*dzj=Y}R<&%G}0)PAt+N8g*W@HvawKP85460qP( z3gA2#S!x<(jc4?fO(!>@M>AsK`v+&J2%5U(DhjZ)XWVq|wc9;=6ZuY~?SO4xUZ^ zCu)MHG1ok-|Ih98@9cw&#fz=oSI=(P=N~`sIkVOE`q<0)2dyJo-f>i4y^^zYf@IxC zYuA{~%nxoym%n;*PP4K68}FvwzZctm*`@V0A@9>|JxgbA^T_JP{@X@po_Mt#{_KdqRVHiE)MCP%`GO&eJ6UM^R;8AZywn^UCRI2=bO7%>kE{|HGW@Z74|Zz z`P!wu-cbjyM?0lV@ zUU`b^)#`*lER#b{X2`rLns_4A``z#RPH%Q-wDH}aQla*J`=vj>7Cluz`oxmKN5Zka z*frKHO;JrtL2u9T*-{G%@=JDzOuo2j#^XodyvkmD$~%95?N0mF&GxpozmL_`W!o)J zzxRHDopOfBJzfi6spRsDwz?OrmE(S!9l6~f$=)+#ewNO*L$g)nTEb^IYU@l8Z8s^p zy}s@v?}UACubSU;{B6XxIpIvM>82#6QvD@6HGTeXeIz8ska}g$*`Pjy6GieBIbBXI zs}HJr2JH$ucy6L}$7F$BY%$4Z_%A8<^SdT^SGNgUR=w*$Tau6=62s#S*2gzE?@j?MgGFQbKgaD-%P}jgQ{h zR3#JYF0?i|`~CIvHx9T~-tEl}s!h+2Pks}bVp33aBe_$3x$rFY3&!<}9yBobop1Bh ze4-dOM}Q+PrO5Hs_x1vnYchxO-QGW3^CG;rbpFo6H7#D+k5mJ+J}kPC(N}WhBoTPtDtR;a$?335y=I+^N~~!$Ns_T$WxNz~^Z6ndg6H9sgs)xM3c{BK2SUV$T*g8f@JkXyIQOm}9*^q(J^vyta(I z{OpM@)VnenuJC*d^SyNF&o#wOJ74m$Ez&>XZB`o~FexGI%;Xl&zqhCEn3k0`W4@+K zRja3t<-MMp^16S-5&as_jO7*$JI~du3=DdL3=FckW-N=#Gt)pFo4MhTk?ZgA2e)cy zEZ#ODm0y~t;=qKe=nGqTqwGrzc$%i21C3mJX!V)DslPw**P@i|rOVi(Z9eX+E8k{VUy{U|z46ckkZ5|H)=bKdw|c+NpWv9bGr^E8jyw zp}ePIyx&Z}%`r5*Gn4aY!#30ZXWyB-pDdnur!s3t{fo-n183tBzqlzE3q+q5VVcmr z-}czOjgnPg-Bij_b$0FTdEfH!{cF>ilk4}?M5V-dSShdmx*mEB#0#$D)vh-w&b|k z_(U&_j5}!k`f<$9E7dKDondSf?`cf+?KsdgLs04oyK86aw2fgWjs86lo|+zKEA=<- zWbr2L<<&e}rYmeolsg}l7cAEC(jrgx_zTm#?eo6PS<_>;xck@<$D4{*yYk{&OsIm`vwSt0!&$PwFxT9qw5j z#krd2eanu9`33r=oV9P+FGwA%Yhx^_dJvWL(KtA7*}S_K8vQjz6gDQPyKiH@>3Q5J zDyrLiL#fr{s_x^b*Xv#6-MQg%*q(-YSxc-F&n)e~RnvIHEXq8-EvhQAZqdqh-!^I* zB|bdqwzcKst1RC*VX5FhUv~!Xe*JY;(QZ-yi$7R;K4fl32^+%$p7hS;K~*s!6hkC8!rc(bJ%=(en8^0sxPg(*cSEp zN>1aS|M$Fi(tM8-v!+bTH&`GVIH8}7+ohpv3QFzt7U_y2~NoJ!T&jI9$q z!&X|=)R%2Jz_m_Lru*nr z*_OM;`wX>K+uf*r?zy*fuGz`;*S~%~zf2_ZRM5ix!hUO1ZtR>dV4dU4k}|XTnb@Lz zx{l4o{C(L;rn`@QYnQ$6_@bqx#oEf+aJznft5)piH8bM2U-i(MyLAuqZ>{j)KyQP=> zY{hzdn|~g!4`1rnu(P@0ca@(>mb#zE^}5%ezUTJ&DZaJXn2~*Mo8wXMf%*G)-{U3Yx10sE=jWkppxn6?`+ z-=FfSR{Yo2PfGT87OHT~&J$@7XtWQQuGr~SC^I8C=jr8m1N{#{OKNt%z4_Afqhqpt zug20=u}g0He>V7P_5VG~uzJdQ$0-u~CHf1})7>6kTD^P9(eG0|&poSZJ97Ba;m0vc z-FMf9^Aw#+PU|#e>yxT=Ih<7F%lNltUVboOfo*5 zns6lEURubJy}Tlcw@-5Ysu>pA8*eLS?9QmkYOaN2r8FGwZpxR+B=$-u<}m+n2IJkBVuojB_5RKiZhl-0YEYfNA!mvlHhW zI$|o&E<8)`?zi=ij3o}tT3r(RSU}f*_Xd7G{U@v2>Mw}+>+LxEMe@>o!#6cgZ|$*~ zx?S!s+Vte){0D0SI2jmzE8!WvDoe}(txMS&8J&OILagrm`UeX9la_5W%jD)c){s82 zbkfWPnZhPB59-`;SfF|t~=Pzd5xjXOw z-TluLy+vNfyXu_$F~!(YAzhRA`I`UN>@BU-lqarJoqyK&)3+yIa^?U1aeDW>rzXWq zMJ35!N9-k&+2o#!M=xFs>0;$e;!+KChEGtNgWYmNQz|K$pP1(T4%rfZ)ij63Yi&TcDPq5JMJ z`|P?SYNsRT8c2lMpY|^@w_Se!`s=yuOb0W|gxkE#W;PaHPEA|6aK1{(!Ed7V`KLwm znLCb`9{nW$K*98@L$!9w7ANC9GFvX)P5b6?xXb;6>4td8gkWDmo;!dzGVmPXp zRrUHn*JUUBC&`AY`E5VlLOPFW?+V+wbI;xx{dsox;$q`(?1?J5-5wa&zTv*p|8Jj< zzI{IX;?cWz`NUSHtQ1iUUNzY}w)VA%_4l_gwRpWIFvV@2y|>7G-cN0hE9dL%nf&UX zm~^aJvE|bh?V!tDo|;b*KYdvq@b|Hu7o&xT=~83OeR>P)*mh)wvoWdXK9JiUS5$T6 zXKux#{lAaeubsZDtzy>A3yS$#+xTz4X_zxjlDk3n$qAkaR_%FbnXLkq&c&w`FZSH2 zksz1qFONOa051TfR_o zVSAGHX=Cxv8-t})jFaCU%@u6j!^?Y4kv&*?RJdV@jJ#lunwp4%i znzvO^Czn6e4!3Fa)8d>Nz4ztIUzeXwu99zwE)8eBw=r+7^Q2@cA?}YI3iDEm+ny~s zZJ|8lW9K;sF99C50!OXGmU@#I+?JbWb)J|xDJG&~ZIIZbHR_*UOFdk9eNCR{-HGXX z4@1^}cD_3y{loUfrUu?!AO0xLWUbGT-^+W`(b7Xc-S1`T-8ZLouid`;@UHB&AJ45H z?X=+1Ue-R>uy_BWYg<(9+l(eM?u%5rxc}hV>nv6dJx*_(Zc3W)2Ia@PWTUGW7vxrEk?a#)Pvmva{ z)xuVuYS&U~j3~BZYi}<+`SGmRC6m-m=N2pb=O2C+YLUS9!R+FUd^KT>1IIsNWm*8n5uzWS7;vyV7miIliE~p9MHt&MxGAwoW^9YTt%{3u}3< zM5=WC3B9{RqvQHIrz*v8-kcjsDg7yLH1n>fWgp#8BKYTFd85U#p7=wY37cHzXZU1r zeMmby`;OYY$(9Q1G+%C=JgIcSv<1hX=yZ7vwS3f3&elP?`Im*@S#w#apqO zK?;t?)%oY@7e1NOC;sJT>#pY1L#6+oR@esJtNr@r=AN_81<*Eg# ze<+vW`~A`G(c?t@f_siU0`HD<=XaakWs-PieK&D>e)%s$mWls@5?m)V@<|_Fk#{-tl2%Dw|S>jK4ll%wr19fc}pK|sJqOpGk?bW{KI?P+mCr}GoCS{=4$TQ z2@&faCQk_oPQTmWvH!=scFEnb9;(4NQg7dI-O1YQ^yr#^`}dmPe5<#=xP8|&N$bUybxtSH2dByti@tJv-ud@F2u(fwa+A~3%Ci^GJ-D@D)4`Xa|Fm{C z>@;IPy}h@6|No}d;o_P}ico+U$)Q4c>=79++}zUvsf%{wMasSH)&Dm%g9&e5cFusSjo!d~Y^K z{JiR{8C>fV=dQP3FLw0L;iP|`KRx~($@GQypKJfE-TF&&Y;SYyd3Y|EH*R{=o&txh zkHfS*|M2*APk#C5<;DvS@9r^I(U3W2qL*;Dpz1-x!M17*)^``uWMe-i@NIB65VKvy zRdcwbg-w=kiO~Mk9h{8SI~3j6{MeuC3Qc!vSl6uW@uhd2hE%2Dd)@n6P;LkueMN7(lMrN~^`Z_J)e*u8hF=!(Ve3WZ2A6 z+q|S$?PTqOTb^yA>$A74@H&;$T-U$iLHM#A0zA)}SQnPgNv<#AHE+{+Wwd+#Yp%t0 z%vphdN@}-j*xg;%Rc?O${rj~0*Df}H{x4yl77KS zR!kRzt~BM|y|HkGvBKB0=f0XXzU)`|Ah6WAf7L7PT5*|!kKXHUpR)7%;WtN>>;(V3 z<=WD9NnxV2<>Ak+E)g!~*xw~H~Hb+7{r_M!cTSar-D=J^yi2C9 z-8|iCy3d>ie$`J_U%&O^w43*xh&%ITlKx%@{kSyap>@TI%P&9mH+)QIcc`9fRev&6 z^A^{BMc;#0FV|mr{=fCsooh-Sg6$B070Y*}O(xU3zd7q&Iao*CxtPG%Z8XBj#Wp3#V4qE=T=3 zu{#F~_D-sK`gLLdTGx|avzhLj_wESke^hmP=ANVHLpjyo*9)~x@?=o6-+yq9)ZwUI zqMx>{y4c)v-KRiuvEgV^NaZ{(e(+6x*x7HvdoGYn^|x+yAN_W%n;;Tjz6o>f&?Pe$DK>vmSl1@%C|M|6)4L?4euq?!R94hgCvTnnMcN z#r@vz_|RagvUE=KS}!IhZjUapNozcFm-olZ^hTZR{XN;#`1X!%8;{hUSsxvhALH$j z$jA6r^49;K7w%sE)2>LtEnMm3dd)skG_*Qw~Csu#agznKXmp$GVeb9i*ox31`6CP~*DYdo8y1Vn}nga%j`i&gBgr)X*X=(3jyA-75oBYgcL&yyGHE&$cb?{F$ zsjyjeri<%#*^7IzF>|lAC&WHpaoZs*v1Qk#Z~NAJ-=DvHx|>Pov_skXygd5-@%;_k zUe0cuB4v7RPR6+xQP6g$-A=dD5o-UMh4x=}Zee=AE;xBseQd7%jlQ$*y?3{pEX>UR^0@N#^|TEa ztm;GF=DoJ(|08QVCE&(KHC1Dt>ck^=TB6Rj=&m{Unm_OABR2)71sm6uGX!_*eBRPJ z^}MwEOr6WtcX&No8QmESXKXyY??d4J1m<{VcCr)}K%i|s7`{`&N6 z#iU&=vtCNixs`M)(&w#(EzjXY=c867?iSxtWH&dqf7au5kMHdJk$3*t?+fix=8yUo zo%r9b*`7AR-07Ks)QuggueWFXdtATV|MTKU!cnFQf^oLw)M8;VRV z-SFW%Lml(t*yQNY4$En;X2cxwNv_)5!Tz;dTu?1G-1GBW^Bjd8!cu}3&cAjFtxe=x z?rX2rmS->U)~uYnO}A0+b#}i2dux34YJ)4v@$03UuP&b9&TaK1BQIKI=jE@?GfnxY zCFY&#UsT84A@g?2_8*>=Hd!-Xh_xk)OYA7h-Eg(@AN#Ibr#C+iP?+*qgnOaJ$>4|_ zr}gh_JJnz9INXux!oI)Nbn$L&-+YCQ_YWVs`9QIoDPxj%Fu%z6-+BV&sd_t0WczEr z#jN>z(>CCb)LoOByO!Ik{Y~L;pf55B*-@!x{8yoYsH|B^etm|ZSd za?Kp=^xwZL>!Od`O8LDb?fYA=^};n>m1_SrFN?RI=kMS5*5h-B?_Ms~2rZYoIeRp% zw%$?9I?$&n&ZF2Yq;U1lagM{TpDpg18anOqDVcaFDKqimuWa9aPL52MML0JK>6}dF za<7i;_|aJDs5LKq<%}z>H>?jx)%U)h!|&(%K;-bP%EcGwn_ZhT|HtdOpI6`QeD>#R z*^Hl$tv8&H;s3jz_qX=e#QjXDP48*}m39$U1_o9>1_osUHFR=vQH5SX<e&kI_!w(`)ahl*7{{ya3B`M=Qm|L1pq-*069@&CPeSRlXNGi*t^j}lEY+KdyxGu^11hYln z`gO&f{);zh|_~fd>Oj(b#<|khpmn6-0T-Lv3*@O03aetS7U)!yBICQgI z`_@UDY=p1ppE2SQo7>5Lb;0I`0Z}36Lph$Y+)Fok5wEuK`ImEZ<<&2Hu2NBqvHp>0 zo2vA3#{3s*=YO)zJuSbnbketMlY>h(Pq?@}U-`>z)+D8`l6pHlCpjd~^jG-9de6JD zdRg(JHb(8Wjwj z^2}nJG^u<2f94l2xLyXCMr}7Q`MHN{&c5kl#|zl&-ps0f&QNN(U936x*ZIx6nIpfv znmaQ-_I18{W9;Qzmis&2c24Y6crIt?;Vs41S0(n-nK@{Wy>9J!Rp0ba*0$&8h52=? zog1jV(D}4-u7qipwE#<9#bf_t(Ra+M+gsl96u%8_e%Kwk=MUqhyOkCcSUl!aq%nZQa_P8^U5{1Skh*3SNp_-uNIr;Mlo6e=X&6xNRL4 zG`lqJ5S)1V$?UDK8|4kHXSk?*Q%^5`J|*|wvF{s|9gn=4^?}LGQYAUeB8yvl$_}jPS&sNKXSF0YTnwebqY*MOo#_aO6E{zqhwbKkF zn*IBJ?(A4UEmxNPmdx|Co=pnQ-vqYo(to+%FXeIPn>9J{O?3~upD0NvDclze|5$XX z*RT4e^x^9NjEF)N)a`NobyUuPhk@akGU4%zc4bI(o6)|?mSCR;r?ajDw> z{b~34%fGN%|1bHov|5Q-Q2XLvi7t!j!J3;GtEYcT(A)L<-@S9(W?q+4)zUxDdHeqB z{j%@hzkR=XG-g9xZl@!6bm@Yv(biQ+RQ`e(*0@tkHXcii(_ z@ysJx>FMR=-|xCSmE`}zFk4OXwBqL{PrhHir}5}x59>*#sS{7!n4+Ju<;%vD^y8pi-=;rqnF?0LB`|yY2UH=|^`SU$6cZJcqE!(!d(oyyQt2OOu&n5e* zca@C|W_3UKWy0Ay*P^?-h^@zZ;`Kv*XC9o>-2FlS-{+TqE53aGeQ~{f{cnQ{)26v~ z{BTS2T+^JLx+k9Z>asQ^QNtjO35zzp*dY^b^sVXWNprgdd)aqi%gdNPJ-6^!q$2$} zXBpdu#}RBlRf`riKNnv4x4x6?O|PCRYiw<_ z+U-}_lK9>?w%Alepc7v-B6)NIw7U^C2L&X1l|}b$d@dH(EBGaiPJz zYa;eWr81|^WZQ2kU&X3_!p-)tsUF1UNG ztfyMsRqc5~Z~^a)K%EDMk0*L1Y-r2+_VNB#h2%pw4!wvFy}WXdu-ja5*SPAb6O1Q@ z3tkh=HxBN9ct()f>yX*&e=oxRXT{Gv5Gb)(?L}-Bo<;o7Ce>yAx!a@*N+T+KCm z>V_aQ&q*1+-7}A*#GL;2D{Y?YUCr&iw+oN{o^Z?PJn#Os3zuFElkV?usp%KKz9eql z>D{ZOC$SYvr{p$&W@t#kT*iQN>It~h9?e$&)l=;%T< z8?)GM$=S~&^o0Y(Vw~%W=IpgxrJ(WRhL|FA{^D8j3mk&%g!5z<#;EL=^sM@zOcM)J zZ)b_hBpW$>NgLfi%kCFEIbqS!6;N`rxnskp;Cbi&uJ7!Lz7{V#*>q_zBlDuvIoI>z zO}Wp_5q;di(fhjk(3yi$cPr0)Jf>U_tg$?JV&=N8y&L%#2exmk)^3z5lNXOvyzw@M z!FooNo|iM!YgIU$?lELfpJAc<=)jf9XQuaU z@tk!2q|gpClb35ZmM$oEQRO~Zme2ZTci-gO72AcFE1pR%FnBEaVxzMD40W#~vRxl0 zEsZQvc0M@a+l}Q~X~qj*O}TyJ{4~$Nc|4WRx{MuJ*T%X2Y5lzGw4HZy{qkF;%WH&t zme2avI%V<_&9g^j7di9P9^EVx*z>ka$2-7%g#e>}%9F>dbZ^%B?Eg0Vp7CX)EuSY# z+|e~>D-hdL`P$P|y-4aL!#xe#NaKSV*9;E5;Ak$l@?e)d^R==m*mz2pzmmsZ)uVUM z7hW>e(yZgnRGU+u{#QB0PSefhKwrzIx4jpezc_e(R61q;`v*^j-aCtF+*a#$ir((g zd^>Z|FZN6JTowP?P47&cvUuX`i;{i|Z>{k;d`ee+mxIc^C6-qEuUFNdSnfJ2S-K>m z&F=S7hFvkICkQ>s?-Ow{VfC1O(EVu3EYaS)U*Y0T9j4!w1hoe2ZEoIPy?)i!?$nbj zR|m0$GViLn7AH6D;p=G+Ut1}DUKbC|d(W&QWd$0xOOD`OUXm+pbOzi=Mk+ z%DwF~eB?RLzHRIXa&Nl9|3c}arbVxE&3EVYT>oF}_s&;b4YjPIw31|2?X+|apL;4k$IPU|c0a@YHPi2Fo$>qWIyY}lPd@8@ zx!JqufDs+@AA=Ygnasm3DZ$I$|<%-_~GxwBk&WAiL?#z)C>bBtKGGQBc>`RM4`$lX65 zPN-BldOK?84JUK1_Nq%)#W=g4ND6&fvRXF0<>$2n*U#m-&R)0BptI`Pa`mjaFKKf<- zhZh0%LES~Z8yDP4sNMg6)674&`=>pd9&vW@(TFXLB5AEQFXX>@r1mE`KihkF@%H?9 z-=@q01-@T@oBtg=c=6x8lw0;zHZ`JqW_{yt`tVio{r+f!eOy*XaOyYmcK4qct!#^5fX{E=dy8VO1-N9to|Y-zP<`p`r*BDxTGg97uHCB3 zjz3eo<^D~B*zb4OpLF5<-rzB3hvP)`V|AJ5bfjyFas;h&4~OqcyK+Q4?n1`1V+Yzg z{+{?|wrR)n?UUR8-FwEp{dnP(n%3B(-AiXMmlOFv4Cz6|)?|4fk#d>Cro22UN z6Pu1(cRk(w#v(HEbc0LqAqf_X3Xew_U+%7#`^$2mJ;mC%eE;SAV~U+_rRAlidv~p> zik8`5_wDotgPAAROgTJ#a@pCeiI|+DVi#*`OMYM z@97$z%s=UsQ|_H!&ZD+aaE`lp(3yf5M@xa}&rh-(5WU3r$!67y_K0aGBiWQ|875a9 zXx<<0q+dAY*-RM+@0|jb)AWv{#?`c}ca57rclTmWLH6(OG~f7qGMOrTtnXK5RQhDC z^TD4FN6za1`h3Zx*6#-9^SM^qPyH&f%w}S0=I)vLU!G?f`foB8occ(2{Y{%y=PswL z5r1P^6S`WmZDHiGM>@WzR(<`=vy$;%p1sFsRk#Fl)})?~Kg%&MyB z8uUc+t>4#6jek#OXO-VDG7by zof%uQ6P%}HG#9$+CMzG_@RF}|8M&>zrN)^ zlE3o!l0Cy-?*;V|%U<8A<5*nZe37T1V*i)-ca>Q>Yo{NZFP5I_Z`gL>@5b{-m|7a1 z*fjn3o2-4{-n_bOUSX+W(l9(G0*;G&ZH^bna4hT@7~Ng z=yfeQW}@sP^~YA8$^Uj3ufJUK{I&g`kE?V4gq+xab<-NI%84gVKYX0;=u`Lk#p?XG zTjb1_O}+Gi@&CEy3-=t_Yt}P!@y>`!8?DzXYh`CVmx$+nJSC3((u4Kfe-%F6Z<`t@ z>%U@m@~`g=|K_R}pOklSIjM0?qqUbcD0fQZfqfJ91}(eH$k`uj$hMOC!aQc?DYb@w zs5K+-s zS$=p5Tc6ef&$ax*KZ@%(jqJs`_o&@tEDB@$KIfx=u=s(VM(Grx3br1tu4F?QCv(@W z%q&(m%$H^gzn-CTbP3x@<(PMG94z%W<5{6`g->A2Jxu4e({t~LSa!0>-QDRigvt^cY8^rXITvFo2F`*u^%ahJ9z zd5)8;7ZYSYpIYqmaSD6m6E^7sM^6|@g}gfL@WrnG(WUplcc>W22u3pbwf9@gEn>;G zb$aB*=G63w?=s`k9rI2qtxDk+TYj;1mST~QJ4dU}3fq&!nb8* zT4|K(=a8~oiToQD>)-F4x9|SzS%_)7I}VCCC1{maY;6R+Gg_p@zytRbiR@hV4Y zW32A#No%ZJ4=kUb_&eeAgo0S5eN|!ck=vWCI^5Ut7OC^LMJWGkm>hOxwcX-RYp?Uy zzm!sXo4RrP^A~{}g)7fZKXC8OQlrJ5-3u%3#NXUgo%!JIWR{mdw)D@)(S0R!W=FQF z+@W6wvJ7T~70*0$XWF7V{RM&glCt~CJ{`ZSntZz?!~58lMW^%a^QX7{;J&iROY-|2 zbE|-!KS}e>CqACxp0Mz$>$Mw)OQ*$5ykxOSN@1V1)2ZGA_q3)=`Z0ga+6}qK_Dd{x zogrqrc%gasx>HZy7rhUi=ec%{&IZez<@4nZ{?MBW(+Rw=G`R$8cqj zM6XBK_Qo~W>O;gYFUY+SQ+;D+{2iVnTcc8Y`G0KWKb1B;_lmLCD?R?w?CjSOl{+V` zS`vChc5O`T`gm#UjXWnETi)vwD?YfN8j`Xl>cri7s=}9!u&)d2Tl4Oh+ib5j@_Q$K zHksvdZE{***y6$#?n6HNlO=CPPH2!^-Xi%wr>d3lnu6!q`b?2TiFtf2QUTxJpRz3O z((QZpg0cIOaQT<4AIpAc3Z7ND#WUZIVN0snD+!i1od=fZWL+njmEGT4_4D-l#eWyi zkK1o!Q(;{7^VQpfv%~%Q-P`r+ZOSx_Pfj|u)aMS@x{Y6irm}1haEP^)`d=zvQl-SY zZ24!7t?66NU6|x>|GvYKO0kevvrinnFyUou@&bdCZZ|z9uHC5MJmJmW2X}%w_!jTi zXXz8rNx88+gL^S&>ur~v{GSiq)MB|^yY017K(M|Ne|qM|1?2*QtBo{G?^^w+=bYg- zf0|-!l61$GYu9pS&R+7l`JO2w&qVQ8>rFqLvzV@$#C@jbM(B$rtzn02`VPrf%ziy3 z_fxZ(`G&`35&XCEpLXng*wM?p`EYmXX+g z;k8m(NPRx^04SL`Y&;q>1VQ8;`=&@3%hXIS49TmH+zl!1WJ5$^}~*Z{Kpt zn-N*HJkG%IwvhDmW-F51I!;A9{+70VhTU_m&<*rZ=PjRQ0ba8k&z_ofJTqqXp1ocM>^GjU)i$P2joxtJbU{Z)^zX-U zrynl-&@~~}U;B4Na_O9|H3oCFLfKN!hWocwB(coj_fyKAcf;4zmgmPU=P#KsrHDaE z&_P|{+Gi$HQOAE}2UY|~RlKzDx!M?L!oFyRIOmP`cgi*Tgu@TzYx8$B_UJdKxcDZr ztqSsayhu6bt=_YPib)e(FQ;7CQ0#CkaM85FX^S_DsS7V^V}IbF%KV{f65kx7`JN^` zr){JcaPOISl8xz$Q&)dv9jA7Glg-K|Apu`?{}Lm!nI|f*9tfYJ>u{z0UEYq4OR?qZ zzxD~p@M|{a-kxH6?n0H<+GRJijz5l>a>-Ty-Q!38&NGjmQaXN^bKB9aU#CssSh9To zKT)^)%rXAIYwz#5o5s#vZh0a2v!KtpNjBNL-dxaiUcWUrVO|Z#6~^S2kK3e5s?*P; zOm9$~$a~Fb{hN6i=huDp3f0;5w(i#D1#{DE`L*8MPU_jw5-U=^zq9^%g4zYi$0lyh zmhb*9yu0Yh`q$QwFCl|*6K}#I+piy9U$*Yrc~3^I z;(V&LhE4@cOF41Enmp{V!cE zH#j-^IeB_2e9PyYk*n*x{jlHa1#3$utT79I{aSfPZ>Yplk+sKO>247SUtG0TL@#i9 zjnYf66#+KBh8@j*kp&Yb7f-nO=;p)3&M8%VI%gQ1>b*q$ZbhbXPen4{5fj0S8cmV-SYME@635Se?F;U z@%YZe`Gd16Y#U4QvEH}xsWTRcE=jp&p{4rjP1o^n)@%;_JB#CY$3NX>TJUkc-3^h1 zRR{K`F$!+jRQ20;_KwF6nZ_zr&F9@@QVfF}#dz-@yxZ9jYnRAu#pssx;rIc^(6sf| zcMl8yC@ubc_3du%Rjto=ojk4Ky^2*^)M7@+S3kW_Z+E{JH+0X)1&`-ZpmzS(ZZmni<>2u29|}nryqDap@?VwP1ZwKAJ#3&jjTCT z(Y?#k}uXxMH zH&$&K*ADbeSbUl(RH-boZNaO)G(or39$|N0PPkn8)<$dZb}PSG+YH;7nIDO?8J4XQ z`fV+7l3Rabqb2)H1}<-ny0h7+dDB_ z@Iqs#O0rrVJz2t4 z#DDm#!^Pl4r&t9pyPJD|eVcvJJifVb*5=Jojy%!pbr$oN{z$mxU%<@cvTD)3H4~Wr zar>P7e#rW@)dIOW0`pg|>Tt7JZ`-!&yXt0{O+GdmD<6wJkKA`eIqO2hB#8$nIkhEE z-A|J_@8D_HrP*oAH(vcqLWVXLz{;qsw_n5u8q2gt~u5lG_ zvt1!FopF=fgB*vu)sC^g?e{kYPFtM!CZF|}=AI*h-_+!aeD|zQ$UCE4E?4ZZcsHBz z5HBvUh1# zO@Huwql&BCuaw)?u`hmTsxf<4Y@X4#O7yJeJ8qL=r#0`dJbkt9b=YFLdDfpz6P^p( z?C&oAB_4iZ!|&@mY!uEdYlwX(?Q$-4&+_oCliz129$u34O}}P_;>Uw?o(Roc^y`I~ z`rL%fJEdEtOZGMK?@r|X_}+ON&k~)krwUKGChXgtZ^s$g?{LY5d-uz`-9kM#u5}cc zG%y=U9lXM*nYCzEWZ5IHK8Ht#-@W*nKViLc{I%xmzbam^t6YuzZnk6Vo?E$HyRA>I zt3B?y{84U4`-0{T2Q~&ZSXr7IwoRE+I_HDn^H@H0hmGGi-_>|`VNPOZHJj$7FLQ<4 z+ar4y%C=-GmhXQU#F8+#hI2)!NmS?zY4izsnyzbH0{)t9*ubSXT8b z?*qCkAF3P)D4(`7Z5B_{+9=br#mA!_O4M3EyykeVS+$MdTUYkf2fgN0>q^(iguah$ z@!uTJ1Z5odyb$uZDcC;6y?WiWl9z5v-s(E(n?-xy+%7TG+xG8FyGUb} z@QacOdyF_Oqxni^R6klGy5LUn@4QP-ZT}ywmzufBb?fy_H{$kNR{VXI@&Cb(iU;~P z=6zo~`IP${n@f&w{w!$z6yEdCET%7h$KPuie*epQ*0nx7f8y<`vypSBzT%x(_LjH$ zIpe&~ml6dpZ93<7I(O(Nm?7E=~3J>~3vck88dUOiJ61U6`$Sh&pOT8Ep}*>1Ki zyN+Bge8oRm`{YFDcg)Xz%vdKs^-8?&vja8{J-F)o=B7WIyhtk6MRT^d!{XMS#adjS zD?`IRwDzc4rMzZ+e9@KjtaVYUM)l;PQgg<|(&Y?6eFo--mThn>%2E5+z`iY5zQ@R~ zs(vE3RjF*pa;wEN_mxX5{TKLZTZPo|r1?SH%D&bAY_*s9`y>AMx5>Xk-KTyQ7Y<_8 z*pQbi>UHY~&pF;Q+vB#;>vtvR^S7ioS8VH_ZN1!TfyJ9+Pv)HS|MEPze9>piV^0=b z?|jUqWTTnh7mrBZph@*bL64%FE*QJOy%b-LsJ(_e!FMJ z#LuUDcXxh}ncQdbSV~uOZ{~^ymH^A|o|Q-Lz5KPUaM4G%C0)XS-vk3bY*|-iw_~f1 z=2XFs&WX+3hq4_{I%v(4*erKdYeib^{MCxSW{P)rD?j#1zQ@(2a>?d@#Ci8qOBpt6 ziM`HX5X_~)FP=hr06v9Suho5aMkg5_^D@3xlT zF1nTGAG4)cCS-qasE^ul(d|Lt8|&!6_op|{xwNP;hFAUBff7;fbB5+>M(^%;9!OsB z!HjkJ!s8lR9}=8pvn1@*{+LZ%cuuqXb*1s{iwQrUbj|q~e&TR!&Vi~}&FAeKc5n7A zf9qV~C9lN8*!uO)WY*lD*6gBTrV8^`$|hz{X$tK+QRKUIb-+RO7wfg%3$4$Vs;ik3^-Zs^+N}vccw9~WL|nf-(B_L; z!4TjjYP!Mix7_)!*}F>~9?iaZprCo}0A! zyI6WqdCUBy;x}yfJPv7v_r-g$95s$(T6E6P&~Ll{n<;gvb>8-Rr^An(Y}H`hyd&LW z@AL~33SKl@Kd$rsbl>U!2JV(k7vtw@EjKyv)H{Xah~DI>cWT3{7Jj(-q+?H|N#57B z8On(#`qG=sHtS{1OF7rR{hV9k%iPeY+7HoQ0j*oV%Wr=vHur5_>AbhU9^Fi{kC7(xOrYvdWBkBq4w2xTx?;BnD#Gx z{BQHz!*>FA?w%WUeIo0w#@8FyB&_#6{8@CL``c{?*)N`a{BSb+_v-6nGtK{Ae*fUR z`|@*z(lx)9|NL)o>#W?d!~}_pPO)p3w3_VCX)WbHQdv}X?_cH76X&vS3d+}o2mKEE z^38SbLxV*BuliyyZfi76ns|68i+7F1m81rRTaIG8B%1DCyL>>^Ipz9wmIrDVIPwK= z9GD%^uC<6`>Vpc!v?;14$BdOv-Cx91D>3B^`{CvCPz9s@v;59D$JZB7W+`_ zmT>>Nf61rnzeP^^xcTAY)%o%t=XWn|YnrF@*j?x41efQMm)^t%c3f?R7|4sXvuos(brd{+)FXO1rQAxSSrzn{IIU z>1oHc|CW3^WM62zNPDjwv+0boV&{16Sf02X*^R90-ppKB)El#Lr?V(mfYjE=%W9w1 z7|t}DlKdUDVjolA^twDB*(oP27T!<|5&g52y{_v)-jV(PcV}$s%x0*#-1XZn?24M^ z<>Trbp87ufXIxqHQGlaDfAP+aO~#TH%P#cGv>Y>iapwIVSpn|_mnPr%e$i!0W50Y* zl0sqRg47>N^~;V-o+i1gF8OWkr*peR?LSB+1sfjbFbi61KA60n_AOg{(zOZGa}=iB+bXG;mlszOA^vW$N_=K{#pPMep3%P5(f_r3 z?Q2eKV`C~=@Mg_>X{EpKcLi)z(l{vBboHj}*@>c!9Os$>1D2S$u77;aw0Mcho~E<* zmg_Ee>KvVs)Gl(TBgT9|NH1$AtNQ`QO@EiUwobkFY2_on7pZ^LT`lTnE&Y7{{^|M0 zoxbndb?tPa^HaGOGQZ1y9};~Me=j0_yJ(p4mdphn7yWkgs~k&t{BO5nzH!OFnVNsf zm%R1wPgc&)Q|@_tnp3Bk=W&r(@5iOw+bzGYRXnKosX29N#iuD8JVG3ER(-s8d|6i(l3+a40){ z&n#?u*IoTh)9rG_|K8X2*LAYr?jafdhme=vg^z?ZMJ}J}yiYeEnSO+^jkMvQO7;3-z_D zjpk|hT<~7p{I8Dw&s7se{vH&Wr+LbAVnC&B&#L@mmsj6j7m{P7_Ud+%M?6pbIV;Va zJC?oC-^CA`bV;`L-->fo-&`$}9V&9cR`lJ2DrT!SJ*S#olVavqcCUQQAP~2G*RoZA z9M*g7IAB(S<%1tDuD;maynS&x z`}z2NRt^7U_WgPJ^meoP;>X+l@9()=B%Jdzb>C`L2Jf_^r`gxf%e^V?t&=n9WJySH zRZ#lz_i-QF(-%K(4$pshcp>wFlZGbyOI4+dz6l35e%^g*#U*}&t2br)FJJO+*;Tfo zbaC81Gmj4zyQO(A3wG}bioO+K*1ff|@$ZGU`!{_1Oz#VnFZ&|hmZKVYtN7`JN0xK` z*nC)Y)Arzz#qrhx(+~f6^6G5q*$Yz1yMAk&dCFqDYNt{D9M;04du&HMo;{JvZUd+J=gD4=desJBzBqN<$tmpSkt)$M&^tn==fj zt(v8&8lR-%G|RolT_#NS@o68;tCQAAAM@~e-615dy66r2^cy>hyWT7-&ApO2|C~p{ z|MhOU+dN%LqnqTUT=;)AIv30NyeQ#3VB$Ni!9{=Rg8B zx&6NCjoSB8BPy*fZ(c4Kd-=eOr!(`+wUi3gudjZQ8+*7U|G=W%$8I*VIk41T{(VIF z*j81BI`hwKG^4M$%&1%-w@&@ehD%|>b2ay^Uc2P%$<@Z{+b@f*whT?*_S#50r+Ckv z$TrU9Ri=FR%hs8UN-9;%?|DBetk3N;U3SU zTYZ0-t9nhSI zV6sV3cNLG!@qorQAI&XO<~De)Q+Tk${JFdO@8fq~CvHEId>s(dIMG`v z;iAS{hi8n%L00KXFK%(o;eN;vB*XUJHMG~uD`QioaLS|SuDf$SM(^XvzSwq5Jo>eV zpJCODHGmW-^q*4Ug6PYzUQ)A)ZFkY7dzRHk3-95KD$?C z*7v=i{WilxUMCqw$%8j0mWV$(`fuOPu+@%NH_lliaWY$D{x+7}g)7T%uXXj+xHomu z+|Fdn&Mc+(9NdLhW`264vEHX``iV!S>Ak0NZg*`C2=z)oe<`bQUrgqzrsq{^Yj(bV zXe#zFFPckW4>wcdaBKVIeJ(y_KS-TQ}{j<4@p`R)_%rzQN?eRxl-+OODen5c;z?o&3jNaYunN4m8+gE{&wQ}v6p&$?Ea>&wAC%se@pQ`?shFN zrGjP#|Bc=W7T=`pEONq7m@63-g$~UuKp0;kA+y=$WsKi3vYTgw>Upl{W zetf!bnO;BR(|c_1Ul!Vi3jS8?bBQYwQo489LACu?iQvTYy_Zb9E=~Gmy)%T!I-$lZ^PTyXR}-{UOzisIPvqK>DfXPeV5CmCO!vFhaE3&N|E>(;6jChIszwe)Pd zP=0XMFZP(kdD?}V+BuV!XMI=gW3InFm9M1wVqxfovl}R|=Waf?PWzVmH>*0`XQnUiE{e|B`ffwE5)0E3nIG#oUmTnJUh+Xf(i(Z+f^%=@ zx2)m5Q61B7d${WFSJAu;n^ql9{mf)`XK7B1+#V~de_thb@Z5i_lu{wqRZ?VkI{At2 zDQ`E`19OUmf9y*SY2*@{$lJWUce2;%!Z&luEwA^4@7lZG_r=@gBK1iAccyQyDxCc0wnF0Ko#?JThF=O+zTRjw_lW(!i!}yWQK2m7|2^hr zc0HcHbJMGhSKb`>eOoP)klB6*|p~RXOoY)56^Kwk1-XQzA>cr_Nz^=<%W*5+KxcKUCy(>2Vg^@T^^RmICR5Gki=RJh z@wcs#TWGU$SH)i2w|ZZDu59xNI>Vp*z9(Bn&i;4zf!R4pv4to5Toa>q7R|cE7*}%q z>nEMl+{>!hTu$KS{q%2R(MrWv6E9BPyI|k0dkb>|4tDi>S-g^!-KC^-L91#(UrYew zXNe7=PtSaG*_S*Py0=w7|d%;l!CKtx-% zSm<7M{*I;J>H|3=#dfJw5&)ar| zORSN7PaON^PfV|)7EcdbcGy$uP6?m0rA_3eDm$~3ZPRWGEMI!hG5e)RZN&ad6Xjoc zE{r~}CMb6xs;_Ion_4Zdq?2q*ch_^@QC<0X$LH7cbk2ktWQaccyyU{MyA8RT?6cM_ z@08jSwjli*)3g%D@Z^+}E>>)EzKKm!Z?V~#*f2hNedw#H_^hjiiOE~N4Dwe!xh3#a zoiSkdvtq_mIqA1oo>JcP^^K79j8{+QY_YXE7BW3O>QccJyQ_0+XIE{GpUo?)V6w&` zmV3=_wezcPpUMjqtJXD7xUFH@UnbY_J;Yz+<*}XDmwp${;Po$SxHvC%m-&}3wo)6m z{5i10&g1s!?9%oLidxYZ=9yZZ_bJexW5ZyR@No*q>4nd{PAhPG-t}+)Znh#jp7->! z>Xr%OmQex@iz)#N6Ue^lNw0G$(>oK`?V1-ki)7dkvqGxvoT9>-4f6yfBurx;XJ#X+?(-Lj5 z;Ggfa)0y8Kn=-2=zIV@Yt$_J;ySHs&KWp=C>FMVEr=<1b3v*w7c3T;x)^Q-qT=#kA z?XR!ir0ma*J{Xh#rELD&lw#XQeII8!w68rTGyCY7jp-K;O!@95{iFPB=d1PGSAJX5 z^5VJBg4toO=byY8F)LeKI`GLKf%*@pcbAs`(VsGD&!z8QT4Vg@3#{0u`|YKgpxv7E z%@fv5aJ|+V$iK(qn)=E6o(dnXMqW;s_57i!{f?jSoW(AO!RuUh|35E%?$%EIy7x-ISBLMJ8}xmB=z)2@ znpxSKcRO`kb zZ{~65_ZOS<{Set%_WW+w=hpA$R$oQRzDf)A zo?tn!pf`hE;FwVLgVPQV7pg7ld{_XlaSp?8TrD>zn7g0;LbbJG0|D@OT^shqPchV^CEQb zie48v#A$WecejDXEAL-L$CkLTSLMsCs%Cmwci?tUvi&K$hF{)_7FJ^2+gW|PL%ggv z97}j}wf`Q&fp>bxUadR+PH0U?iL^`n@#IBjyH}q~*f3i%)S%XHk$;1i(IUNQ(F$FY zrN3X@HnGm<4Lu>tzW5m5q3tg>9bS6o!cLvM*RkCnH`Mn{E%?W2kn?xO%tt!WxpQx> znfG<3&ddjlI}P`A|JYmE!oDnGn&5l>pze~X(sC%HlosUyga+x+%0;IIpD6SAAQqwyE2@GcVht4=wm;pm@A$`#Q_lRsXI#L|m>9 z=R1E^C}J+hZI`Zf`xl*_I$O*9wKtdFY~hU$_kC^E=GmedBl$R=si+(>n8x}2_!6S8b zMM9=bk$2k;o%@U%Wt@J8?AjeMJIn7)Qu05q)Eo8j@2nWhmLHm|lo58sV`|y_psksE z_S-mh&$nGTeUkGQE#W&)=D6RPH#_O}tYEfXH*fm5s;{sPIW_s&TCH`vA4P`5JZimG z!;;qYD{3!)$MbWGy54W=+f%j8xMxZSXVB)ZI&sC^?(Yf-pHGMWeW>~1>h}8`_rm>; zafa2Nox}a6boz9jW$v7zUrwhKZmSX4Twt``{c^^%CEQBUFBYV}|0S|x7K8mwj<0-K zQ+6$8nSPM{nA-B67G6j9$@!^Y$Q5QgdVK#9_8+z{geB6?mB_5(7c&n|PuO+V+1e^N zR_t0*vC4v()j7wqR!FV874dFe);qO(?tBdyG0!r418@DR+2`v~K496D^s)$8cH1X%oZ6smfgQuWYf>ZV;TD(46Znap}0QNG|h)r8oW^ zzJA{>Gw8cp@peBkr-szy8SBq?vZkzFCvv6bP4z6-NPp}4wy)C))2D6AOue{fcYLwu z$vgA7&HATk8nwO)y6`xYQ~9oEN0hJF_h&D7ckbgndFAurBN-o_utc3LnrON3rM2E; zwemw7ESi$?Ia!{Sv-H;6)E%3?ps`l$><-qd_R}_hRR3({e7a}Vv#0OQoqPH;b;T~O z&yRA_rT*r!Up-mWp2WL&%chfmr#mc z@t&`f_g?gn^c3w{o;j2M$BJ0n;~lIs4Cjgor9|wzU$SE^GoQuB{I;|@<&rCEyN$Jq zdk#I%>0-U#xPtlTkAIcylU}Cu6fII}oxE;d_$$FZkHfz`IvN`M<e@p|)+G*sA^Bo*~I=%QYV^do=6kB)3i94cv|`&U0qk;lXe)a@n@N`&l*(A9ug5 zTETJpLQslq!oSvx?4LQ?)uQHEn~3UPkvMfn`kUK_-di`H97yQ=Te3mh$wl2*;OO4T zl12%Rh7(IRb1c_i;qt1_-KAUC>7N(e z{BKc~+s6&v9OhAH^CmB}tTTOMki~OnaW;eK9H#pGiMq4TiUi5EpV-7z>VEUdZ1;XS zRu>6b|J5oPlWyFeo+N+2Fi#~+^4pQGFU&ShT61FMQnNERVip`wxMHTaI_E>wRY6A@Mpz~c3Ld*jAUlo zU%_^vsJc^V?#A60-FLny%yHQrw0QmJhw^Hh-*>Lwpz%C2=quBeaOPbrTI+69-?6WJ z^O++*FXDj0%iFKT7-Lo_veq7F=W<#%Ddqp#EzbiMU3z(GN9o-s=Vx4OP&AKG;njV6 zY3p)}$6VnzHqV=teEhWDq>o)c&0Mv@PBec1^=@1^Dkub6ywb$z`dTZ{eAiq~cli_2e5J@L3SWUlp+uBDegET2~?udg1s zpp<1^Q|j}bx^Wr7VjtJ8aSXr3!q3!RXzKay>c!}Q&pnntW|}J)s(5aFk`e#u&chRV zMnh!-V@s&Rr|7~>Y-v9({T>&||UYdy4zWomIJ z=QORQE#Ehu`h8@Y%$Yuq$4s(cCNZXJi{6;NbHSpbwTs2|_D_b&o!-Ekb0DBVU>RqF+5NZMx1VDoqi643_^QZmQ8M?|n2?y3{GB^fIKTSNT^MQ|{;cHrk*l4m)}KAwgCn!%8fIH#T%jYs*w%QFn#=mnb>AcRbLA#RNc_AvYv1Fy;awc2_cUx6Pe1xI)xU53b8}|v zgV{}m&VHI+Q+C8%E&P1q!e8S*JFhxfH$*Kx`R3t~`dgD4G6RcWI!tA4kq&FUe&AKz z=dTu##U9)KEO462$FMWhd+!r1owT?og|-tzm>#CgAdsYiJ^6U*cBR-k)#)Qc- zdw&?07TI2XX}^YL;fjT84n9<@Es3{3bwT^}6fZ69pjNMYhCO_22}S4s9ir_f zDm&-+i}nYzOK$!)>(!fZv2j((Vuha*nf)9co{70_`ye>)x#ah|Y|rLu&#AW6vPzs5 z8vAyS6vI5hZDzB+NoR4pUq9>Ulzq?M?Bd0H2MvxkGkjgQo@M#j4{oKmjTXDcPVHUJ z@yl{y!)eu|c}?Yuw{hR#wzwY7vVJG;t^IKkiswB8Z!EBw9X)f(*S%q>_36R>d!oB4 z|IUBv7Ic0QPxo^Rk;GRbOV2WMsC7Q=-fY!$pzQytDMwr0%{h}9!mqTKQEgULUB)$u zVuhD~y`-el|K7;GY{GAC^R*@YYX9o4S2?lg6jRa~CEd@26y7-F>pZp7XI1}ayZsgm zPCk65q841|^K6NG!J+LtCv7}3NwXt}y}>%{j^C;?{h1eyqD(|hTX~A!ecR=5S}^@r z^V}_s&oAWW=XVEu^E|HEl8Ptq>RO z!_}eu>+c`fw%Xy7V&?5@D%od>lS(8rif{aK+p^76VrkXK*>_)sEdQA4_JDUmZa9y~ zi>tQxHzl7A+!GT}QuZzMtUZI2nRJFqhT`QAE-QA&t|eKGlD2*CF6|BzcrR{VyUHbI z<&R6c6&sE=37!_7Qt?IDSIx6$>Z6t0y8CA9Xsz0M!>xbYvkI+1%URD;i>_whuI{za z_TPDE%6b2=bv zr>G^|ao*w1*LND$@1}?3t-hBg()a1W=dZ^uY@O9BaO&N~IR_g2SBCh%dh=x4o)5=% zvh;Mb$BN`szUf;n*XyT8Id14G4Gaq%-D8Ej!v;Om79p|rWSJqx!e#iRNm&)fm z-*xnM%}o}1B-{VC>uO||;n9dB#WTQBUd-|plV;8+78O=!OZXvU{_!7pSI_Rd9=o)J_rAQ6sufytq@bf?i||HNw(z6Kp)ORE%!D4rv^W7WsH zc`vnF?-;oKU|8m2b0kK%z2c?2KXZ7_X7j|~u5%CCx(L5x+RJ;G`PX&JCX)cUcRS5y zCGW93e3)s<9wF=B`~Mu0@2mT>zV^50-&0TX3iup0&8^*e-E+l4?d0~VT)7zSzXFEg z?&*B%%WWbKes0M>o2ekzv2ulRnxIAPLZSYz1r8HfHk{Tyvq$FO2Zr^Pl3w?6W=a0? z^=mr(_u}Ql&gI9QdEuHtY45>fV1Z10{WzzMTE-i=6Xf@ku%B*BsZ%v#7rSRqpDSJXOyb+x^Fakgy3J}YB28{?W(iJOV!d`{@bx=kbEhqHh>trnOPynX zr>x9Bzp3wU)LFNGnEhSt?9F+1Q$D4X|6u9woF#fFm*-~X&5$oT=B0l!%1ak*WNz-A zdpjd*Hixvg<1yV$X?stuD?0YdI^9H|PfXIz-Q4dD`*cC(d5hng|H(HxeUtf7%J*N- z?q2a?DdF5*W_znCVM_4ah@_W1-wKxNb<37KT9~arvqt2rjH^QTtO-h!Wj0@5ZG7N+ zU}Q`2M9CSa>V=h!7s&Qqo3ll-;6V1heJS}y=$zYA^D$hArK-GtheN;V$vU#q2*D+W7)A!*{nnc&TgBnJb#< z=VWiQ8&3|gvI!|Efl1+>BR&tmut(`d8anFe?p7l#uRCftKH?2zfu>6`$>B^Y$ zHQy{A#Fs3%YU#GV@4|$g-I3pRy0sl&w>Vm5ALHx?;U5_O*m&7po8yvJA2ah@*(JUO z9BswNTpuK)-@M7AylUxro#T`Dy%fBc@lj(oxuj{vvXAT5 z`(2K-Nz3i!{d4@R`Jzo>Gje~P{2Xon$R{puQG$~&pNd5`>!QFz4JQ}K7jWJe|NWae zbeUYOw3g}tl?v{sA0)KCu4J6FO;kK1s(iNraxHnzWg7n#FdA6>XRml z@Ga4QDJUbklyAfJgTb$JE`QDm_4B<@aj|?Jn zXeiHQs1V;(VCJZJevy(Izxa&J*~g#n%DkX_%+E~cwQt4MM?Dj{qZ4Hh=-qj}gv-k} z(9$CDvB470q7OS|pLLu$nLh8A>CvS#64&bdzpQhpygaYedfBa$(sLKGuVNFKb^T;{ z%|q6I<}aSDzjvs{QZ4&X(xjPN97|3Gex7(!_TM_~3w|rNc3K2~oW!@|VS!X=pjAi? zLz=%xac7+8qvKhNR~&xNnK>{0B&&TXL*WY{x#ajb4 zzv@zz$9j$``#t|I@0oDFoxe)`|L2E?Uxxjc|G)X_@%V>tkKe!CAHDqlj}MA(>|f;9 zYRKoUO!t>M&mpj)=YD=G|F1eW^`M5*(@CWQqEmbf7l~Nr$$eJ!*gS33%PFmMTGL(Q z&R16?GN#@?;Bd8m{)75Lk+TvXP4~{q`Fd)*^_Ns*<%+Ey4l1W6hF+hg_Cf3FKlS}f zChWY;kgwr<(K%h9w)9c&sX&usCgyVuU*7dN*1mD0L2}Yoj)>ze>lKeK=nJ^tB33NX zc6}mq&a@cScdaa8?e+czF{1l=dwusX%--O%E9ayLZ(qn8{{^q~FK=y&QEiqxmbq#Z z$4j;CCR4+IoNZjb#piok^X*8N8@c(uiM`vN$IPD@&z{zy71`&0W6jcc3VU|Xt6Kin z;l7Sz(ME?|8)hvso^g0hn3~M&!!mEzEGuQY`$3`L+JxQWQ(o;`{Z4FW@6T-g|L@F< zn;&itKhIZJ^Ia)Jdd_lfrbfeD)t|fXY%ag>;DclSr6dpDy*g?JVZ}7HTG^?r(Wp~clHQ>?^NxpxHxN!l$GPF`kv+W6B?=HSh#3;OPr++XoZwCAEoU~=!u zx))~`&oB`?vG@0_IFZGlqswQr_%j#Z&wSEoCZGI6RpLQTtMHGjZ@2yq%VzntT9`R& z_Tohbru$ZwPDp>narAK7Z`qtQk%wYa@^p{n7QRQ`Zw|U>t1*e?u@Wl-gCHN_gTIsW za|@DFi%L+B4lLk0;g))^@Y~X3VLAnybzhwB(mNa`G0!1z%Gqg3tdqJH^ZtEr{p#u_ zp(}U4C@$zPKQG%~&aW^2;r8$F`g8XSPAy6Ne7nW-bnv+^TW}CNwT< z-|grKJ-zA0e?Bw4`^Iz6Xt9dQn|Yj5(=&LcO+52CXsuDlqAeR*(*jv+PEXzDuq0$! z#JVLP_nb`m)cACkq{-^kgd(?#wydiUDE)~_{W)vlLn#ftoe5GwlL`adGTv75t}%M+ zwYeKeaWEAD++)R-l`;br*Rle+{fd?do$iyB`(S&`7-a7H(v(ef(e5-;bl zXR0z13F~wwbEdULOqV;X@R(ob^E3nJyM3SU9@uKfWN=FIy~MJ3j)2UmH+ydG^|~M( zC75m6&wW}ZpzFAw*7jCThNZmoCcj`>t(?rKr#ycq^C`A{jz{N9Y&EcbV|h3H-wK6e z3Y$W#4&P5@p1vY7Lca3&`@-EP9$szluh?6W&$Hpfi}XGF82IkIySS~mS5jq5-%4A> zKNoggdG=VZ=CJS9dwCbX&F4CEp7r6S_=9QE zSDIRXKRjO_`(tg2`J@=LNvHib<*1zYE4u2j&Z;w0<=FkI_*)Bv#l&|fZrK?0sI#D6 zXOAL}|36|`?kgWTJ@a|i^i1{_Ss_PN#8iEZl}<~hcx_(Q zW3_x;j>tN$=Nfv7&qFxnF01kDF;5J=xKLpA5*HC-XANWQl;8mB3x`FAB!D z72i30)Si03uJmAj^TG?EKTiDZJom{^w!)5Ww^jJX!uZUIjphDPH81tKR_ZD}a_|by z{rvOu^UOq0}Agn4g|LvEl$7eb@Nj-Eb-jG7v=)w1mSjMa_J&wllP{iU_Jx>r?XX;X=4 z+v4+Fe->vR|Nl+yvc-GNQ$3wiM4oOhS#7`nqyL4dM}NvRtlFFoDO!KC|KYsqL_|&3 zxul79A}h02U+&1Vs1aBG{^}pQkBRM3nX|5E&+GR;(dI8H#3U}0|NsG1L#;4V>+s|f5AFj3FUO=nu)pP%fO)kWV-4qe~=#K}@`V+L35 z4B@C!tDP6MC#h7v^g2Abr9TpZlb~F4O^pR*6+CL)m6E;b|v>Zq0>e8)bqL4 z|L@8#XqppqG<<(t-{gy@Kfbtn^tE_1-@)aEhp+Y;M6I3BcI?s)(YGs?-TKgDdF{nP zyYpJ%=UrZ{Gh^+$>8ZMT8(&WGws!|3t3}%;tNru6(z(H^)l zQ_aP#t>u)-(yP_SiUT|kgiR{ZonG1Ra)0vmsE=G5|1&W8UFqIlwYQAZ`jO>kn~a|sCQiMiy8TQ@31fq1?>!^UmpSs!)}3H?y~h??B@AaruXN?@A+M5qp1~{uN9q4un(E|-g3o`TX&k8=eR1ep5OMS zS;sL{I?c>et%q0V&2L|3r*bV}iH#FlvZNOr(Vk{#DSGPcgrM^`9qz5JP+Bv4(a*C{ zeA%-PC|%i-YsGMC_l-9NJA-CkI;mkf-)F^kPxmcPC!98M$-U0$kjy`S{mz!td9!}i z+0~p|!a7CZ{tANw;*nP>cJ=)EIl-iUN8;0U=C-++ud-PcpX`g-v-^fp$U5)!qHlS> z8TG0?7flZ7F8mg@BXxS1qsSdTzOAbtEPio&n^K6@=^kOLCHHR2TD(pZnq1uZg{xgG z_*Bo0rTbc0k6yRf_4FZzg}M(@^Smre{3J;`R=)HCFipKy7iKz#|iuG zWql8nPQEqSJLX+c1H+8-pVxmYdLCkHyRGbs+Rpvw$^}i7j)vL%U|aF?eW&`vxI=O+ zEN!zKyq3P+^{F)4+o`X}=lIkE{yn?<(i18ke`P4#<&!h>dD2}mwL9DI`JbqK<>jL* zeJ8ynf8Vo6g=v?zU;V?|cK)VJ*LEi7b93ImXe__#zy5G=Aj5*=J6&pC7ydVxJ!5*| z+dCguKbrUY`0O3atpWu1Jq$VKJbg#vrYCpH)RqT)oRX4d$g}o{{nQypf2XwCF)a&A zYEfRvYJJAlwNgBOq5n_ChIiq;?AJrMdlz(gKiqh~z~%3U(|OWb_pgV!3Oze^SG)4L z+dm<{r&DEl{?((M3!CC|d`=#AhE5dOCCktf^Z?-ys5A6mBQmgdHDJk|Bz4*Ta! zWYl&zJ!$C&rk!iJt|YTnJgn4K`qmY$M>9GXO*&-|H|`2E_jh-f7pum* zaLpsYIC(@Sfa@j8XnPM=2IgE64T|VCA_dT_J|k z)h4gp=JD{D#>O?g6BbU@5cGet?V94@(DeSWklqOWhBKmnBu@kwemMK&6Q|H&x7j`_ zGrvxM5|h0p#w+x}_j5D7Qw2=j>~Dusshd{mqobOeOdDNz%$X?;^kW&p4zc@qx_q%ZFV;`e|5#ew#Co{;i!6Ql-R{wEX?Kevw5#@8;B%ThG0F zzx~X99nOc3y-u=hQML#)|ayZ~dfwXTCQ$Kj%ixoSVb*$`=-9`uX*AeV-&)W`)?Q@SYj$I#S zkyCPoea_hzKeZ+I?%T6d>d=u_`GQC7m_BP4+&X=7?+oY3(!v)fyF9SaNH{uciL0G; z>8*ouUTTMVmKN%rdR{U0^VTv4r%iJW_8(vW@Ach`ht4;)=jjKi9mV^Br2mT!TEai50f#gp;z14lP(>@o~`b~8G68712-s%H}eL6REk}n_6 zQ{?!in!zNoWWuA~3fC`oQ9qMy<7@WJuHDh`eEat6AOAj$-~73L&9(h?1v4Hl3%>m% z@JZgPTU&05l(PQ`k=}QPv7b4!coX+TiCL2;J8%BRQQDeyLDFVL6>FA=OKrcSg@~dw zXWH7$h9-{v!M%3L`{SpvU0X2g#3AL2+p|B0-HTrxRFHFH|H^LFZL@L?F7MRHnls7c zrgTJ$9ZyD1<6ivdx<7qsX~) z<88aWFJip^WO?pT>|A$7_1?R<1Di^6QevhjS$h?wto(1ev8vThswy`z{LPBd!7Ev}GCBM0p9HnCA3Xae9=~=dTQ)aACuhN! zrY&oqJlTJLCZj_W|52}7o9#Mv9~nyUuzg-8w;^0#en0R0QxPdqEz>(scfO9~^5xSt}GhZic zcFeLx7YvjSPBWPL-u1G~!8^^&>?MM``%i0idoK-oD;4rLGkEFJGu)!wYg4xsowd}z zzA|RVai<;ryP|GfT(|VjGlPkRXX9@3x&=Ndb8B&M*xMJf_LZCYsnUHXCW`IvSS#sx zx7%x(=arnT3tQ)!81ru4+Hv1LxRb$2=jQ7dU*GHNKiga%d!}w@&A-n-8Jp#|zqzw0 zk1;0CEcB%K$_lMgPWOOS5lh!{D(#-wdg_J4+a=x0PRj4%-u=j7NtA?%9K&i435Mk- z#WtlBa{USNd9lU(cFpNL*3;a9To$j3&Ng1kUfBAWGofFiy1OOFopB zy0dNP*GmqLa?*3|@ZG$kSIsc}!`s{2pL?v3wwV?oRyeiDAx6hl(dfYyj$<}EYkt3Z zB(tIYDtDuY)gC2Z?ygaYu-G97`%*|LR$@#Qf)-5h1HB^}~M2NW9+Ib9y!F zomHGR3a4XUZrZVr?TVeyI)96KCcAgdyYTq+qC?9SVpuPHdifw>YG^TQ&%TNBFJ5hD zWL_g%&}{S6h+FE!K~IN<_&F@=Qd6VDN>8uMwOkv0F6VUQ-A@;`*{q4)l6#T&oC{~d zflVutoT9sn@~@cBwq`DDp8qOz%Z9Z-PG;L?&pQ9-Tf6V>_UzS*?<()J%w1L^Ja^l! zbAQ&Q$<{qCIO-qwI`ZJ^--(ON(6tbYwqGwimaz-gk z-S8-hJGqfhcurBcn9N2djckL%E`p2re5HSV5Lr^YDOJh&=sW`nrHtDeFH*&phcd0* zFz@18O#_h$!Hj#pJ3Vo`-I%)gdP-pC74ZWbRx+IV$C@0vF;$y&cjSj3wnEJQ-xEuO z=K4fzmTyq2V7wt-vB@x^GU1MB2XEs9Lm9D8OzZg8hO+JDNy|>)ENi-;^hB%Wu8fTw zYr$cim`}Yv(pA|KKM&2*m+O7ZX8u{`m*k`Z#pUlFXN4YEI8})yd$E?$^*PJ5__qF0 za0*zVt)N%nY4-Q!_v_;8|0vd^f8X?A_T98~!5NH+M#Y#=iIKCKq2&_snl>|I2zpyzBa&7dfIlmnvkV zRIP8QZ_2uSw_+*dRo;H?t9S33JMS)jp4b{Rl9{i0>fyW0Z)}a+&PpHm6wFN;@SmHhKoV87&s z1!7?jOb$J>s!6M{+w=Bvj$}DQojHraN{5ZdGkhC#rWkSHc&epeV?ONS0 z-|S}Y={fTIt%A*)g%$<%wukh%9xN{H7v3*_OLC=>#i39$Q}NILx~Hgp@4YFIYjxUQ zN@dOLOK$|PFuk!^aRc|v69T49^TG<< zISz!Lt&nNA%<$jv>0rg}64i!1jAz9cU2eQ1x=1T$+Fz55%V*1Gnx2HX8F9~s5icjY+l57^=J zO_ay1Eo#Z>c}HY-CA+(S6RBFfUpD09)gsOJ3GT-}C^xdU&D=MAc3k z!(Rvg-CC|P&HKQf)tfeba1&FNxNNey`0VS+?>8%+O12O%(3frCTiqyN%677WwPM%d zdrDK68$O)Sxy3yHz=xAlc67VmOJB-p%se&t#MVfaa1p*$H#6m}neQCi@MLwL9P2)I z?*q#(r1SD!`5acapDj`Lg18{NJ13BP3JO1YH({PR~EP^Rn3Pb+@^aIb)6M+xNNi zx8*Ef_tf{J=!2uZcifBBmGoPTpL}|IAU4b96z_#P{iA(;W(xvzOJYv!SReZ;_dHhl>7s7_lC{hdLdsh? z`fndyajWL=XSIDY?9YE>C(ZvfXI_6_47U)+>{mB(C4R@I?YYirT)46Rn&mAGT?hH3 zNtIh3mP^#lwhNyrA>Z)yU<}hSHsxn#Q3l5|4xUhz{pbquAVsg%K_pW7PQuevLdk^t13r{hhvF);6x75N3 z61}nauRgqd^Uv|+{`?d3n<5?FepG8z@9DlaTY9r{*;bxIyZbqQ2`?4Yd-0w3FW;H0 z&zx^e14Atniy0moow?|3a{IZ2ktAb*6pL5FttDF*hp(64|Ksgfmcm(w>YEiLeny=+ zX~dSHzHM!c@bBw7{ISzSD!ea#cfTZQqr`hJ!jkJ=>cJg~3cWKg&F8Q*l4pGr`)yrC zINReY0U6iqT89OV56*QlFg}%wn3m99@UGp5JMKvKfkyGA%RYRsyfE+1{d<{r`Qv=^ z-(I%8_K$td-^1Z+Yp=b^pY-&tq{EMn=LM5aa)`^`b-^vm+x&OUAW0qMhT=o6aw++IpY(AXU3)*zd;D1wr#`kZ3%#%+G zGhCSStt(1no7F+N7Pr0DiN+$vER3dapXP{doT=f(Ctc2`b^MQNbjPQ#jx$es7<`nb zi)_)#Ty%DAW_S0>X9+fLs|A9c48^JvN_!X1)I4>-a8tr7v+QrlLanBqFAiTm{d|AS zAFKMGua8bXyGQf* zU2`THsrUamwXW%?P5*U`a`DewLY_JA+a#Z4vf-x}%jA2Zl0Oefmuum?qql>9nE~78 zxe8Gx-Id3Lc2r5#w6yAeSvkG&+|Iodilq-2oMychocEn~Z}Ub|<@GL{a|9+oylJp` zdE@!ou0N5_JSq$eoVK224yl~D(VXS_jEC!Q+~#EdU_zT)6=IL8-!T> z7W(~WHS3c@j6c=60`@g5R0!$`zr%D-+hkFw+M26=J3k+DlZmlw-<+}fO()WJ5wuXl1{hJrf%$QQSY@rO#y;h@{iN(EFdp`%AE#Bg*^T?Yg=;!b6Jue)u z%#C81+8gZ7l90o=b)`v&;nNpa-+dA^5TCp}d|&)k=f}mNk%BsQuS$Go6lz!f{y9I6#MV1 zjlQQnotqjZX0Rn`!P9xa8Iz9lsW5Mj<#G*Lv^Dg3T&;?KQPA&>`L~Rgvqg&M@X8$G z`?CJclW99nJ~OY{7w9?l($38K#Xt72c-H*)s_@(bN9{F@DTFO6K5#d#*y z^_j%2-|r8WY;l{<-v7ovD09Jy97XM>u7533lGnug%&y;i<$s}%=}%Xhapx7oYk`W_ zz8?D}wPdkXf|=+Cu=*{&f0b``lpphrIh(T=6MSWCrHmtIGXd|}d~ck4`Z3fAD2@t@j} z`MtF<>-hau#o+kdnGsciVacwk4)WqP~)j;n`XqZT+!98>n3JwS#ZKP<$|3|MZ-$I zD-Jy8m^V#jS-!yc!*_sAb zGGDn4aMt8#UAf{W&a(M)x%bj@56?G=H?HT-Dp|gx?)QPW7Y~MU2{x+RYc+koc=f;R z{_1jDHaWef{rjzXUkS_o-o0i0?F~XV82OxXJ{4u3XOhtFV5(Zm?2_1ds!6LXG;~{M zN4btUdyISPsY7kDy7!WA9p0)hZX)xfPeJY9mWNx-bBu)B&Tn;X;^5t#{FJAHU`s-un9k(9nd6#*IF|lqi*|#jUYhvz- z(=CZBq;{pW`rPq02t0D)$@_-tqmxTc=UrDyjt&iMHTWQwuJA1UfO>~bbXH2D2z+Rf6uWkNA%IT~9hRf76X`(jVD>gf2B_+RVgq$gbam!#(Ew z%hq`pD+-L(M4#VYw*Be^d!x&|uK(;7^Gj!Bs~0tVnJRh1?7^I0KlU&hB*y-)bSP$ZRQ9iLTiq!zd%E%? zD-#_R$z%W7{}KVE&=RW1^1Y_A(CtNQuR*8ejZ z-hMD;ukG8IbH-niyS9z2rpBic!2IpdU zSx?sR%bYX0`1+Tu(DS7)?%5r@bo|A}?Xlu5I&Ee?Te+%#JhbRBDP?nuH+VDMbk@3! z!PE1;W-_$JYU#wIKCM53{4(y% z*wAX}*soj=He0<%@D|t0z|(T!8yDIgdp$ez`rQK)Oy_TZAzv0|)TgcMa=!Wq@2u4M zw#$0nZvM|}6LIB}%8G@t{9TJI_nrBYdM@Qosdwz0Q?~`PbazXBc+q=rkABa~rQd&j zQ@FQpMXIA&0sBuwj-@Z%t~qmDXO7;PW7W&;?zz}6hi7lD@DBs)p5PsOmL1Hyc&+qK z{p6fKOZr0BhRh0xO7pA_s(8h+#%IU!bGz&h^NTN0PCOXspQ6`%e^!^{?mI{JY+%dw zko4qnGl9|K!fZ7SyKBH49Yx2&1U^r;G;=|R~+x~pd-=bgo6UZDX}Q(G6^%vwU1r;v<{XeK+of?RTI=As z&;Jy!GA8wxoE3e4ttRI8&Zk!E@0=9*{`o{HpX7Cch@{T zlJWaXGknkQd9&%r7nL{i>AfDJa`8=P*enwlPd}&q{@MEaKbc}%1tw>_FKsGX+w%5E zTJy?lM^1B?goaNM`=BGZL&l-MFr@kAlG{2q5!Y*(u73R(Tpgh89r5(Xq!TZawSzs@ z?`xXDcTD)2UoX@3=*cP)^-|^UXU%+iIyURJ{;s&wBHDXBlp9r zMuoSRofRrylFO3u^5gXh&*ekza*HWG5@^XUYFs+WNNsl8t6x@qNyaQGB6nsV*=ONh zV3i!J!#2Z;$tzfb&92?xn?>B=SV60(>9e<_3&u{2RB5y-SC(ICDB9Zk_4D($i=xcG z^sTC!r@!rU)Ze#S34iAB-B8X665bsr`qH$;NyYKucbSL!NoAWt&VF9t-Si_#(|_-u z+PeEvd;EEhG)8=U(mjT_w(6gh$_~;{IR8@Mrn& z=Ot(CNRIg*8d>cB>Ptf0*M+5LJAWJ9@l8vAt2xnrs?66IW9H-A3n!Ro<)3RR+j=0b zC{@Enz{XA>+asD(N@ggSHfDqT}5ZvY_c&*@BX}U+7|7STb!>J zKG_l|wO00gU%bx0856%P=wTPgUM?|f*85{O(_^>4`Y_Ageaowh7q73qJ*nowAJ-|r zy>3nCuaq@T`TXnXk;=)noA&H)-<+HD^vOkq@J6QC240r71HXAr|28n*acFw)-}Pxm zj`gYgw2nOY>(SwxD!O;!yiDfA1BQ9?qc(B%IwmP$u5 z)kSWNnLon_Pltvi#y6f`OSKb z#t$d&H9Poi3|AIh&BT3NweI7Uga4UP=UA-5n`&RMGca70Abf>VW?o5Z4rr-WL~j0L zGogR$;vL`AO{m@aWO{ApbqB5|n=;ScQ1O%Aes{NmKt|`Jn*mF_g8VKe{jY8pNj+@6ZUJt0w#Zg2%?sa#4ZK4zNuKu2FgS!k)n@*W}4s<^L9CM5X^FS-!)LiErI zfi63q%@%wTdzCfTiB@l(JbB;Ns>a7ZO)dN{SU!Dv_`vSv3n~+n&%b1TI`zD9+`Q)2 zTg5N_GVIzPG_RxDG^2Ie>aTL~&;M?7?O&DkML%TfjM&#k3zKeJow@%xCaGoB`!C6k zm2DfGxTha8;CcP$W{L5xHS$;fh1wp7w2z$lR0v4@Z5hcCZ)(%#SC?u_2~WpYjavU(4*wOF@T6dd!Dp2!~X>&M5(A`iDN;Otu2 zKM3pa_oYQ>ewsO+XFv1MNJnS<6rOLbI2HyAL7 zB&=N7JHs}rL^UNcEh92$8iUUihwlplCd^pYuO?>@>fREXTeGxu;j+UEg;wr6KB?sj zOZK&5kBWd*i7_IMw#N^=)!%X2%b||JgHOe?vn6GsLrr4!O~r2sk2Vzl6z~0LoLkpx z!7DvcweNk@w#LXaY+S8p+S0xkPU?t|{8$jz*v;~c%|a*U<($fS>5e<6hg8k||2ONo zgr325*1%aR91BkI1V`2|_AdPRx|@!4nQ4eSxScFN|sa7RjY%BTEe`01PVH`@A1@YAfitutbC zb~C;He{6ERfzQtUZ%@nrymqzb$@Zl;<6hqIJRW_ibF$yICF|#WxjHSxa^ zQg*F3k`HbbIkPD_xm&v2Ao6k4lwBI8UWwgbVoSU|KghN$JhkUm&bpr`KFVI{_BB#G z{!l1Ej?yTJ2VCrWURLm;zA;QCtL4|Wmv`m@Do<-Fq-Y2-G&D?Y=;Dp1JfQ(OX>Q>v_w!c=8{r{~6 z!;9S_tmioHaEppXtUq+0<*BXuyV;8TbFaLay;0J=^2{j~p-!or&4o$9g}bfgnI+7{ zi*Fy|LB!6qGc@z0lw<|p`Te{5weopdKZ#_8aLO2MT(`Ip#z&uzJT&1SA?#&k0d zmJJ#W2`R4xuV`nl7CRKO-+mL1{iolT*UmBR{J)p$=)@I21rG1=@43fw&nqsLXYq|M zow+_wE*Sfj?>e!3xtmRo`&VHiwYOFJ#!HjOPEv6iKV`+g z%Y;^cmHhhg^?R+aS>nnTURP|~Cp|B@zvtzSwi({H7kGWD_I%1Hw(Fque`)O*hK2PF z6Z5r|H_tVY`FNLkmQgW>!ueT6H!arbK3RHcTcm1(j>1EMxgmF7cQwgW1^&#iz4p>= z8#`Z+Vw37L_X5^ss&~Bl9Fj6+*BUl&dS=q_$DHef#Eu%_r@7^aucp4$Jn&R3;{Fze zD>okoN&M}d-dO$NAvdgp4Th? zefCc~YySR?|JP1Rx7+?#Z~ogbBi@#U4_@8cQ#NU4B_MerBDi(a~My zkHd?2hm*kqO_DNk(j__;>p?|a!vlS<{c30phzx79A%vHA4Phwpw#?yau=cKu`a z%#B7hH4`^)+BD(LybJujC%o+HX71^jcX4IjudsFA-um%1pLKP;mzn2mSu|(;&P%?$ z)|+%*X=p{o2G0_k`!>oicv9)&Xm2OY+}5d4Gc{(NP0N4M8`8#gH)z>wx3D`>o0e|) z60_yc9Icgh37VaY?7jCaiCR&Y{rpf#r01avR;L^028VHOwNttgly0#+)PHOLg{)Ic zGh5D{(rB=fIPmnCbXIgyX5dMFi_5$1{g~OBdOZUU&OUkd=4|6VXL8h6t?IwCPP9kR zg#TijLz{%B)+Mg$B|^FL8;mnoT&rw9Y_fLWG|R^~Hwq}0C0k5L^v<1O)cE|!M-f-% z#%=jaqIO$MV?OCQ>4$Pyk?E$Ib?Z`BPxU_j)Av~KV{5*Zx2mS8-SwFInm0(1J4)^J z_x$shFUOzrkB|NH>$9iJj~+RryG43yBy9IQn)ms>&4rm~-fYURNVoSFyd!u;?#qO; zFK=fQS?RdMNb)h-a`QZLZwT&gajwdJ-g;`to9DBWP;pY4Iox=r~Sb~ba zF;;bCDlc?gnjhQjm~o}KM}5hAw(Wr;Tiooqls8|G+ajKJ=h^xvNi|khoi-dMKgy

PIsNRkNp#_4uO`WvX_T)^||uq{;PQ>tC!W#_Fe2<%@)VDxu@pz zxT@yzGsvv*IHugbVq%Vwlc%{Q02ai#FHg#YyK{yqxQTC+@VGv~AhP!s;1QuU&2Y8(qlQ^i()yr{NbmV`35``3zkF|abIV-TUG!%byULkk=xm zt0tHW^St3d^Zavc@!R5x1+zBroILY>#hK6UtdU%kuU(jKQ}Aftyqw2JTCDizM=!1Y zvh_`Yv;JJAr1jm-^X)lBzFPdTT%vKd^6FadJ3roX=;(f(GCBa!PjbbJ7$K*a}t8l%DoqTxFjCMK4|36lw{L{ZRDL-_Y z&-EW+wmav)XKhPcW}dmcZQ9SDOX?#X?&;p$b+>=j#6R_}mok*^K1-hBm}kJWV_A#T zw9>FOd_Sw0g3C`E7oYW8BVTyVS!U^eKO2dwMqf6ZPp>YIh&}U%!{m%uU!v)J4!Hw{ zEi3mV8Q)eGaai%|cKPQGSw}^>HtK6juzHtY&zpVp@7!x8N2g6yzN2u*U*hQ^S8t#8 zv;UgfiX;Q<9?!CCn_Ey5&$Vr4Wa*|;m&N`IPMyCnVkcl~ewG zk$#?4r)%F;9sT9YrN4*&d~r-!ZN2M>-3{6DW&4;*%$fauB!2Sg_OemvaCfy)__bia z%r|>Pkqp`>^Y5%aqber@!yF~TE30!;ON#Q#Q;V`en`Q1sM(5u?AzF8Ry~GjzNdlhQ z!Q$Rdn=>9}L@O7{sJOjes~{j^IYmv)k|jOEJNC)`?`J-ki65IDE26uKJ=*GixnA+J z4`*Jy;Hmxl=U?8Bi9ak7D=I`Ev`n7xAgA@;q^f_6{BtkvC~nistU7h#-+_t7cI9m! z(mV6`C1R7^ghd{(%Um>JOFgntyxc0$E&0i=#B-l{cIzn>dKvfaQCWEBaf{lT%axy> zofV&xHls00(OKuH-Hz{q%R9V3+br(4*qv_wcT(b+8vR2VvhNE79x%lIEBX0N_fzJa zNgU}KUy_98x+QG8tob)EZ13acQ&g&-7?wo4nM?I13D&xlg;ug#=(?;I37+Z$-qXc{U7lmcRHrJwEYrV!Yue*S3Ue_7@XBFu%CAPI39X_#+`}1@>y+ zEwlQ#_Of=%|6BqhWGYDYWMTECp<9E+_?KV=edsi zu?v06XQW+u&nNY;EMS7%GAq9M(jBuU@(;}9JZB;ht&#U&C*!$nj%(Ein`gXeiCT5( z-0?eUoD02*Zh7=M&e}F{85?K)W=n-&jnmf-Oiz1odfSX?Za&_}GnFl^R_cCOD)?iQ z>W8I*JB;&{Jy$-<>x;f~cB9*@?Gv9_y{viDlN+XZHPcV~tYK#E$LWu{B;GuFywgw1 zMN4rLXQ1zn-&#_8&S|8Is@hha%UKreHPdV6{M%E0?({2+(&+P>xg|jDZtnByi`E6R ze*M4s%urUETd;|3&Ws03*wT}gy`3&JcnimvEtq+K=A=72B`?HqX4sYaTnIeS$>|p& z5UmmRU}dLY=!Hvj&30W#FA3quDoAVE%oZ~vJ60n*)J#BYipVv+0mddU#$OV{gV}}v5Q%j zxMT)Bi;U_BIb^s^QsHvWmcku=vm$$DvfaP+W38J-+-;r-nP#^vwyR~{JrpTDG%xf0r{CISTMPH;Kv8kJF&fM9$!CqN6HYTM1=}OCgKWA5||9sXD z2QP(fetKu-YoSTv^HtI^f<7H;PJ0-^S$?I*n%ld2p-iyw>lw3pN^g|sG`)W@#gjXA zQSdU|DbHpeDc0`$8L{^2C*mYGJ? z=Dx>H>F%G&CuJLUDx&y#IrE;=->Y_5do7kf^1E9-&8&3G_Q<}aCunMZ7G+$m3Zu^&ACk-Op_AlPdA>m+P{AP&kg@x)$RH9 zCGjt7(^PH!B;JCKm>u#0?{?X?E#A=IX200qM00s$QKO=lhC7q2;Im(nscRgMYJcWf zvpv`CI`{7V6CYS7Rcg6q@LXfloS@d`T9?w>yX&uCZlKkzN}kh3B8QJ>on94g`~CIB zeRI+~We(hXd*_OM$E15ZJ9XOLeXC9uzxL{>V7dI>HJYz>85}s7w)*%2!TBryy$Tim zyO^W7EirV1sUFw8t|JdDa%H}3+a?`+O!x5Q^eGE|=*Sw*viZpD`R%+$`_2ph?uqy| zTo&lM-TG$t(F=al&O7*gVARFJGBA zw?XV`xJZCyyPe~aE?NGcmXA%`I>nPC1>!^>IPke0W!BL4|7O*neC4mO=cPHjn?8Tm zcyaBT(V5RYH*%&_{V_<&bg{7e6t{ETzqCEAdrI76e`v2x;TM0UC9T8nT=eGaY#Yui z-Ew<{Cu`=;GhEsgwygMKYt4L>3zJK|L!)9W!*g}`0(_WH?6jO-cQ1H1bGXXuQpV_w zW_Ne+2v)UESv%pysq?o?qJAw4+J0w=gxt3y_B%K1TxCD2m`~nt`c@75*;8*m`pa|j zO()ls{j(-4S$pmG+h{hQk6U=w-@kqHg4U9AS{B>G?(y#0WfbBxg*_s6j>fs7*a;G4 zNixUJt8UAA5)}HH*-43Sn-Bp+!@z+FBzS#V9>6cd$2_; z>g_Y7O~pqq{;B_b-NC^N)BOQuhA3*T+1Ibhty=6EGjYkHAD6fDt0wOF>ku?y zxpW}Ub_G)-HOuXs+Yr+N*u1es^A3z3toiPp{(s7~Hy3^tnZ5 zX=&$ZClSmA zDrXjyAL6%RRe9*#w)c!Z&%?;3_1Wt;E@J=u@u;E5Y{O4Mh3YQ^Ur*8duJK;1ORJsR7nq&Cx@~=p zxc28|v)})bMr~{5ojF>Y$-=dET%GZ8&1}E|_zN zgMxIYpt)cabFPBKk*=67>B+mh?=DR>`>?;fEj(~j_Gi~e1<%gBeWU3AaQ)S*_TAAF z3o?H`QhR!-)2BfAp!?ZLbM*BN6~7mm=5^gIrpFV+@5mF=7r#)WshzD42q`u1?v+TAfrXYekbQS6qZ zb(~W}c+zs;TU_p)*ZBH%mN|t@o%6u!+X2oMbDpqm{drKB{h*$>=e;N1Txq&W-l<-D z)?4ogIeTc^)3p^xj!$h{ZNIkshz9s*@^N)8- z>?&M&Y1IRZ?<%6pKFYNBt8ci(nr|gHz2V9Fo|XggTQ>faN&7v+D9=B0;t3+iP- zD<9Pw*Sb!pL$7pDy5dUXznoQv`BhU4zBGld(_i%a=9_|T z!Czk9i`baFwf6kZ%C}ckD|1%s2>U17u*uEa?pLg1!K!%7LHe>!#nwMP>>I2*zpVQm zeIn#-&hNNLofCVnemR^}GwI9YDy9-b`_&9hnCt6~ zNbkDUK1K4V*lvyuOY}azdD_7f`Lp;-)xFE>K1M&UzxJ-E`K`?Anfuk#|3z>1os}Pw z;CX0kb8DXC#KY%~^UrI_d!;ArAFuGR9#K$%#_8PeUq7^vm4U%sfPq1gz;@dbP&u_U z{C@szGl9D6@r4<3DT}8~*zx)>PfEmtl-V1%Xj?HyCrU8s&dpgTv~psI(E1nu_bIzZ zPJC;^_ln)w>eIg8UqAL)HQU?A{FlA^Nu>2y# z7dAh*x;k8bW6%oEwG$iH8K{2Nl;CW8@chRClQS)5tG2z63W^NdbyJa+%>hdaYNCJF(uWsjpZW#iXSD&uM&~ zW0sMy;St-Vrc3MHCU~`xNoGvW=5__NMHayyxR2bL-A;ljIMj zez^K`&cju4-{;19M%p}ltAA!w+Vj^jS6?t(=Z$+{#P>OJ_I$_R26I^an$ufErR2=k zhZI{~jVYL{!rbd>*YZNWLcewSvfz^|IoRH0ohhB9wX$@3R()6DqsJQ`n{zxjesPXL z_PXwiT}A2#8C}mV(vFnjYnEMSJl$ww#aox_mFMIGj_aIeQ@osNk@KR&RYp5}Uab0x zpuVW9D@EK+GUeU0jajNWY4RC?o9vfwuU3?0vf_<7P*PJ@cdydTGPyKyQuQ*cX>YS! zU&iYEUiZb!&iVMa>l-diuTZ%c?%O(Hwo>(wQXC>|H?CqFDkPnsbB5fQF{K(hDqOe zcSzo3+sfM5;^L&WC%cyG|Jt2Ol9kWd1?)mt{dZQnD7@ObRcKq^-xZg7mj{W9vzpwz z&YhWDvBImb)KjuiGM!giWFe*BSjU~fLSe3kn4;O!P`nU1HOeI$@`zI)x( z>d#kv=jJeNdpbX9YjebwQ|wE#tLEiyy+8feW6x^2m9kT+Raf|i&W`&u*JXo{|B_lc zw~6g1HIJOumpyd7w)p#sDIxmB)`upU_x483^_$@*({b;(T9A0@HTyGXa{hQO+x23t zS%h79=&P78UcF3(_P>p{PAK*qR?a)8=lp7CS@-wX>E>T&N5`69%|0kUr@M1v=K`&J z4;6G@#FZOtI+4EXwVzyk&Hkx+zPdl9mCu`H=N(_R`7(F6(zA_bK9afb%bE>#@wNZe z&6~|@+coR=3hrt8$0k2D4yYGh>~V8VjNIWR+WQ_ZI(CmqOzfDbLYLOj)=m?nsd-9S zXRK-jz3$JvJ-IgHljP=Ai@Luw@PFsNx2BwB%k$amUV9!D`FQWb6Yn)=Th?yTnZ>&K zWyVYMK<2Ay>tC#%C4MuH#WuDu{KA{WD{j~_jHn_?*=SD5yucIMtAe}1%H zJAUp*o#5{ezk?5k$+_C57nWxS4m5;$J&{&X=Y z{qEM_?)>VP{}JUoXwa{Ew~^I4F$RWuF9rr}0_A&IW^rj^PH{8;_sy|PTRGXT79ACllg<;Sm0JINUtZ2Q;lb(t zdEZRrlcf4t%QoIH-*Z;)-2GZPIqv!Hllc3YyJL#BJu>QxIPktgLS1{taie!@w`~*4+>^BVrqcOOQ_iRPteIqSc80iX z;j>hwz9-kNeZOD-KTU7*mCq|1Qw=8@=!tametsOP8q?px`=hU2T{E>L#5vw0-Qrc;YhN}tFrl+o)@m$i~fm`rn!?d$c8yr`+wd-c` z`Rsngk@u9bjv*s7a`w^B`ghJph5P0INm82J+=K2->%Os zdw>7Xp1{7N-B{kAe@4cEYf90F?j&U@Xnrta)YPb2F#YbWU6b|8(j6w~ob7y=J}KQe z!P1gZtU~?I8>wAvA8My1Y!{D<-*x;z-;J8$V&(~T>KD#smA?16vDNrfP`%~O9Tp{d zY$a|sPdAhwQcs@5{I6i?Ga0{J!K&?Vy!DKguAV%Z&dNC<-$ARYY<2AJvisbt-=AH6 zK8tz2Uc`yLE!jnnWyCr}Ch(i@5SDl$Ch)CHO5xPLyM1==-|gGI+-&8Y{3DM!e)&D_ z;NP|{H&<}wjn%eCPd{7GuzQcq84n&!1%}J5!PQ&8i_eMTef(~oUeFe~rk7PK-oIb+ z$LrqD%@Q12h5oxoEton<^{3Y>)rIN;SGF?RhGoxVJ({$Am9)f15fRTrwE>Cy9@SU` z?bV7Ausffh|MFj7oiNY3!!Ncg?>MEw7xXT*ibeP$(^95)K?kp=Sl`wRyHYWKD#w0} zD7G__wGq>|=&DVZZBy71H&y7f1)sIY$9v8@V+0-oLR><>nd6;!zka*_RMD_wOv*9!8!(pKXMW>5my`> zt(w0mS_scBF4!r()!9B*JXSYm**g6@(XY>G8j5N7*;PIdnce+u!L5leznzZSELk7f z^MBjYukStd9)Asd(q4JskL*M0f+#Z%o6%66R25zRaN*L%slFK(w~M1JZ|f8W0TpxMdb1S7Ni5>Fk> z*fXvbJbX5BhkDYvO%-B|Gj=@QYv=t_%dOi{;xx;f-Sxd93l{GG5_CcCzf;cx^@8d* zuM*uQBf}MEI6F$IuW(LWw(GD@Y|@sU@e6i5ij!)}?Gr9K$-IL}scALmt{mCti3=1L zaWbrmf5thhl0!de+syZ#XLrW!_-1zL(Mb(9xqeTlo9Yg{mD?otT{{z2@H1F4Gv>LH zuJ`&fZJ&itHSbBS4n2Kk^OYrj{3Kr ziRZ4LtC{x0d&%t@v56Jo_sfOWEhzrXd+zz)i_a%JKVxO&-du5D((M^4;#|5W=U2a8 zz4qX#SBr0HKHg~~zEhUYo8z0v4zuWa;Z@}x+ zO-HUS(k@^)_(o5SG2Se3+83>DOP?P+mJxrHK~AaV`ucfx(#Ni)RcB<`Bs0hD%F1Ju zn$LV-UY^Y2zK2_bn~rj|F|M1M@qNPYSw%^yCzPLcKxfoVt@jFZh>69cfkiwdx5Em$1pB zRXxjp>F&ujl8CHhJF!&hK~C0}_0`>CC7RV;zaz5MZ+*G>Vg9y+nGt8IE5E(VX)>B1 zyEd%yS)<5!y!HMLch}AbtDj{q`IfzwgRgqi%dgwDted)RCjU%Q ze0Q3c@rkGGjArwFmZqP=Vz?##ggjcxcsO2bA^*KaCBpjAmn1L6{8|70l!{2?`NFyX zzNYLb4xay_ic`zwsNdGu=;hpNIruDZmEO_c*ij|ru)nWQ?v_i(jMIm*I9rZ-1Zu}w z6*c^d&Pv~6uz?}=!WyL}VWAY;to%K9I@KTK_&4yzw__y-z@dU%l+LKZGht3}+oQ-f?&K@|amg`t8sC%qvNk` z&gV3(n6^sc^`fpzY=sLnivNB5@aOT(FCQK~dXvoF`apUCIko>Sy- z`OrM4PTl4n>v<{R>&HVf0<50TVoAsgyxp>J@;{BoS8e`e8}Idd6}C-ogO~Nr1N{PV z(VyQ=oc3C62Uq9(tYv?apKrBZH~H=l!4JVlIfFi(Tp^k8c>ReFB7ar{cfM(8QaH82 zK{LgP#muwkaiGHgDX04t=1N<-J7QBv;9)R%^|9ll!+5f7ZnCCkTF0IUu zJ1?gow*Oa0^R3uS{uj1^&69$&x>}QY+U{%3Oq_H1!HLDYJLjrZonj44n4^}k$MV18 z7wN}56E0gHn8I1XA{RY<=b|R&yGeg@W-^)1^0vNq>)d4V|M8pjLeo}8EYj_G-2Q2% zk=wJxYeGfF%mHFt%ABjqOJ?(iYg^9g=83T9SyC!o^W?9vVC@d6x*2}2Hw(GS$oQKJ zz2RK=DEaHbg2x#j@6UY|l))`&aBlmnZ6D^#CwrJb=S|Q%A!lGY<(I6S{9fDo;-8n7 ztmDZr`6anHiKSruj(hX(gdCfw9oPOdBw@E{!h_r;aVpL{kLoS{y0$L7X%KV7@WqtM zS4*Xf4o%piv7wYJq}+Db`VG19zkZpUFMjFz*P%W^`#RTGGe%7ooyygEY^OpEPQP~v z(3+Jw^UacwWfNpCcuWj>vA!p98(*$%u4{YMn#BirH>f=c*v05|Zt)l4BIdjwt9rX` zYgu*{)t9)`z#XyX1~mFqCh;cX`A8n?E1Fc;6#EeZv$#!9sf!TrXI%UUM4ubw2P_#ov#MY zZLgd!A0iE&%5&%~v(zg-UdbvD%H^-LFsVqd>^n!j7->CT+}_JPoa zL#Fw?4_-4&%dl9r>OZ6Ex-Vr5j|DFOZ|ZfYC}Y(Q&G*Obmd{(dD&XR@tWB+7Lb(?F z3$EkxT3R=Ga>2?&jBNZj4vTs)eg8eh+2Nh}vlSEW#e7RRC47zd>#nb+x1Tta=A{Om z-YFTLeRiVZJn?Nif5q^7XM_fD{$N~ptB0LE+VkRZnGyxn&d@!|riP1e8G2;x)PE5) z{ZZ=6yNQXs9Lh<*D-uPf8a>?j!F88!Nt=q9;J#Los-2a`(jR0st1)cUO|RHtY_ZEC zME2$;mr(v$iHmj|+Qd9nR@Z6%-5ryCrS9-g$vv^S=4kK)fxTKE>YC3U{hIRKjWff6 zrBQ@;fxxVspw@C;?|TzAwoE>ip*}7Cq5FEFe>w${8n0K~FA`_Cv@dSoj->N9j{Y+) z-{`+Pqve$LgWmPQzW1aK-{X$;`Zh^bBlHvR4~uY7_61Hn&6ygNEN5Eo)j5P$3qPN+ zx_HAGBc4K=suL9}4Vqe`L|qo2e4iKmtJ+BFV9kGRtyQcmT-JEW{Iz~Q>CgX*=T6_9 z{@eatpZn$#QR)^dsO z3B`hoLhPb@_I}a0vQXen*MlvUWz0Lo8b6*5{}QP`e@(^9RVi%$xBrkazPjLd`iqH= zTklD~PrO!e&?jaS-=(7|h9_;Fz3D%`dnv<$B$2M>vm*X$f~VAF@^AO#I8gsR^3}u` zs{{Y9?BfsH5~?GUd1v{NP@5J511qz<$y<)3OxfLb`~9zo3DKrZUj;?}LsM{CP&ZrZZ-)OyKp%jVQ%hwR!s zPhhgg-l*dZo7VAOy%p*COQ478r)0$Dx;{Un8Qz5*#ic3NQ*5u~3+rgDT736R?TUkM z$gis zS=Yb$^MhfF_}vR-w->&(XUJVIeXBbxWA`=92ag%UyPw=UG&6`nB=v_=g5rc-vr<;h zRIT5B+2H=t`?Df#wJxpb*tt#n--o5kE?J5^HIiQggZ;wEsbcj%H2})6tgKOgDO$b#L=l_0O7p zbl16QZ%oaa->(-nk<|Us@KEr&!}(3#(j~$E|FTt&l+r_0m_inCQ|)1c$!sa`IQSPJj&L=TTX}gYR`~~f4ZSabI-r+ zi8kzQGiSZsv9#Ugs(orlPt)}h0j)M;ht)IUmRy*u_jdzZyQsjLrC0b?B&h|g<6CcY z|A5jKj@M2%t^D?%GWyyPy45h&^F?of(ayCU$^RPSRyEu>{DAexcW-^(3l{tmzsf?k zzI)ic&@}x8Lu7F8X1TnQ9EGfRd&TmN%5%Pbu$&ZqvpMUBX{p#TCXWk; zx=x+gFUd6VMn>`3%i1;vPRLqoEy!rvcS82-tdrB6ZbZfItSXqe%~#DXEL3sXzCZgP z)W7PTXjvIW&Hvf-h12%?*@AVtF`elWR!g6G9`|CK811q`W7W~c ziF)oX(`C->H}3)L91Us6I^zb!RXGZ1{qn7;q#7s=RJB4rvi zk<5$aOLGizR^NY;U^bCGZ}zsl(gYpLt5s}Uk4^jaHT`PN^m!gz1@2xk&DLAGd-kXL z=S<8uXFONE?0eE!SNft~aR0igIWC2XZdFm&BKlRgT{V1~kx-doB-+*ywR=nT%LgHu zLXVb*m#1TnXo>OXzNC4~J# zv=&I21iAkCebD0MHcmB`#(;FGNfVYUsrftWypFnf`D;co^9Sye>~5T|Zi!qfp5T@! z!Lu@L=i)83I~r2k5(@%&-aNT)b?DV@hs%%d+OK^lwYqSMipy+PJ*j_&{Ys}bh57U5 zU$`jxR4ecn@8r&Hxjj7oZVx|bh3J2AtZoW>@W@Z}u;dfNovs1_x0lIGWz66A?bU+z zztenK6f_RJ{<%=%uIuFNJ8!<;Yl#rtzgjdR{2{{uf#gf^3J#Zh?MfI=`YPYckTcot z`e}i9O773&F>)H!t#=P(T;I1#V#VvPoom0Ct}+t6VR(SsVI%vi_z&@cC$hv=yxFog z?X#t7!_>Je=FH#sHzecR9Hy;WGj4^PTYxPzQKO~CTjo&hUmHE+NYaJCId;iPoOKEZ^B8Q1<p5ehssZov_;>k>Kjv?Ld|zF@ zUbfP~zgy{vaJbRIRPN7>i&}zwQWnk2&w1D%@g^siKea4>?WrAt6-vg7zCGz->fdsZ zp_w)6fuw6Zze1qYC*O^YQyIEei5e}FFnZ0D$?{}}TUUV&Pr3HFGUn^IBpL$!Dm66% zBiXc87ER!uy=umqiDH|>9xvK*h*7oV%?_jJS&S3594r=!73wc~_@L;UhD^Y{jl5YO zLkqa~hIZMkee)tZ@bWCj~@H)`%LYQ zCk5*5KBqV3RNRMe;?F8Je=S{g`qk-$m7#kcHagt?@#WU^eh{^g=`*tkfbY^DHtfDTTnJPQP)KUuXEMD==|K6^9x4qNT zQ_~iUUbfzrlkC^HXh&JWcIjBFtXU?N7XLzYEH`|L?R{v-Tk%`jdHR3fv!=6pmzHg> z3H*P%PyLF!(zLZVj)k1I-u1>c_c-^fh^5o?+GHD;ern!IFR+)~zNK*QMZ*A(Z6{W^ z>YAeWF?W<(7K8APBN_i6ca!0nq znrH25^dy)I7D;4=gx}Q?)e-x8eD$K7VBcAR zlQ!xaoLwjQqx$R1{Z{!gg5fuU{`6n*7L}AW* z?}{%pb6#@Upj^&uWvy#?{P?9e0`F$Z?_PPq!l8Hjq}~I*?U&!Yb4XiTmHg~^R@fEu z#=9~as_Rz2oftY%<@r39{`3-Yi;TV}{CE4^eotTeerHO|%CcW8S4XQ%klJ;5@roKl zlW7-s6ofa-lfU!h??p#xXY-R8ox4QNwJrY1Z=j~1?BjRzhp{xvt^~8ac5H6fJ-RoE z%w?TuDY2uhtjTHdmPSFJ&n63;mcKrb9kA=%ow;wEW&ckQWsSX7b)){=)T-L!_U2YE zy(C0^j2Cf~UOI8J=fQ!9T+6SwhZr8d9XlG<6YLU$2UBq92%l6HcjQ&sG}S-k*&$#@Z5)QF3pnc^X$7eTcO-l zenI~Q_tTTVSgWL`e^bwB{xxe=RFa7lVP(5kw^Xs^7T7+t4 zp8L5v?1^^eH>ICFb3bw4&FhI;CsY6N=4bm4yQe<6e(6=4_$SY>U26;btTnTaMP!zo zo!q)%(&}ATkA1wpX)15T^VydBv*wuet~j>Ed_G_1`z^b##0K|dUOyFeRY$+%?kcZY z%I3b3{qg3_Ub9cwq=$&BONJmqRzcWbGeg4&U&oF59WJ36zxaXSn|c6+4tw60M~JW&v_?9G$zyv)wCTt$aB?9w=J!sMRbG!Yq@2g=qFRhk=_ z%Wi+*m(6kFssH)f{#i!(J4EZoOh zEIP}nTuV!(WA4X{6$)IOUwx#_gf_E?Oqi^{P)ucGt-$1;(wf}!YqO24Yi6}poOJv6 zyqID6u_l8S%U4N)!E9aC7U%gGjb~4OT)4i8bK!R5*mq4T(qY}pKBsNI^l{zSy1W#< zwM#`-gnWL{JBQt-nf2iu%|MsH6%W$4CCj@U`}RlYm5zPquBA0DNxGrVQGJuT56Ldu zcSTBC##Pc$?7})1vjwmifWI&lkxW1 z0nQZ32_E)Q8J{H-9?waQd}e3qmeaxg`)Pjt@q>F_as50~zv9Xx$+t=6vsAb)<(54E zEBgN9?ZtmhLkl;ZF5_p^nt48RnxOd~XEAk$k34BV8E+Te4R!rey{=m~>)WPz#*-G@ zRcMo*7Jev7D0%-oUw&IVYyQyX6IA_!uWC$R7VPxUGM^#%xs0KKyz~zl(}Eu+Gd~|U zt^76TzUunWckllG+x;YTbLEV=`LhLXZ@uJ`e)1bv(!Rsn(@k#AQ(V75_<~vIZJ`67 zN-pg#HhL41dZXt`O}mTax~2A}S=?6Q2}esd^|Ic&wJ^BkWJj;K$SUAQbf;=kI*(mhOZ47ld3;SADLsB7tL0rlsZXUoShps2g7LPqXjW`<|n5 zpuEE2&|Y2To9}$oYyCD_GsVb%%5Du=I>G&|sg3j{D~D_Aa+5tJ-bQ(tME7Lb@w6<7 zUX(vEmEA%4g}bL}#NwQ@$E4Ejf;X@Ia`Q#Zp>;76xTalM-1_g^J?R}cyl;e?yubL; zYkQ%!s##?9+dD<%KKVxoC6g=ncp3UJj0q z8rEMtnq~yM3%!bB-Xq3+cW1y8n?n)LuNqHMalR`QdWdtGU>AeWNvG22?uM1zL4g&e zyef{pmThNtsKz}!I73Tp7JtWEQ&(fjRXj5m7O<3@IiN0b;>q5|n?25dIo2)Y7G%_s zj-A>gpyj#t{dDh(p?bO7mj|zE)Z|Nj5xnGy_TIFc;pXPs%WFe!zHp1^t$#mz@q_0t zV(x3OZBG9an0LWlBu+_Z15a+Lrthuw`Wcrj7B5@HJNMOEw~{r@6UBuD-F+Yb*JyUb^ietF?xUlr`l)I4&=Fw%xh9{?q=BHzuqs^>0@;s0A=|;2P7P4J`tI4ylT*7?P?cL$!;o>Q)FTNFe zC42MN+12mw?fKVxH2b*M{*9B)zT}hYietO^FaBnkmh``*9fyxBnk8$qER!){HIJ_b zV~x`z2Fc=P&axMqbs0Av|GetbYlayir`@*pdmVSOw!c%M!{xDc(L%Ln^S;WOGRmx8 znxXXXvP}Blw*wEo_BGoPt^9@`$iQ*99{Icq}rrX8)RXgj3nbxNu)pdoVEimB_i z_s=&zzf)}X+W@&|Z+Z8Ad0Be+x5k@T+q!&_H7{SWK4M6epZ%p{(&1{sS?|BhEi-a0 zn*L=Cd&2t0)&JJjKAYB%q-%5Tx=7f=LdOM{Z9nA+e^NUZH$&n@?&89(N9zMrqqzQG zW!vjFDZflUsYaK>?wh`E*8p$;1>gKu9;L3s7(+*5J!e$;j@9}@* zf2%A%rSe$aXx$!sqo_kQM&Itj?4pQe>?*4wAEx>jte)0eu&-xI&9AgO|6|&D){QI_T_0Qz5Hz|Iu{#&N_U`o8uYbU$8$Jd+5uthW+ zVp;O`y6o0-^4~K;zlOY@xZs`8D$(jE@+Ziqoch$wyjjlH~|m z=YC{k`mbw-Rmbb4O==`v+JDI&cATHMFzQ&c!^3OG0~X}U!8_7e6+ebpNmRhHva%lCx%?eH*&8q;ON;+nFz(J+!>N*;;dcx9j8y zXJ#mgPTJ)D`cwV>cgLC;I8J@?(TkpH9jdB4(P8n$d=se;a@O_re+vKm&il0K;qS{m z({t@kSK21FpH|uX@b`U}`1fx%F3#Gy?(Cx#C&nskG3uKbB9so*H!E zw5mR1tI2cUmc{F4ZHto7m6ll1)+XApN>ZU>_L<7VlV)w+)3W{a62B7wdXs~Si709<@TWIJD_P13trx#B% zdE?Y`{Pb0)-V&z!s#1YV%01>(1mr=S$fcaeSPE2mN!%8?SJ-K@qoh< zwx}Z=!WYcqRGwC)`efr`tGc$ro2lWfI;LU|V(keR*pui(7d zvFpMsC$4N$u4=F00eeQ5LbEeqp9{J~`!cps&DIA#Zbab}bmA~f$p9EFJseiR< zng3PGRc6!YtkC5bCe5wMdac5GiPP=icz2xK-7=V!NnD!OX~O3{@`|%G9{ou{=%Ky?b}M#spq2 zuS54jRj&u9{5H_hkBl@7$(VMpVPaComQ|rMU9aqac3R0(aOL4`Yd^mZJ?;NWisxeO zy?Z~N@i24!TEy6rc+zC*oOA=vhCZ95S?=9hk1cLLS$E3#n4rN28Megl2^y=78uU9w zp4)DkC!^XDx?sM!&B=&Mo2ppZsuiDv-#? zIXskIEqc5mF| zb&S!cbXFRNaZKh-WWKS4>kw~;oX7IQN!MlWP2X;#yu-e3#=f01_8q=>p?gc^%45I% z3k26helnT=^}zJ)32M)@rM^P&?l$;o*|SCaC$~w=;@b>6Mdzpmd_4N{rSv0n(_6={b3O7lxO-i|^d9p=X}5>I zv*Vw$&R}mm|52KG{+bO>UL3AwzFD$0N5`p9cj@}$@^we1-+Uz%o4CC5#pU~qKOa7IW!Wh9PmcBPcSn!56N^tP zTRX6nE@S-f_Ev1ki@7%$W^o+@Abe~GP5HSPW8wQ-L-za3;z z*pS2>l6>JO%fg8{${#j%_SRRJ?mV5xweVWVkFc<(`~Ez&+UlrMuFE2RGU|oJg7!i` z)7x1a?rzNf^jFxxwq4Mz#icRA;>ErTwwglQvRyj@HCrmh8fxoK7(ZMf$Gm%D%pxBN z2I1E;mn`UDsG1bME$XpR7OVHslMdMzjDNZRShx7E(*9C~C%!&*3vgH#z;J?d^K!d71lP%;9KVE@0W{GetW>Pn%!O z$F^fFW0KY4mF?$FFf7stm~x;y-K?y%NM2e(O2pLQ>*s}n-mAKhFqRrr$4J6`GLHD$?VRS%>My3>=s zYHn#dKPmL$tW%1f%~nl+dv#o4 z;PGQc4B_$1I*mM^MCLO7lY9Cy$-ml2;OT)05~Wc|?eb?{JyoiFF6Fs;u8hg{Fz?^N z5%U!pUca2b{GHUQ{^Q&ZDmTunZhOOeT7Un{nAopXrI{1XZuq1v|Gi}P@|S5lp4{&& z%lZ_3DNAd`m$&a7Revrr*Nu*uyr`n@#JhLz_C3FZ&pn1V%((r4y;*o{@%A6@6EdtR64zjJ#qU7$Jw!qo(AVOojS0_{ggiE1s$=D<4Ngk8S^3}r>LAhQl1jzo%zM1 z+%Bg22!_Ry$iqX;@u;JUNYnGucL3kf+Mb-OtKwleL$--Gy+=*}jZzHy!rBzg@ib zU)TkSr&iuwo|2F=bw+lydgSXvPUm;9`kr~FSH3gz_mzE@T3EB#6(r20 zm`~^)tbgVySpLn)>Ax4hLb&TP-rAs_y;rAP?T@n&pRvS)e_CAi*E72(>Tv0J+OM+A zTduZX_4j4HDu1uu-sK^3#%#f-M`ejOrE(YRiS}zwm0Xj$s`|=xuXhYf7u>l%BYWpV z(}+uFrdca7+`gZ_;6szomd}fFfAr-)TeVkln$dJm?x!#3hrVHM7H{Qs4(fE6lKs;- zWyjq^iIxmj_Tk(7x0W8->c=G_pnNBzYV+nOE%wx$gEDE6dN!qsLdW^^Gv?M!zEfDG zX)5`X;nADe&mxA+$y*}Rxumh+Vg(3SYi9^*JbgRYH+*22Yv^Vc zJj1Ms?RhDSz>C*ULo+&mUY&Z}m+6*6?iaHy>$5^t*0^q&FyXZOEuGcNP8KqiU2IZ( zD-hoCM3c>#W8;)KzRSB0h#Z@&#?JSUPl0c>!~bjU74AlvUh>^ z-bXK3qpCMQwmbMj?I_FfoYo}Q9G;tJymBrEd_Q1gA7ARTNF(3V%!WmHvZQqAk_E;! z3!NwYn{==%e^E-OM*oA~JFW*wz2KhlP*}VE(`3)Ni)AFPNzF8nVb{-pu4HO|<4As+ zt9lPxd!qI-@N8UKFuk|A*;U&148o(T$j3R_HnOg^~x>aC3|`&_>1RD`ee zyK5)o8KJ&)iqNm%zYjc(LubO7KY!>1unP*LIsUHe7Q%)N=d~@0YcmlA$HP zx7XQoezOpJ)aU9FcHkw3-bCtr zOS`&hk-wLwknS1AsBWpn6_abeunU$tyRmP7rMbh%DClg~$=4SxE*agrpCrY4YC+Pj z&krwpcCPMt(Xey1OnLnAPpa1*Ik8T7(Z)Z;izom61WkiYVPS{$o>?dSz0;nf^pA_Se#{i~;v-M2{*m87Z+AVK;;OFwZa3@c zMVA8&%4aA&Xg=!GyPLO3`q7OqiWe4jT3_hf!q&epVnWtRlS|td7HoJD^Zrfi=+dl%%(vbD$}Z;Xv@P3pBDy$K%&={z^473ptb%&XSNvYriP#O5Y}r$A&ZB{%KB6n%9!n%CT3*FMg>tn?u9=8_^u6X3RL>lGHo#aaeGO zZt-(Z2jjal-d^Xih+V9xF!%qarKcE;SQflzt6j81b;CK&Swi_GVZ49t=6-)!6~f$e z^8&w@`X)ZM#{$gr^4_wm?ftU!M%0HFXA}OtI`BuZ?2gTa`%B_3G#{Im(0aA;*P^HY z99rd>XVpE8;yCZL?ETiQom)I5s+Qb$yE5_lg{fyR=x5t0^sajH-qR(+K)Hlz$%Mo* zuRrGh-U_{Tp7i zn#ufZ0*SZ$y^CsZgu{_U1P0MZe z{$LTyYLtHeEzPK^X;JdT*Z*DS?dsfII#Z{}XXE<2GycZg(~=v5oPT=byD)I}xq z;fg2X_SJ9RR_$EYRcqtPoL%!lVC{`}9xe;!#)Oy09B?$P-|F@1jOdecWo% zu_8ywO5$;0Pnx2bK&k4|r@d`b_MO~PO0Pvy&dWySE8DCnyc3!|`7EE;B6c1B)Ck{? zQ|`WBe)%)E>%qzX(w|l@bbj!#=C$zG%ZJ@3n+ZO7871Fbdw0V{fxIjobMBCPiA*Of zt5(ME7QMJ&@}<8#Y7cFWUd>XQF=bM`HM@@gs%wA3r&LXz{Yi8}=d$doxWfgr7;4;E z<}m7=z3<1k_Geab0$Di|f%s`_FT2`YS@h>-cM(fjtTf8`_p!a>1Clh=Ir z@nyd2t$eO%UtK*ZROzXb)11_aTM~AQ*}u5A?c46Er=enM0Kp#ba67nHwoGG6HNI| z#jUuzob`F`;@3F`W|Uv`77@D8*;{8hf3KbiKktuh4HiG^wElhBo2uSCObQJ9nwhgv zZS|7PJ9q__&Rn}v=){3LvB9}^ryJ&?7`9ac2jWxrFL+$kEOGL(iJIMpYyE#-Z%n+tv*5$$_d9!Z{Mt37 zUTOa|W{dfM+j`UcYl5%$bhWShduYM(sV=ovarGN-+<0KteNHTU-viaT*QQrY5r{}& z+gx6wekAx=)QfEmw|%))Eq*OMb^7Ad9P^3?{Rh|W=xQ(0=t>QLys>`WP92Ny!rT0N zAJ`vA+>-EQo6D4r4V^W=BG4e>sg%>7kqM#ZC2Rkb(0F-k%GMXci@ZZSUa3Uw zu2TCWd1=|_rgO7iKHPYEf=r3_(zh+S!A?oVbCTb6R%!XSbxqtg(OisQ^Sb(r=f^Vq zD_n9-n5Pz+-CgjQ@o=5zL9?$C^Nrn}+t(l8oLg~s%CB`Mi?xqV(k?dm`zlRnZ`SgX zrd_RxuHn&7-}bgG&6Al}`d%>BW6>rl#oyIID#r{KztD?(_UOzNiRPjw>jG=nKisU$ zB!0?v-ZVe^If`1Zp4cx-`Vz@qnAqDpbH`_gB-XapZk?YOyT#d@;u#y(%WxFsNJlAI zJFTA8E3kUE&C}m6_Dm{#qWW3xw?b#-^+3kgw?F>y41IU`a+uoX#;jw(tJhvU*YNk_ z@hWBYZhz?#8%dW@z26vr)F7pFh<5afHX-@eMVw_sA=Vq=>p^H$&b^lysvgPnnV z7eaLAJM)}-`YBetK(ZlYd+D?#$09q|PI5Yb{?&|^6J>L`D~-CZ>dum7c1(45-gjrFHH&KUAHUOxnIF`>A^#x3Sv7JNE`5c>K5L4wdPv= zo9|Of)@;waS7ORp*}Q_TATvxXlAH&v8L%eCtv?*I;BOh^|Yyf-chrN=1_UldE#tK*PZNFvs&JB z+;i%D(X8-Q-HcZ!DAoB!Ogo=8$8Y7TbDut$EZ=K$OXI*p-<7M_T2+hJSPHtz-94+d zXtLI^Z8;1lEZM{qc=<4&s_{Rxb!G2Z4$Vc+lb4I!on*ZTELv3BP|a+qm|Z&9dmFGY|Ki z-yL1$BNrgrH2?c6g9SIb4kb6dTCuTo$If!m*H$Hnn)NFQ3iyhh5>xTNNwZm`k@W(EhxGMNI#- zP3BJHxp#^W=cU}q%3^!0zg+(QJRc2a-}J*P-wEgB%@mChRX17v`d{QEzWE&DcQ&kI zek#ej=vis#<=Asv3u7P4yw&^k@5Ke2k9OS@Fs{D3_eAgot3B;)hnF$m-|~U&ZKrX4?X%!YX-5Su zlXp{mcPshlpDw%2`5W&*OTpT=6V%qHbqUL`#&4m-=d?(J@SF`%Ju-ulZ*F}Y1iBCWFXI;$MOAZs+ z^BCjoj0K%T1*Hyc4rp4~bZFbMsJ*H4?j8EXZK>E4a$&}zRe9155~Tsz-OJ{04PD$e zF|p0!TZJkE))Woz&E z7)+E}c`Pm?f8**kRZ$h+`uCOj1j*J&`JSHXB4hjZU(i{xO3wEh-|Y7JSnYZC`rs7j zo6nZsQ3(Ee_gp;d%WYQYH51Ig9oSnv*Xzgb_L4#l-w+3Z`n`+GRTrFN$-U!R@AtMW z{_uRAXaCN;4J>8VSh%8~>fSkxy+8lFvi!Q8OJsAMNWIxZ?;Wa+e;98r{kQDM{t5BF z&PV;>5AbGY5n*6p;9vkv#)<0$nVG6GFf`0&U{Js}8JC}5Tmm{7r1pRLZHvAi?|*8S zOx~-$d+SuSmu0&ueRpS0KKCT|))&*4@7_GEu{yd;)^yX7sZUh))qUDu&+wt!qifpK zb4y-dzkWl6qe+2-Nx>txDt$g*z4W{z$FC6BdE3xx*gezurf8TfMU zXSYu)c6mMWzIjOfhvqDPrbr9_O_7UvG~2s`ei&)ZtSLKDG>u97*y+W)4Np(J*I2$y zN84<@d}oz#*v3NDY^L+;7E4|@FaPZN=E7-yk7p{qulm-dC5JQ2arlYRYE*Wqh zSiCEPx$URP*SyCilkQHtx6Zti+wE<&=aw^Kp)XxoKc8~#GrgI@|6u+E0iPQtQ7Tgz zK3AEq(P&J~x%B)#Dyw6yrPKzVSAqWR&5XGxzWr2y}W!|oK5>ljy|yc>0jrbuk+Y>g%&t1(3<`Ug-X2)} z@Q1_q$rgLREsAVWI{33mp?Jb9i}ozZvmb;^F6wBht%zHDh%^uLO-`~yLhB_ z3zfK5FqgPxhO+(GVV%_~aHOUtR`lYG+(O+A8W{_m1ZD`dmVRmQRLj)$*jwtpZKctNO)pL4jt450K0G4)Ye9><+}2gS=S;kXQoe}_ z$4~sLs$*ktt6D`)y>QnK=0w|+=?9kCPPbt-SakUMxlak!6(5_X8FW534)~HC^7e0> z&GH2Y&O5NkPF^l7H>2jlblvxNi`eFteeYH~*%kS8-YkV+R=x$*W@gbHa|#|mJ=4PN zXfjXPl79)ymX!F{ukWA##ueIaXj1JiC(Db@>e(wD4<_6^XCt+^O85VQG6#9dw+`ON zH~eaP`J`7^Of=@Q`^!tG6Yhz`l}J{HnrQEp<4$X2=XrBEi1(0XW9kM&<*`=_hO%R}P=Ox~f3CMxm|ujo7=bD*Mvz`5$ii%w=M>VUu-LOdZTpTrJbP}O zt-Vr_pgJ{FkXe00eN5}YSLLEY3S-pI>ZucW+JOo~piSNBo)jzXVQst{|K_Ri~5b=!eQJEl007 z-`b-wuldLV(Sy;Cn1AwbbMihsD|qA0NgDH=cy&ZxTj)(>uf1?HMdo?JyoPv2p%d0| zDF=Kq;~r^USbXo&sTgT@g>-Yd9znjNxA%RQ(_ra8B7Jz1So7)wksD+y)FaD$O|Hz@ z%hcKGdi-_aYi}I~$9ctDcL-O!Z;Z<@*eI^DkgvQc_kF@4#aBnUo(cV_Sd>u4;2U(1 z=LjdmwijM0yM+WibtLo_oLD1eTqQ5eZ=k@iQ;p%CB!Kcy|h z6nky!Kg$~*RV|{NOn7HyDk)zR;?Zza;MsHCx!7otRrjQ4iY5$~XC>ctU95g^9vv=8GB_{Bf^umOEs!%Wv~- z5sM>Jc3%y?|Le|WNArCDit_rzOSrA}fSAJU`16bN@Hct72lc;Ce8L>G^7d zH&b)6-o0 z!~Xl(`h!{bG3|T*S3PvK_EQU^)wdKL?3X5@^OmTE zE1u?OD#O zkI;~P=d^IPXwDU}D8I8UDZ+26#rMU%;w9{ifI|H#AfYJJ`cQRZ7~R&QKlE+e*7(gPwpS4{ZqJop>f6uX< zTq3Hnm7imy*0tp=lL}(Zb6%ZeDQkZnq&jiO7R5#nF^^3P&!v2S6coLo`r4cenhYvJ zLV{mEM8>2tywLB_o zzu51~rC#8&;GOral?>(lU+Yfpm0no0=QhV4wXP$lIanTu2yz{tl|MYmndYsRspM1yXH(C7r+sH*1y1v@vC2d`Mz`?km zsp#Z_i=q+I+`Hp{c?8_y)0>`Ie~m3y_xrz1yb+GRw-#h6A2@$|qvcyh`_ho8vo49o z>yj6(Jd^umn^y4EtlPT(`0l@W@?-6n_JlQ!r>Z}CuS>38UsnE3{-*sUiEW1*qYT|y zdYNM*`K0d1Tv=qFq2MH|qIPG&zeKJQZ{11T8=cp%`##KFbg{K?L)4S7kR|J+`%gsX zFcgPxOcVRByEFCIv?F?PTV};GEliO3f3-DPCTPR)HEAN-jD08R?@*gqmMGm``XP5N zcW?iW1Dosrax`Awv%j|Y)w`59*QZnM{u(|=x$ZV&UY6$#+j`M|kAoB+S0%QpJ>>V5 z513-xddN6_CT~)%gYUD(+ILO=0-O(jy3Y2}();wTeOr~bKAdHm{V{aO+Dn_(rL6JK zEmbR>`}M%ibC&y}wl*%e$~(U3>N%hHD?1z~Rx*@z|9^H?`fO_v^XaMW53W1CJ}rH1 z2lxATe~uk_T$=64mONSKdDNdXmTIe)o{pMSy8HLK_}%No_uV?RVzJl175Q71&Dvb@W`MRN|dT$L7Ont%NJ zoIRB$o(Bs#cT*9sS@)ysn<%maVSQEL*mp-=B9hp!0WK&f z>zgWN*2V9ac&U>ulf7q>{3|ohrLDbriE9pinWed*Jyuem>rUjPI8LoCJ>Lb3SFPa4 zP1F&bwCute=M_9F<{q0V>naj9%W%`yDNIT)-wIz#2utbSvpv^Ifl=&8-@~xFlZE*w zUrhgUpkOio46)A(vQFhm`+Mo1ydGDw)Ao;GI@3B{38OFL{gRp z)SVIze00ZPvkud@*H(IuPkmU`s<5ss!*M>Fe2~BvB}36 zZ?<@DxVB;cB#@cWb^4w3~O~UbEG)=GfmM!P2{n zVnV*1NW6LLoPt2<(zWt(H)cl5^A(^fq!?b zU$5&(xv=X(h1YM-9-n9|GYZHI< zEW7FZj9p=0JB>61*GS}v*I_+XKrQO5zEQ>T9LnHPT* znfS}X^Ss^iO;*1>t@$@CpU)y$aeaGG2;XDFK+}fz>@SO+e26^ddaf(ZKH$dA-|wV( zJ?1d$cV4=wG;3pR{ha5sUOV2?d6(T}lPP-eZfj%DDh-EoA4C4mv)Lm&=hFNA8&yrT zUjME=J5AHOEow>MSIrHKx|+)t>TK5#neZ_F!sTP{w$4=Et^cd@%D0-(zFXZ2f9>wa zEP6j}re2Wc<~2^|KCg2<$+~Rm10UCQvqf*n-k6>IVCS}-&i6C;TZ9)$=en0y_%v9n zng=>XPSGkq|7NPk<1JHKA6Y-1;WXhm%e?PT9{gIg=$Pu$gOVMwa?8!U4CQ6pk9*!e z(#ITSyKYsg++-^^q0d+Ddi;3dc==}U+}Q{3-!+lbX_TLyAiDUAZx2sq-`&U0)Bn_6 z_IGA^XcE0-vY2Zw!}-TTU;U~#JTo{v*-4zZ^5m)`{J%1 z!}6v{$%|*6blmuGmA16woQQ)aMeYYJ;vLREE8J9)^iWwl=i{7Z^?SFv7GM7`|K4#| z&KS>>cSc#|XA=)KcGz4r`{ErPS|IH3_A&EY$GM@`mPE;?^mJXTbb6h&N@3;M>Y2budkg?lm2*O~T3PoID2QId0+_O|WDb-Aw>=d3s@STEmP<}-~~t!wf0Y3w88WR8`ft_#@j0HTylBKozH)M zRcw4e;r0BwU!HS*Kk!*TMb5xn><I-gkbRju>G+I<;Sm)I9KUz^->&OY72kBi!V9P6niy$>CL3FtJimT?Ts`{Kk@HH_UHdQgxsGLPFp-v?^Df0mKD!0 z?ySz-^4M-wNBZdm4y7&X^E2X=HFojtv|Lo_dx!PlSG#$7)r~Ap z-T83wr1~@F@}y|yPj$EN990(Cq;yU*`uV4*QyFEGx4x9Ha9PKD@p_%GzWJOSw!+_{ zDSO>lD&Jah@`6Kc3)klSH=CuIPD#xuS;Kue?)R+)#iHU7rMKXPUBl z-2WNDZp!|ZDS1s-A_PPoE}oDpn!sbYOmzp#+f5#CBQ~{1YdoB_SMbk@4S%I9R8RAM z%-A)xg}-+5f}Jxjhgf%V#=TcIag^1{eSh`b=jvBS|81{+^>yF6XJ6*LUG?JQwqJkP zmv4T5p{1+R!bWC|=e8x2zj-+s>*OkBa<*$M*!Q-<#zW!b)qVY`s-fv6Mf1lKCXINVU) zs5z(TUjCNcCBJs2-g$oA+~I?=@zp8Y%Ge!WO@4Rl&{H;1;ef8ot@bv@TBFuYJNEB( z6^n)Pk_%72#5Uq{_IkeSd=rjkNTyF`?_bn1XuZXFN}2DAgzQbv+Vb{uPaWf?77TcY8k^i{y>P}N0gY((h{6`A&{hqyA)ezf#|F>Sq{fm0LnGH3* zmh~QCmOSYA$mxzJ=hC<5w~O_7wEA`E?$Xl9>weeuRw&l)>lFQ4){mu){-jB-S|KCT zWx#STbC%BQoY}9mv@1i}+ZULY*z8!?B`xvmxI|8#wP3x(;}mKAz58^jg4fZlE6pcv*1IB=I>o$n*5f!9&tzr)n#2tL-_Q2E`X;XG(Owem&&U*TO?e6LNhs4jfbH?eK&so}?c6=7|N}FXBy>|bz z%6@6TH;L0YzB|Tzx7XBeK?SxNQ;7w#`=2{Gtz4W?@=LT|cETpce@PQ&l>K##STtK_ z-ih1iO;R|jqEmjU#vgR%|NLjq-oHNKZf>vE8gozj?(=QqJDH`b58iN>m!DYkwEg1a zyVLczw61Ea`Z#AnoXvOlG!N#a!yQJc%tosX~!z{$@?#-@*m}xGO=jGi|vk2 zgPZ5R_Fg{QLGXT&b!O)~i9bSO*mQ*5?&d#Xn1R?eJd_Hbp#8{?U$cIL~Ry=HtZpHny6e?aYv$hTdfd;XZ`TLLml3yZVh_15O%5$pyiot4 z+FC0g#&21%$^;>^ie0MEq88orB9x#+xDgZ_drLcGdfE zIOD78vfene@9s;wSI@Nnw2y`5nDLxP2dd3aicI~^I_p_g&j!8eH{x(5DEC|tj^ zsFuzC)Xujp55wKf%<@+r-5;=U^2)OJOa2wIxtd6?e>t(l^5gxDbA7*lV*2dLlYVoN z#OCjk5-;N_MW5eU^`qoRSX%QV#@vzwot$=c^`+Nu*X-Q=`FY)g%Hx|&7Vj>+X|v(C z_-#M;3I22Xrdg+NNZfkDk!R7#CD(U+FkZK}N;^&a4CD2wnH9566viC2xUJG}cJxN* z6~RwE!cWU;cDLV`uy7Rj-^=Nuo4ID+=S}x}Vs*rmV7e$$<`CfQ32ZwR}3M;UE$ zN@4IkGHuJuWHr@QF)9;Rr^ze}c=x=OWdl?0s-0H*(wlpvgkNOeezNi9OR>z~yYz$| zee9WcD}UZ)y8qs}Epd}qRwbIS@f~cH;QsrKPkD8eY*o<{=iPrSYdagiI^TKfr`=r^ zZQ=XBqg;0L{=#L8Lc1R76?*CGKeFtYKJDQC&fh*OT-OALgn7w7ted_x@YLKNXYK9p z*Y3Qz7{M&nan&hQJ!O^Dop8;h zJ=^y$kMr8{{R>(1J6QpjPNc^- zpZ7U@<-^G-r`-Cw{;WB1vSfnE2bqeyAy#=$4)p*2p;Xty^Kt9pHGFzI16C$3JF!o= z#bZe^zklk6-Rmyp@7UG%xTb$rF1{$`UN+E zyAEBJwI#(p6HgtNU(azU`m5~38dgIiQ?;TX+slhms=g#`RZstT?(Bw@=Eqqb_J|(3 zW|PnrcuHsfq(6Rs=V~_{-IEdXv0_(+viOGsK9>Tkdrc(%?cS?<>DbxHRcoW0mt_=Q za9cIOZ{^Qly+XDf5zE-Br$3uDL;R-B6R{<3&(t+^7g^3STJt1-;l>WL=$4zwdu@1* z9Qm^A!z1}TwU@ks8`rw;%6-ap?W$}>;{2_%f4Zz!`P;&l*87Bgfmzno9lp*ky=kYP zsos3Fq2;pRlVg4Bc3io>b^EQ5&Z{>0ruIJ?E}1OcD^$38ckwxnXBYO&ba_y00R_gC$xgg#6~^Vsp659-c~@vbO5K|8AC``UU5-whO3iKAf|B(}lfG zPon1dZ5GuDzFxcD!2L_Gp=r;wyQ${yUYoyO_xaL}=Bn1N;Lq-B=g8C=yUaU%J@3Th z!tN7`#jRQIiT~TCGd;5DxZ#TnvmRcVA}Jzv{TAz;sTIXZo~JIoW^{{~^Hj8sNpr8n z#J)!vHy(Xa+kI?%1LuxlOEpD)QHVFt-f;x4Y)l-oyLl zYwfJ<{&MX98SOUjo8zYsuj+1RZ!5ClY5s5P6Hs>}Af|S~Ui;SLE-z%`GQQO)U&=Li z;+Uk$YJ1N&Pj8y|?FV-D*&O$OS^c;)f9Ec?HS1T3hwCN&UaCC%&`LWCOHTg(KMidx z|NSt}6b;O2JQ*JB`%2eZ&hk;u@#)1)J*G`g|2}Lu_UEIB!2YL+Uk>kZv0u!W7VIPY z{j&KJ>DPKGVN>_C_*U1yYpe8rc53^Vz4-R^!&`<>YOS3u&} z&m@oUtO*vU_sBBXx+e9@CtmD+{@}}R!9S86my&!`cX;c2KMV7e`IuE0n=AKRRqSlG zhR&mc&r*8lIcwvZ9XZ=iWv?(2PnlvWGqv!5f1TyO7k`Vse0=fw;LnSS`cIfR=1+Y;skBz$m-sZJ8riv1Joo$$+ao?{zol9H zrQ4OQx8vUPJlgnke)-GZIXfO}81)_9#mWEwkNCeO_sRs$&wHPjlV=fk`O2qVhNYp8 z4m|!YEXmHvmi7FK&Jyp|HBPq<8LyvvRqsh+XO;cLLQ~WGflH=cv^H7qacR5sciY$Z zRR2xTIN1Ko*8S@;CAqRCt0$N2t5KL&mVDYYx+`BetnX;JGV?>nTGo;ZW&X|U-Z{d;Zk}JN!QcSggsOA=jqmH<@Xloxhsl{-y3u?YgIP=0}7lT@8*~!4yzx z=%?>oB4T=DYOU~=ePVO@@9bL^aNgfuW`FRls`}gVnHNkZ`M%ivxw-hq;}s5zch@fz zy|`f2q<;?YPySeS;?kO6f0hhy|9gLb{S=wj)@LhtA-g&$+~WV&&le9SR#eoKefaj| z#fA5`F6*#b%YO0MeopJfwtw^LZ0s%AWN+*|z3Py>S)GHr1n1n}EgQ0{O1|9wIqTma zyP}K#Uis)Vu2=l=`QYwZkGB3%&*=U8R%!W#;!NQ~<=0|g99YGi-CFu)LrdPF-*X*7&mf1~r2)UMW7&IZDVK0oGn?{_nqZ1~L2<@yERMgIdfE&G`2KJ~C- zbj6Q?omxF1CyPE3RyvLr~ zr#dxkd$F~D`F{($8XISG{j`LAn+h$?U)phMm*n(bFWoQm<>%VYW1sOkw!Bch#Ju>> zy3Z#L1-QIad7T!(bwMnx&hAG=#jk}|ZU4$ndGs&H+==tkM9J_?P4{NXm6jboBh~L4 zC)&H-aM6Je{~jl)zkD^_TKk_xlK#`}?LyJve3p`cMe6P;Z&XR}U->)H}=6cW1FQ;!#thi?8!?tSj@&f6Tj~EF&fnj%^ZjY>d}x%esI6r4?&@0Os@83Ge?MOitoZWt!JE_17rPtH5!=!1 zX`IB>rg}JKwqI<))!*g5i*LVJCVijt!^Ewx-yY80fBU%kzjx+xv$_^slBw`IeDSz* z`ZQ+$;vZ=DGBMtm&$~p9fnk3U{v}t*xry130}%cO-?7-V|8w|@6QMUZOZrT@`~98l z_Q_Q`6Lhw61~`=67hPB**Uu(mv+caRL9x#N->>sLx22qBe)H~jd3fpMRSes%WNrQB zy*BJTcUjq{|Mt=HE@v)J%9lM?5!Jc#!BM{3XBYpNmA{uWE_Y8tb>u#+BUek0-rH04 z_v^LU;rVf!KWCq_`()&Ov*-RNmDA!EW`^2C<>Z{{&N+CfATGT0;Nc0KuJc4iyDyon zUgVXMx$+jv~1Pl`oOJ92%Z$8p_;%@(H_*%iubgfB@X zhQu%)V@;TIr|2tBVAKDHqU#?lt>F-!^D(n_Y2cL`x|7~yISV(|F@!R)M2H*er+&6s zwT?Gw?t%Hc&hPPi%vGTKwYll_{Y}pzD`UfzF4l)SY~8JNYWDtc%L`LnRju#e5GXE_ zoAdwc6NNj!|0TR{KfL(6wKR`i^Ay|Vm9ugys@Zb z+8E#N6p_%=xA-H^u+1SOhRG!=_{p=ZeulT7Ex)+u-M-N=d4-PZB#sOA{1cedpO?=2 zFmcXRrP)_G`6ups%IEWk+2A7Uha0MUr)r0%L~d>FaX-IEsm$!GShr3oqtV5Trw8Ak zp5XM7l~bqmlUKv+^$}+2qBhC`N4Obp?>&2DP0IC)xsuW zLS%RT2MxAE=_v#L8e`R5GX zQ`(QV2;Q!GeQCuc=MT)A0>oFY?zR7ZYxx^FMs`h|pUf9nuDFIR-z;0kuWVbP%siKM zg_W!991BI43kxz^)D#!x__sZpD9YV$UsJ{J1=_ zRQG7;CAmLMGaZvWMO-x3DlLsM`e4UmV0&=|&#u>N7)r%4WN6{O7oB9(-mAG``j;0!?!;WXpY3}4+_6Qk?4o)C|3{p@ zm1XI@cTd7{nW=W>1t|vYG$Twlk)GLNnarO$f;%FA)bjUdk(D4 zxjR+%ndCX{8O^h;zxUl$a;T+-a$6in<5%5 zUzls78C;&YW&F@%I;M0hL42~s`-5Ma^*U6Ho5BSc`(GNKPG6Wdai=KGR^G)d66NdnnEsriGcU;u(_$*V;P1x)@sfT)1Iu?3CxvlX4v~gxi^@5wf%0!6TePAZ9C|^d$VMBnz7={ z%MauvHa@6d&nj^ENk>{$M{o1oc}*M>P9J)xpqsdx(?~8<<;4{Ni*f!_pYt!=oAku%>weEar_&Z`m?xGqUU8UyCxWHvW}d54#?6NhjM$bN?>lDx%p>SR zp#K!p$kxiaD%vlZ%%Q}JKoOrGPaiTB++d9N`4y639>V1lCzV$+qL9W0;EXaB}}g|+C8%NrK4?mH?mS2yOtja5CSvfLYjtWp?1%?=Z;QmmJs z$9Jl*14CZ&W)<9fbc|GrkDRIQiaXTFqL~J!bD7_qy>J+F#kG333dJdtdCBe(E$|Y%)XmWW%auIns^? z`#Q8U9&BdhPDypxXc6dk`BHq}3B&Apbthf2X7N8+7r<7!)htTta_9l;Mb77~; z!eHilz+>O`t^2d&pXqv_NB{G~j&VEDV z_S)FGb+tZXZ{+95$h?)8dHc7NLHPKOgRzQQ@1%9ypG%%lo7Hf5)#E*Zl5P_J{vG62 z(f{4VBxCdSXvf~v^-FerQ~L1Pw)nZmP3|uNeX|WS<4^T*T|1b&VERUjOVLyP?sJ3` zSg#GMn>}4T?m{QOL_)mZmXh+hU&ZR(8x9|Nedu--e_r>FmW{W>?`F=smZ|=xNB%Ite0MI*p|C`PRIR2GOHgm*i3Z^byjDxZF+Z=^<_`krFV-i-I!6P-es}j zJ%ey|cbjID+TrquiucF+g+uE7A7ryS9q_}wP&+vk^{@6{P zvJ{JU_WXi=lka`@bKlqay`OlAe}3?v@`9=^{|T?Y9NB#3z1&Tw1%6Z3^&IT%s!3zd z>u9KdAsBFT)i(n!`vq=q!_>kr^UE7%r7PY2a?bOwFq>2MG;zswJBy@*rvGhPoA`W= zhwmz1;TP}vMH@AW8Fd1bw0ayXtmXdw@chOoZ`GG|CV9oI%NHUQ^A6U1IK{KyJSF1E zlXt8v7sB_&o-96G?46@oc3dug!|PS2PS1V&Ry$!*RoBL2xu+TxS~cqLils(=F8b}C z|L@OP0WH?>9U}M6ov;6xqrR#6luc(sScS@!7Rl39TFtqdj5&LAfBw0&wMil;+adDJ ziaqR$lB+!$4QCs9xo!>GC%q?b%RZsD4IN#I3~Xm|$_ymeU!BEp=ewQU99j9+_k8`| z4qtx!xVWg)_y3(XnJboVL4VVmrl0$AGyZ%5N5ea&{#OEf0_;A&Rb;<4OEB(n>(*w6 z<{fX|_SNyuonV#zu>J7n&w9N-&P-gEusgitz4(#uOjCE|e~Pef?kh>^zH@iE^=xnV zDJLC#-sdvt|L4A)R>?4%$;yCZ^_la`Hwxp^TX&j0V|e?jq@DMbh^=z*ibRQLt0LE5 zTPK~`Ub2Vj`KLGY-qo%TJKo_c>8X-(NZ9b`1?E3Le)ax(YQH~lzs}RepQP@Hbot*n z?d~_(C+y|COIwl`XlLg}T)-ZFlWms99>#|MC9G?tm;8Cssig7r{iCZ( zc{|cf7XClp{CU=l`YmU9yrRQqY+S4REl|#Em5G$9!Usm>IJRd;e46jEEB|GmX_QjO z;p5%9oWaqBB`@K1lk|=YcjjM`7e4mprH2a7Et?s4mS3q|*#G?h?js@xB>Hz7zl{7- zJ~>BB#g+G-!i(~HL0#{U{C1g}>oQJz>8C&0w0J^*!eYxWSKB{aOSDEKS3ZU{6@+F=KIH= zXJt#zI$gXhNyb6Yj+t@(J;@yhKTlgKVXXY(a^>Q0P1a|Og?`!`j}b1dXj|RB-;Ddl z=Q8hax_n>C*3{)q7BH>9Ia_>=!dXwH{nPIJ$P{_n%2OP?y9a_NUwXwPk-!#*4D9XyN&`%P{rHGF5-?#$y}z%d<4>cslDwM8-;i z#dZ9@r~H85qOu?drX;i=kFE$7k(9rPiD|- zeK_aIhma-ghAsPF#+L}bTy;5Jx%u~_XA4!*Ph7t3Zg$wIa>}b3Z#mImh9mLwPQ|+FcJRce@Row!<@4hg= zs~ttv`E(N7&#vM9;ywAze$K@!_wAoy{^7Gt?3ddw7alL2keqh@qGPl1v6SaC&T=2% zOn$!iPN34;<@`WPWA%mQSf})%)a19LN z-cFl$%izKKS0Vep=-4VHcj~s}s-6FER{cnDZT3|5n$DB2^!!TwG7?tjJmLSc?fBdf zrtHgqX2(QH7=M3RXRcW@e?p4jf;)G9Eu5^eQ_YB3DE!pzTZdTh2hFJNSX1fCV!7z- zvD2@(@*RFG_*ap*<3!r4r~cP%-j)lh7D&pmo+)w4P&BaR437KywPR9%iNjODtnRMU zr(=o&_Dtls5I#k8_4`1UH$9VhR9>ua&Tk55oAFKL(EUG;|Mu@*&OclE6`%I(gGSFe z6>cq=Ju74T$)(R`etIr)GWtQO>7K@fJF9;=e@vJZxyYR}d!F|l+cytp?!KQFXGf3j`oj6a zdE2-CGJ83nC8{yAvkMt>KRP_iNm970a-p;)vTOhB$TsHY{}lyQWfe6hJKsli9S^)| z{jcJY+tVb@eXTFE%w#Hla=0;kdsFlMPr>=7>Y68}fufR6!m^A1yqmjSEJ5G=Xx&}k zd)tDNuYHmBn^~E&;os5ArLn(mn*U$3(==-RjqSz1lRmGX5r5f#p`*OZN$$x_zt>L* z-K@57nYuvsrmQzrA}?4=d6eptpL~qoeq!~Z_jv~MD-Iu)J23NzlIX%c6PD#$$9#GG zG6M+cn?yQF<5*|#bdsQv8AaS*Y zgyg!~;@JyJub=T^&aO5668@y>!_3nEHwsVkPk+Cv%`+%b^r_6rE`v$3K}p`S0&n%& z4<$bdxKP${)@b9V2R`w6+IQ-@pS5iLZDpuu#AkNMptJAcn>Q=sZI19SVD{qT_$Rp{ zciQ{6Z%%wzVa<^A^3C_HI&KMpuQs!rJ>2}C z1K}S_qu;V^oREEX*@pXVbLIRB9N$Tss$PzterKO3Z%$Jvd)0O8UM;)nwYk2II}LZo z9xr0dkrg|a!M*X`+4X6*30lfMSq6^;@=Kq2>D|vg|L}Ft685f$FMQKjJKn$E>2q4|~p^yZC*R)y$K(rz=fmH?QgJoK#d=A}Dk6by|R9o5yeW(jPzNP84@PU6t}u zE_0H=85{40k`r=Sc103%&L=$h_%BKGy}o&MC!emK{GGY>Q^n+)_zu6`+0E*gXcm^( z!F76mgP-0ej`Qce6KVw{ULHPp_=;|!$1=^Q4_^hC@EF9N{K@8UWeZDeB!lK>mm`b3 z!qWCMcZr^v+tBDSMN{#!dQ{QkR%KkRCGxwVm9iGhX z-s*Vi%{ors#a=5zPj-jZuV8rBe)zp#xj#SuIhknAznRT(44u-JJCDVjJyW{VBlB9o zC12CjwO(SU*Sb3AH->Mlu62--abJ@*C zOJ1*G_oxR$pRMku>{f42-r~8T$WZ@<)Vtn2Yr9z6Pwfy0p0JNk zVx~}t_@<@>dKODqK4>>Dmp;dPL-KiS^^UJ|mi)Be|L^nsYhV2rWg6%g*oWT>iIht@ zdev-#v8Z8wU0!Cw`u&xr9NjOx?xr@KHueAXmgVz=Rk>GM7988As@}eZlj#AgkMOgK zSlvnD5vLx6eXu_EN3CX7y3*QNpK|6XJz0G3(0a>7$NX*fb4`6z{?l~VzXkh*?~15= z`ThMM#~r0LN-Z7N`QF)Py?SesaOLXl)*tNi4<_$in-zD`w}eSwpr3s^^Xi#5D<9q5 zvHDffnnS4yr;pF7y8UZWKjm^?w$)g)-v7kz_i-EUTChn5ZvDxVJpbs1 z-5pzaPOeIjh}7KbS8`yIX8p-k$!{;dR9f7b)?;H}lolDgmDyrJVvgvW?Pd$>gR{SG zuRF2&e1Po2fY~7?aS1zSn8d6#UDVrmZ$+bQ=9+fx4{c9mI`&#V<}1#B{h^LCdV(9b z*492p%aDWnHS{jdNuGSb^7>u}Ym>;-tJp|tufFraMhHSlb=t7^nd%iVESRN z|NGs`ioU*OtNZY|N%qdF;;Ym2dd=7BACgba6}2ime)7aQBdurG`%kaw-Lh8mpyTR| z$#Lx=(ec@{`?5>^3)J|{RiEG2zg)!q{^ayk&u%cqy6!!>l*3?Ba`4ZZ**m&V9F&c; zO}`+&*ky}#dO)*;(7Smj%~(0+{*Jk@N>%Pml;K)q1;@jSHhg-val@;OEyvzo3hfeU z5C7W4Res>p)azT)ml*Z0-FH5ua?O`xJLY8USnsxy`{d?NkLsVtE>^N~opVB{fA*^Q z+*b)VPp=TTbjV)))sjW?4kxDniIC1Yo0t2Ssg*x(=Z1$OPaO67b{|?G(VJpxwwhTr z_Fyqjmx<^^wj{4+xr2|LlrBXl8Kk~{CqGYL{KwDwiM&!j1b;?&e>eQy`lwm{sHSt^ zF2?o)t3t1Nhb}R#z7y2Fb=ohyV7Q9?LG0PdFIG)vY6@MR z6}qKgy=I};QnRhxo>3uRon|icJ*eG&EX+Lkqu17|3^9pUuL>4#{d?|3idOmJ+Rqgx zC9gle^qX|sGHAt#b>GeEn)kNfRsMNn*Mt|Je(&zypQoI_Y-IcYTIMn{-`=@q?#nd4 z6ep!FH0KR*T0Bwal1TcIFUNLjsiubf{rJnF>1gksOYIN07Bxld{PALbu)<*XLi^s? zw~bskzRXUDOH#C5de7wDuWWXM=mmT8Qv8qU99({iD@fDJ_+f}x!jy8Q^`#q6o&6>@ zYqHU~CCb4|{C+C!o;uqt^aGDt}2Lz-URU^r8FStXY9mPFv%H?}?2CjU(2I$3kfQ*E@u&mO3e z)P3PCv_VEUuhgeJ);;9gnM)^*Ri`D_)b+X;^YzAW_}p{xs)LnCU@$xT`HaR)b;(p+ zlVkzCPk;2E?)chtE?I=HXX}bz=U2Qxpd{IFD{0@S6Pm~6Px+nv-Kp-{#v1uof#XK| z-NoPMm))12^KjLcBGq-))ap&t?dEcXVU8j^=tUP#cg{@EGj;E>WVY%X8uWs!- zYZs zlv2i%B2TaYj&q!%X7c5%Wik*9EXIn_x)tQ-)r{Xp0A*raNS`0j&E;v&E@W6 z`IPE=icL#2e9o4m*}p?MCv4l0u;HlSfwhO@?^aiCG)dq;Kq= zo0EGn#?+O!Jv7}dA~X10LCZY1VlMBeddH(0OcvbR(kr<*dr@-Fsn}m$ksBXg`up?j zRGS-8IgjqKpY)q?(~4*IK4zwQcEToSRGIiSkF2_Wc*gGEW|ujiinqVnvCrk?6z*>2 zE!isDt?ve%ZC?3j?;ejoclc7SO%*qBS-x-DnTdZI*UPBtXT$|&=KpEaDtaj_`M~AR zyPnrCwi&K{aqYo(AJ#YOdhtsng^lGN25LlQUEk@oYf>NkGrJe>t(}C|*4@`C%!;^K zo4xDSFK!E`qLY(D>l@=1tYn`acgNvzI`hj;cDiz+BJXuWYp|5` z*7GlX?7a`h3vo0U^}Vxrn}m5XJX0uQq>K4Ttf5sx_?9kai(gm_Lglr6suWj z6!_5Ude@^>$9|UYk6e=Z&??;d(V;VquLaXz%A^)qwJy45a%gwv%th6j>J_0bm+u8` zZRuox<;K^#Z*5Q6{OMC8%j4>|cwMagxqaHTO-qU*#6$#Em#*Hzw%YZvSj=+q#4oX3 z3y;m8p?ucl%C}Rdtjd9>KFA5p5cqz5(%$Zj@a>;ZOkcvY(olKpnGIWeS@X~2cz1lg zzvMzx*FSM~PyIuGpXypa6F>KNUHr{U3zsi7IIDScje_8w46ao3(p$UlUs_PH?00IB zuBhSBnMxZ=F5UR6)m=LI=hi&e@7EeGrarD`L>wvtx`I*ucle{>lIX<4fD-^Y$mYxbvTb1`^^<=mc3kRI$_buNjn^`-4yw_kXu@rE zCP}&euWtXfDW!6=qyJUK#v?zg^3&vM+5G#j?>}$%iKF${&DfqpA6gdAIvjd%k?uLY zKgG{^m?GbZ`fq2`JGcLLom+if%T=+&&M2;qkF3U#PoD6wMZUA>oMhRO7&I#=QG)3_ z_evfE#U+Vt-V0@y|C}~O$tWmo*WZM1tm2vmysOnF>`#=sEpa_!!2+wre}&G59lN#o z51X>En~{D++o|T|d(CFZ>&!L?JXaPwC&5!+d9qbVwzJ5ah^}3hI%SzEu7@sv`%^fb z?P`1AoEAZit@*sOuN$oQR{OxY=FipV$7dV-_^P&Je|5we*#*nLwJCph{=v!>(sQor znq8Opx+N=qI?`-GogmPPjD{=CZ*!A{G9&NGy8f>E2uYOr8?1;;mjOyWMAIx8mT zc!70kNq!Gk!Nox92X~Jx+q&s_wt3P?pCFz^T`xAS*PZ$IxkKA|uGxi`JUikIQY}ua zsaIDgMcdBa^U}puOD@G{iE8fOrwgTnpXbiGdZk`adFPIuJ*RoLa;r34+c5KV;M}j@ zOVjhMUwyl6I$v0KVQR*M-}5~zCpqNLI9Y41uWq?g{GW>Ed(CYt7sbb}pJle$X;*@a z{({S1-*!ctct4!@V8SI=$;(o1k!r`ok8jcYeYli@j#8BPgzqhjXF|Iff_RDJj7 zxf?;=N{y3$MLj%w!As`tb?)?rddZNcREJe-Bs~AMY zIV`W5`*zur$efwiQUg!^Qc-Z{e^(cIN#1K}<%fc;GkzUDRCMbx@1;+tFWq}%w6R>T zS@-Ve&1d3X#-47>^|0);-nH}OIY~wVnrqMsx=qd6~*tgJakE(79yJ? z`Y+=B{eV|qh4Lzyb>@yNQ?``6D*xEN=~i29amDV0x92qfY<|M^I4dbHa#>-@qR!G) z*QC~jbh1aTIC^i*onQMMn6IzCV6=9_M3<>kChc(iSAAa5)pN>| zH!cT!QYPA5e}AXKXcn)@)StvmVLy3! zch?+UKl?N1#nP8QdDb_v-cXfmQ!>Afa4KKB=g|zi*>9Jg@RWJ~detP4L75>T~lSyH{f#w(&T{kMERpX%;Kmf0&@ExD$A zT&p^>kd=#ZZZ@NPlI!<1|K-w^d~fQhtU6O68a#8=1RH~u4Zd?a_AHsyYj?y_mv364 zrmI%wI-SF|`elaMBAv5Cci+rA)%bQz<@7WALfa>aYcA}%V{+}{t(@$6Z*NWRt=lYl zfAZ`X&t88`t@-!!)1T+_*VV20uglh7Un1l9g(sUMCj~C;_*tjyaz6dvjoyPr%PjX*e}5MTCcXl@cO-Kf0v(lmw6W&TW@ew*um=yvp` zeTC8O@I$f#S?`_Nr!NeU-h!`**r|DI_?MifYPykI_H z@GEpV_pG(~i>_Uk-lP=1DBcHgj(1 z$G8&~6PfPpQJSA|ZGleT!w`NM?Eu3=TMipP^L}6d`sknc(tq@C?fK5MSTCTZcu&J0 z(cfLEzb8mcZ3ywGs!Z_Q6UX)8kXlf{3+{OtpIbis+h~#FH0h$!+RUmeMh7>2owmwb z?XN;stHkp3`^FP(+`FqAm8VTz{CMXkeOaZz^&D53zWrDpYoQqLy7u8;58pQ&2KN>} z5jEDh{PWl?;ScK!r#f5>)GK7(Jaw(aK0&P}j&HVm+1Os2vCYj8s1CTg%anOV+08@& zbFGq=Yu&!{CtYWreLZzEXOW)P*=<{kYmBq~J-@Xd4bgd-Tzz0g`bQb5^WUCI%02PY z?*1J!vr4*gmu|4&p`9LUec7*A`SCD4Fs*uh&Ld;%HkIh$SF5rWuB8iEW$}F$da;{> zO(2`=oY&^U={vf73$rSmc$;5k?A#_({bspg(o3HoTb|xi>pdr}g-hZL)I3|XfyA-ZMT`H$e<;* zRK4t2Nmn4}T$!?vP50d=>gum}vP)Cxx_rJ}vaM`Jwv^6+1&Ui!xvV?9CLf+U#eTyz zm5v{?yxVrhxYn+`RjwkC&2)OZHW%AxL%Ft_oL{wETYXhZZY>biGPzmzyKm#|AB|F1 zmXzomv+S{!*}3DS)f~IqYrhv&R;)R;{>wb&?nY?_-&F-B-6e-Uuv>p*Jnp0)zI(^@ zyf|JD2d*QGY-!>OPx7X>8$L8rS>(2%?C_-ZFZZdxPW*e5<@M8>#}p5K+2Hoa|H6)# z&R4>x>NS@(@I9V&a*npmYWteiK?&21UL|$bY=7l`t%EJ+dXm-Kn;GJE>Njk2e77H% z7ZDU*GCT3o!7|ZXzHJfgMHlqmvs_-uVI^lPxwH5EiI(*d>-EKE8C7el0E?H??@Sg9>l!GJk&yNKXw?+cL-8^Td{S8He65c<$AmW3kdf zS%+=QnX)-)CzRK}vzpzWR@L~Y<*v-ny=^M2d*kNvXB}^l`=ZJ|_g2oYLxqbxKkeyS zmLzB*8@<-@(d@b-zP@K~Zd2&Fc=M}J@O18s+w11}9D2;crq!_GoaQRQV`t8^ZMe#p z+m=_7_OdX@TCu-e=9T7zmV?>xvpY98s7!r*prQZLjIRuDx1D~J*(FmYTwRoU`mo-t zu0WIbCC(}H)n@iuDOuc^I`!+zG$U4?p6oZT{yNNyxAFN^aIL(9MffJi{5;_><;O(} zo>tXZ?dp@0Et9x=Y~9I%>NAe~<{DG{UcdaJu*`8zWzqQYW-ukq&^ItGSys^upzhY-5cEuaa_>`&YBN_ktee}e)HQPH5IlPeM z_|h&m`;hblCX?gI?%EzM-ZECTXPGWMs}A2^b#UW^H|Gs~nSMO3m?~j-Q#$ixaq$!D zpNkmd4cO$Xw*X*(z4G5)j(=U%&M_FR+0Y$mf32rlt=Bh%>D0o1J~1K9&(FEeeY=G< zD9nI^)otEZKmA?xwR!JN;}+fTO23fMG5y$*y^J@ccJAHyZFfmh?{5ZKyE4PHy(gu= zMORyw+*va1^}X5W=g)1{H*@;G@PnGY;mgITd}{p*)frazA3xo;qFB^Kw@mrtcSX;l zs`@W{S}IR#vsTF7HM*-Z(^=zS;jM4ye)KNMtzX~x_t@sORu-xU3^vW#RlQxjK>0UQ zP<551Oisso5DBT5VY!c(22rV zUwxf*-Dc(DB{_?H_jqsK8@0QO^?G*Pr%BHhmZ$uGrT0+P$T(I0`=V#NzfHZR{_y2o zg$uJQPB(t_+?6=};nV&1_IK&k)s=qSem%c_mcPWGp2^=<)uycX>5841wnwPyZfljn z!qDmS7xBlKMAqJ%BANcYL)2bZ?{K+G)f`=ySl#7oz9)o=+$=Kk+!Vo4c5%()Y1aEs z=NU|Y;S#JQSRqc%-owcnT5^& zV9O<&wTn-P+uZhAv(7|@2eWVQxYcE8@X5$GD}`xh)x`JH8E5}Ja8Jx~y3w)u zVL8vu0tC{JUN4m0UKFeFtl;$PjNp)qd^JjED_bu0tGLDgvvY`6QO^|9CH>BmCapdv!ZLMQCxfH=Yfv4r?}# z|MT}LcNu5Ze$UqvYE9Nhrydhc|DN0;>!d$J;!y(Q`acRLT2p3~Pg$|m%v9st*Y+@z z7QPzGTcWSk9@~oU_hhY&({p_AoxME%Xnpn$2cxTbYelZCs9af^v6@*`);U{E zj9!{0GD%Z7b6!COZ&yqG_UnabKb`kfx|4>dmXYF}9FC%|r>yzQ z;<@yH+AW*(*IIvh_6vOROo zvfdRpxgLG?5{V3MKAFoX+af5=&LVvLdH)v4Fq^pdH+|#oEUGN(kV?2Ly=2Gu`@H?Ub5zJ7FQQPeq4Ra&NW@}j+>sCEb`mj^He5`VNz_(VNT8+ z9@o}bMlTojFk3h2b;Z=e=q95LFC>1R-FeEF=Z@v$ouW%`^1sQsw_WQ%!-4a?QgynQ z_M~gfQ#!)^OF*QH!*{-Hvu6IDo3E?6e=x4Ond2;{#L*(OGCA>@_I`OwdB>%!3-0z` z6}n=uI_9qnmKD3CKBWjU@JHJw-Eh;8*vxohdhps)7q{GdAkE?T zV%3(SOSNn>SDCK<(DuIZdP3o@IbUu_^GRx$CmmV)`q{b#iU-~1C*O8UsdRmC#k)S@ zwEoi|NtOi7=B1zawTTKuAMJ9vvi#)6Z<`B`TVL;ceo9EWGwsd>CN3ZE6qYqt#kiIh z>qcr=U9rCYG{;TTZ)K=nv)Mg`7g7ypgW|ut8~x$PsG8B+$a%tt>6g|)my^P8He7oq zTgC80_?q(~_KWJ%J6#$x<(>AGEYvjabSt-VyP?5);$*-or;ka-#-$znRVz~bBv0A7 zH6(FMn9G&bc?O5xm}il5@AePAO+pLLxV<^8v{|%aa#`DwgYR;?7VeQ*;$=DAWJ1?s z{^pafZNxvW($bRmm~SLMyFqjE|Nk6Eg|_QPXl)Rbz54P9Yb3{6zUsi)1?kntIThy2 z->tNS}^MOV|1&+%scs@MA)nC9L}o%b?p8?T8#*R*Yu z`=WO#7jQj_GMXiFNG+y$w$-1=qHvR&XI{FRy*$>HE4L)1A?oXehYrkgOYU9ISNwCx zo_X3oyXaN7E>Ef#yY6sSZ<5~w&bZl8YE}OqeM;ZG{@{k0Njo3TED(46wVO54(e(-Y zn^TIMz7IDF_zSIAn-%#erc%9kh2JKnPGhaR3%3jZmTfV7A+e!3L)LBgyWc&Jb)2mh zmYgsZe^8+O?#1T<=}p(>{?YbVGU7@sUhug6^XAJR-kjoQS~KrmZldgkX0H{NS$`Th zCdRF?iQJg@d(lcBR<1=)pa18-zif+D&a$Fa4sIsb=PsEYHGQ4n`L}hKx4x(>Z~2t4 z$S%oz&UCMTx#vU`_L-J6D6Ew@9qlM=5E0_o+rqY9WLg7@fzZXQ-64KL6)pKw)?|mz z53^wO%$sH7xJmz!j`QuPFEf{G3Pkvcy$^dm<7#o&^RJI?ZhF37Q0%jZdd&u5;YD8A zk~2htR6i$Zumwy^ImlC`ctOWb?We=AvCd+fxXblJwf0-`^^=?2uuq-0-x2GY9*L12%^)w%AITKXh4;Kg(o} z$WOK;S6$=QlDfImSa;TBG%wn5+;^00oVaMw9K|Sm_rg<- z&1sx_cGkYwB>d%!YkrePgOI@_HPLPNe2*oIZkTrRM94Zm>kKi6nP)c1<<8{3AJie6 zU&^~fhVMvs>h>P%uwbWd6%%`dz3e=jwk!L;uUTI5(&4w3n(pV^ogvNb>r`YMJ^n3S zZkO<7;R?m&-M2*+mA{UhD6Z2k>F{h{SEI7=@z*If!V-#n?^8EiIkNF~#EF31>3pW^ zH>`e@cJ5|ye#HK}t^U=aE8m5c$Q=$oWOJ|ZX2aHEUQGw7l?^N(_Za(ptd9>|+Iscn zV}mfz#uX2kUH^9#9v^C#qlrtbAW zdq;lBSB{b?&tz7(EV7Srn;%#E zZ+3F4u6mym{EFvp=~KHa@@3r59CchaSWWGGWKy71oaJQyDS+s}=urdG*mmHgkt{+FR1yDz?crFSRH zHTYNhyLok~8An!5etc}V#;lyRS=v_f-i#+7>04tFh@e%)2B ziLs1-ZXRQrl-G2Y%dJHUnj7qGzt5^NuD)j}ax+s|wo7lJ&C!pHFA{WZ6LbTfH7qx| zQ+d%i^pB&DpqTsf8`Zzp)|T@4NF7*ik^Mtk#?D4)`5f(eb0#R5M>ak>&zHNkLQ=iQr+^!{x}E@_sN_DsulnBnKIw9)H98?W+YI>Uaq{e#nkxMGxRJBomm5D; zE;q>i;-Y9_R`9gbtfpzkt<6k}JJ_2tvripv?{Vh2=(t$&8}BqFtC03p=Pw>pIi=IO zOyf(_(LXnhUdVsH`F#5_yE2E%7O(cyJD-&~!Fwl`Ydv@3+4EPPs^*I9aJLQGK4*=z zU+(`^&+b~>WE2W==|3L5*V;wXw|at%Y2XamH7jFwX zDLSR~%gchNm4BHIZquD5X1h)PvgSYDxDpk+3lhf-PIoWg@y5Wx<$K!;r+>$aweMUy z{jV+K^vX3hCXd|8j(*;dYU$}aRdRYF<4(aT!Zgtri#we+uYq=xu9pm6rs($fR zp z=`j!eDF5eP$Xok==ju;4@6xK3e$SfelyF?-LyWHGfh|jxru;s5*N>~VyKUF9X!#$m z{UxoOli8GS-TG?I#-S>E?(%o;pkHNy)6_EOzGeTU_3wt+rWe&)+Juc|q3GSccNYGGBA=svm!!c9rAr=|!)uhss5}l;R{fty$!SXkOy$#NFF+7EYVX@~ZLS#M8Tb zD^yOmKUuxt|K9s=nq%x#v>jP*?23MOu6p0h$XA-bOX~i7K3FaIdCxQUeBpWKN}_wB zHcd|z$^Uuq^Mjj@G_AEx)vB7^ZnLc~`*HZ-=k)XZH;+!+Y#b+U>HWj>d{n8d!G5d!BQD#rw_wKA*fkWBQRJaW;?7Zu2ag5OH|Rg{^WwIKk2PiIwD%_Y%@W?d=7z)VDX}c# z`{&GWanJYbySMl6hpL?kKQ7L$tkYekG+oVv>#O&*b0$rVtM=Z!;$5>!?#G+uT3X)o zUc6tvVa3|d+4DYY9h%&#QuR^w$mZ?G)hn47=_@>bE)%wE&FoX@*%eHEC#2`6~xE5Qg2=v zsRzt=lF2rHx2%unS*i9Wmg8G%S=Kj4E7d%&=w_VTrCi->V{led~SpD_1Ql z`gmruuYh=^aOWPmTMHuov+;Wv2NZn0l^Iv8mf&g{)2_jtAoPKq>CLTOiP?TJ6RSDj zW^G%Pw(^8UHkVkexKiRryK^owsShT9;)-&9>AI4cS!`~nSiaya-b4}Ms+Pzp`B6Fn zEH#ge7{V^e@|Nj)yywk#iZBzAov^EN%i~Kw4G#K-PN}HpK6}n3}~u(8p_%H>C^(3ldI=uNX=`Rd;9ysNpAC84iy|So41=k z=j)Ab@i!mV+x^}ytHw8JYuA>%9O>BN9nH^myo7cz%e{EHLqPO`!-Ck4*$4AAUa<-o z?P?Ow(sC?GkbcTJr=30e$EmOURTdeM1vi!`>XQ911Xrr6$hPih0g|VU$=9~N*14pEqV*y z_GWB*6E47CzKY>bmi+1;^-+NzpKLs&amzF_{<9HN$mg7VVV{lpy$4DHe1)Gqh%OZV z*8QMK>U6=TMAucC&f*rTeYa-)7SsKuIe}Ye(;ODgtfvR3cqwUwxbD80)Svjs`{6d% z*{aG(C!9BUEGas&^HHgKYnJFLGya_1l1c5YI_I`dk^fq@{>6c_ZJJwF{5&At>UJ3g-seP z$-3Nj|Ju1%USB!$c5RdTQ}**_jSfp!&*n&ca_Y{Pr*iok9IP!0-Y0cWca}*t=tMb9 z3(MaS{PZ99wSeY_Oz-}APq?^amwNCY+x7NGHdh_VIpx9qmd{$Q+k^iw%ijB6;|o`` ztDFy4FHwA5zR;j!*O^7N9tpfX8Y^QbRLgEyEzSPopI2Q#T=^rj&Ww*QK7aJyJZ(#M zl-0jKr`F_@u_m!+uRs5yIWl+0q94DSzKd-4{H3hB&(iMi#WkrnzxG|bxBq`p+O@K! z3zlyFygg0zx$m4MTYfZ}yB}Ykw$~x(jaStF4*&G$X@8%+?)3;@&93@#`TG1X;`N2g zxm3DJgo^Ioi&Q43b|Vn3a)K3vl`SMSyfeSgM$`Fln=<&0N%geF@{pPSsYI%%cEM)kID zlR2I2PPK&bDoAU&OicJ;o%_>O@Kx_hpG*ZygWg}k%NC}_tXN{38ZRWCVHv;^XzS?s z^|_eLLB-^fNxMAyf1EO$HS_9&2Uik)@y6BG{r(qm&H1!UtgKBh!{K=>k1y^tm$#4A zconku5ZeKUTYoj)TCLBBu*_(AQ#QAL>&{iGKZ zzB|^_KKrlZ9(vnEeoL4(yTW{@7kM`(j+=-L`Wt7b#8jdhuRa zzVk}XoNt+7F+2G#ovU$YsyZV%xl&@yag+V^3;(FTWRraroM(NwyK}iq4NIjthwx2l z{}Rq8M!g-v*OdIbmwpm{_WJwLG~usztl3P@6Af3wnc>vOJ<8-$T^Rhdy0xeA{N)Aw5-JvDU!OQw4b=*A_Uq0`$=2EY<$u_;Im*s9v=zpql{eZVc^pV2o!0%dy{WTN2 zxMnh(ys~!XF-Q3;d?C`xQr+`bv%m9o{j_*X-r}}AuB2DSPwtA?>OSR_*|^c#@bDp} z&f=-te6_NpBRWMafi_(FxVE~n0l zHCfo->HH>eo4dQC^Er(f@>dr{y_vt_*Jqcu{X85hpK^Bb*E<|dZ{9J3lUr8YN_hEW z-~0O#mdo6hyZqk9U~i=Dg`zKyo(NiP%#WR8XYoSU^xT|N31Qc3cGbMt)whmad5?$B zrWuhd^rMU(T{-Ukxg?csnz!7FZcZn;N>j_q!&|CC{^#G~$Jmb^9k0&1XdP9$upnHYl}Ma7CzWG z&1FSo^y%ppKKqYv%2@f`j4k%Wo7E=FT8i>E!$b1$>(-HR%Mqk-rQ3e zQ0V&A_i6O@b8(Z`gw6kjc&TmO`cD7&TDIekmevk7%afdQEcO<7 zYTtOYY{iqWg+BQKbFTXMGZicd*WpWBu|8ET>0(OtP2LZ?7OqxP4K!K%DdgPdz2@5I zB|5{{IvCOAxh&^{k4!>@MS{kx~%efz5-DzI97*1B@3 z3(b>XZM|u*%UZ|w{V(CGe@m{YR!xd-_A5HA%dgQ8n>9J`@t>?>74d%yjEtYlhrCQa zXIJ+ta$nfTrwi^MJr^_e#Z~E}H`jFCV4v4`ZhKXMu5gEy%ar>acVzeT1=OFq(0TDc zr@QFfSyv@r+gx+{F8Hf$=9O&qvXZtOquj%dRqmDkOr^68Y8S0$*>}-e|3%ZjzzefY zt9EPt&ug2-y7KkI&FS@Nd1o!Fe@#DpSbmq)>d8ME9VSWltX(pp-k`xPU4BDX+v#~P z9@V3EMyi)hRG2Eyzz|l>z#xaWGg78kQ28{ry7;l#r2qHlGd;hl6=W^+eClb{eHP_% zw~Y&rt?#y-d3INfO;?LfpJveU_T07C@BiH;&EKS;a@u(I-jKOj=E{>Dm@`bI_SZ2~ z9Xsdu{hyJQPx8F*nvw}0_V}r5>Tkbs&ZcX5%@?bRogaJNihXvS8Rwh*?bp-Q=E^_L ze}7YR>ZaiOt~siI+R~5KuuY9TyZGj@V@q_>ba>Q#?@qDdiL{z6o_cnXjsB|@e%*U+ z-I#EG-KL~9`^2aI3M=}WD|hv>&Q;e{nZe6v{#z}1{!=XQv*WT6OyK>@7M)k2<9^*B{o|J+t-3OoRRfi?r5etXO2eXHA25V$7Lm zfhXI)H5Z6I?N(e}5pwKuz`mCKuZ7s=FBSDs+ViZuRPt!4M5v&_RSU(Bsg>^^%*D=hU@=E=oNxYXwgeSWQdQ9Ja_mtS5b zr(Rrevr2q^@Mr$=-w)sU|K2Un*LOcZ*WkyNrYovNEU%5u{&cj{TvN2|z}xNpXC`gi z;MuhMGSd}@=zuj#1X?&snDrt<<({kE^nP5`%ym36B=pVm$IR7z_BEeMFE&aD*QL2$ zO4)O(DNw#CB(C8=%&Y0=Z|rW~FY`8kqknK;m+Qq(>;doF!q@0+NVZ9o&s+S7OJ()E zWuh6ai%tqndlnqGY^!6h+oWruw=-ACy-+H8n~?A4@o%xumyBfPhr&^tuZo1lG;NA; zd#bc%)=8DUpLy%@4bLZRHBXtms72H(=I*Oa}Q^Z z(LayPX>Q9sHK)?!?&9S(!AB>rXpwq%i92DJ#`^i8t?b3hE${wXu74HwpoQVrHW{x| z7IPI}tlGloy#LWnmKm&4Y23?`PlWkCH|><_;^4Z#I@O-P?9)+I-{*ylm)BUwn-<6Y zYIZPh?Jaqs-Q;ZRc{|Q#es%LSwl91Vyq7oXo@P_%*w@~_!2bQBHIKqxuIh0P*&6Wp zQ1!)-r`#2v9<5?yduYBQ)ke2#bm$06$Kt#9Tl|16VX?8!W#r^ha4I;VB{q$OV7FPS!5%N|XAnf-0D!huQew*KRA zKYzOIJNJpWHjPjXo#}s-B4@>~{+_nqN_FA+UFCP{EMC~$fA@Xg{k%{U)r6g@dzl#8 z7OdUo?l$X)K%W4MWLVRG{)c_$Rv&H@Pn+PU%DOUqwu|kSS8|DqOy`(Jq;F{Y*SCr1 zxM_~|qxrF$WW+99KC$*$QMv24mAk_?Y&E!=^Wv)|o6WULj@!ayw<%d~&nXiPZ76d% z@Sediq|P+L%+HZw`qJGEG8Q5M8X6VspJf&NI2IR%rud#c%xUwfn&rb{t4}){bWi69 zebM&(!4bvr=!P`U9oc~3@4vq`T)VMK@5Z6-poJ@*xmq69|FX&DapVLCvd=Ex5O-cP{(l-Z%QQb|_A3h;+33n3EW?ulGWJ$c7io zJcQeRs|hibm1I1)w4q@}LfGl8J7zR5yb-0*H)d-O?pfn1 zej&`cJ#cTrX0>^X9H%b)y>hJ!n`QvhYn{1E4W)8rmagl(IPu83OVS&15=-Wv%Gme4 zEW?OtO}L)))Uca-P8!{k-~BkecykEX5svFq7$?g%&s!209j~vH6tOwu;IWJ*uZo@> z--?-YL^)Iqv}&9_i&yebVEooq_AcGwh2{_G)B5dST;8sn5EmZB`SNU^UgMXt*YPY- zyDe^Ke0|NZ`|kFyiaWiTOd9q@Bz7cCt}QP88T|f};ffhL&0VW^Xt8`SkDGYu)J6Gb zBaTVZ?k^lyW-eT`Yqn|R+;hg^r7t5_MJT#DRwPVnQhk}i#1ioOAQQ{ctE=bkY0F#N z=G)1X^zLCP&&=m-s?1lPY`^|1d%A($b%8bftLHH+td>=?ThnmD-|=|fqtzGQzY<*# zxx7d9$*gU=@2H8_-ATKyl~pUX+E@SU#_3m-*>1?QT`eoTEzf;*lGsnBkkw1yz7BZ% z@ZoxQUFlmhTHkZU^K7|4}3rh%LGNV z*Gs)|bA1(&WctuHjcLiT^72p8?;;|delcg=`=oQYerXuD)!z$@x+y&uw>W<4L6n1U-RcNvQ^6SRV=zAZRXf*CE4H4R) z>Y^mSuks{AwcvM6jfPcn7vt`oIkv~79UJL{g*%8 z%8x5w{%*lHts8p{ZF&NPZ+dG#YtQ|r_JhxtZ|BU-cb}g>`GH}{@q3ON%@2M*vLnA~ zx@-!+YN}<|xdTQ_Yyz(ieDDok*w7JVy`24^_={HeHAgBV?=0c;cM2C+`#NLEC)NM+ z)pXB(s*1MN6h5GEQu6v#+4VKIy;O}l*cY2HXXRA>UN(2tH;wDtHg2qH;p$s_p)->& zf6dSYR`;eORbUYmJE7ry0I@6)*UOOZ&=Rv-}J)E;4;gEzj>v1pO|Q583)`j zd$vf?`=`BAMr72%WU-w7X$QFlT(qm5zWAj3R@g7H`*H8y3)k=32_fh5opYsT##V-e z2YyxZ?s+A~e8!+ryEJL-#B8P29o;t@Vzp$%!+ldrG9`QMXRP*2Xh~(3FluGq;-qvY z`_EmobxiN4NU=B_SR_?pw_bBUgLzR_W60jdnO~;qn$Nk`d7wDXE#WxZ+8b}pRA*Ie z(0x$nJ=-uH|?d{u6=>dH!7W*X|NQ>RlH#>ELh3(^k z|DUZLY8yTtJhQ;}?k34&G2eA3uC%=JN5fe|$bIT5euw3u38habcRbGD=s)L=*#hGm zFFrhY`|{jR|7b@6j~LFJGYxeoZ>4BC$dvs_EiO56Yt?LLk#*7U8aZ{#&T6D@ex)Y1 zH!yEH*S@D4{Ia_xd|A$1dB%NHc0u@pz`EICQ^XtBCK^9$*&f{ddZ+wM=L!b@iH0hk z+madO*jkvhTN?J6pW4&t5+2T|!}(J}SVYE-{pvC%y$H?4oPtw!UDG;hQq8M%Z}*Gl zX`$UR(-dDgUHBF#%Q|bS__wA#dlXtOn!A;TYkpP#xKQM+IMa_7qnABmap@wt->ViE zMxNm7+j4b@=gLzvxEyji6@I^94akmv@**d&cqkGJd@K796Pw`=U0y{uO@2x#%Hd0n;o@x9;as_^E)MDuM92eNl`QA zNE8<>NSxWzekddVs@f#+XKe{$s$c$`HmlAw*vPc^%+#0_YIg+!e;)jDdsj?}IxnNC zH&@)#I9{%W$4u+JwI|BlX^3S;AoOki}${nt143?=j7b>>c zF0yT9>X^ZFeKw0`<7rDpmco{&9LHatt8VU|{x(T`PCEOBsrTPbPYsMZn{qUC!iU1* ztA-mR+V_drgnU=n>~Tc;OXQy=7LA;iM?NWvYP<1r`|GWom*Cf;IrmZ@qik-0-^mbn zzV>{3Ihl8@UrOJbUkJ{*bLEPF*v5>&m4}-j^QTq5VVP#WV(#B9pHJHf*j7{@tGUIc z>vUGeM7ck$>g*JmEgyM=-)5Ybz7TcNcdZJ~XC2qlgurMK-tJ=(?X$QFy|`AExCu$I z?65PO;pW}9f!pn>!F~ROzPr1Vm`7$ z3C{CN&lWbj-(C9m%&NLRxzY#$8QXUXg&IF@R3DL9p>gGxTv@4{s_mmS`?t7S&Lu|M_WWnS2d#I<_^ z*EqW?mCaXkTaw^EO>d3+<)GgZd)^C)haF2^CEB&-lB(|Za~k*MX2cg6JejQKcRX|2 zweGl!l6f45g4(ofK7N#NnDD56cVF$rUlV*6d^GgBHvhejRz ziafj2!Ng5(ClyS}3thOCbHTOhoA;U*Pn){urrJx(t-B5c)~>a4Nj;ueAG53?@uhH8 z)v-VJ$6bp}{~Al#lm;67e12e&=j;8`Jg+xQa#X+0SiM?FTw7#D!Gg_NzB^ne`>Q#m zcC^VkbnNW-;k}!CE8B`F(=3N`FL`ftu00ei=(c-4*ThFzO4aO^ZnJd``z{DLwlJV0 z$%d&avgilP*OaBRE*!CSv|qb@-JR^LyDxvI}QbIoM$$*C2eyd65VPB~ueW@Ra|$o_spZr?<^IK_2I zoKX`sEggk!@CdHkdTqDO!wanTA}i;+nID><#K7@|dqzT(t}my|F2_F#3w>U1pX(t1 z!St!RXyZw1;b~G$k2fgK(@;C@dQ@?%|AguD&a7y!75;PcQ)Q&B_=`-XjH}lpCcQsV zC}eoFG*ithpi4<;gMZ6Gh9i@Tr1f>Omds3%lQ_lMz@XQcx{`yj$*|S0<+Gcr=*=Y; zBvf;{m27@7w){GNV13vA%O5B0SC70FS{dKksq@sb-S2SD$=Jx|85j4yY^wWUwbg6g zsp&C4^Z$6hyjy<4wnH&xro^!a{%LQx?N11WyjI*K@PUC#FfFNjpLL9f!jnxe8!j~Y zZ!GyGucZeusUs&V1N^C$Zz@l9~Dnp3c`=*!Yen}l6H ztklxzo3YZ!;zF4BwxxHnM1FIMXx@)MPPM288ea-Q3{be+t{)YR+;Irh_KrAj`}PC4lwG-u6*t%sSHD({cx z5q?x4ZRV$5^7{LpD;f*VrO4T=coThm>h-h!|4;2H2|7RH$tQm9M&YgX5mTZs=Ox?T zHeoCNbS7qvOuz}=>pwr-^)%_+aaf*lXJy!fg{B@1bJm=F_wZNF>c+go?BC^P%1K03 zGSmi{CSNJsbz?#LlO~QOfz$r=8XH_=%(&~4+9mB}-gM1gPd?(&WqX_V)g^iNq$fB? zu1xo?cG#p9bW+WGx6)p(1!~tloG*&1EIC-eOZGs^^y3;g&XoN)Hi0X$an|40bNZMM z1vtJ{)qe5XtmIkXn+v;L_-6exYMS!?a{1xIYo2a6^Q*e8UD_g-GdDnP@8;ZFcDp^5 z4Ocq*+*7tc*rQh(Q0?`!Axlox+S&D!WkTK*DfXY=VWuEtGBPDT;6?NZjbM5?L3)x3(udq ze0#B>nH!VRk;n`Vg~Ej8wk$zeY`yK~F3ccYo zaY)c0WY(!_?PoDTPFg-O51SSmyyCpEsid;+h){`@OGN0}<%-LGH!YD5Nq$f_ZT{@~ z-%NcT{!@L_F4wX2ynnpmNvFxKNgl@9*UL3KdV&`mZnPKGZ?$G<7drIpMfGy)-STDk z-nX+K-`y_%{oCQa&GF}Y<}rR<9&qz^eR)AmL0v&nj*y_D=aYzO$1;68mtFXs#rMTc zbkdP8^U5}}ZFatuFF4Enz$K+-PY0i{nM{qRB&{_{ip#B1kAIZku)WpsUGxNn=Ukj6i7D?Bx&kL>IGulIb!=|r<096LS6?<~FXP=Mc4pSj{Qc4A zr03cSK5|lzzjN%I@wbV3<(;!v>7_Zpoc^{HQCwx4;W!Zb@;gk53Mjn!$7n&&Ah zuQ{L4oPGD(M!yA{7VJ4#%s(}4J!jCCC*L&wdfcjfylth)_MoS-m8&mK$j!^QleexZ z+LWw+UGd{#FQN4@%yN5;n)FVjh8#DDPq_A4f^p4LKK1u(Z%>uY+u1Pp=tbvlwx`ec zneZ>tys=2jDSXY@7vJA1#_qfJK5e}}^XDk-%t+Bk0-Z-(@|(i%Kg?nXRXwEOtkt;4 zU!CW&%rAM>Z?mTE+pM~nWyxXj+rKVZJ7^V41at8JT_>WY{YTQ;`Rl!R8+Pbx&5nJ4 zVMbw7n_a{5Ewhrur#fYbiso)DVq|Je?LIHXm!nwS64&?bykFnp_;3GTKW1c$?f3g; zC--iCt~6iL`}@Azdpg}>%3Vud&YSb-*skIoYO#kef3(Qm+9>~CMpyBTkbbT>zg+&q z>wn|V35eTV%J%-b)^UbHa{H^3yUXVphrF6A^VrJ7eA&(?fh(LtYL|bjEVy^ZSkETx z#l?MlWTfW33VrHxvv7}@>&b~{xn(owzI?)7u6SMInai95RWd7mZ4R0|y8rW>{`>Fe z&pS;Q4ztuTd8_}ygZuqP2ZeAO{?bh z$A7Kd+P*E1tUm2bnS8uT>(91j1{{_g=lxqE?r{HF=JJ5i(Diz!`j=?qwO;##pM0sj z7{B<@*-|DYxA@cx?n z%Vsvi?!3}3z9+sc-YucwRyy&8>up_?oAZrqXV!7$GR<%`e`4gwx`T5sES-4 zU$`{mwet1wMeoiyM!r{CUS9t6w&>Pp#qN7A2ge47&z-qkX4mr|Yw;kd3$G8%=8X1x z($W#4x#z`>Cko%K*xv|0Q+yGuSr{2IHHJGaY{j0SEm{|Py^h_QmxUt;)5q9{N!uny?du2R@TJL-#2LTkEqsCOCfDzV zB`bA;DlT<<$cP6?c1$VFbPso49nmQM<%sLicLto_U3=zE5u5GvYQ}`w#xJfhzrU2UoGq`Ra_IG|>U!7u)kmJ4n3{g-{Ey}bSNh|=H!V=y9GN_;_rks2 zB9)w~x3YqLr>D*@cz@GMy7}|3XH%u$KeyTH`oN|`c>~j)e|n3fjgKxE# zn51{VTC(Q1RmICrVVn4M-wj2+Tkh&C(K)y0Lc-j~h1;CB6f;+4?~b&2v75nFe+}pH z^o^yPKUJlF>$vsQ=woK*>UK8ny9c9W-vt)_ImfGU>89WGXvy3AHmuVy&FG9&-Bhxn z<;nlO-+!jHU6#6g?VfWzO5dJSezL|$%?jKO|TEtrGFMGFg1T*Z)3i z=7U#fbuG;ZTX9gQ(6-}?+~3zyjyIp|+q1)Wo>l!q&(1kdJ*T7z2mF7eU(&z$I>Uro zVZTL@vvl?57tG8KRd)@}mzK4#wYXdUTl7RflkFS1rr3E?)W7t6|9oz}^+SJk_un)A z=}vxoY|bLyqrA&|JSJA^9P(teK3n1PPvX=0Z5MYeSU;w z#VLK|`Cpd(KQ{J#`NE+an`U8~FJDugn6!}yA;mu?z~;CeI?bo;wIy+ z&9O`WM!K6@a5k;Icy`L=KSFcvzft|Y=vK&*s>GCu@4PkT)YF|c+>Mxa@%Wn<`}}{D zQTXyq)vgPZJ(t&R__@_8baPDa#TJGny|^vYf0l-Bl>BbuS1NnwdxzbP7pZ?&UD%T? zCATLp>Sz$l#wXuZem!~d}p*SsrvP1QSblppGAKq%wD<8x#`}&k`X>&)&1jUpcXjK=U)dnXo^T&*>@&^M)SpVnE!$+MXLF}Y2NdC+X7b=-*ei@#Jm z-^M*wVn6Rs`qus5YysOn?R(AMZuPe&J*k^(T2kD6Xrt1eXQ8`pcU*k2ZLx}H@5F7o z6Ivg<>58_w(#EU3YG?6smrIp9pPk#|`)y)w+|}mm`Ek2n?L4a&>bs}(>grj0B5p~| zs0o}Iwyx^d;dkpa<9BC0+Y=WUxTo~0v&GIui)!9J@jd>1e~a^~p6k&oO5_fAWGy_; zAM3`KpZI$9o!=KehgzNbKl$#|ciI)DA5-U@sQ(*RtrVN8X&kEj;GVy0+2n0|&!60C zqSh;uq5VCw+J3jc{i$lNM5bRVA+rLs88X5oH&2V{j(mOoOj{(Mu*V98)JZGi9q+vR z&#*{B{Hel;zPK-S#zr@6Z~ffx{)geogzry&+&%dF!=EQl0(P;uc+5SLe!H;AOYGAA z_b>ET=6lQKmAL8GZD(n}`qQ^X^s$iXG`=@q4p$qpTz_z`&f5CE{iMg2_W#$YzVo|M zJkaOaYOB*7oSWNK*6mAw)%VY|&Be5?U-4#n_3pMOzwU}o|RuC7B)28h!SRCXm=qnpR|6K!$mgHy_rGIv zU{Xmvz4J~%_8t*VlU>q(-9ER}?)~{A{_^?AL)<5q&ku^ba?|MXRn_YFV<&Cr&ud@q zuKuQ3qdaumuJt#6zPx$#%bzcQdhXsU{$@OVQG(|E4>41+XPn8BTi@R|ZED13jVQCy z;Ex(fH+PAIo_(}Ppfo0Z(S$0W9UZFX>(|R=$B7pHn>c+BL&&7q1G|2&KHf6j;(A@h zZtb7bE6$p3`II=dBWdPZo)fd%ud-KN@V)4K*!0o7bZ+A-`vnbDCVia5{zg3NrN4~9 z58o75k#KFv4ZQ1BZ2E*Y>OJoA=UK5yXth?{X*)&pS34!s;?@^$w7T?N)V$nj*6#ZZ zhQ;ykPpygA7_sU0;>9^9^A6wMe>cWe{@>$Qhv(bX{(SkVC&9q6iIbyQre-tmPbG_j7p3QoB$-!$&+iI%37br<=JkjNSz{^nQ-1CNn;Ab`W z9y=aLiM@MwqvUTTE;|N6Pq}b~d`+GmeZ?pHGdxaBS8$7*cs1~e_dI>(umgGVN*fv? zzr-1xSGvl5d==RKLzScE9a?_uaW_{Q5Vi?D?dgxcf-Jh8li>FKXwK*s2bE z+7V&;vFrSvE3-=y7%vKZWJ&r^|CW2NzlL2T-x;3Z&HnQCFVY#k7pwMr<`?uXE-MQ8 zT`-Cr2v2-r=$1{#m|VN2@fX9T@gY-&16`^gQ&>d*85+ zSCS(WEAH@RFwP8Q@aT24`J4CY2;-|0$r;|P0uGOyF0n6r+`4cr!_F6b7^;^Q^d^LTs%r8>zZ9cI z)7M5>PO$8Vy!e(iGh)RC-hkhZ57iAmv(7r;HD$MrGpmoWq<)cIHrEFk{)8>dS~Zpl zy=cn(^Mdte$+WjOdA&mp@IDO7)RWF`$x*G2N#9^~JMHVRI^{p;voqq{` zIY0UF|JTbF8*>Hk%Lr5Om#Ns#7R@22p6i+Hzn?jT(@>?!{?n3`g{xn&Zw+SZEckYBzR#Sqtn-euI_Q7aIr(Z@_@*bEx10VmC$6lN+Q9ZB?mqML zZQu7KD8ydn`^Y-2#N_CLB^s@QXWvC8Zb_E<6=$5r;&wjV`PthoyZ3F0xRm41%0KaB zm66DNxj)HeGD&kD`jnNIIb6O}?X+p$|Gy{aeR*@!=5A3~!G_?i3H+@$nC>@}J8-o} z@aRN@eP*%swPxO?aY+1_g;c-5qr=x3^k?b#8zwxISeH{d&${5H>E5{ue}B_$=X%{R z>1e6XA;l?jTNP)#-x_Q?WhP(u{Pp|(eQFJ3@t=Q(n$v0f zoBap>v%EM_#J5oWUef{Zik|JB%Gn#gy;GZfAc}2ioW4`T4E{pTJ5NkoShs{7Fxl}f z&5L>W{MLvCZcZmII4lV)=5%Cf3G+_Kt2T~R{kCeQM?%G{uHy_mN0!aDTpC{#e&wTb zrCaM(-TSt6=hg|{u`%Wilml3+gQFfg#F!{ms2iew{JOdDM$I&ms_E1B0(FP zR^0lRVrTn$jbk}`npnAf*@W;=@$4g&>tdJZPkzScVle%0-Z8(}I;%D*l}l&RPfKj@ zQemY5W#+2dceae>tOPdgX&=12id;6BI~#8MqUL3}{D#!Q zU&3a8nQu9lhaWp4tH0SYbTLoN<^U%f*BNr0@A|w;jjwbm?l9D?T>YiL>F(mFa~F0C z-Yb8(?fom(CP$e?I4pp6wI=3aFJBzdO3^u@8$P8*7{&Q%+0z zOwr6GOSOXJ?&!;h<<)gdnsr`w>bNsio#UwI<8L~zdTaxCX=DV71wWXoDsWO~l|)>_ ziQ_6y7Od1%>3*=gF>t9y(2;#&wh>kqj`D4#GnRE_|GliTN2Fjuo2I8+2WM-W0JpH6 zfz8qli=SrQkiN4qI;2BhVxDRLM6ZB|gh>GxA8*nWy7g)P|4(1VOr_omx|le~%~A|~ ztHi-q6Qm~O*s(u>{n>Ge7TNob5^noVc78a(+xNFB)cw@m*%|hyH(N0aX76RrEt<~# z<@@bP!5xxvVU25rnOEmullHg%s$l)|!V8|`4^6Y4nCf5HwLS7h$HrwV4jTV{dvQ^Q z`G3jRTEY7=UQHAE(yA5d`1|^~jgec~U2h+1_^qn#SakD|+}6y)=8FzW-@0b_fJN}h z#YGP)e?7V7(fe!j_Wm0FuODUyupPXYkYDg|?~KN;>kQ}rDZ3$iuFPBex$L5Ht+}6_ z*2}k)gjlkDjGowb?5*yTg@LaVtJ<}9^dIw>qOA5@;7)GvCi@Sc<9ekpdIki|dv3De z!30^aF9|R9Ofh$6lNXD7*L_b-+2fVRvggM>9?A_5(3ovoah{X^?dtnm9&eP%hwe9T?t28B(3%-NN71Q3SHftEOU37h@(KC;rfh?K{6X2)QfNW zF2KVn5%}^|_mfgyYqgo{`NVcPYoAom<(k`dd#3cBcV~M_WSTy{zFb^BgOP{f^?{D~ zZM;_&@3ju^JNwykrby2$8!P^%`OK;deFWQ&3M|g8kQa$dXlS^!FXT|ntmPH0?H2du zuBz8q`D4wt+qV}dozhwPCCWF0Rb}fpR;MsOi&M*7^gcU&{9C$g*6R61tJW@b?)3Xn z9n=}c@TrG&#|;IGQ*1|5Qy64t@9laNaQ3@V=*AbZl3V=dY}@xc~j*zSab;3&yU0Dqe1v?VWXDa_SA&51uxR zJr`L8Kd1Z-`!DxOWX6R?zn2GV`Cc6_o?-M|OYxQT(qylV4^{?;EfV(Jn_Knl#Lc_i zJ;u+K9$P)j`(Loxe}>dW%lI<+d;xVE5h2eu*1G0f25y#$h7*#`{ywI6Uhb9})6}U> z=dOEbUC~H-@#LzOfzievyk%-Kkx!hNf93>EPEML&_Fm$b>#ugpOLwo6 zy;65ze&t(FgFn)>b&a!Sjjt*n%=>3!cJ%)##?XLj&Enk~mh3s7yhpEim96ER`@-iV zww*m8S0#SO&f4Y0Tcu-S>!WsmOgJC+wK=1xw8h(%^{n>pPnZ0;szhD3J9*u>amgx3 zD^y$mxA$siVJnyH?iEix1gv#fr4BMUo}QYJ(dMz;g{kPRRoLHc`EiPRFE5*fJu~Do zuUx%}Pjg2B5ARX62O&Du2JX-9Ec7jBp4g}#e(hXE33FzF&bIz#ik9sYP29w8ExEX% z)J09B_{WxzeJ-a<+|p+r}^*!H{ z<=9S5 z!BA@UD-EAc+q`PtO{@4nbE&Vgu=5MLv#C0Z@c|m;#@UB zcy-N*KjeEajvOQ)})X}@>^;1q^>jyQT^*Q@Hey`Qf zUwn9z!OuEwW0t40#5ep*C zor|%#v9am7`12W)OeTfD%A1<@immNbP{$mjY1Q*yPgHtdv3Y%1+xy4Mt_95Qxy9v> zbh&2fyrVDG^v()>vT52quW{MCVCC>`!>Qsyrb0=!yH>a-zl!?0|4Nge+Y>&Qid@$l z-Lh4$SAL3Xe))k*x#4ES;x+sZRki*8vHbT{KWA~Iccd#wbj+#yWW(bS%Eqbvmh(o= zvW7Vd!Cxv?9}Jw!)z`6l=eJutJLLUEk6+I|`t|Bjwx+-Q>qCy-mTYTZzxIWU#=c#z z?kROHEtI&M;dsTWc!lGE$oDhM^w`BR4lHsq+tX0+fx-BpZ}EFshwIB8wcNE*FPDh) zQvV)wb<-xH**v|!>XWJ`@YyoQelTvevwCnj;qGRS%c57UH}M<};Qt@;S|P+Je(fLo zibHI#E^0r?@@XqCyEknRtn^!(oYSqU5c<$K^7gcFwY9FwdJ39x zW(N1z7M*guV)ysd%0;hM{o@s0_%PFG&w+=@`fE0;WgTDEoPPPw+S_Xt4dw>lE>{nX zz2F^qpGQ~b-pbEHQM}$A0#S#h;#S<2&1f?}!+193AIF|a`?&Wk_u9qrcJ^1#%k>sZ!yPPx0`-I}$stuE2ZIdV7FeQ){8a_rG#hU!yqEUR{{ z<6mIRdn=D;$E2$(oWu$qsCct3k6OA;AmHHfB;FOi(bLLjJAIqu{C!t*4#TmCKDqDT z{FeKK&$>OKZSn@?Tt3Mh>8JkBmQR1)+)}s4lvjWEtzuu<%oTp2!2!QNNS}Lj{L7WP z`ASa%j~ZsLtXNU?u{Ph>e(t{t@k{sL_5XS+cv1MyoYluaOv*jyeBs82ng?RmH+I<= z+_Ow%QGbGoEYuXF2^*v;bS z?OuN7{#436@5qh2bJI?%E)R-M|D1BY>iSQk-y7bpH}DTo{V&t% zg^Cw)#T&0G2=|!G`SMBcLGP<0Oza)28+J=s?Vq@~Y2W_R=PX=#2|e3pHJ^MgZsjiZ zMWS~{f@!)+mu;diW28=Pof}U`sL7cFt1TLN)HWzvdQC_)-dM8x!LsZU7L8h#2H{55 zgqN-O+ur&-+-IGyxdU0S^O>+M1b z{m1_&@ouj8a-f`TgO!jmf0VG*rk+m0H-9|kiqx)N7ZtjEq#OuGEL;F|BoGut=$B~48fT_$_!;`eL)ug>fddUR`< znY?C6yuFJJz`UIl#YC_j}&2!+*CsZ4h1jS7V#`jqC9;E2QRY1@>-xoe{Zk z*O7?3KE|E<{*@_DHvGNR?8M#KwwHcHU0YPRr99oAt9kn6%;&MeQ(5f;7Ue5!{NEsx z`ceBy*^JvMUtgF{c=vQ`ymQr=Z07Zhy2*1F=@<1~HeY^bIfw6+mN%kl35>fBzPC{Q z)FQVh)xKeRgH|o`jiupJ)9d%Y`af&mZ&Q={L-hyM7~LPSPh7-kb;P-ri@STKqE(}n z^^T(l-dy{11s>YSy-%|^1<%)w zF8BNI1pZlpT%G?}QMcI`T>klinS+5LSCWB23C}j0w8Z3+{Gv*|g36;2@%gvS1nR#p zSGdJ~yH%;=?(9Y}-@8jr-!gH1yzn;D;l-+_o+(Xa@;v&rt#(0eZ|$bL6Q{WR^_-r> z{7n4zm5=}Kzkl~-MofLh-^VAd=NT-#dD8V%%R|ZZEJr`@S#NHh-2CI^6T`?;pH}?H z%RjMs`Td&ePj6ms&OecL{)Fn~pb1m%Zj7168l%>BaZ&NZ_4b^T9?#7`*=nHE-o9!| zmz3Volu4SA6V9rw_E~x(&AEc{JkLTWk7Um;DUZ%?@=|d-6?2{aSwzuB<&eo!(?#-E zrkVC%Uz5V**q$>X+}-c`MaOzkN7Nmwigd(z1X|v)07;^jXBJF7a6u6`aV@R zan|FXw>DRWI(DT#(a=u1GI54&>+2u+$9WRHJR3GGWfeZ;dQ2pVP1#7;tVdIo*AAQpkE$R7@1jg z+I7`LlMq$4`QLmP+{HXRI`8~DCGOCX$Uj6NSR=tlg zCc79OA7-7Xm3m5gm%~)?ZBrlUr?h36+>%Xx-pzcz_{qTGx7FJnzXWQ@>u}~cfN-kympx_Sg2n0*0J^0H%H&< z-krf0Cz;Q&<_x&~q=rrBpn078j!Kn~hnty9T9po-$;-W4B0VL$=Z5dvUH)cU!?VvX z+{%8GH~UUlwa{TE_s)>6mqA@3zgM1}w_{=%ALkLf%S@k44n<{GF#LX*&v5T@N6tc? z*!hQ3F6`AXTeHlbdF{cR)h1rQj^5k&%dS0rzeQ=__Ao9MX}N{Vrdh1(-4f;Gb3&Ns zhHydY;g94%Qr-MZIp)_azt7nz$mP0Re%V=`{v&R!_aS9mJ#?{&$7 zzn8zhdL#7srSWmapuo(_r&=eON+_%<6K#r%X>MEHGbPnPG|@KC%=qjl9VNY0V#2d~ z_H5tm^2Ag8(A)Nh5saUCIJQogc9CUzC#CRVuSiadw{h*2&TFpE+GD=d%{f%Vba1z% zWc;<@2gXHqhqn1HT7ThaY}VHwjtACCulJXKy?CQsqUoE!KF+LT%N?Q~RHzrEEQ*R| z{J!G8PfvVydG$u|=HG69tB=<5yR+onO}LY8KV!P?{f8p9DK~WY&Wf+UvF**T_Tu~9 z9}gctP*wT$-=9Zk(@IOf>a7Ux7O^nmNxFW~FOX09%ZX`*v*)pe=RRcqaL2Gk=?8D` z{i50D)EVWTM9NH4kGTAk`@^^2^0A+yZa?38@9yzBj)*IlL)^bNYX4%6w~i}!KQ{5^ z8}85Mbq134?+faE_PI|FNZ#OX&dafkxBEw4p~xoz!DA0sZc?$9QLDW4_E+ER5|Mq< zuO_K(IAV3`$LX-+>GtdF=FO|O*=zH=H9=|`vjEJiau{91J}`boj5`yzRb(Iw_PEiEe@w=M9>R`QXQpLusXe{~vn&$Xk> zdOMq06}EON`rc8x;wmN<=_`KKcz>X1PrJ}gSpl)Xg>J=XXU*J^7?x@N;g_n?MAwxP zXIiB$2)pm)*~D;VmEgH^#TEj|JG@q!vZrvBRF}HQ2i;h9CqUJ;?#p50mtht8oSVbC zgg?k=7H2)E7xdX@(YsY6xjG^G?=7tqRm*-w5fWvV1`D)+ON1w_(HhL+$PND7LkIv5}#&vbE z*LuHvEPM0DTwwO1x+!z}_Snr>SG_ZP>(axjXWoV$`#Pm+Q=7xn4O~my?-xW!wKwMO ze(_-IeVv@m6U`Iu-4Q8WENAlGV&c=nYs-698@2YPgnfRw`+pisjI)B)H8ZY>>E`8< z;%9W3=R41faIj@v~MhO^7rcJ-R+#=eK>tP=k%~Otk=aq=p}!gcK+Pq%O^QwR=!zr zG%fq#pD%CTzWMXz506+hpZv~1A)$TGSDq?c!82|1-IPt&ve*N+oXcHTDbjc&)hjw7 zNbB^PfJ;-19(GB_?X5d+taq{X#}13MKl9#JFkFw+1(3N%m1oAlf0?Dw$-{w zLv;12CB+-2aXs)~*ZVthjaboSuI7(&+HbwGr?2w;sFPfF+vt14f4@`rzs*?4n!qMD zxijLhQp}&f1+uY!%WA*=e*3q*oAbePlQU1_GE`&RyuQAEb}>b0`5B3>(9P1lh4NGC z@)mt*_naa2?Ciyeecjil`nmj@#r@^!WbPSD{kuQ#HP;-fnC`u!rCRmpk(X*Uy{bY% zH#9!+`d?@CFe!Fi$;n{5k751OCE^D@H@@uM{4egvxs-C9l?i9SP_G99&i}G8(b=FDab$>G>e%rP5zAyAjoh$a( zH`XPTqj&f8tNqhzeOx_eI$VF@|Mw9~-Y1jNyynn==ysP3x#*?+vC?-}?U^zoie0hg zZs3Yz9XmC`cKa;3(Y=+U)hE0Z(pFYH3s@6gH{2;~5w#23>2o0c$5iQgJ`WXEyomnSv{C7w)mz0o zQC^ByH~ZO1uxkJ5W!dn!Ghy2D;{{jddAAt^K0K;=XTz1A`D-kN*2wHBl6cu<_)yI7 zmACsUz2}$P*iKDn7Fuz0$+8I(&GZVRPn5;HY)Ft%+WIFd^TdiQ<+6@G!-mj(AFtn= z8+882?j;wtJP7~vOZsK~*?pCyT9^2$SVzfSmbAZXRRt;~yet`yMp zQdx1fWRGes51XRqlX**j?0Nn&Q9J2R+KiCPo6}i~#4VjW^d2Q{P~&l2*0Uk${O%pE zuPxDvXc4)iJ$=6DhZoPp882)$I3@R`Q}ms<(fjAZpMz8tFV~#idV2233ZK&+K};u) zw`j~Quw~u4K1F6#)ibWb=AF+~Ts|su?<+EX7`poD;d%FX#rP99Iwx^Fc$l%>Yo0RS ztTV|mFAo2?C~LJ}So`dk!n(@^9BF&gHyeB|J98$$z9BR(aj8M;lfpBXru0kaw0T=N zY(K2^;Nv!3_aiySlN?QKfAATOk|!1Zk7&h2;qEHHj0Fx96#(&Tl2$+pW!7yeeh zyx__5EU5=i&KGRYm~YcC&-m|uhUaINJK4D}jsKFaVVKeVu6e@Dj$bdk?PXt0`xwe@ zQ@L51|6b3{*nMY0kBAATsku#RgTN$C9oECXX$BC&ta_zr^tCG^6 zc*t6~+AB8K?pVD*PGK$UhldxlVjk|~t2(x$S23{f)ypm6x)#&d?cMcaWzO2OXO7my z-Q(YItEWv*HGST+2jwZ-pMQ2aYPojiyE23SCm#9t&wn27b?L(SNUQ%}7iLcW*(CXA zU+HtDV6*%~YwwnBZaDX_>KoJYsq@6|T+=}>2??1@t2Vm+ve@y`Q=ee_O6b< z3a3L423~%+?9udhzqWqNd~Pg>**o0fPbE_MI)hl?9t+&wjG!N)Fv z<2&+qg!)~T_PnrzZ?}x`p-arxQoBqI&YbIe=B0VxD0G#HrK67I#2tTGP90iyT(YWT z{lvegIULtkx4pX16?<@n?DE?4TeO`5qBFmqN#)q0C!9BX*Op$*zw`MXMCmViR{8QyU%M~77JEfTGVZQX-jiN@z%DBWA;?B+n$9Cm~UNY=G zr|=_w%j>IVdru;*p8;J9CwI`9e+dTzgTEC1D*-Z6(oFRVD&I=p&bw{#EjHfKgnyFS zwq-9D@JlOLTNg}H%eWM7Maxx@BP+yV$qsylhzme-rHmMGm|gA zUb);-S$>8VtLIH+?NeFICtQqoePnp7_q;1*PlAeO>#`V)MU0B6vs7m>2L-OHblMa& zi8q{6n@cMqQv1-pOf^Pq(MtI*!ua%sli>`=pYMsx% zwkb+wmk#$+u~XlCjl5SZveN&tckw6Ax~ekuF0&QE`Jcm<`E2?UzAXL8eN}P8so7T< z?gt;0xwCU}dG$x#MA1_wuXXDZtn`E1IowYEkXl;uf_rljySA(!b58FwhJ*V2C1+)p zzDmsP+3cGlJSeX@BV&W{{Gx57Q4wT){6HG53028l`A-MM0xsBgN2t9VoJPgPsDDoY54G@ zN%xab)Ai4LmMrj^xcc+y?ZRvvYS#`0pTAK5_0?5TQB9Xudv)Yz2=KfpNIWEZQgFkE zJ%)yCTe=tyFIuM4JmX2zYYRRR?M;$`C5QbwFBQ2}?V2mJfB7_fWqyAN*X0Q(is!vp z+PJ^FPVn~C9tX8G*&htv-J4~xh}CJ$3CW)kTw;@c-ap%IYF#J8<*;S_gvh!_+Z7&c zE#od?GyTK&+n8aMR*i#JmS^k#I}?xgFOf;AQQFabW`7~ee(Ou;SuV+)T)oT5eB%_G z!nxAUZgnrVE=in!QlTg6^TLO0X2ou=c!a)9HS{^~L@>NC?3&VD!P$-r1!VUtFFMs* zZ1{4Lnr(%E-7a0t9hZ)Mj*Jyq<|7b0i}hdx*R6tyBBfk6pL1}3W66H8TKYg~ zUDUcL2A#qM>{545%$_ov>(GfQ6BnLYAgbf$6}(b(mhOk=*Xt};jE-H-VfLwMU8?_4 z@ZyAR`#H4_B=0+=IYqa=h35dH*dB%o-TQOaIel8JD6vR2n9onr_>D+!M(e}`73Jd+ zFD@UkitnAGc08ST<2hSaasG|ooy=`Izox|)%Wm)3og{v&GJV-L_6{+=ZL=$0JT04- zmcLj_k+J)l;Lo@F#CGw`{*kdKkBKqlri1FObJ?sP3rdr_Swhr2Rb@gq3rYtWyw!HP zEb`I(1w%#N!zIkNmAm}e7@`<?xUd*1D;6IG{G+4T6BDt?b~ zu$ZV;>+65Zl)v9c>qN-DNEIEl$h7w8ZECU zeLm6f%jfN#7q#l64|<1(AN!geBO1Lde&3siyLKBssIGYys(}3weQt6 zg~x@430#l8`(>_~tk4bIedW;HuP2+&1x#MKY@OxgteeIUvR*c=D&9Hm_QK=dPt|s$ zK1&umcHi*ayxya?5-kgOdM4j6Z;LJ4P+a0O;n0PeeLMgC`1fdjJ4aOQ_lvbB7bt%7 zm%8AbsBacxoqCkGXpm#WS%!$qgbq=@WG)#{?_8lS0^0$ z=FOIz9|E$-yT2xx?EVif8yQF_j&pG z^PKrb56hY6onQ-?;8vUR-lAde!QR>S(w09GZr}8{+xK1hXV|fxv+L{&b6>1q(^!2s zqqxF(Cr8cpH_^sw4?_5sOTUir6W(gP?mEkD#@R`g1yNrPeK+rL(ptbUBRa|EbfH)| z`?feV+UCt$g{AH$QSF^R5f|<{*XV+9%i%$hj*S)Wu+)=&KC)hb# z*yi8-6IVqR_Dz1ibHCgyjU#tnUKeZ|AWa zR7~2mBxbE}n9#%nKK}mumoHD>70+bYRhW7NfPInLis`n@Ida(I)lFP#Nwl--uO+H;}>$5-qSK;&FMVa&G ztiRNAwo84}bnC^}E4M#1{ByxNRBq2ggO@7rrCO8gn?g?f{;V$kVToB^LRS_?&HiP= z%L3%NcYMt}&G_48TS3}V&EwaF8(Uue{8yz^aN*edpUFju@qa%5Z8ZM#G~vg)4^Q64 z^&fEm)X>Up-|3_mDRjp1qeu45uBXvrn_3R-j$8k|pKIAO-`@CdzsvL6m#gRV-8VD1 zEGM_Ws=OfktBskO;^~EACui{e4m|CYM%aT?L`NJ$6gzl zM2d~r8x?*Fu~#25x*X8oYiAg9_>php?8@v5-jCXkv`oLD)c29!$KE?5Bcj^!9OqX@ zbEz#SWu)D?ZuBx$dmmV%@S;RcdHGEDX?13*>N?W<>XMn|WHxv^pZ}h5jEl*{Ur?>I z@@nvj@($*6t`|*?$IgHMug-AqULkh};RFe1jx!EhPtM+;kSZ(N6Zdc3jH$lKN3NXl zohy4;<#T3&Sw^Hh<2O!^jQFAr^B3=3zb_(;U3AAC^PmLbDOuA_3*0d>JF1zO@WnZI zO`N~vN^e)yCn=Gtjt}oPEYqx%z2dVjvRX-1$nJLW^9*E7jdgXhB(*gV4 z*I%5!&|UZC0PE%ti!ZP%i2fHkYy7G3P5V6NG_{2ZD|qw`*7Qe*`A<)>TgL4xV?OKX zgRR2VUcv33g+eb190+XP&bTIUnR;{v^H)YM6ZV{MCtZ!w zrGi)aonK@3LwIuv*N5l|qf`;LLw0k1oe(}IKF->rH!Z-F<;fNO^}kmA=UAi~ zHf^$|!A$=pHb-QC)N!#`*6pA7`u39<$5^(`by1jaSgfd5TDgS%n?iy_z|7Mt-}_xu zPRQWQGwnRl#8#X(QAcTtPQ)aq>ef1Q`epS2`ej=B`_9Mn2yOdNSn#5I^23J)e}Z?cz1Stg*Pim-{dY0vF>c1k zJO3_X`g8N#{UhD4R_uOsbhFkxYx_5Q1oX9R%i=o3{Z}U+m@~gqe5u@S`+q+UzvJ6? z<81t$Z?~odci()sXr@H(9G8X9xURFxh3(dpUQxdJhDPG$ru7`SenYMA9`22NO zc(#I}{>*mMZ%zVNB-u+Q&5{aSD^&7u<$I@f6_2iGO!b|dVaM1#Q!u0?!fKDLi)-aQ zcUS)z9gP27zMPq#JGpq8qF@luhUqH3AC8}5n00~mE3;J-t9cL;?;{JYri{*W9=%$3 zf@d|Ko)p^r@>+WG<06?wyLO*Bu&Vh?=SDfX{9CM3KC&`tUi15*8gKgG);=M>$4vLw z&hj^kEK_{y#KjWtEwV(~aQZn#8TP}B+fJs4t;;i(dQ)tC;p}WF!>27f__L=lhOj8^ zOUva>h!_y2R%&-s1{)gOvK?=P5p{AkEoyHjdziEF1^%J~>oRheTF@2(pm zuwc&0pAuoxGj<29TQu#@@=y1tOGRb}*B%dJ_Y_iHD=Z~_I76pGFE*Fng2=}c8K##nFmf?I(BJvG&LHSh zp~1I5ESFQcr|~tkuI{f@a+0%>OFpLN7cs|0&pSBar{L^Mt@5hdHlAzSPITx=Q|XaaIyM%WY1yswtg1b35z9#VZNHBCLC#$4!m6dvFcM-qS_vmjC~@n{}Vx z$E|77_KRCCzV1t{SbSGN;Nro8LkXXR#8`xHuZZBvZPiK^j9D1A_`Z$Kz8OqL_n39s z;&hXRNv8M9W_sxTluyaa{{EWh@t7qLz+o}JQ*Mh?~KR{sr!CgWI zALLg}+nhS3$ZKIwR_c<|+N+QH9@?+=f0Ds@6TWlj{LX*l;W&KiL(6}+ZQ*-m>sHC> z_detFzbWBnx$C=gN8f>l89!K0y!oc+w2brTx9A@mHJJCUze^|n zUZ)f(X1>_8UG_GUsre^~pK0^o+?g8hy!F`!r7*9X!iw)|7VAIxIg>Zy#LXKs!nOXa z2~w^IHLcvKTl4jRF`&6d1H zpOiKnbSQi5a4FlqY)k071cOw^oGobu@8kpT=uf)9JM&R_x0*P#Wi9+_X8FAHy=rsf4Ibk)ip+s+ z`%lVDo47%uQ;qYf{(*@*1RI{6c9!w>U9r9~`VkXH`twAgW~U1C)CA7S8oumJ`U|9f zt$O<5`{QO?Kjuk(KehO-1q4e~F)mtR*d-)H8eHVLL*(g>~cNchYu?>+b8 z9ex{8@flYg4rWbqICt)lm+r0WKNsy4ky-3j|K*rN-i(6J&+?zU-=5^SBguW4W@5rr z0pA&O&$*{DO|rgJ=@N2E(fds6)l2L;Je8uy8Bb4sbN}D;H_LzedMB8#vpI77mr{0k}w4;(KYW|i;tD`rR>%ZL2so}rI^yO*Jor8CZn)l!M9kI{*@r&Du zo4PjtHY|Ol)RVVw+U-9_Zyo3JzO|@LO62KWfeF9P8K3d;xOZ%_-JZA!ar0DlNcH41uh3dRzBGYzX zEqk(@|o>Ha8>VVCSo)r*(uDF1yEcy|H7Ve31h0 zN{!gGnC)}+KRgjuY}On3m#ItV>}vhOPlDO2zh|vB(yUm?dG6ut+TMcF8$UEtUmriV zlR;s*b6(fG`zqUAe{}?F-p`5^z7B*~<5?mY*GgCRzL2At} znWOuh1%;T?FRK;b%yizqZCjo1%p3KO1v+A^x^7ul#NLP!lullJXU3z|xk6pb_1`?t zdf4fDJ7SXW-OI&BM|gSdmxwObt=8Qie&GPmigf)~=cQ(uZqX_T$UNJ==C_uY-M3ZR zF*Ag?-ptiH%vBISQCfrhiQ3glF9BEn*xmr0gD)ymJj1tT95=TU7GuBCx@|{}x~Is4 zOM6qwb=G~3I&|yN$%|Li_IKW0V$mtK@3@N`L#n8;a>*0+x@}B9OnMK6T^5>(3LQBW%j#TesKjOaoO+Z2Tn}?*{}Yn-_~^9n!2UUm-5!6YJd6f zIip=tIu}2!f0l8`J3B@A6&&53OtuHPJT}{@I1<7wlI-x*(~XlChKkm z*~J>OCn-1HjGp7Ij%Jy{HsqJRJt}J+Wub{@TWaIgHX4MD3wl03; z?|e0bwLkOmv0cA%wj7MhS`)o&!Pd;y@B?abOBXH*ipv*hZ4UUk$7$;9g`pyMo-Lnt z;EuB5UxgXx7k%N(J0;I#zVb`S*$D;G&CiokKLsz5Dn1h;IcrU)V92)Uhl-2;3bt8# zPJ6V^Z=njWb@DIvCC4J8{Zi)e)Z1FyTa>3<I$UG$7c<-(E-dEdaDd+qOna05_ zJ$c&3%pB94hb2Cy<_@o)y*l$^xyH?mWAEen3%8y7xca}PZS{(uOiXnZ;VgXqa(ssJ^=3I8$>{vN>cFTdAEQ$>)o8Kxc-8EUCf5*J`)Ky34 zI)RDu`92NWtXn@p1gf*;U7>GG{lYD4T6M;?tIV>2`u{@&((6ZRecg zHm?71jdwwe=T^yYPeU $C@7{>hAUe$QtL$fv)`Dbs7&F6!=lWkZeqyl^9tYpv#+ zm+RZN$RFCX$M%b2uM4eF&A|-qp@w;&njwJey}@#f;64Os)1W zDlRCpJc)0YtoWF`oTuf1rSUh*+XpxpJg?nm$mrvZUfUpZ?#{1PR!5gB6&KZYRq}u`lN+*YOlqNcVqSS|c|#XmV4L z)a)*`?Y%S4l@<1~@XkN5Uv=Wzn|;52vfP}y=Z^Y$j(OED?kviRpZKt`=ksUftsG_N z^v|7ApCQ`!>AjNunV6^rFWs}ap8ShD>Z|VkSjtV;d)b@McMI)*e*N*hxq9*Xhbt3< z!zX&J+SRxB+iAZPp$98AF@)qExb#71NoVS|H1G3vH~-#K(vP3?{E79W=qLM6o_lVd zuM;SBQh!p#FPYn4PV(1oN}jrWi*L)^u#2lzJmTe=z0*t%AK(2g__w5M!h&y{2Y+)~ zoqox4dxO2}1J{irr>+-VOfTE{{mm(+Id?OY+&a^xt{j-ZRPFq_6Af>stzC8FQJbU6 zrm4lwr=rXvoqX;uKWG&kv6*AqiM7{H?d)E;o#)tT<3;)s@45M&g{Z7w+VM|s9v^2e zd(fo^il?Hwudg;x2!Ad%fBD1P8LYExV$~U6ZNAFtx?%6bnwwIQl@8x>k2r~iY!Krx zQLyu$soej2O?UmA5>shc$A{rh;_uuR`sW&XraS%|U))|h{TRQ;k(*{kUYW6cF{{>n zujrd;xjvf;MJ~;7z5gt)Exu~Q0)gwznO)4Y7Djq+OcOirT>SajPmL#wE9*4*qU=@b z<#VT5SiJbuy~4<;SvB^faJyb|oNY6ovFKIa?8hh8tyZ4JGL`wAg8SbU2JZvk_|NOJ z+xs*3aO|g~%T`jgQu@|fyf>+s-VrSoXWNiA!`ujqZPjTU|UnTuA zHGRqx`VJ~2zA=8cYTI@RbqBKu=eW;npB$?D*sT7@AiHp*P+di!dvOlePz%iH%}{&*Dcy4AJk-3`_$ z+`EwWHDc-ht%0YmGJoG6+q=I|&(FVqR^0smpZ`315OHsxTG6ZerrX#5Etq}g)9qg} zdo~Bkm1&(~`NGAJYaX9_IDYCEnf3b3hFS`zxqc^v&s=GJ=tGxm=qJJ8g1SEm99mg( zToyMhTtCH5P-n&*`(KwNb=p4f>Yv)8+IN>BZNd2k`@KI@Tojs>9C=dc{c7X8S5sbo z7PfuG;&qClaE4&XL2FJ`m7Avf<@s}qUpi!c)mimsfxKJpzR7DZOmpkY^LqO2*XE}E zy(0NXeKcM%D}?%PU*ou<&NrseEPzuh%xap?ac7BjlTw4OE+{wg{l3As+|-XhV{XOA z@L8^#f9+jxN2J5)!9pFz$@_T%R6b0s;6BiDKaKgLTU^1^leOL*SB_qtCvjw%#FCGX zBb5psUoT#;tiI_W=i-(9>1UO6^t~PSel*bk@iIoabJuac^D{fQrfxejgL%P~k7?X& zlcZJGXuQ_ye!E!eQLgLKKXPG98s?vvl{~TiY<9HaE(R&Tt;u<}_jInA1jyl zyhF#7nCsz^DVp3PTd~vwKlE|8!%ZhjBNx%IdKl?}Dt%uFl*4;5r44m|4e~w%KBqZr+ z(4#vG51gOnD|p?y^V=bn>$>COvMxuYWFXuVr;<&4=4BZ|=Ufx_ha;hF*Kwk4aVg z-$pFU>AN2Ax%JaNLy=&OyZMh<=WxVrVB|E2zTnm{zuwknmxWE{_YFdSC*I(lw!{3+ zJFQurzI}T_b!TY!H_dl>^!dSkvl(443iHdheO&T2Bb4>ypFcA0cK^2?Wa*mMZ`OIv zx#er8PI|H__m5pSMK+vIessTR&DJIxxdqQwe4c#wwczu&^1N@iMeDhIPD)fOiJJF+ z-Kwo;@;*g|8qJjz4&EE}TrH$>ZRe$&bFQ2zo@-ZMPYYe9;1yoLwDjy_zAvd8PamGO z;@P8ZZ7)s4973PB{Qg$s^&xe#{b=KS)#cP) zkxbRo(bjj{g1-IP<#EkLN!9OZ?xnm(HLi!QXjmpqZ;W@0xM%nBuQX!inefW55k^X@ z_kQAFU=UQqf22fiL8e|o<^q}X-injm1=NTKTw2PlEo5j?>txk6Kbvwkr6`-Lax)#e?i%MMloqMyeDbr8MW3X%S)|Hm8_}x`cSLQXCk0H1 zG@WvNva0cs+WD!`anEKx%1TRCi&SY|af8Kk$FrB`*6ihEU43oN#-`K->05Ru6iq#z z6q0}XI;(%ArP6h4#hbe#Gf%iwPWzzB6)iY>#YD-TFJjq?t~wb!%iWQ3$VW}_Ma;WZ zk)MqtvOCW#dQ`U3GVJuayy>$R9zFArbLP*@_t)KHn;d`7uWoK#Mg1dzA3R1`X8Y15 zwVh{d7UQ4!CD%A*eazy=!F9p9yBRio=dehCPPk&zc@-_eZ=I!GA^Mp6IG~8x7e4bU*k7MhSWy-4C|9XBhipXwE%=P}# zcy)Vu;!Y9ugr~-GCwER@m@xCd+HKum*}dC#{FuXS`JQv%hZ8^Kuj z4nxw3m4XN2jb2{Ln$gG6yJGn?CZ<#%MpU9~dx&}TFf1!QaU@^b?)&uNMgd*Z& zd_CtFPYm>Y_vzELJB1U9nj3d1?~K{FX_?NewW`ev&Yh@vxMHEknIyUPNv2W!uUTgu zklT8cMXIO7>HN|Uyh_dD?%QU&ZI#)2YDMPOwlp)IrA?s?m$ z&vHv%*D2rcjOtvkaeOjj^CZe`@2uyRJh&FxBzuLaL;ex#vw@p}ssSF*zr zkK0k#qD)>jsW^(Q6I7M|)N}Q*nTnskpq9GsnyB9zLGtcf=A~!mn;&?w@^AdUH;V%l zKX7X8SfhAZ;WR(@mKo94x%P8-pFDge_oDQP{>8I88K?3sWAk5by20jo;s1!6Cq4x% z_FcBZY@?Lp-V$C%=aPQ$vs@F-n^%YzbN}I%-*)Gt&bjw3ujhW5)R$(rJi0+*$~A_% zl^Kg4>(-WRr|-I{my`Q_zpfgeqlCx+NfzrA~Ye^wsXj_z$=7louAxw$Uk^FljDUOQI> zhK&d9774~U%w1*tt>ezxiY-zemRw=Fl6<%JpKy0mDPf*5`%Tn-UT?X3OBU#AEJ_QV zGO=a4Q{M^R5Eh9uR!1fo_@3l7G20N88`YZH)6ul0b=mJ@5l+Te9ezzNXt9wJaBXkD zV&hnK*kb7oQBCasXHjl#Z6 z^Cz@iZ`R^S`C!`NnjXQrlCfDSS~x*qr$ft>oVodoS+AYmwK0ZY=50;5@#lKT9KWKu z!L6QCm#+!k%B8O>w&3##B@_Fo8C(-`<+%?~{=fi?aN!v7omYrwV_kOW# ztkt}xberAR7C-xET;wFg$hcJ^yMD@ao;#wyN)KCv7nf-ptk>MS*+E&=(uQ@{s@<{A zKeEj^xLM=b(r=x2C#MANYWy_c@f3sMz1D!VSDrktSuU;-d7t*_h`3OL_J&tG5*m!p z=ss?#dU9dX5#=t9RrY#MR;48RoO~Yl=@7q8Nwmw$AIbsF=4wy!Jsv2FNJniya(C+* zorfI{c}?7JEiHXextDcCAJ^?;=bM$}Caf07*7@@Efl)^^ht8IBY{IkbcPveQ7`Zd? z@1;cjSH<^UFHtWwDO~*g_r+PC-h5jxvZ|ipqSl2Crt5Q<(*7_f>{|Y~SX6la1Uc=u zi@(c#|My ziGT0@{1P9YpSC|>u7`sAv9x3CVFq1}lFP~;`U%K1?whgFn!B;QM=-CeJm5~{mAs|x zDuuf>eRu2UT3&Q^Wcz#LY*D|?Z#Bzvt51L3ce(j@gzoxNW-OQ8Ww!_j{$!h>RTLsn z>vy?ns?6GV$xl|sUX#2$$KWF8<};@R4FZ3RD58_Ulmu9`G$r}V}{kvR_8*FR@x&MUP~V3sQlSEC zUsl|@Z}hUvK=0+>=KB8*8`-1UFWvp+eIV;$9l!dPS3hsOUTVA`mi^?s;IrXJJW6?2 z^es5gE%-F{z)s2K|G!@pVD&%hoNCmZCMspNX}^_{N%m?^zxle|T0x;bd|n@WZg@54 z%f-%r?0o-^t@Wx^7c6f{Th2{hal2MK&9$>i{KR4-@k*tQiaCcK>N9^~&J~#S_%*|V z*7ti`R+R{UdX{BX@%>(%Y_RNIH?K{8-Z!`w9CSN(Brse~W2cu&PQh7S!v_!2PJiz8 zC~q#jwJY=8T*L1%=HH@Al@aQO~oQiYNQ;+)h9KvnW_)bLGjtIJtdNa(iv8Qo@VR-7B7$ zuJf$i=InIt8E3rY^uB#t=DIJz(I9r}>LzwZZ?V&RG$LoDR!UCuoX2UJCOPf1$;=mw z;va(VepFxh;McF&=T-GL8Q4Dbp2s-pV%mXM@AK{4YdQnieGa@}U{H!l?Av)u=VyDt zLD7Qx#u?Ju`%k``q;$T3zn;5WWzG_rXY++`%(u`fk2|vG!ADhn_BT!9?;EW=k3FpB z^JY<+6Lr7YWd7L-n}n=8A8pvB_;1|*tipXLNzFv=w9m(d=XtvVLhctW+}~Mw%Ko+d)3li> z#$sG$Tena5xjD7|>+7SlAN)9Oe%yX;U4{9r*G1`^Z&ZC=PuwT3 zu_5co%cPB3A34qm1s)%S%6AY37@zE_1F^+5hcZ*GvtU+SekDK8HKJgDU2IXExd-vsLfV z(k1fI_s+Emo^^Pk>AuI)B%$q&mM`arXD1%)c&+{aIZs=xwo%-E-r$4zYz0D-q8|oH z&zwD5+RSXhmyBx-7wv14cWU^~+y3O^&6mpE7qjkj-^tzb;HgdjORqD_bxuAg68k7O z=luzri;T0Mxo(*7!OeH2kSABNTMpBnyXlAD%PnlRku0^6w|uc8=XN8*kDO_rg5-MV zWj$b?ZCc+L!tkq(>4;8|!poGYOA6PYw|H~!*q#3$|9o22)UjIWZWPCFQ}q~W?z>lv zmlqW&sr0_)-SyxQr(&({q%5g#Z)XOxam{AL0+(geQ9qAjC*J$0` z*R2~E7sC_TRM}d+dqb+}@3XS!Z&dZw7j9$9<8FLW9A}a~X%Vwd(1z?=*9DTB?5B@))GmCL{QHgjJUz)tf-8hJA5GhN)A5Z@?w5`&8Jt&o z=5=Hl#mPrpx_)18zOUakt(&^PpS{ZaS-y7TZoYsI^4FP<8R^D0%wPU?y>rz1KN=#b z=U-1!xgch-mfyWDbPY>|+Xh{$ce+Y;k5d_rR4kgZ-pJ~a$I@WI=cYmW7%xl0+Vg*s()HVI#RlC)oc zYgF`Rz6)w|q&9}%ZcsQm$%vz>Y5C>lf{ou=KLzBoH!fi2u5Q}@_VnCYo88>F6#CR| zc(_de%V6xV>i!n_rp~KEwvlqPU+v-$zVWqvkImIxbC2hDDe1p*eP7XNw@1l=t?>#+ zkMqSXSp_FE&xlp-@!HvT=u?x&qOV+UUvzS~UN)K2sbmV7T#0BlhSV zChNp?pGC49U0y7hdWDf!>#g5G`_{USovyaMCKq^3Y#wTVn&stMBtFe#EyJE4#TxMk z87}g4XZ+ivd?6)EzImVUmFu@=6^kd?hf0a+1k0?>UZ5Rd@^q8G=s6KS3x=fYQLi%7 z`GX@X#MLwxCS@3O?z|y5*Da;b&i{7Dm(><`BbL8?5f=E<_-&(dL~ca;)k)%e_r z^TjK`uj+4movl%<=f3d8OsO2d{>q-6wdqO4#g@f$XKM9cjc%Fm`ib98ZRuy5*RC^; z*KC?~P|e>!b4!Ep$ux#Qb{spi;x zf05{)&C1+=C;yVZ)Vt-8?t%@iQ(D_(=5x<=_`0}e=gY6Nlh^I-o_~+^_;dMt^Y(Ga z&7V8>zfjD-s>-j=Y772+d-HX-H~(Yf_ZzMqI-#XJne|QZ@!M}+7cSi>_k43*w%(@w zHmqlVZTs>>yT`xlkft?9i^x}re-TzfmS40d2+sDqw93MZX90KL=TNQEmp$ow9Lk*^ zxt{UXdYJe{b2od8oLy>M_e+(sq?t`s%hxhL+nu%Pzj@!C`R8V&FSq}*GN<{vi@j9n_i(HNWNxCI4`a6rWIh=`0 zKD9GSGMOvvSx;6`OMa<0W0y{7b96~HpXuD)e|0*PH*d1CzF4-cCzR{mX@-sAK70S~ z+kWoH!+4vmVm(#=Ki|Ci^5)BS^S(DLCuw*mM#;UfjySoXXzR~oRXHK?l^Nb^_HEs~ z^XDXocZF`#Zuw7f-tp|N&E%zvyOwskhxF|5&5u>L(_B06_=5_*-`Dl?I~EIlvFbed zF^}tzZq?t}Ywb2K{Ike4r%jYE|HdTYQ)&k`WeD9oANfi0wQ%{3hKcDb?r)sNocBlH zQ|x*6$8b08g+3Aw7_L8E#gce%N6V`(LZu7DRsWx=+4sCL) zi2T?nyJgb#d5aCy7uuyPS-N@l!s|(Oa|LC$Oj^L4*7CF<>|X1~)xv%2jVwDlW!CIf ztYx0Qfa^*`+Wg$SV8xILKFxo&r6pXkF+CAid|3BsLStt49?7}=(NAuh#T-9xa5ieO z^XfO24jIqa*u8l6ZAt93#qMX>ro3Gis_7>B*-G0j^b}*#YZotlqi#)w$-J7eW$PcT zh`9aQd~2n5q1(?SMmIGM*M?) z1vb22alL@)#g^BH!+Osh&YSa)RX>Qo)!F%85a0Z5LPl@)ZM8gO@8iI&5>b{iJymd> z`huTkHyRbSCq1oEy|Ls(e&w^xmm{Y=Ho5;@ddV9l^}19-58XR-hriNOJ4o%~!JVc_`xnfg zw0?tm-q}>KY;zOifZv`!PfqR(3%PzL-Tu%~o4)$?F+A#zBlck{HZJIyVhCVnpJO;SJvzL&RCt%!_l<(P36_@2RcK-W%!t2RQ>Fpd@cNT~S<|bU)9K~@^ zsG6lP=*zE!>nA-WrG)qHB_ z9_88KAJ(mU^=OvU3%k}<>o&Lff5fb(d)9ecZTQT!H7i*7u;(FP!}>F=TcPUq;Zbaaqe+FoMe6{fOni_^0(b<4KYz9sV) zZG7p^>$BMPLl*Znoz82FrR(n|@h^{`KRfoL$)-{^VY99U+p}x8Y@HGFbNy!CIR#Q_ zn?o%gFHRFklzXS#daQSJ z?JaqQjbA<ynpRT*9&e%{XF6Me{#q>83?W??(o%RrHd%Wc1PyTlt-BS`P5(`w0 zuW-3`+;(Q-w*wI$+QoI3=ZSCIY|EX#TDy_abhl5)ynE+fM<2eVvb#2?r|{9XE76O& zM6x*GH2lh1MQFVzw682`1_Fg!V`{td#Zk%%g7BpX*uPgYlPQV zL6%L~W)1ls=M*HabY&+je)H;pNx`+9$_sWH9F{)iES9=~p)Atd{raY>cP$^hyR!V| zrq9lNXFmM9I9th&Auo)g)a`;#22(Q zeF*MzG<4)YYOv5$lfhMy<)+?-6-`bN-2z4b8@p_-76%%HZA>q0;5orvF8)`X{aRQ4 z3Xz){i?z5u-bkys!e<~e*TpKy`s?DeJ4&{m==;5|f7z}h+PX(emWfQbXm)){DMRMY z*@rhXPv5>XWYbFd?7eqIpp#ar!{oL+f1)W~nN&snT@UE`@T|B|||JQ2?pywW=4 zeM0Qprl~Vtx-bW=U3q=AV_CqeHMQc*vuwQeY_ zN_6})^ZE7_+*gct1%+<7%zr%He*T_`$Bi-=SW+dPvvhbx9n)m;$gyF6s(s_bl&fcr zo-v7SIc9e9>Z%Uy=iBEvEOzylbQbnHd^X>LW7VO@1~o!i_pOvevKudUHODirnN$*e zjPZy5>xA~ku!wBeqsRLB4*#lUt&g65=Ensa>6>jq%^NP{^si=X^5wl;xhAw6cr2>Mygl&8-zGF%-dGsTom_OKW zrvPVJbc4O`%LlVW+EZR$PYly4pUw5;M2*eUz?HvB1s2R`e~=s|+@F#3b;j*2m##LH zy^YUb@mIlTacEbqk-VX-#$;{NpK(7Q=!c;Q>#x2J@BPa6K6A#T|0QjY z=bV$C>NX|)=B~AW{>S{V5cpFYAa1)VXovj1JL&SFCCx2L4-_;L*TzrP5%}CNLB!#N z%#wm$rnfCC1g=O-IDI+x@J4P8S)GT??_S{QydSztak1Vb>nBz z>PldFseMI!*}a9GT+8l+EI#l>=IzI`7x&9sWfsj_I{TTYz}%~048m*dvnOkBmhUn(0P3R`@W#Tkz!DM_0!mT1*Km zCTsofYY3Y$gFSQN-0C)stqBbOQYWpAdO!WemE&GZUu`P5tg|(^!fd6d=gWrs34i9d zn)%kOc-mIcF2z5wp-O&AdeqdkUpF2Is%vjp|MV-H-m_oft`c{(w(ls@b9{AZw+-V| zK0{}rg)8HqA6>h1!zp&VgL0>rHq<%442e2@H|c#>-2sW|{g3;EmuzM1I=4W|a(V5y zb$OQO^RoK_HnL2JJZQ4O^77WM54SC+ODWW+pF3K6{iZ{Et@tDS%O;$H@9eT$I_F({;;i@Gb@CD-_LLQ z>-+Zo-JZ{%7HAT3g17k6Y3G<^iKer@58b)UH!j>N)7JO(#7F6cca{IEoLe0Fcb(9e zE5SU^FJ^4|Ke13l&t#pR)_%8VK^KkI9=fuz=XLN~p*7`4t`}UXi#x-o=HOV9e}(aZ zQk(m~huhf`vX>qe{I@4&Np&BqpT_S%3BMT!l9Vn;1{{+xTQj4*b@PRbk2U={%~Lqm zUN$Y3Gp;MpT%&Z#NbS$Ax~Cs>IX6i?u8D4+v@*i3^ZHuLkIXivi=Y3|aSuEvH-lsA zUgxcuwiB&>y81J{DJY)(;`G6}&gu$IZ;#zb$vRLV#@;*e*~E<4YrWCWPd+#vyXlhr zYTvV$<38GMdv^7q?Yy3!99nl=>(dYK@!N6j_~d^w!mBx$QW~X-l~dKfm8`mKVZ3

yWU|&zt-Hji^EI)7VUmvsJ#+DPBUFQvT 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%0Dl{&cdeL94BaSgCzFL3tp9R14i^6sb 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

fNA5FP+v+=Q+O(^iy_Rfy60~(| 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

X0JZ;JIbyfHV8d)JIJFW9{s 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 R@R^~~lY!xSG#>*40|3y;w|)Qs diff --git a/python/wheels/meson-1.8.1-py3-none-any.whl b/python/wheels/meson-1.8.1-py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a885f0e18cea1d1c32987540dc12d91cb74bcb9d GIT binary patch literal 1013001 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⁡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

)H$4bWoJ|!O&FK}r0GCotO2y|eN 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 zɹ!GCHZe($`o>Q~CgqTS#0jwr<46uH*&KB4{km-@s1*}oNs9zGzu(vNS!)SD&R z+azV?^&V#r(#@Ra_Fp+cdfDsO2W{+3*DT63@_2C6_`|u`Ppg+K>)y0O&N2Lki0rq! zT)B}amuSCBV!QQg1y>;d1+Iy;;qMAIy?eiA=WhG1cPV>+zu>#@-p)+jqqF}+K0|58 zzD>U!d}Us=ay~w$E^Hp59TDbhX6$fVW8tjOJ$?&vCztPia+|~b?Fz4$t);&l_g zg&980HGCCm^hLwx2G^xao{f8Amd~;+36%c7RM|V&I_}(bn`tcc^!QleL`Iw|_+ zjd{tBpPBcnw8hi7Ry5TrUyEzxdY#SmJ5B5ItISDT*31&S-7nOB_SR>~qh*H2bvSmI zIVoP5ar~mJaGry3wCl{fY%b+DL#^gA?-lWOS+o77>MAAO0}Pw%9VUND6TW*O{+IfR ztW$O#g-4Ub%63hA)%4}EOe62#mzDw% zzWVxi-Nnn|rjz%Z;9=Fa+Yb4|71~RvjyUA-$FKqx&1nmyWx_`^mjeC_VlZr zoikB}qkPlM7b}+qPER#X+#dLM!m&=i3&)J(@|TyHoxaI(qiB&R_l8U2fk_)@URm-v z`?T8}xkcYALYGZWofM`jEqGdTl1>os4-Sq-8}WFbl+&6@x`{4*e6v;cG^MR4T{&+i z*c5t8{2=Fvw~pI7msjp>QZ71l!R7Riu<~@H+YHSPd2e&49iQJ=;=WL*LObj6%$+qt z_s^vBMM=HZ@|NzOb0|qN)$!wHO_tNkz8(B?t1?q}zD}BLiIzf@!_Lz;Bm5*jUo>{T z)SRZJ6VD!U+h@LX_kz_E4_1YRX(}H$FtsvrbKJs>XCk&b zUC=S;dlm07&G7zrtM@M$rac#%_UK&eDX#CcJC}%8Y0tPnarf>;v4#2J`8yAA#fK+6 z46S->rmP)1(Q*aXeJ10(EDReYfA2b#CVcq(iro+I@WdD#bXGJFd01i^sbi<7Ug^5Z zL}S_Ea-J4{*56XMrW$@b)be7RardhuoM-1v`s&G*#M-H?5K0_Wa9F zY~{IZxbvitMXQBVul3t2U6TI~#yV1plJelX6Bn*9oV2+mdN`%VWaq-#ANzlJ zOu8(ytc=nAVmqs9#+^q`yY_T3y8fu>O-w#_x@b;Mc%eCu1drS02eA$RejKrtEX@lz z>B%Qn>AUT~n~B!_k4kL4J;eE<8JO8zu6Gx4z1YksXmk1m!`+7B6*&s)9HpZDH7%Id za^}kX`&F?uPDk$lzw7&dRz06p8M}V7)T@85-+zC(`$MADpTGJ0{(XI4_xbAj{hvPU z*)#V+iT{(5=ouBA%b#3j=ucY6^08yH;M(JAXFZ-8cAc5zsJM6gquVU0e3tWD*=5*x zq6MezF=>vRHtfcx*PM`75~e>E0+YcZ*}LX)e%rv{V!=@(s{yh_jJMLX?OuPf4B zYjo`)Gt)G-O^cVk|In{w$68&D=IIGvr)k>46 zg*=tIvCE}H{mHJLf@KD`_)EW-o1L`CStO#&@z*!IN#(o8+XVART8BLtZt8^DuDbq` z_nV@dduGU#3sdhU31)v&o_8p0|G@}l!@F8W(>?1{IKI5ywL^eu;;K!DkJWs-9sl3T zVs68)YpWuyq?rmeIxnX@lG^q0?IF&MP6h95+#i|FIIff>bcVy~=`_cl#QIIvtKY_l ze&4w8#KPYfR9{QpnRi2!cdB96%@anuPnZ<&7qdsZe=5sRxn1i2>}HSck(XlE_Itg) zyr>~(*6tm@4+=cHn4+GmCZC-W>r%qE@#3tUok6B+YClac-sk3|zeFlk- zK9gOS$(ajY=IRYPzrt6D>ow0yN0miQAIdiG`Qcbl_4m!zqQ9%t+A}RrFPeR+V1|)N zf2jW>D>sH@A!FvQOY$w<4}Hq7NT~21{~B*|_(9Oc#~CxPc-uT}6%#Yp&HAqKf!Amc zud8Q3Ur&Ey?Eb0ieAlJ9WVTHGY`KbW>U#49!rR2yLs~NA=ZI(DKOX4RGS_+g)$5f$ zCJWk`W**nH{Sp2;EA-mTNzthS(*nOd`)zD`Oyy`t`O{y&+SCqQ|1Wi-SLWOS7b}VQ zrjk_+s_nvWEZSmAepugM7RJlvTD@|@yemuGSQ~kcd!7saSJ3gU?1j^J&rOF67j5!j zKj*yF;&o2`<{6JPMQ`3%7R4_sEH-D+tXC486{j>Tj{TPI-P6H0xyrWPmYIEJyK4CK z_}It~EUntF4ZVui=zcNd^qa?VqhTW#+u^t6uQ#pV_1&c)^TM%)d}rokle6A^2ywc9 zVxtVZ1KYjd92(zF?Z2*Ycgo}0`89Uj8hn9w>o> z+B=bT=7Q)KEctUS(gYVay|mn+KjrzwlFKO)1(TY)F6eN*e=c>zVe^#2P3tfCyS49< z*}t%Kvsv&r&BX;AhhHRc8^s)RIeCsnRk(4v8<*?4ZHd8E*4F=O=CG`3Fts&vFa7q+ zGRnA-A$;d~(|de77U^_s7hgSPP3Lu1$wXeAJB>$o`gXPDn;IVS{Ie?M=-NFyQl3p| z-aX;dW`m8(m;QM3;_vCRoA*?$U-aH^(qWrJcNVQ*&DiW5@$l!ViippRi{$k`Zu>YZ zWUYw3`(8uW%cifmGnuD!Z(4C&;pl^kYucjB%ML{ZyErDjh_^9Y-l+f0D5yNqWlxmA z$`*enEA;^1rFt1J&s}R^xcx?q?`wy0uH(enJpI#`Y)~p-tkyar*dz8SKhW;nnYhzu)<>G(zHy;05nBx?j zB;~Pq`QmF2Eq!VO+Wvn?cvXGs#QF4%W|Llq&#H|3@mc7b(wuOmBXPP-i{}2{axQWG zoN1YsQ`l!0FPT}rOk~NqTO~fMyepgg`jgY&?z|$9@3U9j!^U@KzaxvU)X%Akk6X^1 zxNym1)d8OCa+9piJnR&G^tnXmSiQ*I!s+i`a@*`N*Ed?)y(XNWv#^o#r1GI@ zX=`u3pUAw?&0BQJ^b_w@U3*jyuTD~XwEE%tT`uv3o1*n3OxSj94)fCQlw4UU5Zs>` zm@+>vWdq;Bf5+qeHovesp3(6lt?AIO-x2?~%q&q)|9;Pm@v$z;*ONilp>01c zBA@a4jb)23=+1A;nRjiQz38l^z^n$p+g{B)r%K{|x+rRtF;V>2`TP~e+ zbK$jZReKnW{HDj`^|*FaXuOJMaLAasMx*w~$9GTc#GYSHnOSqlVvc-P{K6&DAI=my zdy5922v4cA57_FSV(!E!_FiPgZ}w4Ilg};ivzF4DqxbK}IC>5B?Q z0$GyXi{A=*i*f$)Qsk6fAS1%)EA}N~K@CsKd(|S>75n3L8XhdH-1%iyldQjA=!>6G zpVzkM_&q6;=!?~v@MppLn5W{#GyR+R=5T(Ah_jCPzW>wW=gu!zeBCE1Y$~zs#gg7U z$#qdhO+1S^_wCPId3X8e=}IQr-?Z8{2Sv7Oym|1Wrta@9uamdDN=`=>N!j(?@wj7n z!-`v(Yg2(t_Y}#Je$B#FM_mHG2H%k~d+1zt=}EyalaocJH-x9hc`3|zYs>Im-@wLj zVVw<6$o0ETMWx*96HB>H*Tzjh_k(GJ|N0}biT!n+3+CDe7o;z-yTkQGQi^?>D7S5U%a7=mr`-ywMn~F?xKW}YxVSn)4z5Q(EVdd`= z&F`I*yD!YU*Z6mtzTTrWk5kR3m8W@_Iy!Dtbz#cj+0)wg)#*?0#X5=4hi9x>HqrlL zpR4gP88(?i1-rf1?&zDp?!lz{bN_yQ`dK+~TjA`PcIpjtmUPOVl=xecZE&!{Z;$rvp42dZO{AUDzEj2@ATItr3XSE6*&J9-`K^p znMGN=;mFdA3^&8ob2hwj4qftx>&T29Px#cLMXvfXF}LMKS={`!jbpO2M3b9QzR|wd ztd0hUsxL@iS(G-jlChPmvG)j1FZWWvf<$lEHkqZ>&cgkCx|w!@GP5NOlQl%umZu8_ zuFjrm)b{&>+3dyg`lr_)V4pNM&X#ZHI*EgoKdfgjw*C3`eO)qxO{(w;)9m{O0?~~f zXLNQ?i0l8=IDMJn{{Lr#gCpd5%0z1&WvV`jq~1TV;qK)5a~FC#&gxkA$!Yr zXCEG(t?+qu}d2VBk#;eU?2NKmC+QzQmj?;8ww$dtF*0&|&(f#aim$ ztVGz~cU9k3x-whJmeC9(iZ4dnaRXWBtb*-sfG{x9)aGPc&tb`QrK@ z{~>olBwwn5Mz;UF6&_-T`#1Lg5a+t|{rHE)UaQVN{!rt2U-46shpc{kh~ceczqBsu z7Cf$hZ@);OFvF(s&+COHQymX+m6*D2?lvrn7IEjboN~P0s{Ze*ko(t?zS(TiTks;w z?pn9)jiy&;IwDsIY%{a&x;IPwVr$Z-8||IWmx^=06|mjo$kqBOcc<^K)3f(Z_YNGM z+&6Ja#*w*}r2(S%&#w5vn3g~7Vs87YM)q=sV&nVD=YRgTK67#N@r$0<-yA+Q@j-~6 z?*U$}*^TPkHYrKQu}<{jX9#|*utwsf-cgwypH|y!uwMP;nfU8VbtOi#T{R!n?(B)1 zw^!lq{Byj`QF6QVPfB{P$XpsLx^8dP*Jme<*v+`Klr+|r#4;Vzf&jsAweYMaahi6 z&1LK5?r1wN*?C8^xzlh@0ejm0nTZqM-V(l7wC~iRq?Db0o)M=vi};<({IK9izsa4) zby62?eq{OIwY+JXD;ap-ZKFY=z9cHoRgAl z(K)VYYs)+9xm%ywwI^#fG^qT{?ekK+wsG|#Rfem#9rtXMNmzStm-_Sg|G%y;esO$u zuR&_V%Ojafy6t9c4_-9IhOwydh05P+R(}_y&)K)jzOQMu*bo&GdrZjV(TWvY z3sSBbH>>k)vY8f|GLgdGRZJ&Zenmd zt9`$A^5NUEm=nKQ&F{o1=q++^o_S-|k6g=@&&>-0&K@}|z$ex0&gbE~ z#J_CKimq63SEY!A535eh$@Vg|lV&krlvDD8V@K>3)(M9h*8eO}^L?h>eV}TEUZ;b- z)$d7#-&ALpO7-oSc476t{Y&o^q$qCMcC5j+Bu`2Bo8oN`y?a~kOj$Fp$td8M^&{Qa zSEp3p2zX{B^ijd&#QPV1lm0yKm5f@rJN)7aC(~JqH_|MgNhI7BzL+O#6}SAs!)a$P z_?)$fV&N70k}EFclM*Q4x?*3i+Mz!SHe?wsxa}b&!rt|)c!I?(Z^rjp4h>I&cw8j) zpRzM?EV^^PFJu08gRPs@bhS6iOV$Qk>R$ZQEi9Q`H?yF3DQ{oUREx-q-xlkrdq$j4 zXquQ*%e1&lVZBmuwBh;n*F((`S&Iyd7jPQvkre3iwwlYl;#nr=L;jg2oazUJC0n>! z+JzICpU${i;#&T7{i^D7@2pc7pFFFzS^dz?%mW%8D~`l1P|=i3d3;DpKKjIxfI`3U zXVyxR6HX>=()*N_oOs)#=jaT^*_%GUeqhph)JiP=Sh0Ciafha0-ft$on?ItaFIi|M zu`J0lHis=PzW1ZG+_w_fQvP?Dq=K%<4!8)_Z*Uex+ZD6~kj8=^awROY~n(7hP1@I8%WCV&B!z zb=wS&aP1dZ;yLN)(K=ble@RAGA2b$S*`DDR>wRXG`$YHK{7jzugl5OPGS?Cl@*aFo zIKrJ>_NZQ5<=LB?<{twc`hUMySYyE@f{_w~9=ANcBy_f8(ls5UV znAAD(et-0wHA#D4g@}GTQNO3!Z{?|{-D?$&{7U+}O-W8_tH?Ir#b4I{R!}SHKD1?H zKj+n#OXqk7&n{ZK<;TCGTSo8gCR|K9CKW$}$4i_m)XammHB4#Z^o6q~oV&0>wD&LD zjb9z&)eD~ANtw91#3*)(rdno0U0@koVEvKXhZdb*RdQifxxJOB;i=MS*+m^Yzgiz^ zee5poYH#uNFo)c{X{&patKWw%aXnanEhA{fJ)a4oGgL0`iuus}Y}q!e^f?>nF?IKf z7I0=H-Z>oZyKeu*D{9PZmXv<-<_JwYv*hxXJfpmafhLagd9L-b>G_<|T~!cd8OU}j z+WPVgmi;N;=e^qdGpRd%31Yq4R81bNjZ~j<*V91{+)VK(w9^8+*t0e`x(CH#~1xjIM4K6U<23A^oBJO z7Az$nA1FHLPB>L!z4YA;f19-+rJmP<}&U4LtrNXea8)Tye`q&btnm^Za zxx~pJRMK{{`@p2M67G|eUpJcge^pEfOJr5c+G4aoJJc(Fajt^#i>K|=UeEhg68cpB z=B{mrCWovJ>dc=xMZRYLjVq9bz4ik*?;Nw=|`1ezsvr8 ztGZ?`VI6ejT#&@YLg9qg2#eX?cX_3j&b%b+dPXSl)QfAf>!-Jzx}w1NJLlZ0HQts5 zydj|tH>Aa`uhHGz*L$qqt7+!iD-HkWh2(O`IP}Nx75IdeXE;61`oyG`Y<;l*vQ@?P z%R5iMmc6|q|8wQ$V&jn2?%v0WqOOZgQn}J{RHDsG(<(94@Q*;X*&^k)Htrkc1CRF1 zSGe=q?a(vj$aNEz`drWsSE$Wwd2~KIHFx=(nyR=BGmZ}W8% z&2|5K^ArMRF5Hv%R>CMqIy=TRa%u+kBBl5!IO{RC}?t1CYm}TUw<>MPE zzGv>@iFHTVEJPU>U+-8Ko4(+4kVQ1THrikiv z&YQcRVWm8C^k3CT73U>4!#eoeGoEhkNN!R~R`BZ!IkPV~#E?PmMQLCz>v@~gVO#zN zT|dpB$Tn@7>)yCcjzVF6FRL1aCmjqv)jgt_-Y%^gfkO&Up>2k+vLRZh$F`y z`d?A$(oZ#YOj3x^wc%6ch+nGrXhNj7Ln&W>;tSOm&$#Apj9jhr@Sw$+CoacWyq>e> zcWm%ib4oD2+6 zekuFaKWAb>{jRsddyXo^b+^BCb@5!KhMXk-45_f}tPQ1Ya_3 zfBZEo^=|!70S#7;n$A=&&Baw;e805t${KbRzj2Jbc3tG>7r(~c>5FU6i5xk${QVb` z>k$MK}FdUE%Ye&gGxPu%#o@tGO>^?P}TKIf%= zs0?C%W;kDqm96Y*$KqM(Ti+O;n|=G4g;l1EcJU^5$MstU*+0)sJ@EeG)IIlYrM7G- zF?kkSetzj+m(w}g4(>11taB1C3SKhrTKmjRb*Jc)Rr`;!)kWp4+o>6GqT=%5By6yPLT{t53#TjPq+g9qAqk5{`#iu`rxiQyaxAaB!i)ZxCEq$2!UPi<) zVByh(v<=CIPc&B?Xm`8L6=$(_MbrsfuWFHSaOJZT3dt`X|MWTO zBU3Takn`n2?^92D16`*bJ9cot|HGgY6|;|sKk`k9(eWx!U!^y>cfqbX(-ot&B#bZf z`F@NNV|D+?A#Lswv^`&MZR$O)m8z{TZngA_bN$nLH(PKAkJx&f;!qj!Yne}TJaZW) zH%~QtTW>7(Ab*kmo1Lqz_53mub~)UOo$@p*XX1CUOM2(p>{y~^inVewZ4jN8qB6PT z29wNf)9*K89A`*8Ymk+RnJ|YX>BtJ_;?kTmv+pigJu!^!R-faHmA(7ce7vEvmPt=m z=kI2}Wm+=F51&4)9)2lbhrgw%FTGG9w59vBTXdAq3ga)+Cv8^kbGhVm=<$SY@z)gA z@;ugM`+n%sxlfDar(NKySiP{Z-$zSuUPb-X+zZe6TDR(_Z`%2jX|a*`A`Rb))iG-M zX1!A<99r$h6a3)weZEsO4Yz)>4G8>n@%vRy-GM!}Jb4{H-H6^fi=Sht5E;DwBn+7+J2nQpVs z=x2!+1+mQ9v(aPat3#_rxb>Z`JU=3Apt|k3{?&53g+B|`t&9E!8r)}!wLDjHVo^i* zl+8Xu8=qzNv%c8OVe>WdZQDy*)n6x4Vmuhjj+n1Jwz6k)^?e3yrQHiPMc9m7(k3sK zDUqpDwrSOz(80K3&S4Rc+9Z?c#qqjj+wbWtm&oruG<|VIOW}o$x{^z?L#HZm=$k$K zS9|{7u5DA&i#c0GelN*7d_^hx&=kwkB`Q*#!jp@YH&#bPg>|g&yYQ^)|F3@;Z@J>^ zJZpD)-Foz!>tXCt&G%PKN*#qfHGDK?FSy+!yw2ohhsTD}2OXAI#b$3^Xr*Lt?X@kY zd4}ZN6+4tZ@A;%~l6C*t6P;o#FGY0s&hYk_X2$H%EjgewQFPJ0;9@J$@?fr(C7Pd|7yvW7sAc*S1NM8U;Od3M9n&%S1@GH*^XW3 zk6+sHyXlo-W7! zdU~^N_ty=joNLx^_j`6?o7R1%(_0S*m7dyh`)cOziL19UY|fk}N70$9(8pby@RP(W}y@CMLUQNPMsT zv|8~(RwsX-@tZ4R0)1c3l!nYtIjA>rr~i75y>pA-M7;g5_4x@#v!LSq6Hl)>$w=S7 z?UbAumhTjPeA>hdCk~&P*xRu9z_)^^qRnqKeQdNBP2Rk}Pos=+`AQZwp}(7z!&IL) zRl3AX{c(URa`lZgmBsQZ6MJNvlA0MjeKv*0eRs&P*0kFg#;|FH>Xy2{IahP`7u7DA z&Az@MZ^hDe2e|lJ>S}*3XNXtfI_w?6IP=_P^?BA$JWSp+uv(OD5Qu0y=$;U%rhhK( z@6VsNCHVY5KGJgNc6#l-^g`ZrRi-OhCl$(9EaZs%D0edDd|Pdv&$7KUWS*Q*<#*d4 zp?sj0-`-=3{lu#Fw`>~A)-T{xj9vSv?p^QNxfXM}e@{MqY?I^}JIDJOyW@h4!*5q_ zk)OLx`;2-cqgvp9y%}HoE6b!$et73_^6eHbk5^CEZgwloFj}#C;kp^j4eVAwF0MZ$ z`M;^Tz02y!p3`58Lgcq@?GZQ zgbab?J*DTAX3NREkeC0u-Y#!nQnkk0lv5pz3*Q}0I(^#ef7uS!xa?$Hp-(IXgl*iX4Ru+6q z?Fo;-rg`O;w?vn)E%x=jA;=Ryd1_?dag)O}T(4MLUzKhBx7y|}!+MuvzK5MyH`nx} zdkXJ%b(P-db9>oJ-uZsi%r%9vl?p2GF@*vFPkp|1^@ z&$h(M-<|d0)uElUv_!c)Zw8b+P}=yEot@RAkiFYuZ_To@E0(uDrC*iYv-RtPy=hky z|DCa$ebP+h#K(>0B~}-6zFx6Dv66ZDOC^cYkRvY9tS!e`@7Wc;{J6*`t$FI%btm)^ z9W6FIVToMCKK13*$+y4F>#z&B6L^zrL5HEW^@pru%YsiB8*OjPJY9Kc+UsTS#5OAx zE)%~pZL!w+Wl!g4Iwx&;t8I2Ds3x;PS@cuZv5#&gTefLA3w+v@=)C<`%9gqJRF0Y+ zubg~Mk^5D}ciUG(aq*jyS<@z*5bgZ2Ln7{*i9kfzx5tU`+0#YCUwWS)5RX5G#ilczbkmiq9g$0mGoUUa5we#p@h>3!AAeJb}8LtR#hOyyy{{#5G3 z)R4uAb>He!LOnZYyYj^(Fi-fy5c+*xNiXLq_aj{G=d4S(T9}W$Ji(dC#H;5~VAp%f zA^x<@I>oPMeKAiyA5EBgTj_PASX}HSW}zuH7D5|(l|4ER<*6K7AYI|Xw9V#J?VKkT zckgDrmHSxX*=3h@X*Juv<)?23xQ70lq4TD1Wy*X#mCIG9U5_Q)WRBN8;+=U{<>tjo zN!OVH#TWK+s+}#0s4QOk$lQKU-Pier96TbEr|oaNGB11TA|t!n^16?|o<8~V_4IW0 z_46_hy}r-5<@zj}>VL=9+?@T}aJpO5^6ZTQo4K8(ZqyjGCV&0XXLE6$^yBlp7N*@c zn{xH_TI;N|cN%L`W6oV@vR}D%mf=d*s9SG@b5=d&DV`^7=hd;t!HeVk#~b%zWlscK zs1|!QXJoCmDtx_e;;wrizs+qwcGIKJlu4m`?ZxnAf3eDJMXcGn$@D)K4129vCZL`@#X`E{37dh zCH8M_9b^+wj)VHW_uNQM|o?^NvP+DYG z>>3M~f6hWb+HM!E>FtTo+O+dpf~L*GX(DVcA9rsSmoW10wRTy_%EltXDkY-U{8WS~ z$!zhcgvsl;^hV$p4JZy{lsx*KksoO&LHYh7QgNxpo(@=w?j zE|=)~E;DUjhc&YG>giAH-nHDTi}>>>$%lRYzt6(e_MEHlIQjh9(5XCM%)_tx`|F^o zcdv3q_-tMKXWhNmVO7!5Tehjr-MXsTtK=r%tT)l&7dy%iWu5)Td#STH`leOr_XZ;s z*`%ozOR}RrtT}UNuVd0$XSQsn9h+?C^@KckygS_@`@s>9S#Iq=!x=-Gf9{R`ym3b6 zg_z`teJ1H^XKvQ`8nY&7(F&)E(za=Vo0sf5YrB8Vw4+5SG@>m`Z4=)eEc~eTa z-@JO@w_oA^OuOkDsvpE3pA%g&`Q1yGruWxwtIzWboU-T{m*EMq2CL=qSKgUFpJpMN zyftj_ldQPjaN#~Rl;{x7V@8>T(emW>mQ9J$ZLrm&)_8?VXy>Q;Axy#%<+7!5z4zuma zOG`->++F#5!*-{Lrfs2yt3RI4v{=1r6I0vfcUhI8jQ8tTbjN)?o?}_Mk4aU`!gMw6!uGlwCxvp|<31Cs&%ab}sa@Tr#&glvue>_6tu?f@{^Qk9UDvNt zUVrvvzsb0w`u~nw9TVrntHoS#K8jcWmYoz3D`dQSdC3whQTv1$Mkh3+7ie*BEqs%9 z?uy*99DZFZ8Hx1u-$H)0_Dx$7{p|VHmTQZn-CX=8rKCyadH;^g=}Ng7S>nAt?s6~F zRg>SF^_wyTE!QY_XsRd032nI$`@b+I)#9qbB=vhqIqw-~*42dRpSYsX z7TI$(^u1x2*!1Q5uV}>W|9QT1$Go>^|L=&}cy*cX*O@;Xcb@EQ|I1{+v0UA*b(Y8R zeGX@nB`+4A{;>EyXVctG%qwrjZmDK7Rw?iKofW=x)*T5Y(~PZpS$t)S{`hU2)njr( zu{*18vC!Q`l{%s^%+K8}2Bn2D$Xsli{CnD!RhH@RRHFZ-Mw%b^e4a7N@uRP$u836c zlLHG)CHOu1Z}93%^gmwx*5lK+pWn~N+tybXeXRL(ygXfh-q!=iw#3h9`?22jtg{n#&@y|D^y*=aNyPUJPhd-y8@x+dnyS*1L6-fUG zHEB34Ql@p-DOsDp+h)RD4i5>97pg`E=k1qD?#?^+xLYgTUU18+W3w*KZK~jRvGL!$ z@w9J5aGO2T`;E-gxrD5uAM_vC)3x!^_XDb72^ZF!^~>M%rP<8qweiC*SFXhx>ZE>X zza~)Q{4VazYTgr%4dQ<#>|kP-TMkGjt`%(&{8b_v~X zy{Q|QPHAZN`k|jH`0Z|ovc@B>=^_tTSie2nys65evvZ@{fAQo!-OrP^$T;s`>u9sA zlqbM#^X0c6moD8hn}wN4Fm0ymod#pKvVf>F1uk;JXB>Q=G+uR`dndL@E^=DIe}4QNnR$DE@pX!E^rhdowcjtX|IfJv z@v8*4DCg#`xP0UKtL2W^kh9}iGwT?!kYw^$JKOYmvpcla1VUIr4n0s>dD#@4VSkyFzU;6 zoqMstz$f(#UtI3n`DcQZtRKyY+I{rC_%VeKH9|Uyf~k_1kKb9m#O~n5r5kdmeXws! znh{^=`ot~&Aomwzo{Q1@cP%-0_?p_Cm8HeMXH=|VPxseF5Xq^c2j z2gmz4eECzC$WO{XygSs__P+d_WBY1rE57&FnwIFdE1nJL5lPySw)@!9nZDez`rQlS zm6!3vYWeR=de^9-LYe!)LNulsKGyLd45gIns1 zck_%+JymoL`BBKc<<##dZ@)kP=%MR#UnA|JraRwe;f_TwrJ_DPUn-n@)bE5&h-;bC zvv-fPL|!(ZwRzU$rn~jgy#+^qIUi^YwVFIzZ0@qkRf`u~C|5d-Cl2IfZ^w>FF3u2xRBJN%aA z{U*IYY2FvoyA68SmPU+?fy?$I_Kb3(~5$Ktv>=3T)&;%=krcpXLCBUQrYsW9naHcgFIKS zE!w5O_Q^%jBX`u9OFcf-1=ybyJRB|jKcw_%Rk5tj4KuD8`I-D}ucFmH`_xJD_MA<& zF5Av2{VhfJmyE*NAm4(Ed)@`TzH+nGU(T27)t+SnGp}#t2zS~rSK{ZPjDHcX>Z!-B zsc2Mm=%ojD$CeqY@wi|AadV5!q886^yWs1|FLGQ;#3##oHm~WwFKAxUs#Fx@e`Q~q zZ0MSaiMKecCv<$dCgk@)SES+dcAp;pI<0f&K`D7wo+6u zW%t(yVcbhiuAGXP9j?E;KL7mF76Im0?7P%oPQR!UvNKs?p;HbmfW$Mu=e4h{NFXFH5$w3KMrrY{q@h+Tdys0pGLnvuyuXapQQVH z>#ToXK6$%AZd>es8H-IP8QjmyUKGjqz0JXsTAQ)c`2FG&$8{N4wKmOMTsYflc@g(Q zi;xrI3({DQohd8%w?byM-ZhEU1;QDtGZKZ+x&2weSp*;lKVyy3~0A1M5?FBZkE%FaGIUpZst+>$#10rP-ge zrX2gq^!;|WpG^5X*SVrP=51`br-}mmFH0XdaDn&c39InDe6Oiy$M)I?%gLN*5B7TT zi1`)!lC})-?}d+K1^fa`b#6^s_sa6v>?Ir4=)Suz!aCt)7Kh(HZ@cUL4ZI6~O#k61 zBA{gaO}1Mojh*{(YFhkHsRfL4CqJkaRjR8vskx?^MOH7vdMEdj#Rj50hk7EqKN~G9 z^k{Qt3kN5!k?Psi(Vi?eW z#Atq+Hz@h5!Kq1K*j7p}jecrlp0U6E-l3~)E2g??O%U&1HuJ=f6&>91mPyiVy_^@t zoP844&*_*mpJ#%SHD92st<@vJ#1E!Rk4!t;swv9%c?CDSiQwTYoNS_pS5`*&&O3L0 zC3kXd#MfH49RaIcX6vig-3traUB2>}rBdLuqV=0u=ZM~lSTn>QGjiQ1`hVnhW#cv-q4S0JTZvqT5vaAD|5@0 zsmh|Wo|ZDPY>c_S&~zsE%Gn2k^-OwOl->#IXYEKn{Yy$!Wc$+>@3d7Ip6C^SXW4(x zwzdAhZkOz_BmWj~KbB!wxT1mOT+65Ircb7my7MG9a-FeI+GPCTAOCS-p$K*1&Sg*L zUND~2H%nyQk%q6qyn9;Jc_#bMu-$KyQ~sr}FRAB^|8vu~QX>_|X-`E#s@zN~n z@ROGIH$}76@{JR&NM(v}&s-_MpQU|$*ZW!ZX>MDN-ea|pyp^`|%(}T}XJp&Rx+@eX za%*+P9kHv$Cr?Q`5EEOy?px;H?T0*{3aUBo4DhLI-I1y?aW#wbC&kZa zjSt;?we%N@vu_q#&Bg$4&rP#j1d1=@OUSJ``cN_I{edePy}nbs-2eKnJj2ZvU43B2 zsW9`VbBd1BHB8-VXO_=dZRlaUkSR%6a87ZG{>gUd-6pf1N3ym^rA;w5>$H4)_c(X{ z;o=3|H49n%+ft5|d=cyqou#0as3Db*G^^CrZyMj4%xP*fHgWt=36a(`sXW7_;vlB7 zJm+oa^EUw*^Rg}}SRObdw?edsZ4>WR&0TscbMx*pUTvr`3`&}v(9im1Pub3z7oxTc zzw@cgxw%Qf({JZOsZix2wx=zVwkVd0XLc^jJD>LHjGI^F^UXRDl`<3W|H$pzxl=P` z?dxM)#ri&vQk;)S_m;<19Wc7e>&_sjxpOA_dq1N+S6(ksbMo2zCbZxHpGy9ZbrTXj zyeHk1{jpQ_P^VMd#7CC{_1$N@+#K2@V|8rW+p>{=( zZ*bW+@j%H_!|le?cF8Kd@+(e^Gu-pf=EpLrh_$C5E^B0LU&^`beA{E!fJNtRntD1z zndJ|ETOlQO;?1>P&x@rG9k#hNNm6|t^FHqXw^LWouitMt-OdqvTt);MYoIStgW0En`_0fEkD|^|K^rOF;hZsrmcARM67T5sy(th zo-oPU{Bx3#-jL_?Y0F-#3DFZwV&kv6JU`j9N&oq>X{j?+U4402^rT{SCcfJuH1lNX z47SG_$8yekc*jmXW49sw^`WT3hjQFJjwT;UEDvuqkCk}tw6!zMLx^!*lPharr#oAB z=1HkbEGe&hFVv~<*eSnXb}T1gR%O&r@jE>J>oY?O7MMpGozBVG|FZi1qIdgUy<3*^ zTrgia?eF977xqf;Pc}Lu;d5-)3F(&;#TEqozS!?@asuS;z38x1GbH17GPyYwdW45ib{m#d^1{5~}4`GhFul$L8UZ};id zTsB$#>&3^%*%BwE=02U??F4VzBi8FsmwX8PjUZ zZAGp>l?@Ng@zws=?0Ctz)PL9#vCqExbXb(h+nZ-(XQi(=zoT$& zvE1hgvWC@v>?-tQ+kb=zSFeA0=4R6#j-%xZcpt5QQQ%>y6)2Ie*|6=}nT03%HDn%z z-WGiF+KlDrE@sE52~S?%oyc;m?nla>(3~R6^PAY#m#yErSS>Ya&RK_m%lz`Q?E~~Y zmz?&Zht`L5-9xB9|f9bf)5DJ4tv zZH-~jdaaV^yB#Zz)%Wa+7TVQcW)=O`MPd)v!WerViCs60%P$=F3Hef$vPJ9$>+g%7 zo1Cg9+FgoxrX~E$|8h>BIg`9|&$2e9&-^P*9&Iptbb`6Bv@J{WNtgcqe7l&G)1qqe z`?@y$l<_@npLT%%b&AWyinGs)R>*GMV1L0=NpIiLRKa7bT&@Y-P~4Q(!0UG`PU%Ig z1pB3lyB2O(uUKn%?&9+I+j#EWxZqg1aajj@+tg`MS>cshhIw+<(eHlvUE8@m=VywZ zo7uY0kFzs&@6O%M&VF2O$F@y}R1eSZcSxJHw&*V5!-lQvC;L$n<=hm z>Jqk``*&dW{_~sMTqlR6-}@~+=iRGMj>>YJ<^iTE);bM4u3g?D9h@|CN=?cN4yU{& z3YODZ)errdUw(M`4i(wxkZ&TMXEaOWjx$=hmcD*@kn!G|myypKR=X8_znj}`bGfU% zQE;;CDdY3(n}dzsaCxtPq#Yf7xp3mLJ83JFatkN6Z$G==O?*!3<*%job9qI3nU@@8 zXfK`i)4rqpHT%^y7nyf>=sY;8TlCYwIIYoR;$`--yJzayc0@ftRc75?G)qT9&wS;A z1g4Lw21NxKIjqXYe_I~Bxc7zmZjltn730|7cBYNoN$G;U8E=!=7o@(QwfTOBoecY~ z)GeED)fml5*IPe9`)BdAwG(8P$OjZF-QRT7G9c0DnC8r;n|A$|vQAwnZs%PVke*U~ z&cVK^P$fe6r@((cpU%jo-yd7gI2Ev`d7ZL(h1jp>A5`nJH@C1wvS(e56p3iO8 zo<1t2%(bdP|L%9k+j+%px{NASb1r{l*&=`V6Z4zv^htqP2grE!S?X zzr9E>RE)Q5!O@5dR;%@X|FnqYuW-C10eq9v&Q=_K)Qbo=t85yGK07 zWMXgaeV>)7;^@z%=EU5kU&itGKF>){uN`hZuP<>aJ#S5!Hh-ImS*7l?Oozj&xlz*{ zGp}&9&DFD$?%Cmfo3k%ulVj<>EN4z-uDYJf4o5$14vW=3UeL+=rQE3Iva_|o9LC#4 zB5E_Q*qw2+yVf^{cj3`s*(kovf;SrbPGkvO{9RglFQj3fQPvT`)GmID^d<|9LkCo~ zPVg)eId<6CSM}y8uKa6L>Le%bR4BYZND)tK(>241r~xi)xo*}mdh zpKOwrsaN$XD`(V(1%{$h2jdj<_;U^z21xi?q}? z^UCaXIq`SOrs#vwPaf;?{EXbjwRG0e8Fz2$)5X)*$Io3n{ru(i^Zuw!tC@OH`P`ly zn+bJyj=wpct6}u~`rTEY2@kb(3a=HMQHkWb`N_Z?gEw7va8 z!JA|Yo2k|t9ir_S(_e5s=Q%agibb+$>2-sJ=TzfNS04&bJ5zcoMc#eKi{(G=if!L8 z&m)xacLUe;zLqDu^>0cauUr1T>F=EzLf^PIPW$G3>#o_IpIiSjL|nSP=~uvdp@hU~ zl5RzIZY_mnlfpgoS3Z95ZjyP=4#PL64n9g$*tJM{{plIcy=QJ~tBb11ID9$#j?zSy z-A`wwq{LXuE-bvus>8fleQW17iD^3<*52lLvmi$I4VSt1E9rgLBE(lLIyh&B=`9Nl z<&HnjX$)Qq9~#Y?TG1bK`c`I=mHwg6qDm&K8j4;-Pd;CKS#|24_WQFMH>Wo6g#FoJ zywOMF&20yJp>sv&njh{sbwWj`t4k>-g6lf|~j{zNprk>21ns+m>G`^witu zd3H$H%<3Dbl4mxoSbO%|o4;>AExvWc_<-{6B^$Rsk=PwByjU=)MoqPC)@Q3r#%vYV z?Kjq*aoVPKt@i3M*Si0|HNq~2DLq!*>ua`SWdN6os+(VR&nAgW)u$B-_$Bx5W!MoK z`MgF+d-v>#-#)4r`>kcXm{{bb^KIWY<8Sw3Uuz#Ya42(L_5+q3LfLt%LabR?@+;Su zmmYt<^ZTtgi;sMjx*z+wGI#U)FqO)?yUiRI>}I~+cTVR@Si$uhd;0!ptXy0hD}2uT zl3JU^q4?*APVMvHOTDLVQ`CKHYwoWQ=|fDa3G@9Rjx?YnR(~Ek7mp6 zo6Y;a(JI&T^ycm>a#_djE@teoUgKL(d&qH(4P(5E{rd@1a!;r!t5o>jKANVzyt6b& zSEHDVD_r2-wzDl;<7RWMu~oaXFKfnH_BA!94>dPgWpUMdNR`gf-^JwjN+)NR&*CMQ+F$b|Xe%@Y#k%DetNm>rTj zK|0~amJg1+57zDJUOp#addu`5_qIDt*}GITka4l{Q z>enxJ7V}ek+;L>DllPDrt*~E{Rr{pZ9PiJiT>>O?2TX~d=ZHnlxW zIhhmiwZ=^1*R~j4Hme(TZ!%vBsb{V8PMe_P>+qvOV(-hTE7G21?YY(SZ(GLorE-QV zTtA<^x6QkDWzWsld65z<9cOMVlK-3(b}xu8!)JqK-#IS9Jl)0IN;6b`%$ymd;PGtA z9fhRV%V*`KY&ufV&A%)4VUFA)Tantyev$G2|E*TvZyI>L^S0{t)qB_v&fZpVu5H<^ zEhg74BCOOrK9c=aI%+4E5 z{;Oe?IZJE)y4gK->^nqyekH21ghhp1ndkM`aY0Jcp|0fyE%|+m)gRygr)`yWBVpkQ z5w-c3(&SFayZ!R%?={qxn5pM^+l6`h^<5vXUzqSYbybL)|83iZ?dhF=+37B=@stEz6?KEd{#ie=j!2oN?t> z*tCM(c`DD2!iypdRY#}XQkUz@sa@6e-gDKC9X|>R-M_x?e}Ba5&g`~+8P%P0JipA> zpTu@9Em85nquHkm6tY7mE$0p4oAYkh+u$QD&J`6k;k(Lg!ltovTg-C%Jax^Mzd_cQ z>#a4;KDlvY-Ut4mY9)yS*G};X&g{(j^4M_oq?mta)+Ner**TT7qv=W3!?w=7YqiDi zE}gO3xKj9Qdq+Ina?|{Ku3yOEIqrA%c%jkRXqSzW z!T;x5rfm4LV6v?Cf(YKKPsfd&>#d#C`o1KsQ0*~D&|dwFdoPFMhJy@;@5o7cKK<dDj3_s8$wUGe!{6A%BtWp{4mOx@C!{B4uo&6!%d;v2rV%s2Zo zd1dA~DceP_3QrtfdGAWeQtQPD^@secEzhpMUimotY1*_k7wbF~{0~HKmzMTtHfk() z$bA=Tv3q8Md9}i*K$wC@)XO$+oe~{fFH|~j`wM7h_;UPQbai7fpRctE zU&SlGBNy2DcrQGWbe^_b(?w_3-9oF3RI_3^))O{O`#SXEKR!sfBJTZ5_F zW=D%1OP-9##O;y0p4f@a>^Z8LWm5LE#B>R3Zo1e)X|d^E>KfaUHY)B5n^84sr{nP>*wgE;OIzQT)&)0r9ck{r=`@8$jKf~QiT8>0f?2B%x$oZG5VZ8^d2vq}^x zKVBiydCoJ#r$2Q27?!%RgJHEnmGQ#oLVis$H($sY3fwdkT(?4H5wnEp zw{25bhHhuiwDSFazEN9!YpLDbXt9^)BVPJ6oqOB0dV#pumU(??DV)WNw|yz!a%)<@ z%l5ldX7A!!d8)9)kj-+5*{pOexIIrPvLvg>HU2u=J z?`y4f{GpFtJ8LIpeCJI*9lKekrzw5MfA+J@(Q6f*)i)RV+&XcIZFlG@|7DC#$7UT6 zt7lK<{C#wNUiNJYQj{bj(LOZ%b6q_PP&AUVOJXS}$(?Cg%Ju zw^TH5*0JwGqP~-a%lyhN6m6g3K5cHp)fL;#)E;G7r@H^UzV6(q>wZ(WD*X7pg8DerBtwMEhHE#T@!p$n zT4Iy3_VfCEE6q=z_xr88!tDKdZ|UZB79t@H4ChX5IjAs?Z+_JE7nu*HNOmhAU#a8L(=*?2d0unqjo4~-;LOc;i?Tl}@G~qvBp-3Rai{*NnTomw#(F|od_4}< z?iaoP6;%a4%Y0V7lEd(+Z&+tjb48P6<^Lb=-W)X++5G6?QbvD|$od6yb~Wa$kThd* z(#a}`(q7lP)4BS+#vPSt*9E1AU%sB6e=g3ZUV8htD!KcL4}PDN4coK7dD$`9$%cFS zt#{oQI>%J4A8$D=aG~Bwy%x1YXL9uqt1NU~U6uIdYDHJF^tU%ZwD$g#zxeaV*_Zsw z)B|c~pO==r%TRc?e5+K|-J3HPzDrT&XjpREt=uQGWk*5P$@gazw}ifxYd$F7cFDxp zgvUao$ze;g@XmJG`Y+o=zSeEg7F3)YEuz)x>Tym?GoSZ&*R-qA5>ZixG3#=oRf=+7 z$wV&yqomC9#Y(00+Y2LgrpJE2i|W0fpEO+P^}3mFE$r zhkw#-MB9G82x+M?N)x{k{a#Y7Vxr@gHR4KUT-JZK>IUn775`qf`yF@H_SN#8mQl{u zfm5z-YQM9xbncI@OEMBsKqcY_fTh7UFp^sL=lrk}e*gw`}PM*Y6JqUq{1 z6Q0Wx!e&l3c(YJiR!7Y)z<8NZ?jyEY|qVA=GYJ=zFS@X=oW3pcMDpL zzv_u|ZT3;f*?qpfS}!$Nbgpki@b;z!zHhIIm$F`Bo6+WfQzHP8&-YNF2PVksy&I!fBDHbi=iO#uAETKT$v!^J4fb7?jrY$!V-n1^U*S^z0 zyJI>6w*S5uJ+W3WI_VgTwD8A2XUYmJWJ_l@h_3j|-x01OD|6%X>-palgWcWdX~|CZ zNG)j<4LNl1lAF`T{HN@Xo}V{#TkiF?=KF~P-)2_D$kO`@Jn~LQTq-`sn3^A*elzF+ z)6C4n*K=l?XBldWaZNOmoxm*nex3K;57sT_CTYn_*bIeEOK{|zFywvv`N4sE47yu+ z&e;VV+I7U>#ikUU3zwZVPAs&YefL8OV|uatjxGDQ{@wmQ&epnGy8npgZS_3m^^YEw zZdvlcBFTHX(VAyFo^V*EY+0;x!G%G#r^@NuTL}kt@jwa5&WE0f&iyQ>B;r&Jw4Szi zOPfY-2$gzSvqqC?5ubm3>&N};e52>f3LH&TtaD7sbY?By(ZYJ|$N$J~z4&k2&A+dg zw&mpQ_p>f_V&}g7dEfPWx7c2h zeJJWgu1EExzL~+_4q2~Uw|-8A#E*$OA%9%sEKb&ZU;O^uzh9qz27VEGTN*IISL~;~ zOG1gVj;fcyi+7C||EA1x@@aToeY=z2wQk{(ohOv*k`CsDPIVBy@zn3gEs4d`7iQ;f z@s@jh-{$A_^DF;;+5Ya(Y{h%NG7_%pSG)f>AGbb%>i!S+$Oa8nO`lq&b?f@%$IU!ax44xSX9JCiyo-E(=PldFN)E6cczcQ-)lay z>m&|o{Nh)5XK?=UBAq=;&WKO(o1?r#P4todh4t5;Uu3w()7xWs%qMi+`g|q9T9v9# zA`V^$Z#K5|$sDScnQR?yDQCC!%gS};r!#kU%s75=U8%BmohEZo-R37V*iSP*58^!| z^2k_jhr|=Eb5Tl+oYu$H6xwx#%CC2?Fh8W|S+T!t(v?CxWmOr|Ss{$EbIz5_atRI* zS|I(1SH|^3qwp&AhI;Rb{#z%$@Rz&3qLhoF<*hK1XkKn(l9S%A#O;Ts;pXy(7?zYgedqEcQuauuz+lj0@b-{XL+?&&n^^Kcn z9S(YA*%zz&*yoFq`=$+XuBN{xacX3lF->o8efTqH-ly(Oe>TMVE~{kx;u>Lp+sr=3 zT!5Rybkm~Wv4uZFZci7QVjp`hC;r&~Px^+dF1p-h4!OPT#Is9nrAss)th=nGzN$z4 zJNK~!O*xKO*3goTQJcf=yTr3D;xF7VFXE4C81Meu1&6-pE#i|*Z zN+F8(4Hcrki|v1Se&QVa%(ARACp3P2@@A|%!kN*(G5c_UP5Q%ptJ}V*PO0mGj9O)^%rgb26U)=ht#zrc}N%=beq) z`8S>M>{GH=>c6Af7;V|OT|K@2Z%!hY{kf|70{45h`FJfHL;tj1>RH=5HR;j^FP9G= zCri05<6HAx@ZtscJMVX8><-B1diU!0=F%9Ru7?vho%f4w+t~A|iP`r^-y9)heXri6 z6~*8GUYqT~E|Z(~{pQWn=KAOUy|7;%9Jl&~nYZe+{{{c%>nDHa^_gdIIDJ;(uWw&} z?hM^|fb-}nB{d^M_A?p6)|tYb8vVx&rm?@9wcpk-Zu^=gFCKf8aF*^?*;!%QM>JOKA*P7 zo#1%-yf8rU(&}BSrESBEpS*NyUVU=syWX#B{);RAi(l~hQkT%`8ns>CR*6FMK8QWg z>508uCUVsNyIzKS+$+BVrETwIn15+)eB86Wt?b!n#_2C_em0-->B5^OC3ltuC4bQn znKzMT-lCA3e`aKaO?%}5_e<%X#4p`MvZoR-u_)&eZi&Q60|+9MmKBQr>M`FJ&);si*a7;WVxf!0sxBo~2iWCAXoRdi z$H+db@QYdWw2XufuG~4kXGB8v(xi%_&IPFRe*S!FlWoj1*L^YiSGO`;nZItj_CBF{ z(AkL+RqLh2^TI7wryRC8DBzZ)m2-W!Lr%uM17Q|e`-~TQf9D-nm>CPY503F% z=BL9aU(SEO;^OZcIm?f4)$qPM-SCfV(x)F+7O2`aPF*TJBR|;0T$AHsxXIR_Got?* zWIrj-5%&yTm-zbPllv+E>#OhIyKC0>9 z_-I|ZlJ>LYZ0zR+v!C5K;?&r8ZPVnv`s>pB`lg>)CVlIA!MeSnc7puP>LuG6nU>i47=UG$kN$We0Arf7R~F68`#a z*FJe_p8VJFTLu?SuUD)2U9d55@0$dDe~qqQ=l#9i_vPllXb?GkC`0mZE^F=q1@$G$ zzjkEq-I_eju*gbxe~J2GHkbTQw-$K2dvjRx?_GTNz53ccakpX`U-hT15;5E-_4)c< z1%9>-T5~@B{`SYcSFZML?q-n<#`dd}OP*~n71>a2yGq&1^Iz^Xl@z5anc%<;&bMn= zb8pVIIy}33%9Kmpcl7woi}(J{KN`O7+Vxej9}BkB)h&9VDi?5IW-z_bj zmGtN%S99P8NBNh@J*}qaB76Vx?sZ+b>=pZ(!X++Wxs0z(nc*j_Y@d(V z%huT3k(Zk*`)0qrmCU@=&Tn7bd9w3de(#v(LE5BS; z&-QisfAy*N*Y7*v+miO@=GR65l@SIx>9#V{BSJOJ;tlK%x25p2Kg_mZKlSb_t+A8$6$%o`WegT9f{U-mp%XP zl8M;KJpzJqul_uG`jp{kX?kGVucY@;Y`d%9$21tO7?-9BdeKPfkM;Ox;sYp z@%O)8pFR2B>rBQ<7tNOcvHCB69bf;g#BSpB$$JFeCZ1uEQA|7EYW($C`CNJS_@2)t zFSXUuuZg?(9JP>`;lUrp9e(+6#K}!7wBkaqyk%2V6t$?IuW;o2zGdQ98lIai5%t;3 z8F_!ri>%~?&yTDMGS}UoAy}RjweYl{+JjvWIkGlwIsCshQ11cnWRuvlVOeFH15{20 zpI!Vy)ns<;GJhA9SC_QENlbis>d7yG;yNN`vro=S?@(xnMnG?6^2jz?R4I>`S`4NbA@C#Oh{dpmy+3bROL?VWg%Xn zg3~oTVe$@37CoqVUiQHD;mjP47YCdATo+d9>rGqezTxdOIi>gR;vb9^3-%bz7F(UV zz*l^9YV)9bCQ|NeORAfuw<&qM$7Oh0;VKMG{&xbA<6;n3}w1#jp4n!a!y zzg^vrf-moCUhp2AKjW=$hS6I7<;$PT-gmc`;%Cb2nOogg|4%Ym_R+D6MFpNh>wbwo zsC|_A&oTUek=ft0r3cUKnDL}xODDsMEqDKY{~NGBJNHQA_MO|SBeokVMffh2n=BC6 zdL(Emud3Xagl8H~=eJzhZtCc$>GP^1VXsr!^z$nVrY~T9FyGH7f}vHQUadw$ciA1E zqa~q1fvb1ExZUr6h0&$p@{;G*4@+PF*vd5f-qTcv`Ii}|zf)PM|IsVE{So7>wbP^= zg8ihNWgjM`G-Dpe^`x@U#qVyGKWbd~?Tgld)_fCeqP@XW_36=aEP~^KeKt>uie^5qW?bb33JfD z9I&;Z*5wAj-rpkol-s3_wxm{`L>7|mE&4NFVTzO#1 z&GodQTieJpNW=coqy^$7J@L~eKP7%Xp_Xdc9o62>aaO_A>BbqIShd0{$_9!$vi(kK zzkKZLZ+?rv9(}=hg@DaOx6S7b_UP}bjfrPn_`K-{m&V2HX}c!Q6y5o@E!N@j)#bZS zzJJ#+DMODpVX>(p3ywt1|Lkc!SHrh^+PUsgY$APoX3yZq->SXee+uQUP$h$2vWBx8TZASi*c%Ew?!d|%h9Df<++`jRx zPFEO9WU_~&@rrZi+fVFT%--+T<)&S0t-6G(@Z*vMj9mAOrSYkt;+^Eu53y^# zjE;W)V*gT?^XsQC=eK@lZOdIVcavDa)vIM{CSS4^Y`hhCoqM&=p&3_Vr$#NG^25-( ziZO2!`&Ny|r*_1AKhM|KADb?=s9*Hej5jaC1FcTQoD@^t^Zn5hug@|@N(&woZxw$Y zUc9wAIcA1uZCAnX&GCvKjB7+bCrZqjWsp+H)y4eb&H-I!y9sX>-QJQVzKA_e@NQni zPW8Rvx0^Eyr~f>f_-bxu`=UDR zm=U!I+lhypz^H<&{ZY{GvIPJjmgJNentUoBO zTr3{fy?tvozr4k97trZo^Ve#~9qY&s?6JcS_Gbyu6joXpgO}d4Rya-+q@`JapI3)_*uB zaH4J&^O}eyuPs*FiL~76WiYsQ(b%$dOVqUK{ekA1Mxs~hR;LMlT^?*WH^#rT#_;=o zbN96H?pHx#S6^;WD-%3DCGX!h|7x9lYpXedliK=r^)Jxe;+MhU)>Qk~tX3-O#NAWD z2^za)4D=Zoz@3-1>Un7jLl;Wdn(K3FY#9W_WY=9+}_nr6BxG^E@}xbWd9y=H6Z!VBIn8} zsl~x=sdJY8WXiMIUa6!}u+eI%e(cJhhn(Jg`*K5wUv8!3)rG4v)EtkS@-UdVZdt4U zHabIno5F&1CoC~h4nM#7!Ac`nsfP2*W*Akz;O3gVNa8@NMUd94 ztkcbrJ?=j&{;k<}Th8UU@VuEtZQO-#c~qLs1t$guZapJ*af?U(k6IDO8g_+K64&PV z>&3GdpXz=ZlsPA|syRn%+44n)B~HyMaNs>+AiCfXmr}*F$GsJE{M967=KZ?Yq_c>P z!}4{2sQYw}BIAcsQ&xNuTy!-pkpEbN%!k5x_aCoKlb%>`GNW19@1sKB6%kG?{-at^ zPKC`(f+@KYPc1H)`b-QoyeaoJ!{8SOlhu{jv&Xk?`+FckY(kU0+{)j z+IVToE;Gg(`4i6zrbXoH^SCqf6xZo9opn3?d7H7=*4*bk84KF3UT>UhVPLA;bMlPO zA~o$FUg;S%hhHw$vaFdeGxeyinR_LNz+SHs5|qiTuL9q zwXZW29{vo+-s^wO078HMe!X|ZdU zlid7Y^3JUZmf9KYDsh1V{w|8oj1T%RxtwIu^tM_1cuUCo&mRS*a~x}!IAQ7(|L-#t z7aiAfW7Ifm%Xwq&I2#l7#uxsMdjgt+Q%kF7?w<@WsyW&|$ zUINQMt{In@%)iLKar-(wX`6hZGxM?^C0eTMVyav!H9wdwkH5E}e-`Ucrmj;8Rs5`n z(_eYiIm~?Ruy94;f!8ZehA6L2>r86Q;p=!`m#znqD(okl5F4eMSC`a73R;T#>}xm}wsZn-?z+ zIO$bU@GhZX_D8>!UHjI~o{*5E?Q_cF_+c6TYX;?-bD7zUPHtLxY<9a;8N;i|!3t(q zq8sK$iDlLD96NvH<|dx>^^1QTW8LFo&%{!*V#bVvGrc5dFsny4sp>TR)R_3@e$=!} zN5Z-71HIN1TAV04t?0dYVaWcP?WLQh*<{~37{l&=*6i<>hhIKwIkI!vmo7ikWp(kX z(2BlC=TldgC~IYTM7mZi-4HtEjcWL`fL$@->7{lSM-RMAd3CqmT0dcL&07_&^^t## zM5^}g(w=rZvgB~vO~LX->a*uIq(0a_L$YS;v6(wL8VxHG@7$X!p{vLsRvI-=_aUE} z*@gl>&U>!htg|1LE-ZXK!Aar|SM1-V(f4GOzRq1@^qhU-PIGCTXtWSSvj;Lo5O^Vdq`%%e7+ z71Km^G#Q)CXj#PH6d0oycsYzig@gauzE50FH!$QRu&Tk_9%Y6fQYYTJgDp=-)yFGN4b?&O*{rxWDSCv_I%4=6$Q~s^j z97~S~d;gvH@^(pE|DVjLb!{uF)~+%4ey6?lxkmkhI+qpN{{r;$B$9T@_gdykeiK!Z zy0Bm5b11*p^7(I-3RLB$t?b&AWR;-$I^0KqF9rM*T35n@)s^k_|`h|7+v?o1$l4tFn zeOIS)LD!2LB5yufOc$s*`un`Y?V__gRHbT`u57z-Q$vO6jPst0p@$iNxE5lANg0SPG7Wm^S150 zjZ!%bi>>+le2Y45tri|^E9|Q(jR})j8>^Hh9y8A>J+nxBD^G8nYvJ-AEo%;DeQv*K zCl{Xx~)%dSn=-t%C7FoIdAJV0E$L#rTRvrx-|TXGyOvX)1l zB|7a4{hx4p`o^-?KQa^dRV~?9*Y@~uf`pz;(dsYLCkEY^&fomN>6WZPJnzc07q(6G zmZ)?3w$EPf_G+)+y^d=)UlKR&3-3rwe0+kJ=dRHM&zOYuGhW~NU{J--b=V^@mrM56 zFVoW{54bLO-A%k8$HafYXZ^JmG1j`-dithw*PdQ}x>bFL`L$PqbIqP4tNLtC+Hm_6 zb4SntcZrwGJD!QoVe-25S?y=|-kzx?-!E#aa|QQA`KzrFPR+Z8g$l>Td)O!L2ZcJ88O<>_a$_)qtXNJS;PO^dzO zH8*-KpYo%S@+ntKH!{Ut+;l}%OTILfd1f@Hos8_pBz+#S)P)tBr5dqt$y=^I`fiV!bKBg{ z9bb=MoE3Jqc?0to!$+}7YZ@oyHFPu^_4>ZC`ncAZUo66J+WXsGe9FZfjcne2Y)Pe+ z43bf5SGbJCj}?Ai`S{B@Q^PqI`@U`u)#&~wonQDyRFrkW&X-N^w=is;Z|n20{Cz`d z{wk-}1)*=<_zI*rlQeEfiwJ1GKYIPw3*iu#?GHa2R2=%l%3P%8W$`*f#*XXEod?|~ zw`l+1o4N75Vr@ot+WnBuzOLK_}()nk`D&Y${ z4l0ULv)?5i;Fp^*L-wM}+QX|_4m0sCKgy(RzTjJY+}cSmZx)%J;$QjqR{n_;y=WVVA-50wj|7S^~gyKA|t#-E(3J%9q?dEqFE|LxcJg?sDszxh^CCZ1iq_vUdssr1D*%qsfn zhku_l&!0E%)U_AB7jNf8I^8?zn>ugh6}P{)xty#MUAK6+#D)I0W1Vf8_WIy8ZQ(rv zec=f^Jf<9}USVK-JUGkQ`1|*{TWvote^`7zD`Reqsr{xq>)$<_P;!;I#Wa$C+V{?u z0AuqlRn5y&*KYJ(`CH9%@|}dN0~HxxDpx0NI~-^3z!v=_C!FnR$EGx^pvRvkeeSlt zw&jQ?r=aV@n=`Lv@rgxkn{WG2!tz4fo>q;UvxN(9I7PU!>+{XCfA7A0aXeq#f&T~X zExxyjJao=|$$d%i^x|Wh|5;ZmewuGq*k>a6uy~_3Tiu?ZNfZ8a1x(xRx|qq37r7Kc{7E?vL# z@_e&*&pG=x#Xpy*zNEZnah9T3-Q&yeR;PZOJin;EUpVjb<+m@>UIs3o_3`z=+oDS* zCFeCY?kP3jZ|md`^x&nSL%72JUF~aMd=co#zr6Uhd%>DGA+xQ@N28th%v*Hd`||ed z>tCL_V{@CaCssIbyTwX(c9TN!Jf69I8#!l&ovf|(zr4i$w}s=$cdJjWX@{EUv)wk{*fsB~ z$mTBwmja(>2z3M|x|qzYDPJsZ-*@%@xmo^;k015x`naIz0Jl!6>+Q}r>$d%B3^Z$f zC_Qgo$AScJDJ?htkiV5}fzGd~`b$b<3Z-rwy{I5up7pk0OVj(ipv=|97AFnY zIDVH%Jh{H?-M9b!`QvW$FwMCt#te%a_8jEe ztR?!n)2ixK_0gM)R~i)j3>2QRaM{mE6(Ww$INvfBmmXNPK19$bMW^JEO3CBpD-XV8 z?rffr`s~SrRr}aie*e)s=}WcX-Rb}4*nW9*v0#@@(sPI6-l=aTUcLGl=Rc>RD)@qL zSh_{Rw2RvcqIkrzuCI7`s3h&+1Cb9Gf*0S}7T!PUq6J%_ebv_5kFSEVVnyFE_qCr} z)oszM-|W`*?%~e`XH)`=WxIWAhi(OgYxLb6$iX`V@ zaP36KtzX$Lvak8J_())syM4=F zkAoirn&Wa0A8_f|S(l<%IA3YH%>spTQ)Vf(UE1?Jil1`*&^XoadM`FRT}XcOTZss^ ztp;1WeY3dsKP+R86Igl5Bxp~p2{ZFnvEnt$XPYR$YgoVC_|i+Y$%%G0Kl`&~vghnQ zy!iX!`QP~e@pPK~_|(5R{B-X}`?yIg{^z&pZ##U>q1%Sj?)*AE$LD*tExVdlqMK~b z;J)utU5@m@i2XtPI%mo!o-^rU`u_69%2<|)o=F>xE_&w*?9^dUv*Oz#`Yk8kg6nLm z%$}Wx*|ns4&G&9yd@d(N|B2e+Ux(I)_Zr?guB@={^@kNzMjw{$mHepQT^iRu)67=S zry}OF^H?zkg4ZJ)H+`Z|Wm6)&2E)?Y08$M|}o-=h6%xwgJw5MAJC z_R{`+iKzRR$QA$F{9<^lpKo-EVDk%0n!qPy;I|-=L+Dc0TgG*XT!$3aE#7r-%a@|9 z^KS33eC~CUiPeK=-NT4h(*;741X-m2?D?YYu`9peh;Xg%0UOC>@;y_Wf_x{xvf_4@ ze8u>$$+0tQ;^sKHw=U~{UF7?>J~1PyFeGIwZ+GdTle(o{rYj}|CLYsnl9O|Ro!y6H{kMwH_D~1Gxx6hazg5$ zfF5tm{kUIS?rX$us=Lw|v~-u>qD72hAr`tbQVtwR>pT2`^VWp6liLCcXU#l(Q?paH z?wrN%mR$Wg*CaKrCbjm|A`XxJ$SFT9_XEMn5h#&coYyWzn5a(JPD|<;r?q{}X%o$WzUiH<#Z&qxvha zUNX@yWxASxV%beQ=7JwWkCN<4-{_v>kNDnp-PPCabl>8yPlE4m;eQ{v`sa@GQg*!k zi@i^Td*?8Ozqq+%g2a0x_qU6y1a`H(crbm{4Ckc}wxu6?eB*XY(D|~BW*_owd0ySg z>(maJbM*ZG!=~x!aaq4M&x}boFxf1;YWdp-(-~Gf2=w{zJ8vod^*@%SG%8devG3v@ zo*EHd#b+f)R;*iXIm1KnIH!&QuThp$`ML$?1$T1GC)DtZXl*=S-!XehT7JaJ?WrI7 z^D8d&D0)})3+$Ni^r^)w)o@R{`*JSzjLK#T_Kmvchw@jew)HGJy4}BR*Oe!ZYM1;@ z)NbhBcWIl=wz%0hGPl(vYuP%#GCUOFnfRdLVK{@3q+d#>;$5%E{fjGvkBDpU&^PgB z`XmyneYkSjr3n)RC*KWzVkD`{8=x>PBfxu_PGGiP*NPye={+}J$s04YomNwDH?>>2 z_2lEq_MHsW~TRNX1=vr@=eCOd&ZHKM#|R@ zSwyF4&WOtY%u=`N=aC-w8+ST0SXLB=1uF6}bT8S#dhqSz&@RO*4dyfScniCZyUy7o z6V$FQ*}(rRe{T4@UCB)xdrjBweDq$0X^z)16SjMYO;kAC<^}(i-NLbW6=hx2&$#HExOyrfVZwstGiDWB zl9iYs2c_tF=ytt^k7p`e&(&b2VWac)_O;HG=;WP8J&hMey> z`9Na5?T@Ii?ZN-AsIoWPd1R^Yx&5N;?w=)(>JBA3CRH-|z3Kf_ud40nz;ecE!L&?61}>=={K5pfK^+ zlM7lG%iLeD6+Zd2Z}qgT7en@%oe;gt&SU)LRnQvwIhMDqBb+aP+9_1i1Z_1aH-!Z!9x?^ERt5M;vlz zwrNzJxZXE=f@Zu`(2V@WKXlHpxv$T;?wr53L~hTM2Uot$o%dx;`>T7)`X}bZDktB* zyieq8W8sDT_&0l$ns1i&NCo{3a0*_%%kfvz(~hm{Up8}IZ}jk%RhbiV@!;p@9Qkz( zp-UYy=iL`GpR!<0-C?DtwH)hB1s0WaK5>33yk0v*MDvP6wa==aM!yZu%4aD_9{8#{ zCCtk@spCV9WyTaf@sH+k=@kzp)+&CH_ft%5ysb4Fa`w zVr_LWE9d=dGIbW)x2c*!VJy{Ell3augPt5(=1}G6A` zVB~YgUfUnDg*Gx;pIEc&(5wFU*{nPd{(Z2NVE&ltCgUH{5d* zwZ0XZFFV$kEFkmx@_!ABS1aT9ma;N;KcBCE@F@2;rEBLkw|IWOz%cvw?fo0q8`_=a z_EuayMe)TgQ>`^Id$J_AbL8Gm63=wnEglh8yW07K)7gVdbvDR&tv6VIW$mwxEB)Ub z@q2J-U3W<)M{(ha^^GaKHm_N1O?o`89aw9>AdT-@^qVWE4`vy%P2V@?#H?EiVt2l- ze_=EC^{Yg+f@!I-vFtXvRnu)kL_8VQFEl*(rlmKn*)xjgtwD1WD^I`MvP9YFMlI`0 zj>-#DZC?eXe5+|~K6asK+ls9@3x6G5+`rwK^MHZsYb~D74{F}e{IQGk>RwAR>2CX$ zq>YpR#GRBVwOMxkXKvW%FF9?2bHfj_h@AQL@8Z|9JDx>2E#OEJ3U-=RAFzJfa_1_U z(?<(>H#^+*m$W*!b#@^8y~zyU{vO(S+ZB4V79}yKf+4o^dXSTrXtrhDhOnG%6n|b~8w+k5D zO`6YLvd@_mfbUSi#w0@^w5v~@0PJ^ocy(|?cmDp|q9 zJjHe;vn#uW*n&+Ly9X>2jNEY`U2JuAbe$>tjSVcTcAed+cEu#psmwrp)}`B1xpow; zJ!H<#USOd-vjPpYIy#d|LNcD^(%?8I$+NZJX?l za9U2xHnn-Ed*}ItW&Lw57_m2A+xvjQ>PWbUi~ zhAY$W&#o`hjQz!aQ}%FK;9rh}b)gZPdiP7JKaE{i##9^oQ+v5$&c_OdgglP&0~UgF zlIEISi|qQ#f9GBO_0C_pOa4lAK1*3pWfseoD(RHdx=$q|*1B=mp>z62q@lhJL|bsYGPmSQRV0>v+|;5&sY9+aV78WC$G*LN}W0WAnU~Q zv&L7=c9jB6$TH@Uml+Nt4LOBh>E0q3rauB`{Mv)O;1 z3P_mZ@AD;pmE%WCQ-kN(fAZJ=v#9u4^x;=|ea+X}7ZZxocvksXJ#_pQzFjq%Nz#=? zRo|nuCF5|#PGzl$b9((>o;+>E!=hfrU30o>PWXXsEOu{l3?E3HaW*Lokhj(6Nxz%m zTfpfOFwJIS5x4hYE z&!r7@7nC~p<^-p2-okddv+!rC;>uRu$Im&G77Je}nA0)+tLee8fQkbd%sfghdI9P8 z57)crTsi+B#^u2my9KPFk!O=U*Em zFir4l#PidsoDy=?(`=3?tT1NU_w4G^V|!VdE`HX&`qSt7g4SsdTUIU5UY9B`A)zu{{!cWfNxRPZ%^BLbkTbk!D0=q8E0H` zT%DJ{h}`cj*I}lnm$3HLR1uEoSM^f)jd$A1U&&;&3)cMo_51$+bCNQSlbjb^@yWgH zm7yu-$CEc>N$91mjQf{x`RMd;M^1|Q`@Y`!z(JGfBoXso`7g?b_mkQE=7}epURV5Q zv)~A;z4&brfjos;W$F2;-V0k6SLFXVdqT3#gYAVamt!0_n4?((L3G#j3-3Rx}9NFO{934$1l6HV%|$ni*`R&Wp^?Op5xoSnvq4WDg4n* zY3@qrNv`YlIa=oma|bLwy(yxtaiMLt+gy(4Y?}+p7?~fQZ(EXHSHFGLl4of)-pq#D zNvj)`7l+q(={?>0b-rEQ->cjHh)$co;-A@S{>vA){kxUV_Upj0ng%V6HNC%-H<;+v zU$~-tC+tA-vBv`bH?J*lzQFJJLRmYI_tmXS6}ulavsamw@fCje+aNl3zTCV;-zRSI z3*vrwX!)~_$sGl3Zv$6N>p3-LV)UdhkyiQ-mo#d*2`=Azz<2h#D*>5Z(@&PfJ(dkS zy7kcWUo-D+WEEL8xu%5AZ2IQUe?LEFKBI8<@>97x>-Q|+F^Z|rHMf6TZ()`5`k1BB z^a;0a3Ey|rVXl>YA=@o-)yBVZk6ciO@|-(?4zBl@?sEDaUbE-uW1dK!CJFBoHO#S! z`x#GjOTXMHwKR(Df^6gA4_>R!>Zo1i;)x4*BKqkd)7(jmr7nJLxyA06t7Q=^UUfq~ zn>}S-&dwD-!lxX2d;9IDOl zbE4nAiaT+$?b-dPBF}&ecIBxh8h*1Aq-wN?F0E$^Kw&i_p3?%P#)OxdmYrNG3c4tq?GO;6Y%GG(*U^P*>oMJE?1 zAI`}250o`(TGo98E~tNba>R#{2V6w6EgAO5n=KD|E^PkRG3WCv@eV6j)18NWDz1q7Y~?(2ENzE|U%`yTqfz~5 zP8EJ`keXP$v+K3a-i=q+2K;A;KeuB?@Fu@f3uDpyHj@@KzIb(dvttPt=lv>`2igH9 z?mr_ulNoL}R`_no@A<=GEc=Ds_o8Ke_!M)`$TiQB^_j(3m(SpUSh*--&7YR7$J?w6986_SGrV%2 zeql%I{aw6IWG^tOJAFO+dnUKb#}yxp%xznnp419{$Y6=C6K;vPUwqH|WzXTskIU=r zekBAXwZ43KAjL8bGzIxKU?uLy2;%R{^n_|A$vVH5y zPEG!5a_LDXk3!v6Syxe`8_%nFCHeO+s+x02t*vz0);z(3M%rzG=1Ufxna(d;p4`1A zgX5LM)O-Aww*1@n%;AYbUoCIY;;ffX3ahyL-xT)Fj&DC~@SL@?c+0NznYU{GXE`^| zSU#mJ{CPrWyrI6u{-uRUf9oW@HufzC7RWziCvch{~m{_2(z^&*msz{;HaD zmrLKlpp8k&Z>;9+$e49EEx12ex@yYXKR3)5vK5(f*h+8A5zGIbTvJ%_oz&kSy!3V{)6JGgVs#(I zk9oUh-c**^kh!!rN~egYQg>P8R3G0()~xb8i?+wC&Yz-rlkfT8W|5l`?5}qSF^H=i zFV-{a>{9r$vDt&Y=aX!{>%BWqO9OXS1y$EnxW9a3)W+p+?d;_ zf2eLlV6n`a-r%I@DYy5DEe~1i_NV9Ps*Py}cO8uL?Vi}Dlqt2^E~{6Mt@KSL%e-CJ zzsl~-%U*xulb!m#-7^e$O1<8?skhtDd$ZqC+NC~_iT_djbc>RO_bZ-k=}I?oWB71+ zW#xxOYi`WY%sIAq<=w7ejr5s1!ZoSpN$zaTUDMyTub1$PU0Z&1uCJX;|Ml0?=AF~c zoV(IoThptmJ!(c$*@xPc%_p=T&utBsySk4_pqXXkWarY}9}f@zYv0dz|NZ>`ElIxK zl9sv`6_fWLu8m*fvQDtk^meQMUn$ldQktFXni};Z_lgM~SFyYz{ccfp_yi+=>pbS5 z(g$IRTjJd}S(>|7U;mPNvU77i!?G6H>O3VrrB!RDRasRw*+ea{5)N3zymIBcpcU_o z<uX>bg-%(#!yma01&z^Onil4Oa@qA3=THOCh)kk;H z(mJaJR*my#X>aECe5&hgQOfId;%(R}pTY;3L6Lu$G;`nbH7L#d(p3{ZXXpDc{uyN| zdQJf>-Zrv{4VwgWQ`_1&Cggb(rtgV5U>2#Ns;Pa|_4DO(o?DFnvNWxaD^J`U6!rhp zsJy zz`Gw>#cY=*y)(HLm^Der(1vZAhPA|$1rfVi_vn?bc$ZmL6KUGP*Yz{k%}jss&5rF2 zPv)mAy28QrGV>*)cT$mP(Ydbd87rSeX)IoL`*hvUmA&uh9eE;j z;Ea^5gDt0=&)xMi8sBU?mnD9USE`PEkx8u175P5KGKB-Y8cQneriS}1y%o0VXRO`v zzfBIay1M?AC%;m2t~l(dtKG8dr*x)>tUG53&$=+15LWinXDv^-zG^wwDz3kEg<=1f zQ1L6v8a*vjV+GxH%%6sRnOiCQ=C$Ab$d-Lkvv@f_y?n>NpFh_pJT6;u$z8|N{EZm z=w+{E5C6H9IVFl-JqvT@TUDB&dnIt)QGUNeS8usY0D53YyVUddH0+4%XyBAq-%(<^q-i1;HLKpY4-JC3Q%c8lzFaDBf&34oFd3@su`PhqY@0*|ddcSc{=khovJo}Ql0;q#mQ zU-Hb~rJwgiYj8=Ehz_H(Mth(EZ}E&8C3=7T0D z@wcHBiEcY|{acSc|NH1rcfMU>@8s_%esNBUQ=YcCLwC*lf+~qcf^EGo`Zuj;+F-LH zab@vp9f$0KJK?|PtPXzkLFUEYFsapQ)|M{mw>vLP-ZocHQSQ!TE1lh98U6cw3;9EA zn${$HL^!Svb(mG)rOB}3!qzqc>Ah3Ap9;=g_BH28l!nCOt$706Vr%)eR_jI^tE5O2 z3!VR-xvs=Qeo?a)Kf8fO;^U;rc1pi>Cu^UdwCH8!>4x}r27#5!?Q9?TS&JCv=WI87 zq?ff&#^=A5LXCVAYqj5TIqd+B{g#!lQsz84v+bNnbMg}DGmn4C-4{Kb9IK`(om}U@ z@J?Fj?1jeL)yHn@Ce^S9d^kSgCab^$wz`(K1l?CLHD=QM^H|*rtG>C|UY>if?a?I% zjnkIyJ9_?v`5v9R>&j1M&d2J^))Kj#tW2+btlXV_@@mz0c==eJowV~Ff9kZzC0rct z>zs9erRIuVKl;Z}d`8d2TYkG*l6Co>@*R0!Z&mv}TyQdP<0JM9uVk#=A9!KmadDqy z#ul|{L0|t(na|$Ko?jq+~ z$#X;#)Ss7$W?ED(E#KC%?Q}xJ{u!V0Uc3zH;!fl$W)S<`xFY{DkLWR{!r=a6YuHN6 zy9_;-uLxfl_vGbS6X~At&8#=NxyzF`A1K?Y9C3K*4pAOSffL~`=Xk9sd*D>DO`2b7 z)xlEp=eldm-)`OZRW3bvhBep87Jar4^%gTuf79Fh)jq_2@lx@5OFtEz<<5I?^30`@ zIVJPg6kaObG~?BJ%g8K)>2G7r{I6L=+DH1FXRZldwCl<-N#R~r$r|mix07~M1O!PR z+T5LVYKFtwm(p>&Cn#xjPd{7ZVQ|4N@7Kk(n!56Pnpb?(`WTS*FxrKK$>PEmqeS%@ z%e|ZnWmX8j5>~rs=_2tUb){UZK#~jVySsdOlV56m4oUtuO-m`W9>uxMv^x2jNx$&qpGM^+?}Q$jUdqzSlCYhz=R&50yS+_T$n{)nwBNFInh!LX zjk84-oPM__aYgPq*}Fy`W?kpCweOHxqAp|G{3FzLww=m~58oO8+3#9-VnX1m%Pjp} z?EjqK-Y-d?wj@<>Q@X`5r$r}bt>e~uYLk9(euMFpoT#N)Q#TvlPf?xV<36uNTuwYw zI{1_F{}(YU+kd*`WS;z6zwZz45200WE(xEV!`Y)geda5T?qzRV-#2c5cvH5<;>5kR zZ|6@aKRdzsPWIZ6+%iRZlKBV3>V9#3t_JHjf|{X_lStlQdsljmccuf39T3<>V~|P1|yGIo@xX)h^DqGJ|!s-WO{5jy@~1o2|Zo$5t_&!nLNWm(M-EG`cuyN`Y&BvAIO8 ztXsn)t{C@SD|gNL|E62-_;D4vHzkV|d~KI4nPFj&e(WX3SH}j6Td!9NFMMCw5EC*} zBVgf<%;ICr}v6xUnk5Pw{5gF zvtij_DyzNH_V2BE$woPq%q#pa8Esslw90mVN7Lu>lT|_UZMf=Kl7sEO-tXBbn-EpX z|Ki^&r?;F-`F-4df-h=S@49bOm#lbc&u7gm@o8J4T>Cb#UEEeO*H>JkopEA&dBfuR zQr~||9OuqXxVn1T+h-4XBDU`9UAfgEGqvW$3$&=lA6u2r_QG@j{MB}wiBra$wv~9W^ zt)0hJwKX?gyRt-g*GhY~MF(~F{k*YjcG^>Ot-UvQzEWdr`?$5RHrDw=_jS+eR#CH# z+e_9;FOD$!Y7m=X`@^K0>*9T>>yN`vSuE)jcooGrStL&Ces%Zjg$EzMb2F7oP88<3 zQ}B3>rio0~>lYLq=b^W%oc7a|yxS{wo{b1w3_x8VPlX$Kc9j#Nl!JZQNvVd$pfhTnmY)UG!2{XB9)+mWZRolRQx`rf*~m*nmKfNgJA~HmnU%2HW8!X)t;YXwRbQ7Ve0Va;9tXcuT!|H*mhWGmbR(Blnqbaw8QPg$=8qklGZGc z+0~p-Ip>q1hmmd(NA)M2(@st-&s*}MzigkTv_Ag-$Novpvzy+%s$Tkf(S%PcJ>M~G zjF_{_SJv(k&pQ(t2ATFRA3|rEemJo!`RB%*O$Rj^eUHia8oc77**Ki81y#sQmE2$E!?AscgLZ$r@}1 z`943jH1@DMUvQsO^-Ow(!WI^uof-^N-44xpyUM40W5<+7CyYXmxBU}uUj3?Gk8|OJ znt~b2C3vs)D>(hVl*aKU$!)=+yddG`hr#FP*&hCXsN%}ZlesUl4*h&8Hr1wzedau! zAcadR^Ot*{J99+SA&BK~;GM+kqtCT_u7O!>@MUecg7Np5Ir>*Dl($^h5YosgL$bo7M>iiKcYF zWHRbeTBc{>@~m0t@An_q`D%D_uSTyt!O+0<^k&_yM-Sc4tGOD^`1A4UX8($ex>fc1 zY%hdnriFX{YB>94&i=ZepUS^zB}JJqRw*u+D9m{G)&1`a9)ABc_3WWX@)mVlt*>aF z-E;Bx$1jI}w*M_Z{J5N5U7o+6!HG?wk^Ol7y}5N3RyXXe7sWO$<}?3WaqW&zzv-P% zZyxjK`|~&VZrqw>wdC{Z6%(_xSJdx0F4JMO)XyL->~D5M;pQ$!?gt%vEmmH#2|uLO zobf43f0>IG*Rr`g%qD9tSM$B|c7N*T6$LWu!mRw$1#a*hO-x8)|Dk{4{hI6UCg-<3 zUUD{=_tdg`Y_HVMO~1%}xuPIcY_;qA(7*3?iSD(wwZAp>Y>0crp(c?vne$g2oqF0P z)>qi)WEbB(wS=!GeWkNJcD`qpb^If{1DGxuM>@}CIV^rl_?C+EPH$bu-Zv>LH7Bj8xgc`O{$0~*+Xdn>+nsMW%}$RN zkFh;Eujucd$Yfjlg)>dgep@8br(9}!>T<>OcRN=dp3PGd*)%hFlFllJ*_jO~8Ea;! z|9ZHKzvL3j%76zNzO(95=Z5km$t9UuUK6Zjc)x>pO33GrTtZi8@9J8Va(lr8#+~A) z+g(2@MK9~+b-OK9>&qY1=a&{E6>`um>Q(V7mb16NpEX{%gy)Ro6xFNDp=Y!gr7qK( z&$4B9_#b!vT;}7vEe4zS&&X+>`%#=@uj$MMmWswPiWAnYRH_hnle_uIsEnnHN%YSK zH<2Sf;S8n+)C3YTTN0xu{an}>*2GyGFh_ssCij)Me7~4oIV-Y`VS-Y$!iF$r$pFa( zF7jcIv_ENaKb~t+wEWhEun?vxzqymnb3eOz`rwgHi;MDa7c733u)B)CXYOWfTBDl#l0Qva@lfl;qrEOt=`6uwUo#Y~q~m$`JeAg(Jd$0b z&*FW}?&j8b#|N7h7!}RpKCImGXVZqvhCK|W2UC}B(_9$*Eka@S)62CvzrR;mn=3Bl zk^kj+I&E#SNmu%h12LUpYlEchN>+un)kH+_Yn5ile0y})B4@|5DANgV&#`Fc{s^_N z`n&YKDF1}{H}=%Bm>HNB^Q%eC|7f+qAym{nXvUE{n>5NJT^r8&wVH9-KQ-=u>Afd5 zol(Y4SYp}r1QCWe3uml}`IS4XY~uBzzl}`u6NLU5TMN(M?-Ed`vYO*pV^znS{+4%> zE?jz~%{Py?q{2N{G=6sIo9e??S6j8X%zh&Gf9v-y-@gkRg+ICpJ`KvB6k=06#X$4L z+R2f3&gFh)xx{VPE5u_r+r#jOiIT|Ic6|KF z?EILjmkXJav-jPrHh!#K^S9`~?f(@jlKwy2XYs6dn|S--SA`V!pWAkLuKRF|Pks5V zzKwft=52h>G5m1l$?*HFZQX18ZMLiuyMN?$Ue0|vRbD}TPob5q-zzq> zJ!`u8=iZx1EDt3v3g=CnB`|58uc>Lq$qB+fGu7|LICm*_-CDRQto=i|Q}wQ62eXfc zc-g(%pl|2Dz{&nyceUzI_m1uZ(ofbe>%SXfJMY4^z9+^~uP2)&Z}7^-lr>qe>N+8=Ehz;xmbBP~*zxE3|Vp)ru9@Ej+m}{)pY} zKgx^SO?S)*`?{3#c~Ze*wff$ylpp8%cDbqZwYX`>vbi35`Qf(6>T5?-bq`Hm`u_aV zN1J|cSUPJ#Px``AIkWFu7}f`=Th5!qb*et_F)%!T$jG3KJ(ZLd8yOfHAkxX(y|vZ1k6kqXwcnmKZ)K%}nMkU&XZ)1t zT+zs~lDpfco}M&$j{BvfPAVFTOq^m2s;k$X|85!oxMq`a{_ieUkCSD$FRSmm6`|C4 z^X|>NH)r0Qc|XVPxV_Eq%Gar8e$PX9m0EZ{FEu-RsYv}+w94bvC9hw8__+9N#{P&q zQ*S;Em9?$?^W?SekMr*rOm4cW3`L^T4=Mta8fg<0! zRSOo2@bO$dE`IWd)m(qApEqjuo%z)H|Dle)-rw`bj^<2!nt5}9!QqoliYv}vz5nX> zy~P}L^A7K3o_FK@wCU{ckG*8ttt%f{KmDbW|FM@Ev-{L;mdu)V;Id;0GwfeYq zwSK`H%ab9aFv@uRQhYN~Qg+Uz6i}55NB*F1II>vno2| zuy;jb-R183GpkZ3$zMP18TRJ{|B>bwrH1~$U+v9_yXrab@RaHIb{}tF-|zn|ZeLB= zk7JdbX$;#oeb@WWTz^Vsbx?lc*Q6UVKU?l4KXbXWwd41;8Gn0O@EU(+P z;=j!22J^)X@*C|hOkZ*8S@Qe`lhqF&-?8Z7?WAefB)90b1-Sj=j<}SUH|N6(}X?^y!7035;mHt`1uCM-ULtp*fOCQ(E z-}{*FB>R8a>c{tO7CgScrR2}|#=ghJ>8nz|w{AAhu>W#yR`cK5j1BwWOTBq7Z*b%O zR-SMD{1Q1Y=9;qqK7JwL{|(a{_I3#y_Ve?9%goSUE0ObI?pL3RyP3}AJX~R+dnz*M`xz;TiZw63%Wsqm(*3kXPIPhRyqGZMfbLat|Jb*7 zPhX(0Q17r*>sRy7g~`dy|7_j3L^a-(U;Gx>qVHZ|X4I|y=4p$! zhFZ%6O{GLH95Qu*?G zna?u++gTwr|8?8m^Jh2jztFzEj>G4a+WS(hKXygskAZTr!*jqmHpx7#-) z&Cn6s5#P}EGG$hH=7*OrPRAzY%hXExc2)-a&Xd%d9XRiKYURvx!5c&_UsS!3raVPM z+2lwS_oY=I_bYF>5)?IagGzah(}!|?-(8CTo=gAx`t{!G=Ew5izVW-|-`~?xsrGS8 zX>e}hb`#4Vw)YPDPhhFL_5ORiw?yvE*Twr?Qs<{W-n61C({|UKnC}PVRuvw9`=EMF zU32HFFDrf8Hz*zt-)mGiv7xo9((H|`_v+WXBK|yn-u>vV!2eTTbB9 zwEwZwnx63Nt@-oq=jX%o-PPR}Pp@7dKj+Zu1l?S>{2q;oeQp+~Qj2D~?ai6Nw^(JD z-}@gAIzMV>+N^zKcS^FRFsxyxx$fotx`j7?r!=tsxR6>l`P@R+O}r0X6Hg1+{o*vc z6&e_l*)U6Oa!BAFjm?ok_l|BbJg*IdJ$P{Nw6=GfTq zC|NF6)m&4k#dNa!QK6@vv!-51DzxrbOW2o|e534Q31|G`y@5WhMO$@KR_AVbsJ*=~ zFH^#`+M`tJZd~f))i1QpI+nyQf7$e_-ng#a`M|PZsYmx0Ucc}rpsdDL=-NurmYlbS z)o%Zc+{#%cjyz5cZO-A)E3(_Vr8mbYCMwsUXw9lLdV zO?kHN>!{wH9zSbcX^fe(>%3?o0I(Xdoo<#-{R$2n_lHVg|nKY+jQsQsz{w{G^dLcnyHtx~8D|@GI|IM7qXEIAV zWXgjb>P;J*f(=%_&tT_Ek#)R%Rdi+ah9>n3i*=*7u(enH`XTeL-B|D$i(L4V)f=9A z3;7y-x_VHmr%JqB@SJ%S%jM#4hd;cpea12Gk*C}Gt1rGCY|LleDyLx(z2QQlk(R`U zH}e|rO|4jWVE)OJNgq#L=~fkb9wEQtL!VHuUw(vO@PXT`RigQqE|_g$nf_&p39Fc< z!>kssu3e0;Go!r)vy{SmST-L?-XNMCKHHaP)vS9bjuiZUD!89#mZpr>%Z!-)w-uN1 z?~*nB*PpW^$I1PjZTz($H?zr>+x*+kFVKIpzqo$8O!X`K=g*b=5*~_rx!^W;}B>Pd~pZbK1FdsKJX<7TW)e7oSfUChZBWt@I1%wE4UsZ8p0 z)!y%ZysN*=s@7o57G*R%9w*o5V6W}?r~jF;fx(q?*Ur4U?Nqh5Ox{-Nxo7ClvYpRQ zxA{6O`N+gzB|2I7Y2hD_++!ImO6)zi0{MNVBg^DphR8neGr&7nm^cc)1Ej-{c>6qI>f6C6hn4|6Wo$@51Ya=lPyb{&IKctMh&-xt3pr z?g^g@jGu8}nUzK0_sz_Ub^8uDMCw#F?>M#h+MlZzkDU_zwCMN2u&yNx50pw}tRh|g zj02`s9g;PTXxEj@36PU>e}>7ZeDZO*mh>nSmwf(dA&T*gknx^-9+VQVV#q-3yog`Ve)Dd4>Apyn6Y!d#?(cr*co&nS;hwbL3n$9T@2%ZjZ%|eCgRR~DY~;rv=f}+|j&c#z zuZ}PJdH43=>E}gG9$<<)JHv0D#ozn&zn`5w_-7qi?>`<%PcPw@T>s=~+Lr0})yhRJIVQi@cI5JwE8F=_@puYvNcJ*VVIcKU%duHj zpFMy5rOF1CIFSYa*?E-qT-f?9>Ti0s#7~W#D{2<*>l+~Zkw;M{>1PA&aEN;YuRYqwlo71@7o-ac20 zIokz}bn@a0Y+HxPq@i$w(?3uPX%H8t<&(^GevFEp5c5c)-edo@uo6{KX zP1sm}-TZ&pt(#GgxuR}AyjW(bxa$vJTGr9Mo8^9%&dxh$dOjn#q(h-7c2?u_H@Bru zJDv(xdH(3m=l9W1qmB7zU;GzpwQpJGo6g?3_rETFYE#>OJu;zF`((#Q(~6E>$LFh_ z?BcKgkQVyu&6i7D7dJIuum0#?anvVFd%I(zm-$p#!=*Eh+&i>6;%nmcDepJm*tB%r z2fe~$7w^3C*tB#(O(^fjgAXe<%J@!>oOb`_-|~zDT6OZlE$)Bb@$Z*Dm@j{)G1u*6 z&Zph$4P$!b3-*P6KUXd)QMcOq$oZdTwFXO$E|f8NFLT{+%Nv{bQjZ-^pQ*P$W+8r> z^?@;$vqU4~#`Cg2*6ci=yURZH^ZI#Zfy*>KCKc5j{XAjH=4U1+J|wtZpH(*h=(pFq zFS%ItT~Fw)`l6`wbm9)@{<@1+&{PaDU-5o zV)<^tNorYK%In_zJCWIHzb1Ii=BGE(CGHjLP3^x^GVSjDy$yT!-A`vVKiPh*Fd<@o zhGKSF-5swyzQ_As?`(Cty{gRO(#AEjQ|w}DyRs=>Z5AF5;#&qAaqvH1URIdNIKPT-D5dAsHto>|HfPKMvitzT)dvc$&w_3EUgm&dmXs3hIEJFo6~3+vA9 zO$)UnpY!`BCM;jgo4Z`9BR#9!x#YH^L*3B;xjikMqAii`nltP z_1n7=Yc8&}|H1gCd&#G~EtZMCGbfm6U$YM9TqbrvBSUymsQCYiJ^x?b%y@sc`{K!N z;UDGytA!pM@R;et<+oYx_rDhwKjutaHv8gjt*=4P9~A8HJ@_ahDIzC#Ps9}CP5G&M zyIk%*{FOQR(}hff{7-jM&bjzyH>U3uoV~#1_fw;@ni~>Su6KXD_bGN-x@Tp1ncKhK z&6{s{|ClJ_q2ijeW#6yK=RPgEw&(YRteCX!suVq=vjMqj3-_ORE5@PO{!uUT#oSwp zPp+)23UhvVS~>q@%lk4H>4VSzyfd2~e!1DpTlniaKc=*YrkY#gt+$r)evjAx=Xizr zqT}NY%s1c7cGZ92y3GB|V*_dBE7ouPGR&zoBZCMSCikL((3&2nD|wk(^^GafxP}YAuB< zJ%7ts*z0apgjX$J(rVB8{bk&Obc=tT&rg=-9d_hBIg7`Txw`Jh=he-!ex0W+T=(fU ze*P(YEab3{qrcF(-4iEzXw`D>75~w4wJ0QD&wH``F^zqEt0aPIK(qzjm314;3KfAt(FX~+FcFUT- zcG8Os%~T%n^xJW)DK&nuExF$G?pDi!>eh#x|993z%obdGaPogS9geRIPo3S1D@x;+ zoqW=_i_1DSPJ?mj!l3W>YmOQ zmHy$IZuDbu!@-StvtzyQBbkpf|J=RUT(|3R?UEVB8t)Iho0RzD zvHqH`rqkDjS*t8~k+;3Vv3u6+C1pZojwN%?S{|P8D8ywt^IE>elOwoaFW~t#Q+N*l z=7N~%rwvnQ%YM$2o1mKMbRaN+zc)ibqg`r!!w2!TU#hn=OD6czFALkF2|ogE9bUvT zao#yG2|)qwU6J{Z|B7F2@3pIG5qszGce>ryK<@(YfO+CJk;`6`dZ`O7&FM{@oM5|1 zvt-+{mWaP+ZEC~6n+SepduM6%D)sio>%7jL^Cn1?S|4Arv&wK*@SiU!PlRX9`5&;X zP_Q>4t8q!k&ZQ0N>B48$9u4a|$A3nJAx%v6me>@(vwFL_Hh%~`!)bGMLDIe;+h_i_ z4uyKFH8%2dF1SD<w-V8E4`RpS{riSp#9)Zjo(IH|KH!3#IwHJO7w?{$(@%>O26K{2yMxb zHt5bdAAjIUocoEFjPoU*6qe{Gin815WYXh#GeX)GaJ|O{~oFsw26@MNZ z+PiJPE5bWFv1@Wz?@e^6&e*|d($Hs_wL53%SoUzQvx-gN!v zoQ8Q{Joc|husrC;`K;^P?c2A%L}gz1SmYTSBww2FfS>dGC-Et_szTeRyzSrl>g;6e z883JETk3z*IXwHW!yTrzHy-q=$*(-C|hiUV5T?8;Zt;XUmx%QyF(Ro9>NlQ$fNFITL(o2PZXdUbu9xp8! zH(UHh)d^Xny~%M?HB4u)&AvFhS)6_S$2F7hba<8=++J>ZsB-z!Yq?%K?&b4+>yNXy zule}xEaRNBl6&gR7q}Yf=d}yY*_ye8fj!|^vU=7M%}W+SjQgcEE!bB#o_oH$QT&U_ zn#Ueoro1*0+XE|1?#S5xJ0Csap9fnn-+J#Ad+U8RRtL^1v@ZzdvUzGhv3S#L)h&*1 z(|>;6XT583V^+akoh^|c4AiX7?>*7ot@6I^*_vm|`y`j`TP|{@w&_rWQOy3X@D%~` zv)eU##Zy<^%irR~A+79o<3mBOfpBIm&yuzuNyT5T^e!v;x|;1-kbC~DMTe4aME-UC z+OPkiW?8*w=(`vt+q(x2@UE7d;kPy-2}4%}SexX0q}D;f1uD-8^nJbAhyPdEB_R}KG>!}lNWTHYF`z4UBG zzER*ub*|LV!@7cd6vcc5&aw7RZ0BbA^Ye%kV|^9(2KC$1Pe{E!TXi)#!#nF|T1iLa z+Ct3+6RA61x|T)0mUeS@2)&UychTv&i0JtX@5LttG|k^;vPzBX%b)k%(O=&2TO7Lf zl4I-Hgh<<#vo~*DdbGlS6Z=Ddj@eeNso4p+(Na&3v`I9&6{d)sX(`XVSS0AnWm|OR zbZp1E3=5fK&zfGE&D^|L|5{AaDc!eCvMte-Oq1SjN?`Lnd32N8;w?IY!c&;GaXy@L zs_f3PQ=4)#MatT&7bbkTW)P4#$;svH4bD^F)py)*v{_voYT)!$fpf>xN9&e4zT|tW zlfIW{xzbuMi> z7i8qItLGeB@P77(OXk(Z`dqm9q2~S5j|W$ohnK}jE?sMWZmx3m+(kU%x3gPkw%X5~ zX7+DF+RfU9N_*pGboU%{eP4Acr#bBP@9*+*W}13}ZGovk zyvUWFY#-D9!qUo%Jv+a<_Z*LH=H6X)VnLTQ$6BB5w`cAanr7NwdSP4kzFk_yCV$#$ zvr{&d&q@yeP!P3Ycu9(tBIDY$XqDj65@00T||9C)b{Vm zj~y;Pna%Chp2X3X=3n`*cyfU@?+GE-4boGa?rj&|RyTox-nmS@A_PJu5|CUcD0#O(t#h|^_|(_ zHQDo3GoNS6rr!&-Dg+qhlomv0ZqU^E!#X8YIdAK9)+LQ49*^f&eOOw_?fR~0!lIsM z`$T5OI(Du4;yYte(zK}WCEU)2g-l!BD~~o#7umF*CGaa zQ@bBLklOe;k^g#H3B$DCvJ%@;`jYJo)32!&Kde~d&9!0f+{7(f5<7%-t_!IeUG|mU zUdy^dDNM^Rbe_x#O*x5WGtMd|opMdsmbgbpZpQ7&6CNymA)&8#?6l$%x3vy#%_Rox zy(>jaBRtDAHCW$=yj*0M_iu*qOaI3Y4ea{syal#~b(^i)$$#)zv)`#roQvwbPR^9L zHf5$Pum3#htdl8=_`Xj(cSK;;iD2>NF%H|;RM>=0P+4?Dw2|Sf78^^!F@0%=vKtZH z3-mMoT~_;W_o+jB+}=Rh@`m>>;+>B+3$o2>YhYDsH`6HUVNYMLc!%wrhOPU-%}(}8 z0(Xmo_%?nqS-e~D(YDD2?Wq&fIhq=-+O)}?oFBArV!+p|Ip&)FOIy}DJ>BgX8LVp^ zabM20l;gqYu>EN#Yi_=An2@T!aO!lO%z2S_H%3?-jqJZ`ddCo5~Y~QJ(;^%+Cb;a_xdb@lZzE9#(HHn_lZ{NGCbI;D= zz;8@W=}Q8+UM)&@HQedmaj5dULUhZg1F4N`AMZ+e_4~ynzkU7AZH<1-O&v>{w%8qD z)Ah7iHd}p*)25A8*DaYf_A0;Q_YoU#I$BUX_;Iwl+@head^g&%3uynD}3(YO2TurDB1-{qr|= z&$K-lx<@#7LVS7h-5(QwuoQQSSe)<^NtS%MHNMXL^z$1THKEtL=e~WLRWtS6q^uQ< ze+~8&S1)pq*p@E(lIym=y!}6|e+ereJZW>?T=8{f%i_A3F-t7BNq5Ptn6OD{&8Dn7 zmE25Iw#I3^YX6`5Q02o9wuK?N8meWv?@Nz2dkKdyMD&T&&sbj*_^-*|G%fJ_dj*^H zY`vY|H)@D~?7QkH(EoqK0{1I>YG0JgExi(W==Rp%3(p4xD`d$kNyWJCe_wjctnTL9 zw4O%qU)C`>j??y6%zuAHYys~E?So-cO-nVDF3*`@8S50LoW>V-;Bw=1=~WVS3+M0J z7wh<^{?hK~fNq^b*SB{q>HhFT_4|>aPlspEe^qvP!_wQkQ~%7q*Z*7T%Z2rq?Ju9? zKK%D+l17qX;90TIH#_9MHBS`WGHkiyfxJdi? zg##Wd?%MqPm3bw&*G+xbpNO9OM{0GVJDI*Yec0Vru~klY2ivZgL_@*uPX&jcOZ?#v zyqEYQ!}82VwYMcRCm*vvttG?#ZTe%u74x1>UVq=R_HK3Yf?3|`hyC|jGRw3la*CZ(h51Bxb_M)WmyEc4QudeBDv!e&!H(&#f64FL<>~t*EG)`ypN(iy z&C!H2J|B0iQ`{MMc=EQ!uKcP+)97f-(P&nfhlV*DHv8H&r7llU2~f0n;A72imBeVfGV=z8z@qn`&K zu$|s0UAV(}>Y}ceqp|XBuP*re^q4okntQ1z_UHCRclk75oBiD86~Ay+i_=q;mFski_pq(C zuiLV1&%JO}dnm-@P*VcJ1=#H?nCN_u8gUskObZRB&f)!$le2c;Dl?eyo>& z@LRETyw|Ip_HY`g+=DH*}Z4>PkSXEo>$L& zh=+gOt&Y0Y?C)Q-h4Ivv4dfD{5T}s!jx^3wx$N3*SePGePDi!+9Y|d4O+gYvbwnmTCcKb*9eRkJ95PSaR zw}LK<}tYTGio_CcUyE&ijlt)zP`9nYZmTAl?y4(7f)A``MuYWIiary`>S9V^( zdM%rQ5y(j(-{`245QSLqSn{!&;A|v0lAN*>3=}%n)TZ^i7Y!>&d}~DUQWwoxi85+ zyHNAD)5qv#SE*I@z9Og2od*`UF`d78U8l&d;`J0c*~G{K3rnv6{VNAes?1MUA3IzV zwCv6I_p6OhTHm^pd$DxaPSdjMb`Q23N_3yFW@^c%v}vBf-`4o3|NMI4>fBFyj_)LY z%D%e7+*i13_R-$n^n|3Ts(TddU8D?ErmXUf(D7ci>fF(bFH4q{>s0NM*!-rV>GJZ+ z_cRaX@OjP@x%$YXF<{{olh@0%j!#uco_M|aNNxSw;$!+Js_MTUUH*Y{wZ*#Ny&sLk zbDvaoi8sY1z7=+oKlef{%CzI&^u=M`PB+4c)uXs`km(>pb0hI%(Yx!&f&xEPOR1=;)WE zImx~c>mIy$5_&#~Z}EcKAL@E>6BX{59KDxhVrQA&>k!(Q`fZWUw69@?cb!c1uE!Z{ z?*2OYr_tp_XFpc1c6Bgi^RB76DwetDlX@GUSnw;kpV_~|HaIWe_R8a-|LP5w^fuiK z5Dh5YTBI1FyJe+^v7341?o`pr2;rMw`tIM~`sVU8u8iIDe_fgNT1wUa>ccCG&i}K1 zwRcYb&S{TM_y1e_9W4my!i~ha!>fEcUpSU_*b}pGc zm21BG{a~KGwXU}NE|qij+z>Pu*ZJ1qyS_$9tD*$i~f|Sari|{?(Zk*KYF&zI^a~ z)wXwr+~++zxBiur2>$r($A_=oFWUdUU)aCCul`Pdp0R;ip}ij$>$c5jCI_YRM7+*Mc(9QRRy2b z*xqtuvWSby6B(l}MVoSmTp{0SS1imn{C}44{>g_IrjfRubI-Qf$^YO?aBb4Ru}8pe zM{Q$Zv`EFDZw!K;m>D%U6wXXGK9PFV!tKLSR~Na(g3BahkHjp|;y$1?Y2D=Tu9c~N zku6-mT@U>rlixciD7^pUp{lmg?7y1$+1=?gBXy5#^18iL+2xR==M=8ccwm&*3$GB?pxvtq)cD%Ki(^>FHm}O$Wgv-C@;rc&QEpEm>zc2gqU%pAh5S0i|Z-dSCQjqwdS{K?)|it z|3`h>ZuOJyteGZW-!|_M-}9r=(35@15rz7Xl@zGpzqmtFYW)#$2Y5jmk4ZzPsl8^G_*U`S3&bq=WlbB^2bGs8pDuQ91>lf~m8wHAigpKP2LC`SIR%epV~ znB7oufm1H4T8*6}U*_Dy&sa3hJknb5{AE<5oZQ0S9X;GNvF$62R~$O9ilOfuYxQjV z<@?Tw73?~jIE8ucmYV9&2V2$KE?$1A6Y%}ObV)ZmC;uPbY;R|a798{SUiB<7V1AHO zi14<@mqkxA{hW7xXD+LH>Q^mE=Km7qUFTm#$Q(2>yX9h7lEWBwT|#C13k|D(j=!?h z`roH#iiVzZ2|GBm<}a5TYna!p;Fsdznx*WInP**G_)9 zK}^#oc4eTJiN468lBhU?rPe)9d^w6IzH73OkW8<;eN<@6jR)R8=W19TyY*#>qt>&9 z9bQHfqPOPG`C_5g_mNdB*Yz-usXgzqfc+1dDw zE9YdsYL5DKLp;b>>%HXHBYckM7Rpu5c8hq$ZOV1&{e=G)cIo_l)%EQAAw5M$UB>s7 z8@7FV+yCZ#;Fqp|b%93@USyPgpvXM!;>spp$=EMU(mn=Pe=Duc4-P1lIahSO@r7dE zNyie6fRfNzZs8U!BIT2=Dh9vwU@kh!5%3;#HDZ)vX1v~>@>4$NH`a<(HKS+~k(9Gwe(L@%;IR=Sj?!>5Y50x6V;?M&q4^#C)f`-mfaP z8$6ms3!a^j*WFWiVb9ydSC4o3_N-!_^2|Z)PxShw(S}byJz?sZnH0$=>#ns?=c&T% zJ1K#o??MBW55JK+S?rs-r2UNaht~fLsn!c4*B%etcrn^w&PVobtgls=-rZ? zU;clTo*Q_{zPr5q{G;!)Znf9%x&AUEy-+xQwX>{Kwa@(Q^Jg}S@f);uR&QDTdzq=K z%-6lM45Oz1@R%nVT8a9MF;<3zAgBv&Ne_(l$xUC~<`2x-GmQ|aI zf1EE}qx|0WwgcA&SHZaRURf{qr)t+~Z<~~~+**H{d)C#O1<}m%o7Gj61C*aD6Lo|0=|FwP$9%i+mV=Tgl4rp|wx+`m$}?)32tyQ(e3K^V-y{x(#-> z#l_?QK3r{Y^YgL6O0oBAX0PM^^n~f9B9}s!#jCyj`wv|CqCc;$*^p)b!~6S>-T&{j zzkaV<(_gnej_d!*#s8ib_xqLgpTFn-{4W0Uce_tjzNw{pSYM@>qD|aX^{Z3){+xOx z(Vr8L{5<;4g(bX4t}i_+8FDIL+xXyhZ5E#1x*a^-def%fn11X2mRY~bE4KHTU2a%v zAtRLVrJ>^g>zna~7WKB)zq2JST>o`&%1qfm`hT*Ywsv3cn0{))GJW?8c6yI@9Xpi0 z%lgOs|Hji~ccs4ge%vhh=(c-P<7ee;-QlRYA?Hol=}kxGM5j7(N*W26pSX06rA4~s zpJeve4E~5GDXEWdOD{`ni0VIfyz>}??y=4#DI5Z_Cb@yP4Z^ibqZaK9Sbq4$j5Us# zoK-HWzlE+yPB>$6aCXxRgLx0D#WudqX;PkS%Jbhjx@UzzO=VzQIM>YhQn75s6?>mn zc(<-U!CjVrXwkPVNs0HS@1CRcZ0+~VJs;=I|FJ=^d~Ffi0p$~_ZvxJLZpzDjwV-kG7`?-ix}~759GReEsU%_K9oCHk=Re{+fVn z$j249m{ux-KEx?=6D!7pF7aJren<^|@41g5vYD%f?QklG-#3NtDc6^TvzNBrnftypRw_Ll#xK;Fu_C@tgt$fG# z-IY^zF?(tob!k;tzMRID*Bkaq34OjK_gB`SIL8F@8O(B|%MfA$uivTrXLbW|3d>cgo{7ujg8M{!uU7>$~K3%YKcx zz-PT|XVER5G@E?=dppdwH_33bX+;)#Ju&cDR2y^ZcYNK-n+8v2G#cLJSv||?;y*LH z#jE>oh&nMF7Yx;zOa#82yzjL#>EB`Ppq>!cUAJxSXng0kIc$B{)9RdX znZM_$d0VB{J`(z94HK&v3{zkO@VLP-YAjWuUb3huO|0xkc{{pemtQlWm581?n_0n zJ*$dr9_?`ZExc>HiFn32*9Y?^{r>lM#-}YB=XK-HpIB(ac2{P7`ko1*-NoycJt@-r zG51l!@266-E;6xZDT(&!<~LammxkoO-7TN_GJ4O2U0z~pqCPwU+nBGY9tqp(as1{L zKK+dyFG~-0CT}pmus}1?v2VvB!!I6R1=n&_AGp^W}>+PTRF+_4mk_^%m>wcKFVebe^>QxsS5Tf$EF1 z&V9ZA#3a@!;3)gguBP|%uDC9kr@mo};ELe(iIFZoH*+SaRIc*-Bp3ej;{BotyN;`T zuXrw7vH$Vi&L0_ap;ZJzDzU`|B-CuL3`;+5GhIg2H!fT9GVLOTXQCwcEYB zE?Vl=-l(_}4=esZTV3^O<*aS0$5S5ZN=F&hsAsn)&5)UQ?8|4d`L|WCOyxSj%=OZ^ zV(0Z2w-l=WFZ_QpjQ3yF{Dnp)fdxypyfje!rlxzEr+4d?JC{V&rKS~IC;Lc$5BO|X z_vZK6!q;0okJKITn7(O+)}qbAZ|&=Met%R^{r~y=m*N4IuRaRgUAW3@wy+JOQOsvn zf5*0(Wz`;mJ45XZihPA0y_qSot4BCDj9;^&{`JxBhco`32`|)Jwf11R-v7z>zAiIl z=PFupMnUM^do%SV@Ab+|7cR?Av`8!7S>ru%ir+yqGoziin%462*zhJinAl<&(5T_I z?Q^GBap$+(&g-A2T)lnxMr*f;e%^062hKjmVBW)xdCliu&uf&HyS}IY#qsBH+cR$m zp6i;rz}v95=tgzIqdiFy-KUk0zRzBI_+n{W$iy%7?-uq8RbrPv%t)S0X~{q zN7wMGPrLQG`N!)S%g?;r*z)d$?R%kewWX=y8XScWWS5>T)^?68R+cJy%DDcgt#yvU z#kcO8r{DYh?_1F}{)2v-?oA2Q5!-!TI!fI2Q`MA|+GUdyzu3l2<}YFJ=wvKda(t8a zy+xg(l8$SpnU_t;FK~OIpp?I7+Om1c%*^eaCppX{?T$=Ub)C5X>+aLxF+4Rb;*k>f z&ld|9NMABFs#A9kY~Xe_^gpAUd1CSQmGOre^^dCT^t;@;p>dj)ck463j)ixS$%oZ)50&mxBNL(sLtlpU^RCR)8hNdQQID!SYn>4lDj4Nlf0|_qt1$e zX|6YqT5PReS+Q02Mr4}#!&Td~B^Gtl=82g4JW+M9KpzLj}7*1_QUKb;dbi9O0; zo${?Foo-GgM+fx^;x95iJQ_Xc-v)fL2`4vH{=`N=y?hd_ulGR;B z*XOlU`?bK%ZjZbFTDCmC_B3yq&5kpBy)Rsz>u_=Eg{L>J8DH74eg4tf(&;7tD|E8% z-*SE>wZ70lMdC|O)BLpu8X|+@*!4_(x65DC{S%m&=Al}%X3MoL-{b9TrFIBS6Ks8d zJ%z!^W!=p?H+J;hT5_*BRxsaY!UGZcOCs`S%XZv8_3Qe%&(6QxTq>&VE4I!3E^l+U ztIPJjnoj=JmT3Q1s|x-EO3#*7lfS3?*^`OuSFYDghBf+mdo(`WPCq*1$)z@yohe$i zhBCjd%1kbgzhI~G{@}3=siYep7jU{PITg0SS0gs@^r8){Bv-zO6F~`zyZimocrY{!v>I$Wk5Jt z^Uj{yGUX@C*U!hDC<~9czmzR%32%Dd+>2*zPXF_3WL7@)=UU|o@zdUVT9zFlQQJ7v zCVaa2VR`A38Dcq#3-;XHCHcx}^TWE1bJOJ%Ux@`Th!5YlWLMlSCHLApa}=E2UHSG* zy>iWUW5hF^=fdY!OfnJKZs!rR_4&nIH+`cP6|=y}^CV*u4#hYv+5Uw0hh=ZVe7^Sd z^osVHGPcXLWoqq4t_u#9-~M3#r)+l9Tm$vCZ(moZ3;+7QeEApuQ2(-H@pV624%Ke& z|FQf3T)~Oy$KBWSxt-^m_ulT|{_k<}b8G59wAndbN)R|Ce)!>sn5ttkhgG&ndEb6m zaNxqtBAvNfuOeSsm~7f-yXD4~U%3ko<|kKPF`K5cqgz2HCn%AxRywKAxxA~h@uw`~ z=H?&14qw|X!@M;vajxuTo48l-gPBoJZ^P;n7yHhhxF_KBKAV zAszDf_^tYBcUL>`UGOMZ5#_A;KKbo2_2|gb@J3yZ%X?QQrs^F}_TgP7t=DO`jDbVo zapsZptCxhD1|IwompA#v8w=ix?$M8JUY%VvyHKRRIJB}|TGZs|zN=Qpf+Fs2-S;s3 zgmQS5Z@S05+>3kKJp-m~W^MGY$Y?Y?Dwnu)%3B$sQmIyFncCYMtF+#wO@8XSAh$(y z@>g}O1v3TiyCoeD*miyU{+FICKR<5%U%20J{ccYlxm@qBTx&h!o%hVY=j!}3=(S+W zjVGHnsy-?X?3eJ#5I4D6Udqoepm%(?g09k*Z?pF{=l`m;SHCXRlc%;u-{AJr-x3Zh z=f7t^e&{i$QD?=KRV6=#kN75W2P$v7f424Oy_l7v8+aD25NWd)JKfrJO@M2rxcc&| z-8!UU39zvdA30dVImbkCQgH8YDMWIhJdQ ztn2?iJt+C`xythAH+JbX>~&#C*SjuTvU%H6;X|IU6_h`o`1hsh=FcPMZD&P3_ug0W zEjqR0;EZ6dE!~0FSFY=dzOY&Ez_hH8AIH>PJ(Qx{br|cUnj4LKFKjseN6gD;LdP$y zqdlp-+RWJ}qCb9F<#u4fqwKm$@wR!Fx|KGGyVgs%9zS}3E9Qs+&mOU(-hEG<{FeRk zJDR!b>Bh4M)Vh9KMhom%vFDopB`Mu{$7(;vtRM-clL1UN>lSdkONjP%6kM4SE!Hp2 zSvb30-O=b`D3kTcTBca;Xg~I->)dL3uIbV*BEDZcDLiS-hpE**KTd!1KBcr(?`l-o z`^m-jZ9Y#_-SPu`4@;((3jP-`>3BDjM}=GV(QoVYO-<(_?0>v^x&7JZh{LxZoRoGC z^NGH)`=k)R;CqMnQ8h7Z^(>Z)@V`7Z?{aq1y%(o)6c+HD`?D;er8e!k_ZOxYR~s7N zwVb&)S!vd(m#N(gswRmZ*1pt!aN9|T$FGAuEIu{AKa-&OFL&nB9V#Crq%XIhS!cAE zL1Jg#E)T)=tV_lHzPKE%59nctyS(wm(ih>s#k@bCJ|r6b7who{XGf;(V+h zrbt~7ot}0wc1hkGjwt3}(`R?w@6NKFB>Y6&Wc`BVW0kYcTx3(9vuo3ih_H_O*@vnY zZ$0qCwd14rCmZ2N;jbEdm`lB1<;J@n@>i+jy|v#>&EmS-iD|iVZ8K$W9qEzroaY)f zzv!!ft?H2$ZlN7nbFA!G_D=Yr*P)p{qq;cvpqNqWj(-A2*cN85IQy*fH;-QrboKg3_&e(I?WE6P6|_tTDd z)^_JU>1}FodgFJ#KgDf#<-#mWMAaic%vk5Oignq=sUZS$SvVqvl?#n)p4?15VD>a# z{JoNyllmq`RhO#SdLgF`yXu>Iq^w-_H*Vyd^?<9AqbSn7YvQ(|^>tG;+vl6Pxd=uc z;$+EodYNWl8j;-EA(L`U=Gw)Ow@Y>4W9CrRhaaTsxFb4^y5 zACqtGC+zjlg(aOmo#(GymP8o8i%rT@Gp#n?^0eEHb{QWII4=!Qt#tQlz1SJLN=JYB zsghmI%=Qw&DeB30XE!vjEPucKsAqSovHX{PCz=cY`WgI_yVm%-Kgvn|#-(&MyCwgb zTwN7Ko;+eKo~SG^=}yI_J25->Dyr9i`PJyvY}@v?%RMCf=T|+g<1Ne5oVQFnniLYd zG&8nW?{wPR$9hSt=DjuCd+(O~dQR#6|MzMY%D#8$c=%t;FGS~lkHAK`rv0oorc0Wq zYggMZk#bxUIAg<2-c>h)zRF#xsekM!tH7o-=g4WMlH+@iGC7u%Ccb13__HC&aL3a2 zuRM<$;#DpDe(!r`H;Gs5O#cFIo60}3?8*G{4!=T(2`-aFlOVUrTuW^H%l5t*;> zXszHKe}yv}G=tb~C~xQ68`qj(tCLcvv}%Lz!~J?9saGyrWG86KOO)GO?ppM}Y}pMa zsoO7D3cJh8lM_$a-~0RSb;V==7!}@yRE$NkKg0G|{@;6V*UKEae-K~cT;)0Vw0v$o8xY| zpO@#ZUH(GQz(2=LKS(=jrrqQs@omd=e>*&@v|fAs`J!pJZdJUAIka<~a=BysE-v;M z{T=LKdGj32rS}MMzR%%Y%e}f}XQN#G{v;0hKTgkHn=V;3v;JFKQy<^*yJjnYJMQ+` z_HA+R)VsGU3f@aN-+y;Gzsg4N@At5|OZeaSF8gsXSEt}LQ%O%!hGY1=s6dwp?UVjD zI1g(J=V@q7*C;z}eMT`_Kud6WlH!hShhC>z1b(Sv&0n)Lq)9<<(c=RLgP;2CSv!sE zEccm}5qG#|aOrl+i$xi|75*Ztp%Gl-p7kMB_Ni}*glw{&`5UPhp*Mx&^m|TvUS?5W zEIf7f+a(9?+FAyQ@~u6kK0SuBbqCks4+gXMe#`ZFrg&@J%NmDi(;MB+9jX2Dcw_e0 zg%dim-}-%wK4+0zxbEY&j;A{Dj+riq6FwPg3^#I3lWT)pPV<*n_X40%mI6#5F!vgcoN zpK<=}C*PI-Pnh%k#hm@T7PsF&S!8v-JNi`YEZqZcQ4!&;K}$X2`I6g;rpBJ*RO-6( zO5yf%PuBG-@01!p^{%<<{@1-;;GpwxjUNRy5#j;s? zc58QUX6aj2sK)S|V}jf2q)jsE;*otPgKtS^zpB{$IC!zUQC7Y1iz)gGmPkygKKaeN zu+jZnT;KM>>0BFJKF%xhd;031)?Vin?@K-#x>s#7o0Zh*GI3@5hI*mqa}}PagBEf9 zZO9Gzv+ZyrLx{DKx~0m8Yft)@AIRf+keK_F&-Px$++OAT$Bt_2a9lCmd4JLNG|Re< z-XevI0rK9@dk=lBGiaU86Z2!^`~P1On2wih{wg?Ui{*QIce{wShjtWx_c|q@{UFCGci9)p|{b2yF8{h&e*m7 zSoL!D&e<-%^0shlk?o~`rwJ1-YqGhde@iV5TQvEZnqcddqe{Pv7gRPe zun7M6^rXYM{`9St<;_m-CgsP;ZqO}Hj`Wt?cG*9i^~ItZ*_xD%cMlzzueLK*qS&~K zQYrXC7fIk9}8iLSg&m8B(dGOHL}T zK3pT0R($8z5&wGq(6!t36$E;+PUQJ+-gwNiZ28A^N?h;XKi{P{<1C+xw+r8ws>vk> zZ~E<4yS-9>D|=4IhO3&l>x5HTFqde0*)k&(aI;YaS}gf9Ltz*vjBK&trC_n5@L{9HY+b@uvB! zzew`EU)r=c_o)ZFck1dBH?spPTKkqvUM<9YN&U*X&C~UHJ-beQt%^Thw??s3+r})|amp|OId6wDYki7ExoEkme9!k?&P5kKC{J6P=l<{eL))lpdlahL-6HIl$FJd&X*jvteEu8n zNUwa`puCIEGp?=L)paa+^UeG9)6)7soivP!f31JvYv$slO#h`ihckSl8mwn72)3y_ z!C<|WJ1*h;O0aa(DTGiPa2!7as-;OV(9r(RNOdT>u{ zg1Xh5nPCjG44&n!;r7y~J#s8jYLY`*<>``FKYzq6J3Q;`-dA~c-;BF_w68ADd@3Pz zvwiV`9l7~gebT=sZxOTDy~9ZA-iOe~5~4>c9!ayyTkg4WvcW9lm$T-RCjZLRmMqu;i?eBtpmZ*IK`DvDcQGIhOZ%Y6Ok zB}ab?tvx?IN2crrpMB?&!rst{_H!2TuAj?uyuj(pqgBUP9*0hA|6G>yws!uSp!`oU zyBdq?UfHvqm*iPL!;CRvzKit1ldm>?XZgpPz5n^18&T=Lo4uq`gJ!w%309l0ktypE zD5~4qGi{sy1$`yi8>{(#oV^ygDOQl@{lfh^Zau=Av_os2Stp268v&_CWKT~{DJ|~~a%rZ0l8RBbmS}W$oHH{sO zZ|?ERB!wN45s}_{{`Og;yho4z)mY6*R-2jifPvdB{9T1X=o^Q;H9uaeeb#%opDoOM zkNJMc`X8LM!^Nq?W@hih3)64Oe!jtVYD3sM zhP5@T4(^;C(93r>D&v7%@~qEAA7hQ?8=JiO_ImMjcl|zzg9|4u?F{!{v@yd=DU_9Y zCfD~>zuc8eB))Blu2Xnt$G*2&xcSQ5*mmU)y*9T>*sJQ?r>9&G%&oSFFA{50S@>F? zLu}RJ@E^0Tin7h;i4)o)YVslecGZ z&n)?8wHniE#RAvw7ke@yHb0D)_-LY_;hM*ABI=ZkhE^{ZgYMi-3;%MizpR@4n1ywf zEKAPr>aS6&I7`ZQZ7y;2e!BlF+v}}z64}QO#8owKIxYCdMSs5MLq^VJMn^eIB$@i< z*hNaFDrKy8Y54oSL)9;^NiT1U)bC$qhc_(Wcw%;p)Q;6Ltl>XD`^Gf{cpOrp1;Cg;?^(mW$^{SumeYmc5rhQ}D9e&R6nXCfG z!ehl+7aY~xn7K%J-{~n0^(${E2QAq(p>$#5wZ;4M_V#T1w11JG;Hu3MCl)Q8AQtui z&+D?V(9>IP)qVP{UY`-5V6gjHZiK{|CyVoTe^J@iw59U0^^%|tVaD%Ey{)5itCm)s z_Epx85>C=zI&D+Qv^VqD6vtSc{m3=%Kx3V zYP*iuhtsVtUK4Mb^nCky&3^ym0&kv`n=%^jtbOqHc8*_bjHe@;)~kFiRv(s=Yz<~1 zk+FVK%N{Uv&pEQy&ywB3{HlbIwB(f&jI5Qr<}98xUpk3*t4T+fu)DyM`Tmq>lV!&dcs_j+IX+?MHAs}?R6 zv|Aw(a^6X<$+J)F$2MYHw8 zJ!hqgSqmny{SFatTU{@6X!rZ3CRx53qcbH-xkQszY>|lJW$v50@$~aW5*ZVi=ROsG zFnzUMOZi%xtW4XYee<@Zb}Q_U_)&3{sq1#-<;%;nj4$^#xXk;q;o`F9`_D|zKG$u# z#<7s$Ub>m-Yvb7;Ld}%6T}*TN5)*oXXWIU-+ijm%Irjgr`*i%_n52bdsPMBv`_sRE5nW5w37nvJ)zhrxfGOlr) z_FP$W%dP6ZG_U`G-skTv$_&3pP_Nn)>i)Xle9{iOf0K^0QvJNTw7iA$SYX3AXO(eifZ zrJM-~{#RczZnIRl>LTkHbZ^(m>*1c2x^}`BpS~0LW^mFl;kDoN+-B7!n~pNMl>A#c zQ=<28`>wzhZ|2BNG+C(5$+OR`X`PVTv&E%c_wwD`TcR^d?mXL9f9;w4LHRw0!hg+; zVgIq}rY(6Gf7A-b64(I==$lt{e;HYYuT-aKlXmAmff(L$(G;7^oh~jy~pDodKV^Gr22>T ztG-hb;0WU=-CdkvaB=mq)U~YXF5fQge;)BBJiM2wIwSA)@`c%I3(qSsoWFZpwQ4c5 z*a5TERkhqA4WAQl-D>jhll-^q{oaMQF8wqy`_DXG+V*#uvsz^2ZZ-Su=R>#U9(40? z3%mb!#p87S_^?M$ms4uCvY+otl4GIlbHH?Swt+lulmT zc8V$S`{}v*o0@x49G1D=$-nMkFX&ubx6z+Dzir1dj(FoqyNn;?B#ABI^`5=EDtKkJ z>X~V|r%D%xv+(>?;GMF|N|K{>%|~sIy;~a0q*ILIXU#kvd{4RS`lZdK>mdwccNuiJjF+|QDje%qle^|q(w?(-Gj?(K={ zRx_!!UzPpsYkBv9&pK0aa_r=Y(~M+$DOk?C;8@9 zWxFWLEEiJWKgZPSZ%4I`&YBsmr;J2;rm|dCxw+v&h3L^M3VT;scXs*-s6XLje(ZYT zyl3x)EvKW3j=fZC*3>^)5ZREho;POBx{%w9obKgaH$<7kv#UIAL~sbGyf`$+G+y-Q zBqc*F@%6l$pY==nNZHPua_D$xb7}$qAEK(~7~J39 z7|qVaSFk#v`c%jchwX2!t+-LrU)AHb-~i($ONlK#oAl0JeBH#{bp2Y(RF4A9Ba@%b z$=afKTEi}s{fVVhr)15(eY2P@#GOtGOnYH^uG_G^kgKsWYlqi^n^F-zhd;fPTF9i7 zzxDX*o$Fum%*}Z6gJsGpk@efob~(Rs<1!C8air>}>CWbJTI=dl&YLU@X}BA|sx*8- zwc5jZd8-w4zD$(pI#a(;`|p-&?q6)ox1_GHWth78Yklok`oi(5s-dkmQR|P9gsym+ zlTRFLsH%v%Pw(s_b1EWUp7?#GNGmu;(zcC@cg-V10bkxLe9af#b{Sijaq28Jeb}D= z{D9oN=?^=FO|R@Q;7VLrr!w!};SFEjF(z01`f-QpPO`=-hBtCnQ>$+p@U9DVyjyJE zt@`r6?n8ZFxj#{spZ>j`FJNnYXLG%%%))!#y}5^1_k3x)o3`?E-$Aok(NA9l)-Kd~ zIk`MYvOkQ!qX%@nkly>3cVA~t`Sm%t;&)AI{&mSsSJ|I-9%?%2p+*o!+_fM&r~C9OaGj;YYN4 zB;*P%G=}dJQG78qV85^FGMS7lZeEXeIhU@0$rE&~(oak*a2y6c%4bkS<;Pnq} z4=##daM5(Z&Ff`f58Yn=yiYi&^{CK?O63y^j6<$I@-;a3V8#ML$A_B1&F}0OHOo6E z`)hb>$+#_1eAGt zZ+l8|1C#wF`ED&?{-hAiYci$b4D)OYp6@J;d{yz%s>6Oab7Nutt8a(CbY!o5aBrH1 zXQVaL#MFhaPfikT6Hm_m=9b^RZQYd9KkXOGPiorOq{}q>d*`ps)3j5h_RoEMETGYw zXKUA^v)``0zLfTtpRZ)kK9OmMo-=bAHpQ1jY?1$|_I|~#2cOdS7uKX)&9FTGYWIh$ zGdJDZV($`U@Iv%jp-)Bpf=>2d8nyh&uM1yY=6kk%ry8$u_S4+&XBBvEao(GA!&ve9 zNj6XCVp|UPrP9nZzkDzd7s%(n5>Rg2`{1ESVeb1!^>Throf~4mo_6o)H&^mGurBe& zE7ARnNe4F->TSPfAv{&r0zO%hRtVW8qY9tyt01(aAIh~ zmYsiFCj5z=!u8<#>D2+&!r^O0BegfCys6zWYswufH{pd2inT&5Ub7uOT4i0F8Yh_f zbMDI1@|PO^T)paMz4(_|`9{qy%S*i0_mdu9yZ&SO%sK6jZ&yCqnO4d7dF#|)mrt}x zM|}7HRK1{NhloM$enyj5Q31C(UYQ?E+5AtT>!Zl5ySndkrk`AX;QwzAfA?~Am#^zj zi!8i-{XNgFolCT}?<$}5KFMCnR}%8&_?o+W`JVT_s@=|f*lPWg+bydPuC586QOf_v zabHM)z_V)JjFbEsEZo1_SUgvSuaxSo($eWY^X%ymh_^=`IgwVH>@|RUEo6nnMx`AcVYR6X&TTNF@Jvrg(MNv!l#aI6~rsZVt z{%(G;>+aRPuaA}IzHkWRFUjY9wyJmYtAy3RDpv9Ggk~R{bu-mosrGW@`eS!^w?0k& zJ%x>FmT3pe<<#w^{88QhXS-&*KDt*{w8xe)J$p`SQF;OAWvf{_H#Z&Y7JN}|+A}Y` zg8Ary)2+dFUmof0@(W(IzHuhQ^^()-j-55T)9?B{;NNxX!(zcIc}|IJmh)dNB8<=1 zJYQOu^~h3B@XyZcA5yy9FD-M}r|#==hRQr z)tDMxJM){Lw@`64|B_16ruM_%1XxwoSh}R<9!p+xtan1h^Rsa}E4J-fx>4D;oZafr zs*k+|XP!h{_~4|^W*mJeMa6?})tfs#{v5fH(b9dGDx6mOb|%K9`?eiCx~R3{#O8I0|8MT(o4tG0>8CT+34NFq7k?w7 zkfGw^3l;{RH(z`wpHEolox#$0O>ldvXX=L+vsT)QFwCCvJ9O6#P3bF3C)lv*d#qZ$ zODLl=z5ayhPQ$>dwGWEqOIVFQzgx)qfd5qCt}~NEHHvi)yd7{rgKim&&2-P*WIf48l=!YG00hOi;&m4 zH;;PlcD88A^=0$@H}0Fues9WGx9QnkRk~|?R~$cCGr@+xvw$c3;199g6M|Rd2tQ5q zviH27?tI{sy>V#SwmiY*t?BD7svPs_o^d3}UU|(;$A++s+}nauD>4>+U3SK<>cqQQ zT6;w1NSt25Q@4NG|DAUqZHdqczO=0OkM?sm~&))zm@h{ma7K>PgcF&>+dCG zuxWz5*AqLP5B0GVSDTe~|73nF|Gf7hceKYZ4VLYqldiwI&K3C3XXV@lCtNRNL_4$J z$ZoUVeSEKsOI6A1+}g)gl^vGK_jIqX^zDu4ys+h8RpX|dvyM$mvpFM|ZvA}WTE%^@ zNkTuS&GS9@k$dgI!sd<3V|*2hct!4nb#0q&(giSC)J zKlnOsStL^0HCM@cxgOW*s(E{_Sy-LjdNxo&RO+lEN8;tG{!YWW2eV_eT^30sIBd5* zkT(BHY4FATvNK%4nXJ4SlQ!o6-4P~#h{ITe=jjh`fsG+~saFIyh!{?sQ!(@0%8aU( zPjbmU2i-Qka?hLec&-}b-?vle&F1FKG~Sr?XV&Z3pB)nwLTdQ^IL(}s+v;7zepi7e}y!jW--f9Kui%ew0%e)|24n>8ooe#>v^q6-ItrY*ENGhu4m z|6bn6qq9oyrprXAb{)5>JA8^cC(!su>gi3D9lRe_vL(jIFno|^4=PT%WP;*2*liau^Q zKZAd__)BZ;Z+WUS=0;w(zVynxJJopRa^(ynR;TxxyZiRq>{O9J%Z* z<2aX`S!F*}y;%FY(`^GtT+O;_z8gm||=}(Jg`TerCCP<|6tMc=_Bi4a` zzJ4g&lP8eNbJ=A52VIx`dpGZ`I~M*@XJwnztj2;R>JdEblbyDui>Cj!tNrt1^^fLK zyUQI3c|}Ia?-aj1_1#qR?(@A>KKe%=yB(XpOd;|hSAcIxQpiP*_c;n%RbG>IZAhxAFL=6IcE}*P&q^UXw?qp$mb^7-WU646(nq|Yj~=pnXTcu^1Ji4 zzR0`spAN-HTX!3DUrkZUo-s4ehp%b2-_nZp($UKcmEL3@NOOG9QuOmf0rRxLhLCd; zIry5jPikJX*;;wR!*a^e6+hG28y;D9rOah1kxP_JEjh3%kR|xD$nA{{{1Tnc_06xB z9=Uud!)zhzR8~>m%C)?qHWr-AKMBpU*chDl)6}h1zw_2c14icy)+#saVg| zePzwIf8J7ICQXIY$NF@Ib}&>Nd8$y(ck{-j$numn?>`Gxe_ElM#?Mv%V9%M$Wnn98 zWW1HHXj**=V%Tdu`xV>9qtheXv}dfRYjMt!u})u|h11)UZ2n(Vmn zAd}-><<3XO0?#Fu%hZ4TGCTiR;g3fvFRI_j+56*-&bDj8$6Gx9Zh0#aTJ>+mNf~4R zeK$CbON4cTCV$dAobsso#Uh`{ue-_=*_FTkyAyt>^2K}0mrv?jpD)RE|DgUnr|0^; zT}D2^7dQ3>AG6)FK}e|9VfpG^Z|(^y$aSd4PRpgtUL`-Z z=jz^P9!n=F6wG6;w)Fna^g7bt_xrj+>%_9NyI4#GZg&-*`xy6fs_6UY$DZCfk@aPs ziJ-RD0fRqFwq;L^&Bxl+g(yi(;a^BR~&MWxUpl^BQ^UA!u{p6^NiAzGVEhoa(`ECStk4*)0yblo!`G&*vv$h;e1>;t-1%t-rXLUV zI+-$MZokn|_w81hl~Z-J+O8^1YMXI&k)%*~utH2;=G?}DZQB}Vb4jSNZS%dfFQKq< zL)42Ct+Gc_SDCH~IrJm#+CgsalZu?N?V(la1?Mh&Q}k#n;{1H+-s}@m{mZKy=ejRf zQ22P*qG(6vgP)iU-tFb=fm^kW#1_5W0@9xaB4%Rv|4)~!?G_?hxVHUMWh@k zIq^R_W=A4K(q$4Gz3tNyZmgKLXfNN@Rc^j}9hQT( zIUiEn-@C^xb6Um5u&u{(8^4!4(LYg~nww9oNfUk)HP7q7 zRs+BOvpyc*d*|)j^H|unu6RTJmtQ|0c5lz;i|OE=xcy$^?E<}-J^?%JwrOs2SXlnJ z>_Y*6;-Y85-a)Icu2Xm)P*mUD@bR+B>CAf<+RNvf1w7hjbLvEkwZYS8Nq_X-MLlVo zwbg*O_ zttGSMazh_wt^ToOMNr8))l&HGDbU?7>mix;u|QRDMw@S(vm+Z0QD9_t05W9^i{8aY4w@1P|Sa-BO-M014f*;w7%QL?igg2VMn&Lch1MAXi zxf+$DC2M$1Uw-=ixWMq^bGv|^jx8sy-qtwS_ax52SfC};ZPRk@y0Cqbj++t^+7Hf? z_|njJ^u6W3((;vkH!92$pRf2UAeW`Km7(gAp`fq-(ZdbSXN8}6sWh-jWf!Ys>e+^MC0xUxqn)>ZaTX?D0L{mYtLmRGP@=3 z!Y(~O-@B~=N6zZZHet4&sS%dfkZ+y6`oU|zv(klIBTJLkd@?WlJMCHX-*u+CyoD1* zzh0W_8qNN0-7=wi|F{EbU-U~p>}=|ih+FIUf~9PQ!}pSaRiC>}Gh`RpvZu``HDBP- z^0IH!!wTMA3%K^|el7Pp<6&^p(cqVCjG|Xp9Q-73*Ktmio(7MHv6uQP)3_y>-7oT|6c(>S6oCU#9%~seqqK0;_Yqr0(_PPugT;+d9vYd85;} ztsUQHixya3tBFy%r~3MjZiS)HERUE#=?NXjnYTY@UgemlaO#J*Nk#-`l)Glw)Qf(z zqtqrVAJC5CXR-nQNtbnC^ULm@u0FA7x88eBj1@9M4J;*r%VQa2giZ~5?H zXGV6t?&`ek?6?Na6WWV(pFK=wN?u*%v|IgK_E}T6uc~3omi&8B?j-wb#<>Z_cKUj& zw^lp5f0$Oe{^O;HtGtUMEt%IQ-e2c@<^S>gEwlI6i@kq0@92Bp|NlSUYn1y}AZ9MT zWBv48ftgOeyNXwPJ-K__E?g&T!k+z^zXcYTxjwgVH2nR3L6E{^`;~SNE#vD=Z`7OK z*!|M(M8frnJnIYPo6p*MpL+f3{5fMC`*-=5Cz}}`sJ453qUi0<^R;o7vF*Z-Ov=u$ zcFVWBpD6mOt3G1q-Ndh^tam3&+AyJEeRR3C;Iy2OMb|_o$E*BOdKIb1v)kKG;s1Uc z@z;|juO_`*n;kB{&(7{<_0LcD4{w^b?|)Vd1l8{;)P4Oa{P!>WWBbCGig<;ikA~F> zY5)FjBYf%6m-;oLne!)Q?a{DVDl#d(|L^j7TlUYIyMNZ)`S;&k`Sj#p*ix%wyLnGf zZJX$-mLgRt`-gu^pVXPefTl`A&vKm$4UQptl~PMrtSWH%cSt%@C-rPv!KC?7OV=50 zp0wcZZPm#!?(3H{Tt9Kn`N!ISpV)Gqyqv4G%~!OzoU>Iiz{HwceznCLu_FvJ_6wEQ zCbL+H|7$Csa;CLDqGazM7p948t5%twZ+7sIjcAUwXV|;9^(ouw#RoKg-mQrA-~LbF zyWznsDUT-Ed(#s1zL}ZrtXt@EC3x2VwwEI7Iry&UJlMAK@HHmeO@f&r=idrG+Ow0L zDNK5wkMxnXZ66aJEdO)3#XeMtE#vo@k}#+CH$~CEC*HG~^El|vZ2unuEBFeWbQ;Z$ zE>iY;_UGZ1Q~4hG29a$WH<#S8*06q@8W|)j!TY&E!8X%Zfxqm~RbQsIQ?Ba*WG&tw zb849-$}-(1_-Ts9Qojb%McvljlWtU~F*2COXJ3*~@=)iV@uuaJU)cR8IlYNr)OPPV zbQ(^17735Voy%Yx2ISheO<+bFf)iT)Ve$Tio?a970nbzttBNJwAKs*HFWY z>~YP@xwSsKu}jK|d{|%V$ME*}Fa3%C|Fr#^qNrxWC?|05Q`sNauSZ)%c$XP>=v44C z<{WgFxHL}Byaw(#z}KgIiK(IH8&MEt-EwFAg@AW#qu>Wr;6u>cRf$k z=-(;jAr{+Kc`PBd-|+8)zQodi2}?l-gbJPIx^$h>b&AE*(6Gs$nN&U7p-uG%@Z^l=SAffL!w7+CA7e~&HShjYnnd#hB2Txt$^)UFev%EHl>CNO% zOLl3^_|?ii+3d?H_E0x--r7v{Sp^e~BTaruu9jHER1_7Lu{?9LO-cRRWqO|tHN>BcV3wP_be*g91=fRIB&%IvEAlDb{k}uk6@kov@QFp4Ta(fi- zk;d76P47PPo84mkFOPcLo%Xagi+Cmm21Ql|24y_A-5DWnyQ>X}&Ax3QQu}@VjtT6y zw+MPlG_(EMuq>7P^{qpP>@<#Qd@I#e^LCqb_v`)lUS+c^crQ15J}EwL`Ta$d@Q;55 zf3vH!i$cVfzh;^$ywqWHi$Cvq?KyfkbY>m!GGFgz6V4~L`DeSPt=*wzPCwehv^6$3 zube%r>!9NL#Vbs9wdrU_Uza*#Bv87zmwDZkvOAn>b3}Nn-)$9qCAp*ZY`}3VZ>G(< z=l?IzD%)y*=vnA~ONPj|Uzgr^=Wy`++50lm`c6`+IX9ktKkU2hSJCEQyY~Iw)6;M* zU|())jqr|7^?diao?b9vd%5%Qn(xtpQ@rzX-)9^C@N(0;oGS7|WWAuCB44fUqq@xp zCJ707?a=YoIrT}VX|Af}KK^ezYk20(JNNLwsTY46=P%!qe^&ptS;nL(dq1*26ZGB1 zKH1E5UTKET#;V18&k7#!nmX0#kz$VDVMFUiX@$sjuMLFXOT3I=k_c7r31d{zxlnLm zZrG0eBkMVH-mQN>{X>(9%C@B%+PR%yHl5FIQ9XKW(mg}#(_0TVS)a3Mx@9n}a$2C_ z&R4H3ePyQ`ot&w$$L~$?kHpxbmYO-Xdk`!1nz9rg2 zbooy855fyCXq5$g8#QNoW^CkT^D$5@pdUWyo%p)c3 z5?|csZ$Eay@??0D#LKne+c&uWYQ1vI(&Wy?wJDhrDo?v~{QCPplo+UdtlRW&cCz{W z;EewasOj^k!o*Xc^r=7~eH!CQpVn-=UlM&!i(NBqZLJOH3VicA%4b@S%I??u?@xWR zrBG@a`{Wbu&*xOX+p6~A@4sKyzl1$mq2m|Ms-^DLn8r9?YF@a7ZSv*}Chxm@BtC{% zTFgFc@ALAbpqc0)^DR-1jj~>Muarp0e6s5DTAY1i)27n32X&YO&2L#e@X9ipqL1y^;L+xzc-Y?jq#*4^CZIC;sN zsrCl_8JElrGK0l8@%5^PEgDyK_j-5$v*Z&hswEIpJV z>TrnZEZd#T*8J8Vrj2KRRqbs^U$X4hv_)&Ss9rj4w_b3Xh_rWA`x~9>Y~1fGK67Xt zj(8U7)_yXye%@t;BF)KjIuE@*VrOo7HkD_o*@WOe+exJ{+cGAb$VT&pooExerpkVz z{pMrqHQ{N_S!b;B=G2O<^Lq5twWj5l=^M8q_r6zWGIe#^mi+bbh?qC$g8A*~T%WnO zU0-(B$*OQpHIuy{*V-g@(f1engJ;ym|9Nn!X&P(b?k??m)fk6*YmL8W`ii9VbmVF_ zdHRHRINtxY$F%L2N_CV4vD=K50YGdp}>9mq@{@yrf6@nu+4e+F~Q@}-;}@R z$Mfpk7XD>MO`q*<9(R+N7#QRUq)$^^>2r;sXC^x|eQw2)K20F$^ZC5ucNanF^C9;1 znF>jtQXgY1E#{s*zwFBoj@MidrK8p^IKa0wFH4K9eNW$_OE080t;vbaHaP8YrPqva zN6@W8^(~tMP2TLh?zSTRf!H-?+1EOpXUuH=H?O*J?H@d;PEXp*%4%<3U!1dtBXi1z zwAc6f&2N4>efHDqSMNS6F-1B5TqgR-_rahIA4}n@?325tz6eYy`5Y4uK#>6 z+^A@#-l7A`D|!n!3tzmpd1ub8qp7&C<@BZ_i*)=IZbVLa{5xU(>EjPxzGV5frsv-K zpOs#}ul?DS+pOk!Q@TDu?&1<_gUsM3k?qHXR-50tEyK7bBvMo5-Qi~@GMklmFiv{9 zi_iGs!gOmHS+9mguUal@Ikd1!@$R_HRi699wDIfTuYZ~1Cb%8hCX%vLH!$v7X77e2 z*CT?gQ_^>uMHC#L=^h|_%;>z4mRfkN?edwAgVZdATd#N4W);mkE#Z}`uw0~C<@Ju7 zi)xux+ho>E;MH8?%{QTc^YZeD^=I17%qYEM@mnco>XFagKRCWdU+I0)Cv$b?<)|ng z%ioO?HvIX}Xm@j8=#2Ocd!29TE$MoENBBo)K!&LGii-BS8He8de#SmsY>Q6EtS`GFWksDAu4*`v%14Es3oSMlbEB)T>9V%}{tk=pCw z0w!@Zhm%qu4=y8r4b7Af^98EE+n^ZjGZhARS5{R4P6@6$)$h63HOE{a-d}m&s zT&uV9j!@c(S6fPSSXfsxzHn+d9RG0h>WDS7)JpOvoJ~1=Nqxf2l^4zT|5zB8!PBE;?5|z+wXj0=BdQ2BrkYA zy=_YU=RY$mzAU+>eCgq(>iddY`m%H1C9e`H5xH!<&;8xOBe{m(+|Ez7&1hcHm*KlP zJfX#>NN+*3*-;JOxRu#nlR`x89M^q0zU|$tKkxkRguLjwYv^5eD&gYqsQ){8_|Gdh z-6>wX#QjlQ!o3sXstZG3+uc}Ya^uBQzFAtllAC*WaXnejTl%(Y_QuKg@3+6%cW_R6 z3#Z`HDd~M#9qsztABVK4gwI-%ksIsz-6terk%io%xxQMgn|G}BSQB)pq1>aRR*-L7 z!w#Q=bC>-P7YWKy-?8yx_p9S4e_gFQ-e8vQ)th>27W4Mq8guToiAVie8zdg(_{`kg zqUDvb;^k;7$*%Rh1_e9Y`-7IHbSNfO7aaU9epT|4ftgDuPjteiC9_MnFOjPbl6~PC zb9P6g_+u5WLc6R2NgwUChB1#M1FLMOf3DudSi>~ML`ikCMIoGqkoKd7&tC8@Qe=2gq5SqXbS?z^J6zWCwt4WBK~NdD?@a$2qZ|NFUx{|@!+ zb)QkTP-u~9<;F$)SC{?#+7)BJ=J$;cpT3@+7Ag_U?Oq=uyJDe?xv$WkXrpAS&zq!d z>z*x2Omhk1nRv$f(S?r&x~DJP{Zkx!zarFX``wfpo2swJ<329FzrW1m_`R$D4&KO_ zcJEHh$6rrZP@YJGyzq8l2B|Bns0@v_u^Etn#GXGiO zxs!jN&tCu7dSc@ygMDWmEdx0Wj6dyqbW`lu^cwx_E`{LJ&C_0J z))KwRM&_;e$pexM+a^5tIQ_>vWwF!SIBrL#7)O47BN$Sr@kLc;Unbwi5XWgbKi_^< zn!7*#jQyRuD)Vj*J6@*f>rQgP_kYO$t#2(#&|>~k*|GC&-y)4uD%-bdR^FY~!_G1( zQiMTNzj2R}Nx;5kXA}8Y%e*umUNYIH&@ISWljiYr{i*L=r`sK}OqFc)n*Ud~gn2GL zYrk#Xfg_yOkJz6u`dng7&P`kD#jU7#w{c^~+n0V9nT4yQuD30jsdxB=;TP}Orhhkg zAAi;^5@4OUg=^sNEG+B_{#P?+Kr+ ztxhof{QPR)-B04H(<3~&UOy6_$Uph2=bH6rZe<$0-ck6?b4RYv#T5I7f8mAqJSUye z*ZXkJyjSgVw%I~;jptAD6?TSQnW%fe@q5$`>A0lRM}>5YSqh@pdEAgZ%NO{obFa*t z?T7h2{~k&xyS)0e;zfa7n`_O@!`Cl&S`lM^^Y?6i_RqK0t}B#Z6Da&>-Tc2ByzH-V zi90>DdSzDsMlrkEK<9Qt_e)L#S=Phq&9g5$p7EP$Zz`bKC!%~A{0Bk^(R)7@{&FC4a8ai70Q-s#^d z<+tqRZ~0$;iYzO1oP5lO45Z`=o zehn8m*(j7$oSWb1%KPMkRi1gqEnR`d@*d2M)7;DiXNh=t75@9nr+IVIqir{m0%db% z&a3=<@66*llW+Hj#~(9SVopu0ncG~nNFd?alhBi!b$il5`L$JVe$R~@*_pn}^p9;m znd21}t?(X{VOKc5Dr!G@gz>&>VB(j)C7FRcPdUsI+Niy?utj^RY`K%RwCmfM+uF^) zhj49Gyff+Q!;JltdFC)Ccyr3tx4ySa+L_h8;g-_Ule5zK7kqMF=>PCTX>rF=u1!g+ z*UL|T`RM)AM|Z!rZ~xr!;IhJoQq?DhU$_3h_&;2OeVIwa{Pr2I-)VF$@+r!8K6!JE zt|UK)%4ZD*t$oZzo*A-EnZ+}l8|Mmn?J()pJ(1+XG~Y7l-|{beAAQoBuuFcT-1LM0 zZJi{xGEVh+nBaFU%6rX^Hg9gv#W(G@X&pSmX?=}Xl>LM3sizNBUw)dXwmE2N>x2o{ z5_B$oIJGQeI;U-Kw(}*Q_f6ggUxH_w{$1UD+_F_9V5>n?Yd|9BthSm9Tvm+#9M@b@ zy7ZZ6S|+n)`JA5|Dj7PrvtF~Ej97W{d4`l;>Kwy~lf9p`UJjXEsHUm8MN#tGlFk&< z>7q9*JljnAth`UkE_)Ny?z>&UMbGBOqc%PxhkrYE&2RW~^p#}Tq(i%YL_WFucq7@^nrO+oWt)*_)rF_WV6$ z`bj8SZ(7Do<%Ziuu7BPtoZS`pYoe|Eob89pLD~4#%WnI27w3%J-+6g?nf|Q-JL|S= z4}Z`1Y-@Dv!&ecD)sDp4|4e-QC&2rT?9$gOZvR=>zUJ-04LQtu%hV5)i15tk$#Y{j zv`_ta!(oX

WChtlf+D)}*a5Uexn)d%nrbYXWg426r519o}{8LEZ8A~bywN#l zdA(NuV9SdxjrERFiD5d!a7(fI$D4p3IWFfuh`yYw>U{9O|GWO9|JYW(e6+vA*28t- zecY5EEfA`&Qs^472xB3!Lbp$h{lUdYJ5+jsvC_j1QMtg{zK3Os*k!*fae+_y{f<5*_L(Yji~=;mCj9#o1l~f6~a~uZ<_W zpHxTF&#y*3=Vk4S{VJH}HCTUKKEJ7A+Q;ipe}_t(U8OJHQ7q!O<$GX}-o2kMD@D?F z{@5~EXIi4jlG`sUFSao#pAyiFTYIiO{BlBPtjvb+qxTmjIn}2wy2tqUXL13r$V_YX zdneluKdgA({_tG?;=ktlauy#xbX}1Sd@K5|kg0-gXH42D!?UYaoNhg2!G9@L>VSV> zPRPEh4+&fLTi>xSjI(-o{7&tMy5|Yy9T9u)+O?FMzq?ZVa7W}OujL0#X0qP9GJ6+u zlfM1B{-b|Nss!u!8Wt>53g*31)cIffbX;ty2G9E2;&oqE)IMyz_A}*E_s0L+Yc(8> z9!fhPF7<#r*)aM18P{GBWAUp|$0r?Il(?pU|Hgze$#b8*0>7OLs3_wN=HxDBn^(y# zU_ZO_xSd3n%Cbui_bmV9x-4(%ny=dvGdr|hciWU0mYwpUr#6+h9eN%Zrt7`_%cAZ4 z-`Wq~ef;s86_y2i-~KiKeLMeZ=kCSf0+&;t7reh~_%C0> zDTXhVFYfPMmd4Mf`T@+#A9OvQ@4nvuSl-qHZ=0JBPhPH4{6O5PTJmQiPw2PF76uc_ zxEJP1cIN&4#IoPUu(q-*e%`EoHiz}kzgd$ib2^-zy?TxL59zY!DzU5qe+~<*c)aJ^ zVxIrE>Cul>D$+wbFxn`_NJ#4)MHo?kxSA>)^Mvi{94J5rr~Eq@po z`TC@Jw8zYOzvUv2R(|SbpHi^z?knjZM{7UD=>D0*RsVVI&JV_0KNyGokS>0>JnP}| zH6MzL6Aw7+{W((I*E&CvD?gM=_{s8ThoZ9{>W2O3-1uSs{FABw-`E~rly<0gdBfkn z1$O_>MSO{7eYKtC>(6@0Zo6tN@!Ds$M;ARiSn=zqN$2LK z^_CfHd%|Kezr?ihPKouiz0eSr>2v@8mrFOZ98%xq9rtUnus&I`%jw}W@=SaJ)ioPeM&KkhC;!bhw`{^n@)tYN2Fs}01d*!di?_Z1E?f13KU$>z0zP114 ztDCl8{k|zx#3}ZL!+gft7d_9eI5OJC>8dSwe0Gw8a#ie)`Hf7|ITx7oiq}2SS$I|E zOYWsVk0dYga91}et?|8}6>gY)^5^Q$TU5F-p1+=Muy{rr=aL^hQPw4=15+l6KRc-O z`s?Xa406B!Nha(QnGmN@bDHgN;;z**#qACxoj5+Z-+HFF-;9F|>V8Z;kCOLC{NH?4 zXzSeuw!a5WK5g!~@m__uDbXj!FZZE~WdC7{GshptiMbTdlG*WZ3df^t{b=8`#94bA zIyX!E6`SRYbfjzah0@ZpmzYu{Qs*67D>Ec&+u z9Na#HHHbg>b2F!BDW}Yt>K~%7_jWf<@^Vc%^d;v(!>!h1_qhKEpJln;z|5ELmMrAo z9Otn$HKMk3jrSDWdQPPjw@@!ju?J2!1Dx5;M?aZyh()uidgdYZdskVuy1sesSunMq zFW}iiPMf|9i)tJHWWJCL{Ujl={kvhAx6ad7=agrN9u=P>p?HofGiS;>g}pY85xzC2 zb5HfwoXy?pe(ug*&b{aBws7Umoy~OVt;50dJ}1xd^1PXQZ;JI@o-1$vwA;YdSKut2pE2PQk}d zYX08HO)A@aaZ--8(Jr<{PY*nBQSEdHFlD$MKWkY;ms;iisE!j&Mj{@~OSOb}?}@}7 zvX7|WcV^D)-SUrTFS>b~>;D3ob*c0H51OXSo%0CwG#5x<^IOQi^?^wP_xp#-U0H&% zn@tl{xQ(yeEwT&X({lK6`=yx9<^$@|>jX1FY-#b2S9^_{ z%NBU)G&ZpvmRK=;$$}kL$pMRxRmB#m>NQ2aI4obYWx-ty?+M#itXl3Xe95biIcWO1 zj_04_;&qp5>0jazy$7`ld;ALZWDDOFKa42Z^hD|a%Pa2_-yc}JFAE7Q zF{-@4uamW?ca^HB?fwtO!RI+YdrorEUnSE%Lpws-<;jl13|2?4OSe6hJniEAio z6J`17q;>mj?W&wfU8}$Ni+3yL&o2nPxK1lW?Lbqx&xEUwDM!oC&h;g-Hz zR$t_4tjxQ3%}{e;{lzI4HmzSK`lQcy_Uy|iv|b$P{JmPxQ;DZ*s=mL3x9}W>+?$&^ z+f+RN`yMfK*^;=`CvYOiS>2EQ^EN5W;0iHu`AyI1*=c6?QQmoJZe_EpE?LLeOJt*#PTAsHt#(^}b?Ss~zv3=( zIR+mH5xbK*>ra#2gHQ`$H+O-0zRN1dG+BeSdDH6NRZo36x9j2^@pRZJz_&&0Hd-rqRT=tI^b3(tKZsqss?7LFv$x!TR-xW1g@ydpe z$1b_58-+w)4HwmV<~Ys#&|)VIognxG7sF_u6b3AHEfqQ-)4rXhZW|SBE+q^7f@9L)u%(#su)mPW-JZ0RxUTp8jMW$x%sn?F?rW;H$darb{Vd8Y{t06kC znq5A8+@3#wH(T}e?GJywWa3)!cCy05dxdu8lTPYC{nl7(?{4(e&G7rg#Rbftb$Cxi zeO!K-VanH;pDn)>-dFHh$-udhr!|C6N%r1yzNCV;4PLyT1ikfC9=teJ_UA_A(TDb7 z34-Trp6mJ~-3gv?s7fFv$l@suZ3XHIV5_#^R~-{L1Xl*zWS5Y z8Sx1jQFk66P5ijKMO60yud~FH>F>1W=hr>|X6Vs-b7k4xM<0`)`^VS*efQ*Rd3^m> z^|J|qh2dLIuica}Ni@5#G3e&mNj5QlVtL9(y^q;4epuHoSRwbX;@<1;d#_GfDf;Z` zyjS({E$=G>cS-phrft~%Vg05L^ACEf6viJ?l;3=@-EL`8&kNU=6BCuDy=^KqJ$XB_ zF>FJ^d$$cNF>_zmGIS*UG0Nw3>dswZ^kIqrhPAum>OU;KBIx;miI4k#a6@#nEvx)m zLl)nFV=|Wa1b^u6VA4&SQ&ZI`sQmX;#>XOlkxzb|K~1M}0)H<$Vs;_?+1dEH92-m? zd1<5_kYJWO?qd;}vEc1az8wP9fyay|%n$x_uSTD{mtNpl=OF5y`CPvYMEdij{n>Fif7<{0~3YL&O$ z_v_v5kK517KTi2FiAkz`=_-9Ef3-uMlQwNzr?q5h%a!(+i+e(jGc11Uur#&wezUHW z{!jgTF^-zaalr>IMcxR+JZ07P{nK-7hWXX^^Yi9kG~*a#?Y3-@VCg-!A&)!PWcye0+Xha`XNeEfd<&dO)N8FlWVS_eaYVuD*RNt#oN^ zWltVgEI(J$`@FqJ))sBa*pQML@-8T0T7u8Q;uY-unSQ1pjQgJ}{!K%yKtLHzt-rn?{&S8FpTV6Q3$}K1F7moP ziT&sERlKWoZnm9zRo=}ieW7dnhv}5lfLrIlND+p#;H*`i_TpLo|nd8^#I zRrj|ZZ- zo4HSEPTJL(VrLGoo_BD68ry@Dw~s&FmvO#UbWU?x;g45;zx}L~n!}v4Y&}PPb9CvO zQ*#WzxvJW2vfX*MZw60dV`jVi_P&WiZNKt%>rI_g&Odi$Zgp>-%-UV0%&BK;OAlZB zCUw{1nCn@V?B38#Z*+90PP@16YO?mMySw))r>Gp`ky$h+$GoRCXQ{y?L(d!45*Nx| zl)P5j^fT~kY~+3GN$*>`Kg<2P+Tna$Pqd2R<6*^hYjvx`vILII*`jmbojp3~%G&w) z1+Uk}9=}o8zPtR$trYV!-#s_J+LWTX>V|E}63*tlzm`wz7KOz=+;!NtWYMylc|YXi zSprLJd=IDID?ODG5o(tHZeje|i!X0@U)pNT&AMz+`uDrX%}$iOmVf;0?jfg)>$Yb% z>}Wr?_23fc`}f`p%q&Z}y>Vx8c<^M?n(Ozr9$gyzT_od$f6mq2nOm>j{k@G%>1Niw zjLR3?Ys)XL&eL1vHe;=;oS)$N$#L;_cPR!7>^*Vkq{q1e?}+MxsqBXL|1U4P6nNnB zS@osL;#;CuzVWvCvo>p+k%|>-T#fFBM*Si-4wHgvS5tj2y~6H*z!eu4hlhmUp1klB z`_1r=%Pn^Hn3h)r#+4rv)6@6Xso9vwlbW&lM&*k?9@1Yw<(Zm@T&(I^cT8ulRpz88 zqTlB|aTeGh5^j0BOt*QzX#M=UcYz_NPaJ+%D0x@p>g=oUmx^#?KeM-A%pr5iEaFUK zqtRBs&Boa^y$*JXCqDnY*;12a^-XD>%k3??0e(>mvrUwx4N@AjgXgzx6nxk=SNmhe zxoHa=Y%_e{F4)I>rOz}eqvfYrD?aSm_@C?Fei7-E*{6=F+U*RNN}P4ZK*Zwg*_6ov+{5;`d-y?NlqN*{j#u zFV($m(tCK#^=NMP+uQtOf45nc3uHdKyCE#6Z|U{)Qe~ZECeJMI&TEWrzSgwM4^_laKTR_KU|{@Cbl zn>jTy(eZzg#CoQ;$&C+I{#e_Zr!;X@fDe~Lo8v|EfY)qImK{BR78md2*skqVaXajR z<65?VYgTE!T4U6|xvxU{Zc}t_ks3p=!vaTMv%YkGos~XaF0J>McSr8G$ozD(U(5O6 zdA=`2-75o|HqA9(FWarAz3?i>%!U^_X?L8r7ufRxMttFXE996jisY+J#b>2mLbe*;&^yw;G+ZDQ(J;m-SEI>{qJE7MpU}zig(W?N zx&LDA++z!x4@9puu~Te|)wdP<*vI~P+G!09!Qz)3;?rg%Uvd&=xu`eKH%+zs);H#t zX-0F-%`Tl@)?(sl6tVYM!QQCZ*FzrHiEyk6m#{8f_@d@cis-g~3EinzQdXYVReX8E zx$xD3d^wf_4}ve+E62V$oF8lZ_FX*lrrZrCUct)So=v?Iu_ezoI(qj(zGt(lOMU6YwE(4TjMsIygFmLafc<>rX*W)u~*M#PPnzp{e4egvi1CSMT6~q0aYJ&PjG6# z#+Rw7BeL&;6p7M{42B zmuDr8c11P@v0YtIc2)oSv9^@Cr*HHuTWb2NSnto7^PffLTIzk*-;rBuk^T15rln;a z(rYUUI_EcR=DF;=TqELZoy!ho{@na2FK0PU?o5-8+s=4hAm{MHS&UPrNMACQ`StYM z?$m8tMIxI^KSuV~uI0V9vEX71yV;BBR#Je}SQH4+PD4*-B9p{v-ZqEx@yXJmW zO2f4YbK7_2|2}P#qWS6gL&e&oYvkT+9<4Z~QtN|p=Q8A{t})vw_xVZmQ^$bKx573y+|GLx zaWUkNzuM*n9xMgRjM7bm6B@f}Tw;$e;pN(zE6%JVe`2b}+IsO1k<2=Gr@!@+eOkEv z`?q83@AZBwTU-7?!=G{gjX!y}FTIT1ophy1G4`6IPNSM!O^ETQzgDwWnLLg>bxZK= zi@X1Rq*T--?T|U~WeRV}@~Ft|KE7q{UVJ)AkJd2nbn)9d?Tget$#?wy+x**PIhHMt zczx&XIhDzt3FY4<`M1tay}8BgYwX4F*(v(p_i|2nH!=NmfUDhu;Hj6dWiGvvb*CfQ za)XUz)#PoK*_sDdN0@iMo#~tNI9T-V=CVb*1>27uyZ*^?%l)}i*kc|2?oKn#`zd*1 z2~YO1_N~Wu*XKWO?ysF5X>&F3j8)Y0n9#@C&X$5tC!R^UZjqQ>+?9P{$EkRG$t=(C z#v9xHKFr#frsT9XN_n5>1QF{KO9O(LZgMr%FdEod&@K~Y3||q zsKl@BUZFMkjak`KG7Y;&!&oJAXqX z-2a0qzi}Vyg2mOTJgL(&jiP-&*G7xJJtB4ZZ3(wa6NCDznQLP;Ia_cxb#+a>#Gej895#~d|_}scJ|MqWJ7qCQ%lH z%D%|QnH!B$o&LmaTeivVT;7d6T0LK7Aojk~aR_6nAx^9|g~pUh96XS_(JYD%BfL;b%d{L5FL z@L!zGy&_ZO$4cj!JB90%Mg2ujZs4j+E4I1SruWxx762Pe0bR;px=MO(sj>uG|#->y6DKq$`=OtQ4_o6p2}`L z=E`ku->)iVHiV6SAYp=QeSb1%>yj8D{dMR6xHgjElij%qfD_&1mYk&3P zyIoFq3Y1ptzozoKi0AQlv!fRltj+c`&pP{7lIM<*%YL&Dci$Y;Juv0tAJfDSyaqpl z+7tipag*0g{1d%kVb%2)x@*3#F)2D|e>gQTY|nbF49~YNn`g}0v-HS>2^&6}th}b7 z&h9)z-{{Yyz%y$KCk|mbl_jlCdSyAJC@ka;0;(9@>wqK&}@?khm$iW zA9?dlVBVCAtBa>@FzLBltD4g=^U;zW-Y$Avr#Zd<>^ioCgEv0Jyt2Qm|C^&yRH&OK zchMJ-^shxXS?2tzKC^oAiOC9AO_UmMSX%rsu=|tvyTZcG&QeNNY141^P#)e~?Y!+t z4WC=o(@vjwed4(2lKgLnZa#FMwEdy}?cDvz5r4lt=+f*nU<|yVwOV9)|FrFMa~O&) zcW?Rre0lAeYr7TICnfdn=sP{-qL5#_knxm58T&pKK7Ke~&i~Ml!m^JalWUk;^B&&s zmzLhj=WuGtF1_IC%lC%bE6kl@w%IiLL7c@UwfRYYBGqbJ_Ak`US>&4OB2H$N{k(o~%pRqJk_k zJrl2WyjXi>N!;Isn`c}6W>^2S$Rwh7y4|iy!!>~{k&kmTDs=A{9p~o%@JnVF@58$u z{fw0wdLhmR3wSr4629=qj&XVrkKT&Kk{YW^7PfAVILPwiz@`9Nx>bDARSXTzVxoI76g~2yg(C%PpL-bTOCaI%W zPU~wgOELMmQO+*F;aQNRdEYFBo8IM*S3i~waP>RJ{@$;vbL&>cCygNs=2S@MxC^QG zmlV(Zb7StM?1b3eomZY|R@J6^^oHy%=H42z-?+pui($X|JGISUSX0+p$YyFkuHal# z@V!xDuJ(zzdAs6e=ln6SnY7EcZtwQL&u*BmsZmorD9ZV6;)+w!2W!}724{DQ=)SC) z5NT-otSvsdf0yqL3+p4>+h(TPb6ZSk*rfM5@}>6byvTzqtk#9^cX(&uc~GKk>649& zyC+F5{LFH5&E(tzm%P{I?DW5N#Ua_6|DMaqBmHi>-^|;6%C2DMr&XqV0&V;myz(9| z^5Xkff81h)=&mCc92G&!T8{bFXm2T4cWwo@{bRnRS;o`$bsc}zBGP{}KQz~kZ+e8j zlGDz)3xh*ko}~ZmubA|vH1pt&>6%uYmx^Sp8=t)E^Lpa0F0f<0vqInck4y)TS3gww zdinM7pm*oLHX6_W;wcpn-(OyTWVV2|z`xr^t0e+zetp3=*>&9o-a=8kp$^{$7ya}6dGihao5v$;Ekl`ZmF{N{%b zw&y*XdMD~uuaMmKKgoIjoNc#Fw3^-6IX%AZ@&TEq!~^qAZ<&>Hvr0BJAp-C6xQf&y`&&jtkUf& zaZhoZ$bu_dc0~LtRA0I#YWM6vrj8lP4ZdHcT%EQuO=oXf^;T=E7{`w*E!!S^&TiqB zQ{MkWa<_y;&#t8Zf3J7!nS52@{QMNpEl!t(es1kmyCTq+CAneiqQ5!b{@+CuzDu)S zUr{^DiS_l97KeP@!i!3G)-?B{FAu9)5Dajo>{;Yzye!Xu@gwBeu2l~rZI@>^bQ z{p_I~n=O#B^!2j|D^x6PuV$!z&6>AsM_;MU%bFD`3^oD&YjZe-Px2NjJqlT&z9G$1 zYpRn$v&HIF*ZNfFp7@|OV_nAndsBQ_7*Z{*8eOg&I}`oma`#!5ClgjYzZFrnPV&ID zC2GgT>$=iJc0SG$G(2NpzAZ{;-QJs~99GQc*AtS3lD7Ir9#PCcboWPp&f(I3i|ZOx z>R#AbpDpFRJo)<~-`v+V#^UV%9_1GJWe0nfTg>U<@8>JK|8|Z{GDrKK2Y(fr57!&7 zRN&3zee*7SZDWz)`;up8vi5J`ZC^ik%CZlAZ7aSl6TJ|#|E_wxI{ZmKhU{c`g2|Ehm?H|Nj)AD;U5z{CYC zhSxa4WdF=z|0y>0>(>|G1s^GWSpQ+2rnmccA4#jTmqKd<+^?^nTw)&KcGC1$DBonA z_+^|gHcEb8mV5Kr;mTQSrpf-C|0-kUo1d#1R^R%S`HuC)E}#EZ$={3h5B%MJ_VL{! zf%4MIe?f%{b7B?eO{Z!mN)h-=2A7)T!`}B6=(uxgP2bM2Ju`wwHhb#7taZzImiwNW z?XhItruwCZzh~zh*le>lAa0T8)0#D2x+~W$a1Iv>db!+TS7(xrt{c`xebBe$*jchYU41+2w^Lj5=l=h`|KE1z^%|Fx zm#TKZ-p6OdeC2Lr?4~&}leuFS9g4a(edaEy8&yr&N280Uhiqo;zPeS}a2Dr_{jm>U zC7(A)QizL|&%Rc-qeUWa@@lE0ADz>!k3C7+aL)C5YiyvY$*xt>U6ZsA8?4?_)EO4+ z6tZGIm)M3&JSz@ujO_Z#zFkD%>fueNrkTz?bxPV$r1{>wkgbn<%Iq?|&KwZeyRC38 z_;RJ$kqvK>&k2c(vnPcf-hVb%@ovQOEt*$Dqt2bUTw0sA)olHKJ#)Ru+t2;~Yrkho zU+D3xYwmhoQ`uq7{dOJG?yVd0^jDm9x}~vTZPX-3z00cNqATx+1n;V|(NtAkkTQA3 zlZk%cK6D18RV;C4n`G_8Z)94wtGFQZx`O{_hAsT>-dJgI_IWMp^9qiLeLi8=x`!p9 z$F|*zzGk=S9k)?gg9=a968GxRWLZ<^D^GVew&dtfU%Kk{$t_Z$bNqL4Tlr2ZH4!=b zKm34%g|zzzYdMZd&mXwO=fC@RO-}fPnRfrmc}r{rzC|2cyZ+J&)vnFAJUDd^cKiu^ zB`lhh)qZ!e$NVjPOhUWfB|YVrI&3kMb;iCf#sfY-|C#1FF8?5YBiH1k&hGLzk7vAo z{)hhzU-Kll1J8=DKbrkuYZk9}+_KiM$GFVyu%;BA?cT*KslIiYmx^<&ven%)p~rrBNDN4I?Fw!X*BxB0!Z=bnVCkF|@N zTF-5jD!u*MhVU3{yyb?dENf5xHc_cjrwTn82JJ09oWv80@7toSKMhcf1N zJztTd={ieqZvI5=MK}IG{4+(JXZa%EqbX0lD?bLtp4L{Fv18e$9q;x86t?T@^MvQV z42t40^L#p8b4M*U-v1%0>gmiY6DU$@aZG1d5`*s_U1CnaWOaTRRNxHr>-N$;_i z7;o^LIdQK{tXE6MGRx{X^rQ%1a(z;}<=7F8&VXy@!xpiQuU5~{nYF0_bk)+Z7Pc&<=lDlZ1uFR2Mc>V)p!33Y_G5U z93(oA>#-bPQTU~4!PkoRq$zTxoqK+vTqC7ma(zgik8wkl@`uEm=V#u1dstpa(CV~K z=r>RHg;KS1`=(?sSrw6+yY8{GoyM;RcTULX%YRnfKIg;Q{Z{>VryZR&N9X69wMS;% z{5=*`2Y& z>&`CACd;E;nunqSwLh=kb8SZRGw!3SCa(NpndcaCMz5}oBTeY8?TyOs zWjpGP?i{UHoUP7h@Za5OrQ4iHi{%XW=Tt3CudM7)HRcg};Pm>?f1T?|`KKQi7Cf1y z5_sj?86VkXiM%I0OT6{i9jp)M>DYzl&ybueSn}dkT*0b)`#o2DoF3c1PpduhX|~s=M;yS zeOx?U-E)cD{H^mRoK2LRwarp7J6k8IbZ?Ks*4%Ah58hdpmVVtKbZ_ir1K+;_*Pd>F z(I6R@sFxd2U;S?P4`DSCk#1SpqGOeRWzU8` zoEWJt6Lm68i+R=QT&?NGQ8V`}3pslJvy}a2R)sJw_0@Bx9Aj!?ToKY9q9qdO6ZhOF zEp_pa3;rM7gwH&FRVN{5UcUU^2hpi5Z*L!aB+7DkhvwCtOcT=nU0bLc%Ni80c}-`X zYz_lkU;LRzf3E&aJ6&M!_4n$5tr7{PySiKsT)f(9nx7ZA;c~6QDV8k@Ix<-r{!KRE z`uuvn1n-d(7k66tO?PuhP?q!mYr&VcesV}k*~u%1lcuebxN^=+vf}Wki_OPw{rQ?V zL+;bzoo|i5U1>g&>oh$#w3F*j&4%J;R;BgfIbTz?mD^V@zOUi@})qG_@F>=l~T!cj_TM}Ob>$I!o* zHE#8e&wFo8tMp8ale)IF^c?4^>SZPjRvwZO_k*VP9;_<8YP?&jXN~BDpvoL>_vI^= z{+IRi`g%Qb?aIn|{~B|ri7i+&{lIkB9`CIoCo5VmMeM!H>6IK>Xthbi$alq~xhxvY z)>o6B@3IchuIAe)#a#Ns zlxcl@FMB&lA@#WR*P~| ze}5*=Z(`auJ%YdRR?6Y^rt2eq|DPA}UsvtgGqv1`M)mB~ z>UTSCe7f@LeOHTBcXZVAi__;87_3~Z&c2&nKSF|izg?=3MP|do6PEWnCw-6(V@@-+ z_;YVXW5->NIV^QcQa8^u_7*9f{zyc*r$Qs|Qp&=(zV|UI5{W{`>Z;Br`CobMy1g$=Z4@Q9zPgx!L}Y}6Y>UHbSSG>EPnJbp}qT70gxTBXf zJ_JAiq@>X4ow|TAB&U{V$9@;aSN@+xWxwxNcxrI?k)b~KYc7e?o4I0qQjB$%n0S>u z>s%mWP@>Isfkk1(#VmeF)*l{i@xR^)U6b#_u8HEMM0v3sHvz&5U^aY{w{O=I%LKRhUoUx}!Pi`dJ3tBp6((bUw%5sbl}Rf7aD8}KUn>7p4BwT|B?Ow%^Cq=d1_m)e$8KV;oMe-LPneZ zhre#;DjiyG(EL-$V}sVov=3LK)R)|no3Lt`0hWX~knf2rZ^lCyka>d=g*4XLIO_ z^@&Q|C4cX3TFf0DRoJxjvDN$ak|Bp@aArS#Xi#+XSE^61=7-DcyO*!DY)@WseDk!z z)vc|wvnDQDbtuv@Gtai#qF{-Bs?W;PpLN#=hGyCBpR!o}_40=oUwmyBKhxAGe<%Kr zeaP39O?!5<+!dR3%0BT$v;47&cF&^Hv$x-bU%t1EE9Rw~HHIw+ zWvaf;X??=*%VACb6cai3)s|B(ZcQ_6{d8Hq%JGxrSfLju`YUkocW5DI+|1pO@xw9jkV&y?mE@WZBO()oe|1=BR&q(um8BePTyN zIP>HcsaAqZ&SY8LD3+hTG(+9Hi|(WjURzF{1p^mqU=gRkS&z$S0e=AgbPk}B|@@|JE+O-WC@n5^dew7}X#31wLeXT_P z`#C*zQhgi4e=S_R>(+7m{6A`3hnS_kY}WE9~yyzy*6hEcYzCD)unE-n{g? zq5p&{2HzeXS~f{~>B_PuKFc}L8@P%${@0%o%5q8F{-%6sRP3+JJ5v@c)KT8L@nfid zk3N&nMbp>evMFYLKP!J{)NlEpw&!zI{%_uMw}eWbK6$t6Pm|z>|5j}e({=w@8=sDH zt~bwneM0;9$<&D~F&R@%Gh`j}qq$B+?KiET z)ce!*nXK$2nZ=D6o~_zH!Yf3&KASCaJX>MP>k+KPRm%2oV_#T+^rox?zG$a;MeF;P zx^?YsJa$t)Qgxe;Y{{gqV^UV?|BqhcJ>4NXwKD1Kyo^MJaFfUn%R;ZrkiWTM+N^TL z+pn9`6qkRG747}8VXlr(=*sJJmpptUQ+0Iv?ga;qwVe{XX|bE<`BAy$KcY+StHiyC z)A#(;_R%EjY)1O&2m6=l+H2Vzp7hM=hfn&|PIKnH%Bj{h#&Zj=?CU;xwNyUOYV(n$ zYnY=1x!g`nDU@IAE#Vlkz%%fy(@g8dPG>_lRKAe8e8B(j4Nh_IFV5$hGM^N8ADX%R z@w3uN+4Q-R=Vc%bvJ)b=K9RE=;R~1H{taJv)Cf!I(Q>^U|w)@6UPvaesk!_RiThp&}(0 z1y&#Bw$sYkEylQV{+<_AUi|aBl{gmXb*|@`wqoXoaNUx9O;)+qk9UQZ1#Db#S4yDV zsc>!JB&$cy%B?oOt=bX2>Ok(rsb&X4SrwJY4AaK_!s-5X|^@87ocv&PJZob6^QtyZSq20z`dPs){E zUpklT%Lk`0IqNMc4|$$Pu3u-r$mu4tbI6XCKGXltoztt$lB)!k{TAV}oyYAU=KkY{ z@&Vrn8;z?|RJUcb1zNQlw1r9fhsk<-)vN7aARuwLDL#T%mDyRG!$*H*_t%FCH!K_1 zT{Mkz-Q>-2^KeUpP0?zb^7@;()|<2{FFd|7S>a~%5%(zW;O~#wx{@Wk-TC&0&fJk2 z7jp1^?BvDUIL#kDjQV!jqN`O?x#oF-@*-}xryHleIo!nD)!G=DCaEW8d)@oaKII0D z_v-t1n7--g&s_2*xy9di-ovezFFo2^w<0-qii~WbkmK=OCpp&MpHG%lnE_4D95=jQ$+XTrGi6h|k8*-oDW8|%RcZYdi_!!(9ZWQ53RM={!n13x&pNf1fZ)xV zjDe=RnV6S}HATkW`*|g8zh^F!Ny<8*yLYm<+3IwsWzE!I#`)mg^Lslu!9XKv}_gKmW^XZ#fm!$kT%i$@!x@xI^ z#Kxe!yx*+$3wLf4yL2aN<>AOX%Nyr4o6KQ7XXIgibnPTp*R{8H-n+WVu-g6Y-jkuT zr$#$II6hb8m)n&jJwhp)dV^B0>DcIdc>(1v-B z+ziZb&#WoWxXi$EhX3%}yALn^sOXSB`S|eL$?|=gxh$LtHj{Grp4D?4vOT`g`M~VO z$DdR!JZ=4Gs{BSiVF{K*yL~6jq%W*IY;K_Stnb&|jOE?SZ%hk#eIq>Lv5)9%Ns|ei z8E@wsc6r>dI#E8W-RYi0Ov9ck#l(w}x@AFP3y%357UF)vP*66ht#sBC=X962`JdM8 zil3u3H}2ex#FA6GZd%GfXKyS@HSN!q;FUBAy3 z_X%sgJ?^^5@|VN8od?V#uBK|g;n-h)cF)ZN+s^ol`6<yVpH^UMl3F*@sHZda_^frWrntv*WEutqeY1HpMX@yQrt~y-fzQS2uFt0GMEsf} z-@}*^dE@!S`g1Z_)<-zc^a|ARmHl{YSF$^7QhbEep~=z?)0!vCCopZ^pf167Wm)Fi zyOm#7FnznIY&(1Hcd*6csk`FJf z+OA~xnl)_Vq2KMivu;^d{Lb29FZ18vmaR;$d;a$OJpE?{1Ijl{%ISSycSCxwRCf+X zkja*ZEal8S&D%HJ>Wl0B=B6&6r7+X?Xx?n8*IzjNn>2kxj9bpI3hQ4^kc->8{Nabc z1<&tt&V1JHe)#(0@2;!r_)c95*fwjn^rG(?9vR_ontS=ej=zsHUL(;_mh&?$JzZzh zkN)!Z_4oExHa}c(T>joZs~gU2wWS3czJK|9j=;#hI=vL8iD zo6I)-(eToHS!Ubi?7-aYTrVRM*f6h{qe^n^qZPmEzFjtmOtm?2Fj3tz@v7;9#_!Cr zlMgma)yw&X3ufdr7_SPR!r{f$l<;zXMVZ;WEf*8bv(x!Usc z-im;p)?%Jteg`~-pIJP+P#>^A?fQa;slf+W%30?weW5cW+vZjCrPN>ZBa_tAd{cHv zo_MEp=5luW#-?)(HLhI=9v$mS9oB1`iR^jV7$lrcp`ECWseD2@zGR=jlnfIJWK^IShmBPPnam~ls3E4lw%QnXwe6Rkx_TyL9Z?WP15&_+Y zjaktG-#0ki|2g~fk#(DO7d^T2xNiErJGJ8JtDjElli)fV9wr@Uk$-dR)C6%G!vf)w zTGlnY3!8QSYwo_waCN$yu>Sqj!>8UUJks1ZVcnt00naqH+_^T3P0%`Z*OQOxp|-w# zno7Prp~gp8K7VD}p5Qf;i7V2UXS>cp4>g_=p=2Ma@5jRT9$wtMpTFGi#hgoS%S&f; ztA%j89X)ko>6FO5nVf-)#^s?h^7k`bR;BgiGVot0Yde0N-F?H0y>f5+1G40$zs#^Q zsF|3vIcsgwyp?V~F*BS@Jr@+r_uRp^Woee~<=tHeW))VlT{GUHe?8xaw=^fuck%1R z(}O-FuAXSJW73hEY&|v1i=WJAWVfHze5mT`wrIHynYZ%uA9U8{oRrlFba>0q@ThuA z?U#jJg;R_7H%JCQ_S|Lb;XkG>&$sg5Bc>bNvAnas7EE6| z^V*B|bqtqlwk-Cow7JH#H6!;aUoGdO1qOSf=T$5EAHTQG;-ToulgnqVmgD`ue8ufB zo5qUUwd{w4V)@@WbUw(cyu;@5_Mo62PxR%W10t6nUtzfP?eL+#7jk=k{XX~O>cx!d zZ~C1+g)dlF*fsN~)h@Zab9bBXdA9cBgS@i2g);+Y7jj+sA$vv7Lw{bARiT_kMdH1! zn=O^*PJe0~*W_>}(Dkg-uDIEG5A=>!vZ}0kv7s%$t${h=tn!@?b~ypYAAaSWvYC~f zbxre^WaedUUnTaG)sth6iDuONOpw}fz0cB4W_L%~q{L7A zlb8rTInQ*S$}fI6s!d*t%o#)ty=I6lEC? z?%e%RP?-1F>F7V@ho=UKIPt#-6W+rqwl9B0+>J?2Pj@`%-_-nPj&I}!nI)_49CzI4 zS^xEk&&&0y+qD-&R+Q#We>1~8Wk*=z{r-hd){3l2yL;i`ZebnE_bF4Oxqj9vY@cnp zy0}Co#bU*_+RginA8j*QmQbXpuMujUt>F1GU+u;PvD9Rpb3Ov{EXK#w7*AK~aIyZH zrf6rktVmaA=cmV9#B^Jni~(CPS8Yv1`sv^mM*eC}7#ezy9HU ziK^Zfw{JH7e^0hNNz1#J8L-jw<*%MAe>2WCbo!rMWhaz=`0j%H*=64runO*c+^ry! zoY`sJrLtx1*Y%dyHS$L%1U0>rk|Jm=8I0d%d zwZ3n3m3#N21q`MCzjKN&@ZBx&%l3HI(OJ6_eGAlYEn|D)|ZiH*x6#yHj;cTkC{avx@F)yZY1gQ`YeqiUyMA_Qp_%w6}@+6XP?35#HrmC zN=Hm@bX?uzZ>P2H!!*m4E+6V5PjYtDWiLOd%kzv}z?%Yi+G*SW`V z-@0RxtE)G-@uglkCDMJ?>$=^}58Br1yS9aXTcT}kwt0zQS@g6c?kBHi@?Q>f|GK6z z{3*}8X$CWPpV)rw>-E%=yPhoDUpViI%ai>#Kb0SymUS+T>&(MvFN=znMlbvGeUfXX zCMR>rrN$Y*I*$rJd|@~7SdhMb?;joE>otaa>$T5GY;W<~+caIN?&Jz_iRJygW_Jsh z-Z6^!+Hx}9H#1FR!HT|~RgLSFoBB$`E^1b3yg4Jfv{vkyxiia&-~Sl{yqQ@<7#J8h z7?Rd)kCI^Vk#}QYU`SpD_YxK#A%bFCMtN+Mb*&%~aHPt{O( zc{R}C#UmyLRQpZm*0OA7XJ9y~%)lUx&Hkj)%$$_eBE5pjw~@K|x6K6pt&2anOFm~| z--XosOeqnQwnc9+;S5W@A;7|xd(kj`<`)+$$AB;FZ}Zhzg4{imSi%?m##$;znZFTVc7Cr_@pZu^xd z>+MfIynXmE^N-KEmg2Kg4QAx0_?b>u>SAj?SgQBF@{~yArkuk?u3|>&n|03z>AgE~ za=E97@3a`fACbmdCKo5IdD(TK&)3z|f4ltiDZjg5qrYQ2R~Fx8my6%e ziFkgMnYsUo2ruIc<->a(ND7yn?d!O-vv%qx)|pv5laiK1Y?BZ^8*FT&_TA(*Q|7`T zqo1i(j=N4iZd*A+rY5}q!Ry%ych_E(vS+vxd2U5oi;%O!lQ-pN*OLw0CbO@b?xHVw zaz}zo&UNE2n=akH*|XFouT&^>QeT4Fu5GiFx&!Bbn9_5lY@bVlV|_zK%n3>1WzP#I z?`307opS#H_tm~D>=Vk4voxPzu)PrNYsuBusj@Qf@LQRr!OZ?iOT;$TkLS14s$+h&HAbt2*JqtwAs{b4W2yvC ze>-DK&W;~a+ZBvV_IW)pnVj(8O4Sb0<*|%O>AbET%4^(fu3XudzUEJ2=DOtdzTEfY z^tPnGU%K$+mhE!ya@Wr_O#%OCr3R)kY7_CNMS^OlA{X9L+Gr$;NAY-=^2wQg_}?dbC<0!eG^j zjmgcbd5cri*mkr*5PDFZ|J*zR=D(c3Rk^raJAbKicoKZEoM&X8W+qR!YJ# zIy>-?Y4qyAnC2kM2t(Ug+XIh7PH37e`+RjpO8@SfSgGp;U!UuR*ME$8s}o=?KKt{Q z&0lUTtY7%*MrUpO2a}MzYd-p^Q4tZkpOQD!NxfjP*?%BiSv2jy)R((6%Pxnm%u|fg zTbjWgVQcck{t|E59dozNe?>O^H6~_T_XL%0xt3oEP%3e=wiPleR@`+lQ&quU{{bUYz~H?6TU@iw~9w9O<<>**i%=UM^+cH{sy6 zY3;|>xqVmlGBtnp=otUEIJbok%XTl7SrPl}>S5tM%bXM*KTqr5+0}ny?^>$~tPzD_ z{HZ&CUYhDws?dAj>e-@+Jg57v&Q!l~qHmX$->-gvR%3}!o6nmZSc>2 zaGP`Xo5u?s*KYl3wmbjAnY-OywtuS z%U%zEyLlbg>nSm<{kyap^aUO;$>lpgb?R!dm-c9$qT1n6cJ;T(nV>$Vgp+%CMQ&^| z4^m%LEwAEX_{&8{jDew0J!oh56!#ZQp?=qyS2mfjh#n9+_w?@a8~++t=E(00`K!sc z?#9Oa`60i{UNE!nW?r{p?@^t-=R8vvd}nsu@L77>FC`fcncnk8mhn>snO84=RasKO zmhU(5`tc(j#j`^C*R0GuwPw}E^YbKZ9XfvA-*Rulm0$Ur*50yyP`qyXg_h4h`*tkP z%qrtdG-qGDKjr0grra!jejC~9rOn3~Ehj8{xajw?xl$dk=3TeBuCVC!s^e$p9Gv~w z@&6S@#JA-DMJzUfuMduBZ9-o$iv>4tawjX6pGH0Ff- z+xh5`&f@6P*BH&?dG5#*HI#%nbgWwMyUS@d_vEE9GtN1-OU9gtz1x&<{_KWeo0z^p zRogrRl^VwAYiHX!OG1jH`O8wWdH@Edo zU90hYhg*~Kv(s9ueKuS%6`%B?%;(IqiuD#h5|&pQNpO|2sZ1^s_Barx#{VUlaF2;jd6Xz+cNR~t5v&{&SpsSY?}7) zpog<|P)uUpte2;glNq*O=f3vmww1w?D&OpVT8oZ3x9cu{#5YSI;*l5Q1F28GHMc`U zqpZx|$#JRQ{MFdi&+R&^v9?8p?Wt18ES3pMQ#V-rl18oTS4C}8_TgY)D3oDf5XV;6 zC#R+B6;$q(yq)*>*w?x7h7;sHn2ZE-x)&%sP>OQjEtpij-RQEK0Z)}r-

}D#p%L zYxVv({_U-cJa2h;_l`-ca-)@<_UB3R$*FRovN>?A%2zGCopshLOe41td zwMTz?zt1f_rnk9f^^?oH68`^Eul{^@w)yi9U)i^La8Eq2^px>Y?wL!cna=c?wp8!N z)7{^7o_ldWjTDfoetCJtwZ3tavwkN?TRWRIN@&If0%A0NZH)q*%hpk~f zpyK&0a+!Zl=rX}g7xo=JC+RPAd}(`0w%nyP4eZ&|j`bYh=n}wi%V?1Vci1zX=#A_* zSDbivgY|OjuKEu*?q73~Y%6Hch|J^g(Ve?7H*AxJ_T(EURO5cA`8&*XsT11w^}~mR zyP^vkHEe>``aJFa{otsQxMo53k_+E?TY3eaSw7KE?t{idDVuQl&MkMY zoPRP&$9vZ4q}hvC??`J5{rEBKQ~y$*q=l<4KdVS?T4HyPWA4(E%DF zLOVMRb|y87|M^xZ7x&L(|DVdj&vHskc8LtT4xcp>uYY=KG<{ z)6v~WYb=W_ckhz2-upB6$(Lu&21QjrAO5N`E3*54T7R=*?&+?hU8;{IJEumy*AK2>8_;?(krE$-{5GfGvQNi??M3D;iJ(O9lp>L|$c>AvK1Z`nhPE_=_*DT+RLB=o;oo~%mTcSFx*(c1^tMfU5x3Exv7-E*+b{ zy=U`si2QJT)1>D&mdWNGVdD!un3-^1g4eCe*Ol@L;R-og_ z$>PzAt!~VB2|ILc>x5q26Rm4DvDfvO9h)-$y3iV-6`O=xw-)vkBo^PBT;I>v{`G}Y za$Z!k#afjaVN4~$XBRZG3gl0)^!ng0u-m>wEo6P=x??MjZjzdHpgw=6SOJ4rH|y7@ z-Z7R1-XAm6?)kr*W^^-B=e1!^Q|GZM%}yqqRYJf1e4nH)dnRRV?S_9DC~WS8wEFgJpOyCnd_~#+wrB92O$ly(=d>gt zRWv|!RRPPNWhG|ilQty_SY^6)D(!4C*?D92*;oU1%`3UB3OrHCtq;upL#A22+uVH0U%yZK}(~or;9F1F`=*)})^-wEAi$x~B*}ESLct!eaPu>2jxjDI{IJUf; z#W;Mi_K9~XR~%RT_!?TY+cQKprT>8EqOe8}$0rJ{wKo}}oBr?T>ozXidv^N--<7c& zrq*bQ_L!=k3*D2EdTL%P(=NlMU2UBcPRw4wxb*XXjlKz*QU}sMX`Y>8VYsfZI4-r| zjS&0Xlqk9B6Lwkax6YaR*E>pF;_}VT#pm~3c)vQ9f7fH#<=68P^9rkciH|*PVL~kr^fR3cFQ~N_E$^AHRLWUaBr?z*~mV{v(MZ8@2^efwM>5l z_@q@W5)w9T<9u`FYQQ4Nx{SEnl~S+lX80Up3USFcnh=sWvGt48xrtji9Tv`+wY|LV zuh9AG?7EYAQ;p>MB34Ye|52o(tns~<`Grj`HsM-}JC`3m68wl$hx<3TFUyh3CQE{6 zNcD0aG=42E@MYDxvKfW9qx=*0ojY(yTJE5W-T_^=jxzh=H+l_sr%a2oyQ8H(SA6H> zxpui4c`h5zB^~ekWEAtU*Jswob2oUU z!Pu!^S>?gYZ0hxM^+`KPwcT(2)OYJ|)mc9|ImXZU>h?CNv&Me*r8W{*wRZ(*vX`&g zYwhOYu{d8;u&dT$%7&=U{^^gm1U1YR5o%f`%+tZ-kd)#tdu@l*wAMv0Rec|~-reB2 z#OLeLe8=OxJtEOpCrIVh${07ct$oM!Csb|EQr?8UtGMdrlQ%q>a^u%}2_B&*{}VRK z>aqKL%SUa1Y?EI1?4}X}gF*)bgFLndNM>G1YEeN^Y6*D2;i&EHvfDehzW>E_t#W~h z@@3CkpBIImH<^5LPTE=B>_;zCS4Q!uItgWWg;Z`_TlKT~T>cz=>)%Wb3>>G5CcXTa zWh}&*lauqt+H67k!QbWg|GoXwo}=0oHD|xC>&2AUJ|UYQT(yhLJ^J(Xi=QtdKkT|A zzba>QZqxt2^B+9@JYE0%!}<0s`Q2_$K5V)*J@isas-e`}xpN<0&Wh*!VIDC(bc0s6 zbf9VEM$S0(tIK%Sor;xPk~CLTvTRlJGM+k-(nyx|_u_lq!lMH_6&n9vf9l8LdQ;_e z3`^y<)3dA&Ob`4JF1RFB(5!KXpzDPY_7+9#YXowA^XS14GX@vF&a* zHQ~JWDC}U%#Qg1^$``#q?b)-od0n(YoLcF&rswT}fnrHUypxnzk2Lv4E<2c8w4id^ z)=rk5E!_=H9~c$ZPl`%duMlaPJBi(T&O441*BJUL<#b#FI_tMas$SyAw2)f6x=8%U z$6dL%yp9x3c)OxBNWr!vNBO6Q@2r%m>ZQ70l>hn9)4keU|ES6)xJX%vzXuc$Zn~%-3#b6Z^OLy?WraNLDkavuRP$Jf_;L6tOxfLEQw2 zud^Z^p1te!MsRxOhjn+lmDWw(8eq%RYj}Y>&7QZca%W(E{^}I}|0~koPr6#VN$`GF zpLFl0(gM-gzklz}{_%DG{XPHwz4iZZE6w`BT_M3~(X|^>GG}*dSD0*yIxr=<@Or}? z0q)fcS8dX4oN)QU-V@i|_QuOLi%y&_dbr;nd@B&Cx@nPWIh9++2^Rr~FNW{@L%oyq)O> zugSw#51M`}M#nKub@^=4aDRbF!SRzBEU&gOvU>2uvu{W+U7IWThX1UX$;J1J#r2mh z5O7$^5!b)w;51H?8|er8ei%CBvUGP$*reI8N7Rd3YvmKeWjkiMUVr!Md4ByoR?k^X zdrS{RFtu(FH>>E3dh~kYo6hX7#+?b1&Rc6nF#N4&Qnk2byQXc!yj`qXuCs31Ofg7o ze32}sHzSbYd0(s>hS9 zGd!O?|H5I);ZJ?19pcjEcgPI#JUIV!v_bgQDdAJU{4?7rXz?Y;qoTv$ z3)74hF{_w*&zY<+7BGrQp62z+)J^(Jn4M#Bc`xrP-9?r&y$Y@vMXq)6J;wR*Pr{3S z{*)avPI65uIvIb_LzhF>P>1t&S4V~+-`Cj!mR5D2x37+mJ9>Zr&)>g)tY2UElk&Du>|W<__JrtKH|nb;J<;=~=J?Q6GbuUEk`59c>6y3Mg+*E5pNNhp1A(G#fM z)XdS~!xnMd^gQFN?Hn5uc5`J<+@`%iYZtRg#5@y&jwbcDfdT6zFPJd=SmCr?>Hgx# zc2gH=m#}pcE(qVPy>0Tls;qD$&nFsWSQHZp1B?3v5zt3 z#KM9L4^vk*_iC{03P0MGUOqddh3kevz`0Vk9;vy#39=EEi_5=WTXdn{XWz!$h^4F4 zI3;@z$TA=EyCe}_))Nz>Vr|InFi-v9&v1oD_ZRKbo1WpBQ2JtjPzR&nQsXTT1XoVX zkP_>t+sdQ^|fEIn1;04;_S6dEE$bl2M#n;JfGk5eAiEtfX{J0XE@&|Z@7>fy2dNw z-~Cv&^R>bo#7|8y3%Dt{y7t3-PL>B7^JmwKC?+O9IN@^C&*fqjkM7fK2WHI)jGjw= zwjE1oO>E@-{nqtqPs|ez!KQyJDurIPpW1I#)2qd|Z~2+sw^R71{QTv^cUsu}h|2!8 zn|GJVPi{D3e&CA3nvG{mKg7Fn#5{Vx!BmU6OJqT=T}Eko@~nYf<K38Io{$?L(n=M^~ns9a$l6Bih35@?y;5J z^7+!iCkk8h8V^SnoN!vM`bF`ehT%Wf0Glh~jUvn+9J-x9Jp9A_`Wyep_LVYHYj?eh zetY4dquuny3(FjS*Xuqxv;JW4bOi>n=>M@3?!-06DxWQj4!bV1^Yf4OsV;W|9bG4E zzS^^8TZ!8#F6T=h1m`k(aZ25cYM%0Tum8eW|Fna= z6aQCn$tUc~WKsOGPR?I$iW%S28mAiG4OXf>_Y$72dbKle|BOkiSl+fUFG%C`Wlk_* z`SRqsN1BF=hj8%USl87{@{T=J|M1g*yVkXze;6Kd8;#CR3&cfsF-15w`}Es$Ij~% z<5cWY7!QOOg&hcFS(~H%$zAi=W1T+D<{$PQkGiM${!wdARMc1*vE#JrPIa(`5c0a)e2^vZQHZpf}g%*g{i2Im1=ZSi>G(VWY!-i zSKgd|jZbs4sHfKC-XBvRa|s-lO8T$yV{4vamr)3l)|v-zas~gic;8=VaI{S9=BK`j zsiE6WDzH5Ee6h?&H7JoGV!ffEtLvFbZquqVxC^(l*GsCgHBQOs*x&fL>G$rAIU+~? z^p!ME% z^O>$f-p0)y$7B0XrWh$0&kI=pIp6d2Lz9|}NB1{BaQ{*lFy-FK7Nbfh5k2m+i7K2= zON%yGEpHM}s@q#|x7X68V|DAwgBuhxX4ubUxjH{}iOOc@&4KDKmt`!PplYP9Gn?(h zx~7Ub*W|W@UwX!S^pEAyH-f2op8uvud*5F&>8;$7MRB2$JFhg~6rSf3`^wjG$!?)r%&+^hOk>{*smv8AbY_Ps1 zaD;11{4dWb@r^;Z8|DelXJMUMu$Nu^t;W776Dm?(9WAZh(z;{unWM`Uv?t5YXG*%S z_waO?n9gaV<1GbOjj9$r6wa)-NOb&}dQNS=2^;IdAh(~sSLL232<)G9X{nyxk0j2z z+5dZYcpH2+_#k#Un0fuQ2QImL|9+Fqlz4Ab`26vw-74!_dybv_-sPAvOXB{~k2}PE z&bp&uy}qemxq&xf>YL-fl81#~37$+BdNV&G!emS8s^gC5IUbvANqzE1vdb+iOiJRr zPtTpVU)zfQzUitG{{66Fs?|kdcAqW!c7?~j{#yE>>(7PE4Sc$j1@0VP{Zq29cv}UB zb;2bX$N3+{;~i$7R5pA0cOhF#Per)&@`M{!SFgOZ5&b>u;>E+O@2F@zv0C+td+}3N zb;qZRCFC=gKb^sAykuH!l%~Wi#m>_e>0B{pAEx(p_2&pDZ(49F=vwo#7iIG|z7AgU zBc$z$@YFq?ubLz`ZI|lW@SuC=Pvah?IXQ9Lf6QSleYi5hhf|DcR>>LXeGgSPYPN(t z7TDk3lYiY~X}7+A)47I_E9pH;r(Klsw{13D`YK@U(^WHjpDH(hpU;|~uz>mZof)T= zPVmq-Ij*hkU~te!vV8r@UJZjx#l0E&(-U^o*1F6qY+Pq~Hj?FgS5eiY4;N?5IrjJA zLG>Mb$~L_Y3C>!zVb-^c!Dqr3Z&)Yuu6TOtiN%vvs_Et#XP@ou*muu4fa70{$K@~{ zMmv*p@~XWn?c*gjuXc=!5zaAj*d*jDIP2_HbBm&u$O(TdlJ*`v`24(h*PDmo^?P{I zZFzhDUVj)q{ku8;LS?;<5SPfuB{i3W7ya3196!nX1kX!Tg})!;Ok`ODbORX~b@NS*GsH2p=@&CzlPn~~gFL^BG#MDW_ zOMDtWidOjNyFHNCIKO)tlS=dLB?lD#UERGsYK!L8CHoSL#G}$&gUh)l%bJ}r_4#F# z`zv?zJeKAR_0Ztt9&5SgIg6V1>|u$%D4r^z>UF8)ja8fZ=joeUg9L@6Jv;8ms<1rp zZ~S|RJNjMLL#?O{JpWB=?rF+6DT^PKi1Teaefq)C1oI;)@v}~yyEpxa{rkL|RyDp~ zqYmiwt|*gSA@M`~_SW71vhL09{v^;U|9)S^HsgOzXI^|xcKEz!*%_(4C#6}P0bV_C zTk|ISt8P^}Yk!FQlggsr(kCjv8<^kS{(SJ=Ep79V)g@;N&oK7Sx%l%Dw^Y%mh+QY{ z#DA_lv1OusagasI2jcR}TK#_czs($9v?NnTLkH^ZxAMTO`5 z3vQM!J1;K?bj|&7@Y;p>+`KO;M1-eSZ!$=D{Ap*vf)~FHg8~-E1{Kx{)&4%qVbtM0 zH6g6CXl;W?ZQz%W7t^={H?6Q;_Vvo01v>G)_U)SYp1)PouF0^o-2dR+%-fc2jU3v4 zl7prkO$^`mHN5TB0+w6utC!^$i24P3$JaPA+fLK^(Rl5LfmwP**LTg|JJ&7OHlM}l z({_vOR7{WEnRkXEJjvCj{MiNR>XVaf)*M~4Q|Zo@A37>pCzS8xHv9KKyTdd6 z?4om-W%J^)P6ooz09!3yhv$f0@zP#m6AZykzg!^I?r$q7Q@@W>5WI zCcB%r$ok#%$kLS!OZDgPj7;1fpe<_t@#Wf+yX+R$PFIwF@jxx^Z%o=U0Rf#{DbK6N zDpF&^+OJ+ZB%u3~N%X)Wk?O0CoND{0wE69y7PR?As`r_Y-DTIG?AWv~Uqe3Mr{ZEU z*P#!|-)4%W3C>VF`TTJ}9mD#hJdw*m)#oprI8&f6xz5)zty?|p-VL84E?L|YWu1}_ zvmD!BKcnPm^rkw`)Z(ezBsc$@Cbh6w+{%+p(_^z&+Z(g99eQ)E40C2xSzKe8u;`NS z8JP;XQ$HJiy)rvF!C?8sBP~a#7-YVg@Ti!#p!nZxey2_Kw+wQJdfRh$YlPS%*;;4rfBDJHygG9V(@oWP z=bLuF5cn%S|L#fl^U4)1{12MzSmwW+c#r2rK8vf-n?o53GBVEm{CxC?Wxj%Fcg^WA zXI0ma4^@7=GOF<8WZ`{!RA5T!51U=nedU~j3llGeURvaB5Ts!+El5aO(r0SR_RMB> zsnivD-)5daSHFKju;{VF9BmUSpBD2tRK7o*W4P(VzVHL`=iVoNVSn?)F(Op(OTjk7 zw+DWC37k1MnVn^QyU>ic{f&FG?%v|Id?RI5d(my~mFYb{%WY&!(|Knt?MC!C}f3Z@Cb8pfy z#@`27g^!*+W20%a#p2n|N8WEzpRm=nR4mb!Iu`u-$&Lb3eckC{eg8zuSFDI&&#d_W zfQRLvz;TW&=blZU4^C%%d;Y=BFpj_i>)0E~C!gI7kPTcemVY|X^x&7uOi#nZ+K+`b zY9y?yVwXLdy(cF2KZ|_Ns@r|5Is0e$ozGOCurSiqwIU{I>r~SNHu`{VQ=>#s_4*{KYKLJKjnDtb-*q{*}zdkS+zMP zcWL0}O$k#>4s`CVs#krz@1wz1L7PYOt(u-c(}+FS|7z3PFr_xp;2H*I={5KL8BfpV zwb-kpReNe<_DqRA2amqq*i&1XWOO{+?EfdD8PO>Zr8OL$ZT2;MrvG|d#K)Bmc2d28 zg8Ls9Yd#hz7dmv3$-ni(@s;dp>~7aiD$A^ny&lF`clfJV?2i{sW&!I~Ju%oO7`-`q z+p^8?u1l}ID9$JH`S+ov{jUC(7h1c8tQL+=iF>-yYfJeY);N20r=?R8PCl)ibyeHv zcGr|UilyBifv5gx#xXL*oS*4qrE6&F@agAA9`8?$48GA1%Csjr$@=>J2x-^6+7*9P z_Q;d3KVH7+7BMSf|FQI&^1kbfZ|=JNt0cMm+|rd>H|>&Kx$WL3=A+8H#F|eRnOt2s zf1^`ya)+mV{pp;|E=#TbUL9MrV?(K0_PgVEPON^hs&xivQblv8j+>|GylFd4bT&O* zE$Fb_>57rPh#UjY?+x$29@{PI*K#3R^T%-?&ObU=uLg$SJm|KzVoiZjBy+x8$5q27 zk2;Cy!;uq0;`nE-Ty8cs&E!^VpSh`x*-du=0f7Tt)6dCeui~!V&F%fcil6&p-Wv6& z_|u2~v~N{0dm3t#Q6crCw>Yr=m zzj&KbqfP7=pQ?NQ<*1XP6}z$&oAwC)Jh);fi?2f9+(+yxeb<=N%0)T8dv)&klDa+UgzF^A-E zORUiB1`^P?p2)?@TRQ--%{`YFDR~_zg zzqPZ^|2mN*?V9$z$cVpa+v_zCURS@9Wna_%QtpdY`!w&w^&D62zOC@;;xkRK5pb>A zI`uGX;Hztw?c};&HuhHdlwOFlJ@ijvMmE2WN{79varn2-oz5jjPfetzXx7%H1}y9G zDl}eVspXgE9F_X>sEx%(FXv;r(HqKC@3&mZY$c?M z8IP_tmGC&^uvkx<&pQ7%OF;ec)`=%xzJFuB>y`hrEh6QcJg4^`f<>9*Jey-i_0+Z?Uc`^Ptk`;3Bg*y`1Lmv>28 zUQ-F!X}RmkM(@5AQqo5rWv$-6<;60AeM)`-dl%hyl>ObNH$ykHeABD2SI4?l4lu=h zNDhh&RVg%?!(S#HA+U?-{ymYmi&Ol}OZS~V#~ZZDXx;2Dm)={P)Oylh@F*>!=dE(} zPJc=BDc{qM>}+`O{ZnN|+Tw!#w^uxqqNo1&^t9kRbInC0MK0hY*BD!f>y_{OzUH6|s+Zot0hiDr`nsz3!1XvAZX;^>P=T*c)Y^ z`Qb=X!TLNIx6)QAm$}yqjUO&NTq7l=er)b`x99BBcUPZYxNgISW65R*R;5>Yrf%p)L9Nw&ai8E#*lfPi+^; z^!VK3l)K|znd`pYU8D2qZJCXwi?*IuDKE&7KDk4wftz2g?7%TUqb*&jvo1K@3tntK z!*Gg$Qt6iKJyUDaS!_3#wOjY-eyK{CaE5KcubeCGPh~z$>2%wEtEjrd*9wp zTwU3|Hf-aLH;?l+w08Y8F}TAmx%+0+`mjk~RZCiKM?X^XjaG|5n)j>mP0rxt zkAe<~{+bnUmZaQ~tG4)c`1R(p(8Tt}+b%g$%B>t*8>64D%m01e_V$vZY2Ucl3r|@4 zc;U>CiBk)A=-pQ0UB0UMpJ@9=nN*{hQPo+0d++f*v&(<2SanOcRz_mp{KH!9RW?5* z=K03xnf(7Hb?o*P=7WX5)~|H|B}x|83ipJMGG!fN9s??$hplvFzU6 zrnQ?b9>hHqWMIp!RLe=~73ni*Q&OXy3-)Po?=udM zJ2qG1!=)VGoAP!$Ltd>3lRY_^XVbf`eCLu|EVK8-T+%NoVfc82MSMkqQ12w>ile*V zExN>Zx_Qst&8wulb}liFPMyvB?x(cEOO56^&gF?F+sgXQc3k<@y<*eXMm?S@94oRV zUOI?hmASCK`3ZaPtbOzLM%!=R)Ub*_&(M9Y&d=>G6PC4BGb^>#RrIGcd}oqkKYm~~ ztI4<2iL1DMRU_6t4{Sd!@#g3D^78WMp|+D>%$MhDKfNrA_3l+aJ5xFBi#`k)OP0D? z?Msz=y(46ewClw!@?qx=H%>fsbcyo1>vA^S3$oA1O;LQyVQ_{0Jo7G>ibof>{`Yjg zboi^E-2% zPjTj>KO*Won2*%$v2HYYZdfvVMq66Mwc{MsM{Zb(1z*m~So!h2-If=x*p@pyVb8zM zXd)xB?A}J(TIY7fLyzAySDm#G>~p;M>!?Y@{yB>n^yXaq(X7tt@+td))biz*Cw;fM z!WqK8JnnYG)rH03g8Ld-P52If3a(HSlzeuze^nv3Q+g0{Yo*PP3b}P3tDeg}u3TXA z=yqwINAS z+Qy^1u>H+(j!G@H7bhNUvd`V&e#7^#?ysGHT8mT9Cl%dUzs*bQ=H`DY?o!3wm6fk8 z4{)91{#PdW-s#_^YrLsVD~vkp(p&#MJ;k8aWoRxRYFQHf`D10}`r7Zt`IS3QhE0s* zxixp|24SmLyvMZP%{H}rcq>L=<*i-({8z(dQ$s$QJ*!##HE!CvA8|K#z51B2WBSpL z^9(+&THvm*MTPvo-Hr^+iR^^A%s- zJYNy@(?z@gr-=F5@KbI-{`DwM+K!ev!V-4^PgT z$?W*yLE6K&ybu3hzw_4fb$QXGi>s85uRU_y{C!Q;u@GgU(wQH>tx|2i=yz@1Gl{=P zs?MLA=cBd1%&dOvsx|gq8tyyJo<969^Y^yKFOn?p*Vq?jUsegrzkPOvXi4#-6DHfX zyu4Sk>wMkww|?Fk{43{2S6cm@_^zQqed+yOvkP7HYo`V!%)fFVNx7!dPk-(z<$sZ` zw_D04>`4pBv(nynad)m%-u?qjAGY@Q-8n7%DN*(R>F*C8O>f`l_Tcct&vDjSA{|n@K3-2%dA@I$ox4Yhb&f?+# z>2+tKPOsU2U25H&gJ+&zkLz{hKCe~ocIZm8|ILqYSP%N0-NiY*Z{OTalQ)D_{rvQ% z?r(vZpV+efd52jh2ziws{rvRiucMJKp2*MhWJ)aZ{&eWZm%X8Og;SY#&)Ch8rp#x1 zT#%i&DG=2EMu*BRL-r-*MGlPpM&S$HJ6@?TdvJm z_U+?>ysu%FyKjYEI{diw@@w^bcXDop{L|}udQj%zvxD(`-wUGr&fZe~YGO6-B#*7k z^T>X?*3>tb@~d>_8&AoUT$BAu*5wVKA-}+ue$Aid^VaS^_~h%MKaRmxm8S3b_MNEx zt+!erTD^2h-Rr+;72i)+|6+gnV+FfgPsNNqA*>}&tsXch{VLP`WhKpa_vN{R%{Iq& z&fOrrefRUjminvwUrFp=m-Fw6(Z9fxrit$@`<;{jG&uXzvN!PPH`LcwelQRJXl8i4 zFUmebv~GF*C6VKX9ah{g%^q%?@qo44cT&8Sy;DPd&|;xh-Pem(DQ{jhdqtssfA7TF z?H#)|AJ4k<_e@jX(t7LjSsgt~AMKepXM+b%4A*0p#e1IJZTRG*RduUeEhYQ?`A3i9 zr~eNM4f(alCilU`zu&WO&Aq%|jm0c?JIkG4r5C@fKKP8e=!D3z=@ChXreCao`Li@7 z_Gi7LoPf)er7w9cY;|GC6JZZbh(HRm_i&S?4j>*uypD=)eF#-0DnH0}4JXRS2_2Ltp?u5gE*zO}xd;i7nn zwc_-9C%Cgq{wA)s^=#o1tJZ4I_jx4Ea(q^D?Ai`J_hZvdd3P{zX>K_5YjgZs?_<4< zCKn|B+1~TXl*-`Ve077o(ub(UXZN$)@LjE*edR^iimTEYXVgS*wQl(%H-mrQ?$?z( zs}p2r{PvDN_)Bi~fu@5cme*M4TQ=!`an$-+_tfg&-_@d9u7vsjGXEEDtF}XM>&x<| z^9vgGeW{cCRG#qsc}e)BUwyMCx-aCObjXhT;lK84l@ad|b@Bb@*ST=Dw%tr+YZc69%sO{( zip||aZ~lBq{nWE}a_ZV6Y1udG|8M#{{rPj_Ki_S4>+n2T5wbMo4o9TQ$&)8fF4AjE z-5}PgFf%QCWyGngZkuHFk4SAv%%0e6=lWPBQhR6e>8HDlrZzpD)G1qK+#}vZ=C;DwKVB?-iwdX)3g6~ zCa!X~{^ZZo)9rnh_1M+t*quMGW`1(Ff4D~70?zbP)4xHet7xrc1)py;?J}-Nx zn0xe8?KH1tn`Ql{x*R`g>Yx9U?Luz#k>{L;_jg|QS@!K?{_p!*T>F|&?y2q9zqMj^ z=JI>ZizH+=KA3vbYw5+L!Yb7*lCKmuOFHlE4pLBKA34+ z9zVz2wA{mPF<0l5?E&{ar^?nfPm#Xiq55D0r`3+D5qCCz4^{n?^Tgrk+P)==JU(kR zA6~e}ex3g6P`xi=U$r$qJ8Wb=Y@D|v)-%*md->k?PhKq(|7*Iw$T&Durq*ZYl3(55 z6j`rrl)HYw_Wo2$nF~@a9~iH4aV_cH_i6q!=IbB-TxFk^Jwr{uL-XE-1qCx=j5o7B zYjk|yowV*%oBE|W*=OxKs!z;0`I+HP<7e^DN8Ww^!Mp5)`-^FzshdUDs%_w%kn)s| zDOrnsecY+FhaRqKohmA{VA@*qEn6==*fV!SW5D+}211LBj@0pj{ATK0) zyR30`Z^zDgoWAi7_OYmz?NC0SE8P^tsCsRd=q83NGu?I$8FQ^wQtlG0H1~4b zr5n!rV&X1)v%5wI<9dc$d*ki*HcN3wW$P89{b(0ku_L~T#LVAF|Z76Lo|uui)8@nBkxr=+y^4Ci9u z4Nnz6u-b?|P0^^;nA5o4(Qn=Z&3P+VT$;Y^5_@jNj1>*;vInYTeofwAS$9BirSiE6 ziN80yJNU$|sQbM6;*Whh`WNY~S*iJZ;^cDStC`7FkqZjex2&wV7u)%AN^#zV6Jb*u ze_oe;6Xx+ce&&Uq=jD5@o!L3>kwe;xqdWL7&c7iY zlx6w-eZ#w_>g}snZcnnW{-tHzSATfdGr1d!jK5^e?%_^nxH@~sSy}T>XW#CaI{Tpf zme*Tne2BWRY;XC2Wtsdr%F7@A-GB76Nha^SjYp4n_ZP2vRr1?PNcli<%!gk;c6fw* zIQQ?#)v%{gt7Ogha(>(#aD?&R6NQyEQi@Y+H*a&@>m0pV^L%k-`-dbiFX12_bDgO# z*x$SQh;h7Wm^)$m_Li#NDGnL=?;Jn6)G=+TF*H#p+0~? zs=sUY(tuq-&UYS_w_Ts6t6%CY>osjs$K#f~hIyy_{C@ig#CYEB`6+QreBY#(Z@2%~ zIPh2H_3YNKm9rKH|8`E*FMYBkyZVdB-G^J(gjCcX^G>N+y*jr3Lk9o9Ui)O5k`pf? z-tKsJyw&kZUf-P~x<~)`R!y@JZE;ko&b+ywr; zi#POLV!W>@*~4D3BV_5Sl1riCTWeOdXylv`u-;f+yE}V_iPt~>|8Dh>>DSFR_GT7k z@+sa+dp^?v=|m;DEiTez$%_>kBeb9}bMQ;E7W5fTp*p0JNx?#E{uG&XWmm4#Pt~sPJn~fN(UbsFgLAFh9-Pvwzf>N1W__dP49mXF$9Nf| zChxs4BPNfxe(6&7X6_k3<&&2_|59pL)*xrvw&qF1#UQJ zTdu#CE@Rzs%D}`hv~`-xr~cp?Ma4J;v+BuDST?4lL`Hr+RCeyV%JrW0qAxfupJM;* zH`8;%N1NA&ef=_|6&*M7zOvT7SKR#aa{Bz9Ba!E`=LM9c$b}hkiv$V0%8C?vJ@0n; zURObeiLVQ7_pmJ#kt|K##nsbZg)Qm@#6Mk6s zt1b(9nU$}xEmGnA%qv;quUA|z*1u!7L-?~%sqOpDnwPuI8znDwubQ`6JgJD|sogH! zufadgrf4UbE#-1Neo|_o-&+3N8hpwgntPv#To$-|+0DCKY}PvQd!g$T9aE?75H0+( zNW0SebMK?DxFe0WeTVfVw4 z`>NVs&hjr_cbG$3&nt@x929ohEOPhzx}7b{Y-LwFq`lj-D>p1Yw9ZHA>&obsh5zsU z_-66PjCIRmCZ*P|AEmUk7lyHZ{+O^MV|n>+pA-9*Io#8k$b04CfA6f_8h+iHZND;0 zGz}c@7;W;r?t4SdA$Zc$PP62RnS1vAHp}GUo%q=D&5PdpZPkmc7h<#3v zbI9~3>f#?P(>r4$e?3dj+m&+F_$9;Hg|+NYuKfM)q}jLS(9D+`zn1ORRCuvd>X);9 z#9A+5YvzvZh(JS8p^EQ(VZsYiJNIoVu=iwkwGzCow1#Q*g+`Gp6PfD22rV%`#Azkr zdt&SKiqBbRuSb75zx%IQ)86}y|DB~@_ICa0C`b^y;h3>bJT(0BmxFtjExN^7xmw}u z%G0;_vR{2E+^;8IJSS?q%V*(V2Ai#&3d?WFIz;E*3gldq#hkWWD`&>n4LQu3yEVf$ zCxtIio1eh_=G2#(dCSAo%r`&N`qTDFPX1cbaqSxKg{(J9@1E-2eDi{|`lT8A*4IuS z6a4mcr*e4ZtiW2Ihv{x}H!E(kezj>%->VIrGt;)VykGW!ZC&ZKf9+E$+S|2{{a#z} zvUI-UsjHGncQ((h%ly6P`r3`(6V!@rEH3U<*)xTA=Z`tTxtH<+}A&VKaJ)WDGor=6Azjl&g_F)5o z*7E;d%{-BBCZuIAboR7nk&^OgbJBF0cz#=lE~h8o+5PWtZWKB_rRu_mkM~}_oR_}g z{@%K@_dyGaX58a|bw%G?sUxZcxa z&K#=b_eQI;!hebK{f)ZJTdxGx9&>!ZJK)TBORLA_lSIPIHwf&?T;Y9FBG>jvwWlK2 zyhHOp21)F1ahW{hpcoUM_~U>pPhM%um@Iy$d~?NO$Cu8c6W@geaDA*7h`Af)6Ce8K z^?chIZnb^6hxMA@&o5Qqj~Z1ysX0-7JPZs`#taNnXd4Q^QI(vZn+vX=u13Y@-*ywK zzrH-;2>+CTNZ-q^MX%1~wwN?$Rq2}pL42GtjZ0Td-DBwb$>Y?<#235opLsLsj_UMD zbF5hX_|3L{E>BOdGgc`*qV~Q`zVCeN`NLD>`^9a}90~fcFkXEO+aXNxs#W``^30d$9fDgZ__4XV-Nfbk}_LaIVLq3E!3- zaeq4LoaUh(^}<6B-{0}BJmsd8RrWS#uP^$UF0{Mm?{A0r$%l4CoobKUb?oZplhNOq{)totU$WZyags&+ z?>BcRuD$c3%HlQxYsWx6K;Q@HEOT7;@P-IpXyz9ePl8_X~r$MQ9jN{=|#?Zog8}ur58E& zQ8(fYL3HGee+N4jZ2p^*_`6fkG5z<^L*M+h6z9I3n#*l(taRc8o4_rHB{N^I-y8i- z?}t(AfjDo`=IzVtd+xk^`t;|6?Uz5cR-4($KYgY8_U_fE?-w7uA{)FquUps zd}8WY{Q30dg^J5Ggu_qq-;0m!)m!%N^~a+xuez68?7MZ?VrNagsYIk?`{K`+`xh^? zwy?FIe`UpslNlL$^LzE%-d%nA^h#~H)!(yAJU3777hV#+h0$0;#($Za;8FYRtqL=I z+CrBI-29n#we3(l^Tn*YFE>1nziHFO#3{fabMDSw@4qU=GdLtUzWmX6$gTfbV13Yu zI=#rwSj{%$%|+kBY?$Y8nB8felx_XFmqV-}MCQ%BIR@=5bA#@Faxgu0m~YpQ7i+}1 zm!F8taf19^Ka>NJjY9%TK`-`msUvOIv{nFYgI57!xKaW6iXE!^b&{OZcQWec`P z)iFHE`5-n&dzRnrH;%G9uS!Vp{<~h`l&%!8@PJHFtYFuf(%YK+(_*)|C~cjm*VbgT z#$WH^_n!61Kc@!0R^r;aVo{r%R>Ot|_LC=MGbhzWCOdqc)EBOM_GHWP&Z0>=%OfwX zKbG(tu#vT;PfFE8>Wq_B z(qq-r2^LPt7G^&#Bs~<7IAizValLuqvE4@=)D#ui`YqaN-o9(1aP#tGTxWX}A~)2( z-P7=?_TioxGtIj9*0Rt3{pDolO^!nmTXW`3W8PG*^!3YIB{l~Q&L;7vv7%917M$u` z@jgtJhw)W##Np+sn%DRIJSE3F=al^n!2?yjM#j6BDY?Fh^2si()p{=EHK#?0JuHEp zk^lCDr~5Zew^Y6=74TKAr6Qa!Aa0Y_>|KFt!#@4w=KktnqnnnQAr^G&rN@yq%&XV! z^A=rgEOjjL^0mZ(``@<~|6%jHeX4wI_H0R8sdWp!aoTBEu*hqPT)r3ZLu6u}Vb%Gx zSh3G3x(oF0YBHP?zAxuyF=5|6Ex{Cau?Meo>t7gkXbZXeGdx)O)=#&yu{$YQ^7*Tk zUE7WK>c=q^e_r+0r()VcR+pY@&jUAPH1FcO(%m$@L|D1ygKNL9h5CfZ)6rW__@DH& z?_5yN*m6v1f%V3iW$Q~rc2^$jyZL+dXS>}eH(9)`|8Ki;nI-F_oWHiFM<17Nxxuoh zeDd06Wuvk+lGaDq<{YmOb!!p7$(!SI?{}ojUyi&GXWp)mj;$@Nk6&yuOJ)AT@#2Kz zlhnC>#u_?vA3s!PDXsp*u_-z|j8UY!D(gXMuY>arC!L*p3NGlM;bjqyu&^%XD`70X za(Ba{S?WP?JL~hTgC!Jib{~JsozwGW|19ka<(`!fPi|~G`6;PIz>i-eTR;1;O4seT zBEb&g!IBdev8A}@R9WtMbNX;}p40qGZ@M{{%$`r+ndAD|gzJIZOjiMyQ2)Pd9)2+wUcV#%h%-bqWIa z+1U1(vecyhyzXVMFBh1<=GF;2zP|~ZGvsc3To`D%!Cx+j;iK376+SOC7)}0!%N|&2 z;rrmzCvCTa!`Y^#i`VM1bY-f^@y<3$&%S+Z_7ro^EuGTleauYLI4R*n()|WZBBsEl#ZqI_p`;aZOdSs(DP#Pmqm6?)AxEGSa~?JoS{qX%)up#j!P`M z7x5+JoU(5CtHg8mUvC;tUwLox`w2Uy<(=IU82n#Caq+9`hp#SMtW{ESs_WgGyjM=M zRv&+;P(An0i;brk?wk@bKi$#5|FUll_g70p2ieUVzgr3=?q0K?FHCf)P-r>3M&O(> z)1&XoRysBqWF6o*v&M0A*zVA?l6U+swS=rLGS$~LJSnsK-kt(oIce2=(J(3J_BXvHid)=|t}^*#K_ z+?w~_uJc)aU;cB+)cW&fSA+%EF@@%QDowamaLre}>%G`no`CbWCC^Ztt;j3b3WEta_@b(Q^@(NO=Z2|+c-ij6;^(XKKop0 z$*GUddrZ$SS|{~*wVy+#Y2NnPCRy!aJsjI!ZZ&Di->}$vo{E9-j#t|kwz^K_v^l>w zzwN{2KV>U4f~z!EO_5?(s^6rt?l+U#1c7I>g_nOy5&YKZ^Xp;I!YlE2XXfjFS-SLd zMRz{a_P&~vJU6p6PRE~!-g@4Y*D^Uv|*AoJhnW-SUmF1r0? zjcM%ssxx8sMRS*}%wp4ac4eDx&v+%oepTI~F(cfk6 ztDJPMfcMkpy}v`;uc*`uta-A#s%YVgDb^e32At0d=qy=PXr%Om_v4(rXof9sz zYBj=IxmdPcX4&1@yS4evFX*X{om&pFR^eA>YBUccYu<3=N!vo zz56?Ze!qG1<;C^p`Kel7x_tN27nvAMUo>x%xu}2sk%O;)T)k&!9ddQowCm<=d+WYF zm%sV5H$lE7O!f4Uxf&r`8*0yR?7MOMboSN+&q?}cH;H*3da@{JYvLZAsSn*&1-*Z3 z`u)qNRjWd^wxq>uHr{>p&XuP0O?&dn=UwhC>yHfo!Ewxi*!=m&pY4|)KlyO?<3s=V z_Wx>k9e=P$SSv3t#_!?lxbG%?u9fQ9p_A^-Ha&h&leh1;XU(yVUf;@@1Q40^IV z??=5zO}xSLGd`?!$AqOb4@{rT_4af(ckZj75033oo}jd4QuM~Mj02N8|Eu;TFSvB4 zK6-V1_a~nj-1)qM^WMK*%E~SxTlZl5qaSfgyccJ!K3mJAZOdok&3N4BDT7g>_~b>& z-=6uM^w}(3*Z#n$EA!y%FKtg(rCl;<5mVUGGI{321tDtQN{fFkDrJkjw{nVs++{H< zQ%~`Nb5nJe^WD>vx%=gd&HUz|T~ieuJOn1VTv6|`xa&4m9&5Wr2g>q1$kf2TE5@m z$tOEUkL)c^&kIy?aBTRKbT9bQ-j$Vy&DXC#el6e3VacZu#*Y&cuFPaxAJxFHbUU|G zo&AiqePZg&tKIBEd+vYix~^)G_QLj{w!`zhhYWSTcDyqd$A+&u;ne@}N0da6zl7^# zMZ=ZbbB+ox;^ba8O}es8J66)Iv$?G<{!~36BkEEqx&C|G=&aSNJLDw4k+BwSfQZs$y?Vuw_;}32HUJdTnz48Wb+Sr?=EYQ z=AZ6-@pnLqK4aa%gBKsRo7>B(FW)b-zxIE2(XVHJ?!I|w=&(JuK$xwb_ffrOWLvZF zqKtb-R~Ej%BfG)vuz>ZC+iKR9iDoZc-zTWNFI9TKdGe-+-6xN#DV|Z@xn}FaD@`oRnRaWeN!`3W>`sto^HbX^%VQPvk858~T%uaIcg{6y`9sPRS=qT}8T_$S zQiwgrczfD>&d06`!#t~nGna3@RCP_C<<@FnT_gW1xzaq2KfYWG;%OIhXI9#4;<}~H z{oz!t1)+LJ&4hgKNZj>4*0MkGgP3DJqtVw%Cnnsy`|{N8PYN|3Tq=5+7Opwp@-&CV z$bWg~n;xOBKV&ZKZpu5q-}=j@{6!@vCMSOQsM66^bu0ZsMuN1%iDU`yg{()JnD0*c z#atPCs)ko_rt~(UgR(AfnSNjS%3&z|Uh&<{vZhDB)&6b$do=uJX7vTW`Hf9$#iT=2 zDtMK@#=XB-9DLqb^7W=YuRojZFZaE!;B3C~&gqN6=9NJLxv>*+MEaK6v4qLVoIEyd z6RSk^jU2s&<~4!#dH#j7e=m#s?Y^X&N94UL(~1S+GBZDlg$bugH{~@6K6*Ai!dZ69 z)mJvVDokr_zn3+w2+f)48LD=pTe8};L}figxooFxLk5rcqY&NhHG6n?R!^T0?6bi- zj5Sv9_$(zpi9WYK1wO%#>_n#~<{x}-ujTwl=6dPvcm2hG`PVGDBJ@05`{IsR|F)pD z4WCaRcowi?%Yve`_Yanx+9YnxQZ>uKnx&DgR?$={(}$;)cbe?=Dz&xe@-0~AXF0nj zS8OWl*#6;~JEPZ~-W|UZ@_#n0ve}`de|qwyTCJyl9Tgj;_qJWw(O{gv;8%maR(lJh z>WLud9lM)?%-5=#D4F>={dQ01EGn!E?Xb9!XKGQrTgaUMlI!K3=Dj&{cwZ~1?ElIC z_qTJ&%KiCw80=cbr$^eHmQsm`pEV6rE)2yFS=DW6>JTbeoOy~IqS@&R*Uo5*@ zKiE!tkslzi=*N#cg448A(<|FqoNK@KNWO`8{$u2D@|x$#Bk#(Vbno=jTKd%1&P7ex z-`6#f_v(rd^^5gxi~7&Cn2>ALaB&GIr(k43n}$}aY`Wo7U!I-{H@2Gd5AOZGocxRH zPyW7Tt8>_5TBNrrKdNZsTHyHk}HTxToUv$}bMy3J7#JP``%nIEk#5Z@f)6(rCTwCI}WG|nIF3@c~ z_F>bp-kG;pUQT7{v(Q-m$kbd<@%N|JS0P7&jWv&7F4+^=mbUF*#!r6t7}@n#d7os= zO6C*xN?g7!qvb|W=f{*iwm}=sEV<_Qh5tIdjB&m1%r@zTH;-tki_A#C z;`v|M#DPg*e@m^6Xi4<%%Fgvdzj=(d%s1v)=hwmfVMg|BwL&58X^l2N{e3zLGdG$6qZqR1}(- z*#iy>KWvbm&)msY{`Ok#0txF)%TG(Z($X;d@XX`jliN?1+7^~v4b$DGbZpTXlU+I? zg@TJp9NN^9AD8T#viajYY5nzQ6#v<dvA4iu<&*d*?0GY%n-iCRFMjzgXX0qQjS=`P+p<0I#jcat(By;>ynCk3t1C^kJD^Nsbvn&4CM$2Q)3HuJ5}hs5TN^Q>jj zpUtHWWNP!Ande(AJyv+=*IC8~u6nB;^*46^&to`u?9utM=?@R{IoP<}(6!5ns9X|N z@T$X8*(=6HD5qZW;0?y#?;P#w#4Bt~dQ+<3-p&yB?T#^j{Z(Sgyx9DxThqHA$G+Sa zIH`Ee^~G=OYUeb|rfk3Pnr+&KPti)Lmlvl8J&sxW*Y@}a(Pt8~cKH=W9JwtP^75N% zagY7NLgB*8k+;ORKh`g~+g!tD-^^3ALUz@W?D>0_nlCqDUS`O*_y4RMwVe(tD*I1y zTL+~6+~l)2eAyQEB{!@ZxBbbxc6+|w);ZgX8}BMG)fGtd-u5z6vcJ2l!L+#jTb}Nh zkn4d3_ZluUNS_pB5D>ilZ{NZ7*0(yH+?R14lT|!$m(Oa)p4)eL|Ge>e*y-}e(#8E8 zZ>DrmAG>X1in;gqmEY=R7S1nh*u7Ty_MWvKLBA#jyPy00_OgZJcXQAGtf(#Y`cmmF zr+66{nvF0g!ol+lX_+~xi3OQ@1(j!|vhyGB__({Cb)%-j&gU8O^KUU&DopoXxASza z*z7Gg4waT}ak+Wt#H3a3Lgf?x-u&Bg&;NfW?^@GerByb`8+Qn2 z#^o^dUv0`)o4n+Vxem|dWqDqLZ9aKjd)7#v-?Zo1)-#*E4zmRAyUD=GTkwl}zi2xD zL=AzAW%uecQl#de4teqYvW@qXRhpd_T#~Qdc1qJerd_sJlfCVQ+S%||(Fb3bYE4gj zpu9)wkAA58YLUq&zn)#*-T&}>dj0;i<2mnKrDxojZMa^AN^ zQ<}r~5o4I-v+ZB3=59IhL?c=I;*)^spYL(}+gFv5Zjd55Sv0thA>r`;C#p7ko8L>% zy!d(c@#8n`qEa&UGtWIIP%cotyZ=T~#*(#D4zYC13P?PzAe`T%zgOb2BJ201Yg{9` z+i$tgP{=cLeJXsQhw=V`6_3kS{?B{uGG{hv9azM=xF=-2slei`&UqhnZfh3LcsFCmhBH;7 zkDBBX7KqHS=RWYo`~CbcUk!ddw)gO#1V7U?+m?07cG z`yGsPjxLhn)$u-AA!}!_~zTyv3}KxOmlWXiaTdi9K-`Gi)D+CQC>vKzi9 z-CPrK?}}^i_W8+wBo^uJ{^zYBNQYg1DT>Ftz-R#JQE6prI z?Gsr(_g+#H+h@wS{*co8C(ZV6*Ur17ar3bM^>F!Pan3Sl_SSS-F8L%@%iQ+J&*7qm z_RLUI_TFDb$C4zk28++=TI6!oGj$z<*xK!VT791U=Xs6uU+UCk9^H|sx#+at7Ga&K z_n5C28?2YKnV)jIRhey8>X*;Px*RKe9&C8Bt!?)luhy1zyoDL-9L0fM#X=4!b!0?c@Sc^tT}w13uUJ$c_{Ze$!R)r{JdYPAcjRg#wNoO?U9K)M zb(Jj13&fuho)yqrn!i>!;iH00owNTiz?44m+;rvNS_H&U|5IQ_5m_ zL+j6~9-CJxzA%{BbVK)Yb?$>QgQR&43+hS)w;X;{v_Z4j=mkgfxk}v~b?2@uUAxFE zTm9|JFwLu1{zRy^tTxK$nx2-vChn^Ls+jOkOFl~$?>o6Bj^|CH>ZX5T-rXsG0*~>( zdhAi9dF`6&{`SO#E8A4oI6m**Cv*G2UEN!5I}a4(2^<&YeG#?keSf4@LVDs^+f;{X zO#SXld(Kp?Ir}uphr2$a?!+3wb)9T1BGWhh3QS>ATJ2D6|2!dyNKXd2A{X7{f zC0^<->lW0KT02`|)l*iMz`_nS@!fAq+V-3ixRAQURKM`)@7#hPHziBcrU~~pMNd)n zI;2&7=En8oFAr?yQ}~u(=&;kqcV%*jp?pYagT9l+tLRy5+@d#bED(N{Dd5$( zT&c@X&^f9-Rb4nT%yi1!pSmyNY(o-68+N45>@g4wiZWfPB~~sP{n^@3LA=}JSeAW* z=G5t`_rtbm9q~;qM}bhSt5hwYL%QB8&q z4;640@;!CB_CZA0Qtc~O8K3F0?+e_;u8Uq;b!?ey^2!*iwp$;rw|TLIJzIBg<4dkN zbEns|`rh8Vu;AU)O0J_4)^=@4@-si)*?9QTw4{S~yiIDSCpLz)9Z57*)n9tUno;-X z_6zqH&9=?wy!Y_wb$5M+%0p^5-uu4jS(RKkbwlR9^QUj;&;0ynW^v!uGp93j-yiuO zahdu2j-6HYuBt!RZ`5GPd!!Wbas8?84RvRa*seXa>Q*x&@2}h+WttaeDrp?rc*pFj z=}(P-2ZcI@6JEZ$?&_RZ(9bt<#nV*oe$$-S8?-Z&8v-)BZC~Aa$gdK6y2X7}t$X3` zg{O5QmN@m^;@;)v$kuyhgGBkwlFmhXYMl`&2dB)uV?0;8U+RogUd!bT_tVvUoVLZhkWDH0_Vdk`_2%mKG4pnY^3D6M zEOsj8BJ<&zH@`~)p9PeMEAd@4xxMHvo8#sFFx%VLd%bK=_8F8M@Y@h+y7+3-?8{2& zTDq%sco-M2l+sez)iQ@mWJlO;><8sX6_i#@ zH!+IJU7xpPOR$Ay}^DXf!+Y^75%uRmQ z@TueBv}wPl&wU*dp;stoKHGPG&#Kk$TrJlu+3<7X6W*4vxm~wy51X>^KM>9 zWDp6RmC-kKs@0Pqb-`U%nE2mZuU&ZcL|*j^<_S;daeFN}SM)lgu{HPixn&Qs9-Ot^ z?6c;kc(Fji_mgX6_U(`4iArtan?BQDAw6~G;S~FBU0cgL+aH9QYE^%K!||1kyJ6nO zgHrjQtT=6wXJ0>cf^kjM%JVB88Sa~wuwKjR)mbJ*`-}4Io81L%`q*Puy*2QtY}rm?W_@gLlvOX5WHGQOv08TS z{3L#Loz35;Po8i7@Ob&^`RDxd5AB~@yKCQ$Uk@_k-|cwDdE{NiEspbXD@)HW+aC}y z$M3<1E4$^=VwoHtNY0(kb7!q?PU`+Os`Dj^eTo={(DGWB@0Tp!p15$3?Zu|B>x>Y*KR^G8TH-$cMOUL#CIy^pU1B6;b2cN! z{C>1zh>Y#jYsni=Tw~f8)wm-^IpX5_GyOsKDgLuvb)%>5E132{O7S9zKdg^+ z76z%<-Cid=ZCOTeY~%BK&f3h0A!@$ap`5vb&jThUPyU+KS;q^f=;R9DobA9PoYnOyZpo&q`4?IyitG`6@3G~9 zQljF_ZkNK9Pc=H8tn-}qh;@>Z;>rlaqmwu6HxG1M8(wN6`kZYFSH`Iz^YD<@g>E*p z8dQF@9Bj-e3S236P=7*g7w3sN<>7o6n7G3eZ&<4&PMDD8%PkBn5yCAcr{MJbPo zhRT=9oU+`txyvr!c;75%c~W#|#?74zzZU4t`D@f29Ohf{ zQbCMk<~AdTjxCd{&a&=NpT2fxQ^1UBX$6**{C#oPk4C90|GY0TMZQ9OYKwxFtzzh_ zX-j<{?b)|?pQYZDvt3>r7DsN|b8*Fn*j2#~*9&h<>%23!ap7Rx#{?xOdvaJ3%4^z-o6pwyC5Kvl%1Jze|KrF@#FKoLA$KC-#hzw?j@PVQ!D3HI!un- zt>gA@;`Q&hlHcFvuzcA0=yP(#vWK4!HGWunfA`1u#y@XoPqaMqTUgObO{qKJ@P_lJ zM1B9{X9XQv7j`gUhy9xsHNX7#7AZW5t~+`1zx4Sx7rnDYSe?q zYu*mo9l0Cc`4lpGY1Ji3f6uz(YwmQUr^x932Z!zFe$Fd4miabUtn=k7%_S+f4{-;q zeAMJH?TYk@f2$vx6f)cGdTXa*S|eGu`$zr)yS5)UcT4lQ&--Wll24v}`#EVx{sR~J zE>HK+dwuR_o%a5G{oZX?GY_{d^|`j=NMUU|FZVyU=9(9GJ;^Zjz}Mw>b97?Q=ongx&MmI`QE%VJSoz1N zr>=bRtE7iJ)aGne=@j$JUrc_No{RhT&8x+Li~ZC?)~fm+>Ir2Z+BO8Mv~6VXo4fGD z+)Hz?ds!)^~dn#0u^Q6Gfe(1)79fs zwqk0>{EuDzOIREHo9@rP@pQu>#Y5$*B)BCT%nvHn=rMiQ(TtY}U#9rVVDZ_Ub2S`O zw$`KVpPjYobl5R71_rw)n5W8vYi86_<=@u+Ex&zY;)D0Uv^PB7%WkwxyThq@ci!$6-zVA4vTHRMtXjP~ z-evmp3h3Ra^I~=LD{L@rBmZi;KRW6xYkM}oEW*rjic--)R zpV#W>Ydni0qweTkj-Gbr@==9ZXC8(!=|A}26q*?v#woJq;aS<)chvvb+6n6VewOqW z-+A?lbwyc)osjB{F5hVk#}BsIi==KypKL8*x%$G?8mkLa_0*p>os0_Qs`Xku>*j&= zAAVZentPjFNp}6oC6V=QW~W|Yr;CW-*0xPAYQpaEEwU_9;OYOpE#|{Q@%~i9pTC%S zs^c~+-YvAFPGD}Rz_4Qe|-%LV>erF303`CWOX)t&9gm;fA%D2 zrtQ_wx0|{2v-D%}lJ4o#bM;q!+UE6q)xpW48%%so7ypY{%yGqV*N1m+9=(0>MY5S+3Xk}Fne|^4s)A`WK^IeR!wcMM(Z#g6Jzm(q8d?ydXc*TMex z$%a*zw*LHF*7@jI1ygfT^o{fPm{xDP(ol3W#6a`w`@pmseWPuc?Cm!^TW1nCU+=m3 z8Y73b&&{9q{D1fU&6_8eUu0E$J^jT7OZ?ua z`)PrS5}ud5`!4pE{cunge0Cr|vV_6pXM{ulvC?4PfF}M$(h^e`JufyUwPY_(GGY$t zz4eP%Agki!zv7c!oW^qT)dKJ21LTBy9@ktdV3{Mfu5h8%xoj1`Dd*AzuV^+Dl}>4r zm~;4q&x4mz)0lN8y7E^Ri@$w$X~KbDlNdvbR3sdBrs(X-p5?lC|91CH*%4ve|J=SO zJ6rdgL(7I;H-FCwvt+t${j1=|WzV9zZ*?VKygz+@cvQ2%r|8SWKO%OAccyN z+gJO3+Ri)eajd`n#(wu5aakLxzg4ug>m2%KZ3wetr7iKil80nSX!pruti@ z`-{15FR1%}?B7rJ&(B|n|Cr|C!^6Ev-D~k|85VPn$r^uolKLLbn!j=O)3>@4WGj+6 zb3$FdDy?52vy%IC&9sL}r(SWer4()d{O$3JzlOX|+7B129BVIWd~?n{V#4Ezj~y30 z{;OfPOrQC&rq|obf92C2zUDUjEqP4LtG6ptl7EqhQtabfB~>+_zCGsOW2D2zvm@-v zqV-H~WI|*ZI`ZwF996ApWm418_$#?9&`F(>^~I|#Yo4hvB$%CzoW?x)%r$F&Yip-9 zc{k6WUVV7=#lTN>U%oy1@JRf~0=KK_OfhxAORq*P`tk7159NX>k?-_aPtH4YI>$2D zcITguA09oi2sp!7{%QK;#r@$YmPE9z7CCX})8Cu7|Cbh(Y?WMl@#WQ%M|U4q<~H8A z?%=AueG`?Y+xMP3nswQX{ZW7T;_r)B$0t45wf#MRe_fURu039T=j`V6-QSTD!au!hB&FVMTwbw4yT?9XeaFxP-->R(R(`lw*N{rl(anhoDS zOaFTw{qOnqKm8f`@1O6#ARqg>=epJ7t>^N7%)#SK0k~m#%KLZU3u#7*YYoK*30~gcdrr4uG%L*_um#)-S5w0j^2u|J^p)D-T!~q zugjy(uD$;zZBfBP;R=QQZ~ZUtn)&qT-k%wo9w+L>QWyTn*Vk7QJv>!&?#{gyRrMWA z-~V2_`}1K_l;zKj&yM^qm@~8F(G}hRu83XIpKLW^a=yKtt$2p3^QX|X>fa}Gr`_h4 zbGV~(fx&3r)eToHCO9yEk~{F~naTDu#-GhsXy1HuO>c7A{DVsb&Tp6>F5bR;`ul`9 z+4*zkH+0z8O3jT?d#`uSZi}yfu@^JL!YAS{=ctPAPSw^3FKo->c_2?$I^<@AUs%PZn^w2yY1eq~=*=I@_1M z=B&>qnK$Jjn|a=R_`6|e?u9jXwwo$1%sjean$zn9mVzS_wqISmIF&bRVnw0v>+_R& zqfL3=Un%d+n3c-p?vV7~TWTqzU906f>(cYrOby~)U(jZO;w#o4;_ioZ+rBl{2N$qExmmF5SNf%$Yp3sGKP1R##rR9A>FxATzNlC$Z?B{; zy1PDyI&8dQE2dnx;Z{@L{l&i`r}Q4SUf5~4&wX8^{4titm&GrvdZqSr&bd!L8y@eu zbF$&chGU2IXJ-5kQ~!L;?^()}3)R`ns_%+kI`OJ>ou_7;@=6olAAba6x3Rukf6Z2S zz1ghamuLDXIm>1FmI&{Xo5g12An}0NPx)T?-YAZyWWfj8Dk8f4sh@p*CI;PVJAK!U z^OsKb-xu+GI)AH-1wNj6l%y%}Z)5U~K$&d2*$lg%NlG32A@fmk$LdEHq6B^((!KsR zyFO~hJ-z&@2OlnQ^_f}6?{DAX@w~RaZNYgf{b^^a0yng~=zRE*zGuI6va3G(FW2?! zZ+qq4R1930-)P9uvZzSP{#23w;p2Za`2rlmZ)zM~dzIOg^@Z2`-DwYQPw02Qouz!b zI%sk6Cnd3CE}=~KlRSf>qSRNNtyuPE#nY0z3RY3q^p*BseYnl(dexK*j;HTlTc%*p z;?SCR{e#l$Ail1mOM5!(%q-vboT!~7C95hlHzUmNl4S3Sola+kzQk~Q`Q7&HJnv%| zzP9;Mivmxp{l4q+QgI*Vt$qEn&*0X%j(>B`O?$(#Hbwdq(~7HmPs~V))$H=@uF6-E zR_B~nGv(;~Nh^Ye`qqM~^UgEALn4kT@+KFuKIp!*DI~1JZiBXwnaJDz8=zO+5hId zN?y8gtcwlDv`5P}Y6~u0x70C^_lqfKe(E_Mqub}1OP6i_a!vRA{JmQeAEe3c-O#8r z&D^+X%Bd=^rIYSW$=>aBOl-w9mC#=sQUjemAOD(XEFU#Zcjb}DU#nb8gjoB2J-l>Z zS~D*5&nbp8D>cgwao+V_W)<3OcdvZLo|rJW`|F0}OTPBD+1 zl|S*Z^tLF5?B_{~?Pfj8nO3=Ex}aX_A?a30rXJ%tQ~B4t`uaU^_j5hnZE_0U6HBvQ zSb0CUoy`tdaH!eKmVb+}i@n>rC987yb$)x^dB5PC&HC&f%>dpP?>-gg$iJ)dx@X

AB)OojD&DX68-uUI-(xa@qTW=oIdSyK0A)Drj*KMCA z(*E7IROj5;X2fwX`9qhx_?rB_tOl)bTq}-UIWCjo@ZbbamDv+`K!z4RXKL$bl&OXV_)6YvF}9twxY#xh4shYeSG{%^P1j0nJJSsKg@ot zQ^&WH>F>d9VY>vgQGm|Ie=1MKAmIA@yyfzy{yVdl}R@ZuWA^6{=5Z84%WXtxc~S3|Ih0s`M>|(`!N64v%Z&$*35PdWtx2D(23{2 zJum%t`MtRBd6__>MTU~j^IE|}Vfy(!@uz02l*rP1q{-UzwmNYG<8p@hBFDoFM^_#E zDwcj-@a&1j)Ag0VXr^UOz1Y0w$loh-Zg0qH*;z8XIcjIbIgKqR!nuxrbTL|XzTu~_ znBdZu$b5$k9jlVc&Qr@byg0l5Z`m`3gNANxU9xQ=;@5sZS>GkRuk|tS+G*x@djGDJ zj|qIPE4=35fnz^EY}1k30Y6W33E*|GHHTD;4bD&PrH4wQ>G}hZ^QtMXydARQ{9v?(zx#*^DzY z*ldpNzWn*3AZxF$xKb6*yg4V-b?RPC_;N>sudM%;!8Rqe==>k2&v(DrG-tCK`(?*Z zPQHiY-rw=~I$y`f=A8m-Ah$yhd;1a>hW4vGt9KmmSfAj!cTK=dzmxZ}7}>o`j=pk@ zOgXVx_|>E>yFN>upUiWAi}3l&*2kRWTEaaDSnrvty^BUPfIQ-c)(uuYldV_ zR>J3v&#noXPsyAqlb|j7`@E{g^;=obn&xnIoc&Ryu~_g-fZS=#%G)dghJTjm9ofkI zHcD)pW^7@KmEWoz8N4aim!w&C=&-&$aQ)^lyJyqd{A;qsMgHiVTFY~9jpsej-G1AXR&-YwEqyNk=aswuPwnRirdQ?7`~7Nrq2G-K zSI+Jic^m!De1W@thn9ww^X0C%K zn(FFPa$GS&Ov=$tE-le-VEp8UAubbXjl!4<)7 zp{$UJF^xT|rt`40*f5lESLo*#nBH65>G63^{oT{At4_Y!dwu=>>aW&||Mfp*mNS+p zxc;fgE}r{lpl*85PA8UsbFO=D_@*~Ib=vd=g3pi1J?FOa@NR15EIQ!-z*EFFhnG$H zQs>$aIicqj8bjVLYTshk$oM?#Y|j>h3Cb&YzMcHrZu->mGW&tUhnFS&QF$XfyIDx? z?;P>SpBMa0F9fN7U*YGU{*+lz|L*U%ukY{w_wKg&{jxXBEfJ^m6j-L7j`%2$DgAxD z?ca`VN>?}fe-)Eu*Sh2=`Tdp0(|s1V(thrKakGs>=8uMqdB?@6ThyQS{fpajtB`w5 z$&J3Z6;BU(`6(ybbogdP*e_)-x_oELk^WUz-~JJ9ls}ev`<@re0!?)pJwYw5h3$-4 zi;7b&Z4V{adMALMjPp-su>=#P&la)Jt;?3+G=pRqoW zea?o@N!sroaCb=b7O<;WZ`$-y3C_4+C6ydDSsHyj}hChv~Fd!*d2`huY;f#*eq1RFPHG!a+lnn zv*6#i2>1EhvX8es+q&e-6W^BNXv5XteWyNa(x1Mq*hjmHgTdJ~a4L6y!&#|li>s;@ z`DH#f^Lgr8qBbpEZe-B7Y{%i&I7S!Nx@`&qdEBR*gBNz_=~+JbJHe@{%5ICp1c{sd z0mrvlTbJo=?dmmEeYP*i%g@?oL&LE@Zxmy%Z~1hu^u0UtMb9aYN9zjOEhUycx0V;&?njZ9G`7E(o__LZr0vd%ErEAP4wNn9o!vv9UK<5w`fk3 zZTQAAyZNTj-7^R393M;e>TQ&4s69Nv$~)ro65AIBuOHf5ZIaDpUB5oUrS0X7cd4~S zlILX-cItgE_MUmb@WnROF86z_7mWLlypuitcJ&;7r#%~N4<|0~PJd>psJZ z1B0>?+m#QO9`^mPeWz)WcC}N-g$bKa?{~S(m9wOM)2{9AbFCi>{oVHb_}5vhH_7Im z_q-~q)G7b;&BFzI10B{c`f$B9$8gC_r|7yzF1HVDo*gRhq^xUD`Zwd*^3rhMYu)9g z!psf_`l}23&)hhiS=8(Q-C<`PyMGDe0;9hS$`*zVnQW^Tm#D36+%_ZPSX}eg$>(^U zZnNUmpS102xJ=-gy{6$ISrZ!;txeo@V83nPjh-nF0);vS<#m+R4m=R&Sa2nH&CB^K zWhO9B59OSszxIM%6_}>y6neiG+lea_65)KrW**mR%C`= zoHF6yaVE|Ank`>>|EI1qJ$w70ZfBOSGQ+P~%mSPBE`|xU^%a!1U32i#H|u?|R>DG;X?Z(9-4J{n8DGN;01({M<=N(*o z@g-lgaqGY2{S$7#*r6H}?Q-Z$`v$(14wE)4K4!n>_sf$vWe@tXcsdAa1WBmfdbocR z|JQBD9eyiqyBe>$M4+=q2U(ld+uJ9e%3x;=Hqk&`YqQ=Y8dp4-lQmeFVt>z&0- zR+GfIa}^pimdb6hY+jO?Bf4z)+IMqvB@ca^&9d5azsLSsh32mzjn`&%erPWVUmjHJ z9VjDO&a?T>%*NR^yX=@&8b6#pIU!?xp}9ZX5rO>^)P-0kZ@shlf!v43Y)YYBlHr1O zjvxO7GtX6L+ot)V*i&tAMn8MBSXYF6k+h4DD ztFUikU;LoZB0y2qT)H$Qg4K5F=WXn(%}HmEyFdN2?1_HHVrKXBeQ|5vMg%*iuCSORAZ04GBRSaheMiZ3 zzK_}WjTY^>5_H;3na$+!PPKFFU&KE;r=&G7>RGL5*_s|U`Q27G_1dM1I>L>;Q(Tr6 zF6Y$c`q=9IU1oBZ!_8f)&pe#VFIj42G^$?bvpxIQ#iAzqm|rn-Z)wWZ&r2p=%ynP) zWYha;1%Vv-kLQHCaI&&^zSwtX`qf`;ytW5*j+{O^?Mxxd($!+`CfwYlx#tC=n1I;A z_lAqN&zt_$JM(qP#gr=Ml;B@e=>5mqJ7Nv$PVbi$zQ4$M zqWYEe?ry07k+<(wm3Sz;c$s`SSBo!ts*!oCjE7dHqkzy{iAk!r8Wj@1^*VlNOz8af z>yYDK`8D$93EPgW`#o3vPRH^WQ+myvo-L1SnlaO_c<)P@FW)|^Sw|H&Nk_LGExe!0 zaGd{idCw-TtBfbD6z_AL)Y!_Y{qX=`FG|&b+$NIW_1*^g{{5NZA6O)_P-=iK0o&Dhq#aZ;F0$ZO{8TJ0#rp-(6yQ zeyPI8s2x`=_g-pTc1r4!C123f7Y;ru5e6)qtAE@!W;*n&n^VH!I5VG$-G>0?9UT+T z{1(3TCim<=w@2?$KSJm#YeYs$k)c@bg z^A^^09qaeMet)%b$es6(Ww*;@*qmLG|0R0KO_}VL-hhPo!dtI$p1=5VzWu%X@ry?} zUnnhTnNyRmvh2~_pxEu(UCxRW3s0;GWLq@j_X&^d@A(&nORf1byF6QW?%!{h+-A-> z;F$PrqvuYSW`#q~K1w=lnz!}i%&DoTcHVs$?qRO_MtdTE%BD3221Ywiaz{<&waQze z_}I_cbc)fnNnboIj)ZJ%xTcxqpDefb(BxgLnsz1~e^X{xNuOTq_y5++rD?~sRL{L} zc8y7~lFV4jt6-%wZ`ah2$o%Q599K?n3ie6=sWM@EVyFxY#^UT^YLU(56~nJqpu3v~6* z&-#35-Ph8a_a~e>^mf6m-}Td%ypS*W5MLu6{ODwiYTe$?zcZ$Hi0QQ7FZO@?ImN*v z+t511LhNnY|JTa><1X5-)A_>a{h!0#=_M{FE1A!(Td+=dcT3}TKTqv|b!R?l+9#>1W~sR5 z+dY*leY5b*Ed#4PM`xe8#hE(o-nQRUnr8Xwzkau_CuHi6qs2$^ZGJ9fsz2MFczx>9 zvlT2cxiROD$$iV4vvPl&q>9Z(|Ge-XZEmaJ2@=95TaCE(>iLEpz7=Da_+*F0DGSf+ zI~UX!Y_WCsUU}i|0!iiuNlBrziAB%4BQ4y7luetA7QE(Jrt{v?R`c)##gIK085g^( zkXWdpv+mE96*g^pKc^%xWvu^qtZLh<b%k4ze$>IOf~UbD_?_N@(xiitcPiadGw zCzKwCU!QVWcFT`^zHW|=i)$vTYOHI@zE;$GE%W~VjS5Ut#J-+L zR;T^4T{_{1VwPLfKZi|XQ{A@ciXJ^*&hugIsi9-8|_>(xaYv1B$?u65n#8E+kaces3iuKyV&^CLbPj?5z5jRDQyc@v&J?^(oa zvd&vKdz!?DTSa#s9#7vP;Kux&>v-Q2wc=YlIUOHL6m8=_vR8WR@tO-?uGYeS_l`r|=g#%y=`T zyoh6Kz|z76jRyPXE;+U$yczE`Oi@f2t(3h{n8`Tgu;^)qjnSGnn(OK|-k zXrm=FKS}+fa$Q_P&bKu?SD$+NR#xu%(#w%?hL*4LehF%Jyi^tWbot0675f0zwE-N8 z@7BK2eYGa}*a07hty?0v7aB1b9ti07_!*eV91_WK)OpU+xJTboqF%4vvb8VJ`0AAh zS#M{(yQNVjdGzq^AGhLnuFEELdzUa&K-}V&k1@r4K6& zk1fc^wcvMIzC*_TAy4q6ONvLB|Idjx*f}?rJt40$Dev%77Tp&SsRjXSR!PhK)>vep zaQA4ZtFm>^xh~0@vaSnyn7ugk=e5mnPY>&HpKwWM$KuwNbCS-5%CY!HIX3iL?Aa1# z#<%~N)tto*;%4tP?<)BoEWcm-TkXhXkJ{65igE8*YZa>_W_@Z___k2=+y{<{e_pg) zwt8{w+~VE)`!!peBpwI9Ub6cn=j{9*qXILnGG(U8>#W7*A8=ghaJRSc&nLZ24zV-( z7#*AZ0_z(1?yde@d~Kum&xu-V)(CxK*dFK}_AC8I&%Zy$HEE|mNS>T}=i>E3XU`jj zYYHdN=6+=+aF+31Q*sRZ%jySz&voT8pYQsX&wR#s>LF*3+ke!M672`h7Zo+;RgisPCDrbE@R6n)h~Jc9ET`m-&v~i_bjlI{hU> zYK2;K`Q2Wl+2(gD*ZqI@w#-WXzUYm_3oA_5Bs2HE`TM_j_y3~JB5x-NcKvW|J^3Vh z`_1hq7fat_5lwG?uye;cyR!GzPbU;!x+wm9>8%ZlM=hrWr960AwP2Q(JWE{ek_FAv zgw#2|&Pwm;h|b!nyX&Ru9<>|`vqp`M12qZa_p;`nMc*mj!}M~)mRekK?(vp0{4mV zuQ_nWHig9@>m=@dQ~I-IVRoZOy3#&d#rDlB3l<(z>L&xecO|jY1c#mO0U^@$cV* z+YevgKhz{;wd&!nGa^S6Q?0%(x^QVv+9u5_o{c4Ye<+_f?x}1S&3shnAmL%cn|a}~ zE|=!@$>F7|B=eVDkA1M!v~=!iox-Yl2Y*>;2iL7sGAZHN)8*}>zfA1gg!1n$l6r?8 z|NF4;l=LpA^uVX{8(($hNmcvUx^%XSeEQVrcGu;C?3zZonWsH>CLBK9pMPHeoPqn= z`~I8x8AVd=Utzx2I8Rl`Qavqn=Y#g1owrwsu%8dO&Ad-};!pE?jC;Z#T~qBlhK6&>zcM3zl-<;%@yYbH?)@x9gF$Jd+;$I|7wfs3P0t2ncjT7At-fO?)HZ)Ru9h!*nHtUsw=2v=~M21Hl8P|V-UZBS4PxsrH1?b#H$BhrZ=iKJjyz{`k@MI zunpTmF@B~`HU&Sp4b1)Oj&eo4QQI-uoT=bScSpe#cV{NQmD?PRIlgBcl+gZg{n?6- zvit}AqW1B8{XFla*5sc~ALr$L`Sa%Qix<Vea<4QG!&`WbP# zs;4>m;L{0L1z!E!qIyGTeV|0@#YJY5~}YT_~lZ> z(b6jn;;|o!?i`x@?%kSMI~8g_yjO8_-p>BZr_tcx9wCzlv(k+`#d+Nt3O|26Fk$W^ zl`7r1ojoDGY!j^l5+V+)+TX#VR`)V9>IWC!g^vxBixnzc=eL$^-FYA(xv8?MCfblK z>-p2;ix*Fx{CM)?8GK7Zg-z7rJ_ehF@QLk+`}3~gi(Gfhp7|;}bfmN8cYHc`sf+Q= zeujwho5y-{=J_p~wsJv6yzH|B=ND{wyiD=@&9nOR*SwVTEPQUg)?meKR)#6dh?F(=;_bH{j9#$r?&o9YZu+VIG4%3fd)@VB|CF<(dwxqzOQ;R*_~<3~ z_jZn!&*Sn;yT>cfObtwn5m^*`(M~8sdx7JQoub<_fBVHyhGbld84XgiYvKeW^CA334 zZ?6T{Iv>_l$7@OMYVw7)3%Aa6?n-!l#*{6___(F*_B?Z+H!YEJDarTEPcGMZ@k++| z=15^o+e?JyZ3)_U38Z&1KIhE8YKo*muyCz9Ru*?kc5d!%zo3#IFW8bF9^S`Rew%T-J7@pSPMi6uBIvl;F?;p(J-UI{W8dv$ zxBvJkz^hevQ-3H~ZF#>r^rV=^28Gkhw|u>2 zQQVUv5xeF()73p^oOiXR_DDyqdB_v#Fs1s4gl^i#zjZ$^zp!~&DXLewdeQAo4hbgB z8$Ldst{NTPl+z!)MM7$|MKp^o!^NjBHeFu!$h5#^ismgzv4dZ86Q20b4AnV%E#vGJ z1CD2^O5s}Wayys0EK;f5-^u^C@#4%rhkHHZ$0n_tmbdTg0%;b`^h>>;w6@KAEu6b+ z@{6r{39*@CWj)C{9-n4?W@78@_gn9$cTZMs?h(OuvndO?9PhZythrYfBm~#C>`4-k+miZ8~&-Gh~73HSP7joU4xo zA5eLdl)C8Pwlinkzx5h#I`?kI{e7F6A~I$~r`tB{{kvz=mVo@vXAb_1-X;ImT+Nd0 zVm{Li%by*88%i2XJF0Ha-S>u_O<7>ktW=Jxk>?D=g!TRI^xs=nYB%vw$dj9au4mUY zY_q@l=Grv(`X7~_l}xhgn*J=TcDVR{)?0t6mO?3sJt@z<4K{Kv`j{FaAt>A&u*6Y9 z@y~}3F0y&|E7g}+TOHis>b|}x>Bkmcd;8{4n9oD; z0GkPVH-Ff@xV37__w;w4yp*aAKJc%LzVWfIqHns1*e%m}Q=dN4{*c>$=uQ1uof}NM zEH^s-GB00sc}nR1N3q9ubgY+}k-)cZg1Y85pDO!XXRp})UYp-~xB1#?^u1>Hbc?b7{)qvj`+FP>WJc=cRMeq-5M$NYM0 zZT0WVKOEh(cU!>G`I$wWvrlc>F7R>Lo_0C&N;gjKi%TA{KS(;o%pCFf**Tl|z#X|~ zHqVMnoSP8wcxp@9NrS_xRvmFC|6k}@;wIDc>Z^>~3iq|AWxA$+IioiD;+ndDP8N%HIH%5ylu?k>sbp{)Hx_DFkdro33u6n^^F^)Pj6mwz{@Xt@tUow|4wBe zZH(4=ZoXzxLg*>!s#{!9`^^q?FR{7Na+^)$%<}A;9cfHKX)7HgKF_>AN7m5ys^*1d ze>JvRs@;ovc6d?8Fg&sSLBVY6>*W?SX0kf{@AG0XkD6g6%C)TNm^ z_d1_NwI|p3uDq}P_STbVl^;j6&Nl`hP_S&1`(yQI=5?>2nui;Tqqgzv%>VK6k*$)Z zPgmm(uBq+0t1aa$f>ksG)8;HOh*;iQY@unj)2-oB$duQQYwP3Jo69`2U2~6Pn)tNJ z=NlT&r!jvMlQI$uye0E#UXH6q*ChSwNuiUS?B5)JXSeFaRObn~X7e^bTX*KdDg)I^ z|7GX>bIAQadGY`H=NSjIqxy zvSo!&H!s)dP*-{qs#uiRwe_myx1J5z8w7K&A5*9bX^i@PaP3a@xt3RMZeDEZ_W4%v z31Qx83oiMss=3(lMWcjCr=%kOTEX{eEpO*1JN*hfKFccT$I*x1qSeM+7yaij%LRV5uKYP`jpUB>EeEYT`4-K{D}C^=U{~D( zuPX&1X9df|KTg^`@kP?T&2zfu7+A>5ue_-KyzH6Y8eOjLf_9gAe~wj$eZT!Ka%u9O zIsa;;c(+_EdF!uvPUTq&+k<<*`u~~i*>m;Gb1!wzxb3%QG3_uewhCI~`8yy)=0fhq zJ5x5FRJ2{F)XKJTPWck+6G3{bt!A1$DeLf<;5IL8s*~yy!=wEZMPfVB{JtG<)qAp1 z%=5hY)XKhXw@=o8V&A{IYLVXI+XcGM!es&?V!Tb~t9)spSAM?gl=xqDQ+yq^Mg9zK z)9SBWu<6CrHv!k*%~>=}zSdx2ZA80fz{%qbo2;j$ZP+I<{mH{%uT81(`sanEEdwf| z0t>5o!?wH**c5u_Mb;u|wq$?J{W1cR3cY3;^%Sw3WaVeiw8okg8829NUM>mn|{n=|js>AQdoR-?}EAiv*wBWu-%*9y6x5MNq$#8y{HyDXWb?5BB;%|`ox(d!bPqp zA2G%ntyx>Iqp{{fk7&=n$|;6o{`Yr8{<)KPQn@}w>2|Q8zM50#ykq@A0(K8`b;?TY zmd)ds(tNzka?dH%06sbEr>hcnf4Gr3UAO7&Cf7H-jQY!cf|k#>DRWiXB3yn<(Yn(- zW$%j`Q|3Z_wY{HDtPXdxQ)1*-Ra!D<)jD-iS)qFmKF|I8B#n3PVwp!0zRNH2wd|RA zsO`goB{x;S+T755?Dcv2uf~0jE7vMosq9$4^@xLIVW)r6ldxlc9IInKM6F=Fc)r)R zEPrL8)w_Ls-|p{zsdk0$wFIPEvPAHFf~>uoBrIlJ=BBkgsY%=I1LGg6}Zc8vCl}iP{HG@ z%6+BuuAC2dzpsx>Xk6oKCup3rSMbXbrne;?OB}8q^nN|zgX7AdJ`a=q3M~^`19*J} ziY*qfCGOrc)6x8F;{T~GE#~!lor~P~M69gbw@-66SGoToGjOTv+{I}bv+Qje*)*g0 zGI)bi9xRaDDblXbVKaU1lFzdio>^|Mn*Myo?e9f5PNquVbnL%(L*U~iO|y>ox;9~V zKO8l9l~#7=UPRo4yvfHuS(nb7?)BWstYC&@2!9RNkIuD93wwCJ*wsx~`$S4^kA;k= zsPw9U*lo>Oagpt_^%ux|7A`$-refXelXqK>+>KssdGHmp;90|I!44(oZiESUd|fX) z<42IJ)r1hK74vvQ7RNbxcFXS!ny)aQeP-b^W1f?o@n4S>o%1OCdUnZ5{eww6|JE#! z=6bXI)w@Mn`nNxAys#?OKyl?Yk-gU+zHIs+Y-YQ$mI(^ld;6%9dzkNpbi-qA zz2VR9KE7tT@!MnY_TvsTvKh-Y?3|hcZb<}Fs6E|@|^CywYySS$} z+T51-qMz`6!JHpr8p_|&wmY~_c~f@!=f#S(RaH4BJ7%nY9dmZ0Y0>PxyS6IHb!dku zeQbX1{K&oA=!wE-QLBsG87~jo8S2Q~30ttZ_F3NR;)e5gvhJqME?sS0pQdu{+u5wt z3uh}IsdAVdzVc>K+^2XAt^KPe6^TB4v%LRvr}LyrL*2RE3!fV5X{&FQ{gko7WI<3^ z_C^m+UVom|qPxB;EfSfkF-;><{jRC;)$eA@F1`+5|Bqc``PnCWuQrNW*{j$n>Di0t z#7){L^jr5}b+WYj59Rr*q>60*#+>=qW16@9OIIK3hU~@7!jJt9c6~I-zhUSke=H?2 zYws&5tJc2xr*BSMzUPah_rnK&Gp=2|_4aR_+xEL*P19{T?gg38;V28582mf0v{t<9 z`uc~q(bpxe{XyRXr`jeGb)ScU!BGRp=Jb;M{G8;B#7xjtT}z{?^B?aJ{BJ+M>8{9x zn!+vpa$U|`@~<|}-CH7T-Lbd&ZW^=Wv==kP_xeqlv!iW)b-IU_lIqQy+ZeBD2Om~^ z{#W|a@{~I3f6srKe$G7e@@J^S<2h?3&gz{o`1;4x_Wy%D)|RS^Rqm#}DV#f*|GnKF z#<7otrd6d)AfH z*A=6uv26bky075Vna`Q8Qs<;Sy?wFwyNkF*o%S)&rOuCg=O5AjmLYI%euS0RqA9H= z(E;LW+5Ij>XpUL+>X;x+Bq@8i!PMmH%6&X0gX5O3? z`kdtfU7xh$#Vxr{=l?WI{iyuWBGN<6L~qfgvn=zTX86T_dVa?Hv^k@z@&O_3O$B1{ z`ReapTtE5Z^3^Yok8(EJ@09=L^q1*dMu%-+vy`k>N2;d|PsrL>-j`GM1xc*0Sj9M3 z!)bMP*ltGkL_^uN!UYQ_3)_FOSZ{9pee#rB8rlANb^m@&zrFjWz1m_{Nr7(h(hI&#-Ur%mINPNJ?)5JP=yZWPFu9$H9xcwbdDK3o%mu2))8_S(mI=}DPMx)Jh0@s~i=N>;h zo_)UAU4J8~ik;#6Yp3#RB|kR3F{Syw>1^j|%kJ(L&}8{X@kiVeBFR#!c2`XcUKlU8>7%%0@YW%_mggo)?MF2v59^YCl_ z;q{-pxKsYVpT)NF(p=y5`<-HWZ!y|sJkeTyZcXX6m-oIXX|LEPz2cU;Nl^3`(|yz9 zPGsgur4#yj_B_5L zFo$9Lfv=JwF7`T1qTaoGtM2#;pNlh?c50_2>jAOy&am4H%xs(%-;&^dF14ll{O30d zujx-}c=&$p=Z`Paeq=tod8Y4H=>u$67C*jfz@Z zqc(lt%roi1-@oM**-H0GbHBc0H9gcy&?126pX}pFKLt}}sjPVDK5Jvd5{U*`ODg_|>T}Nog!J7W0`^ozT$n`ycCtG%2V1 z8PWImG2YmIFUoe~A#YJ}{$Kx|nXE5x*8Y1%bZv5OXKYB_nt-N;;Ij3`oBTw>Ru*&} ziJK}=^Z8KNzGS9E_T7Pus#bof{qr~k_S z=Qa%O+ou+^E7!Lt=Iv>7m7N*)ChM@(nhPiTr}D67?c#3dd&TEEFDWlly-hM&)byLu ziyP*$hKskGy03n7>Xzd4zen>PKe;{S9s6$c`s&Aj=54rf&q8VPmv8H@d#&ZY^dZ{+1WX#)_v^>J*oYPCA%el?T7!(^{VAZ18!f| zztM5=s@I%;Re?t!PvyjIc z&k8S2@jB1U7JcA+$j7a%tex*0wTm|G`2Ff$?YvvICf|(~-yk}=QCL}t^MBh{-@bG;i{ZXJ1XudG(&iO2jmldnyGG$W%;Vyuhmyy>V3j;>*wqKcat0w9J_tj z$m{+!NIQL3r%~dip8M16%`8(Fuh06JXBMq-@`^~Xgi`fU)$K32_a5lTOt0Lk_U*IB zRpa0P^<0!UaZi{fs_80tlyQ&p93O-1b(4}#Wr$y4yWjV43ujEv=cQae5~l7>rYc2~ zpS~}BsmcF&*J|I^Q*6h0TMK+n2F_73SKRB-^0Z}J3B#fy4|9>S_#>fmYt&3aW?mGn zKB%OnyZ83)(5?FECT0v-#jdMlLzuYPn+s*OMNd2McG_gV{Ozi#9?84sTvN8^KfyjR zXO&ayN+m9Zqe13^%iovnoLjf`&fnkdeEV13iT12#yL3J;Z{hKs#p~PWFJBz5uGLk# zd>YSvTa!zU&Z=KeiSysBVit3_esZTZ$L-xBv$fUDzNSgEvQ8*sPl%IWTlud2nqaAh z{EmII>VmQ*_BdSiZ}`u5OESEGAtTkYK26|}n9rAmtj?>qnxzVKosB%M!`k7qDzU!O z_K!t4=ck%CyFMSSc(SYcdzIFk7S+4#R(IoC9J|B4UJ1_f)URH%`IeBvHpaNqmQFSb zqGxTF#Ju@_oBI$HPzhd;G`kCUZ)wd)}$~(Fs|1JNrpvM|NJ2IY6 zD?3xYrhDCoO*0QN9_e&WQwxl{8>IB^gVO=ggVQ)_0dAZy(9r{;|qG)>Jyw zlU$I=LRm&gJxxV$*8Y?}{4QCoI-F>pMFkNA(ZH02A zWye)R=lvoETW*(17M$Q`%yGE-ebd{8o4HjA_Wu?V>*$X=QdV&JsKNSA{d3RnQF`n# z_h44hgYzyY7JQv8_%^DL(>qT=!eHz7EwlgBT`k$NF5`-h-sF|<-8>y~cV^prb=4^3 z?O34Ja$c?>@xJ#_{)7s-3p&yrww9-k@07Z_c*DN1gBCe#!Ig^@Z+7@svR*#O2Y^F~B)9YPp zeeP*<`-g>QGTXP>rBDC)`xwhbeuZ+5T~V5R{?5~GS3J7WSRB=T!t;Qb z8qJr+|G#=Yn7@AQ6}=jz3miE{x<$rvvLCDUcHasJui1L;@rR11?eb4*3>V18C#))% ze%r|R?K~M5Tk#ZSkp%m%Czq+~NgT5k+Ffb%F;W!+mq$n{twIH#mIJHQx zpz^Bi-|*WWllFfO|1zQ4|JxA@#p>VsvUZ!YrCQx~oNT=n_<8vBQDnDsyR9Q`wE`Oh4#zY#|lzmzh0=Ravu z@1+$j^`F;tOgJ?*8#SUgsI0Cq)VBD; zz2Os++^h3u3|yrrF2B3A2-eObN=&EquSSRwR#jFa?G~{>RVZ#*` zSpSQs`MUCl+pm^&q!~P!@pboKfAzfu-bH%o(_NUmM<=61H+ z+O?fWRaSlN&N#w9xrdvcCb6b^E1jd;b~MS(YOj$J zo&HqpLCK6MR~hE<+|GF{Ykf*I=8tnhY|F82Yd7vroZ9ZOZkp7Z+;4{*7mEKo&%~~A zfcsCp`Pux6i<_#Hk}fd(-|m+GFGxwdciEm|Y=d|x_XwtkwjD__PU zyQsw{bfb1wn>;g~cXU}r!?fmwH*-w%xhD8Mbe+^%7?ksJ$r0J70vBF{iY>mnciv|1 za=-dFU$>t#K4xZC@^8=X>E~IrXPq}Ww{rf=n#%I>d3Wyy&;Kpem#}d6@3i*h>6`y) zCSA6XS!~AqFnj%+)9N?AJ~fLL_h)L@W(Kv@`xDY{Ov>STGr5taUGs4`fAyh#jIR?+9gn2&XvKYWWq&%m zea77-k1lVzYL-+bSv7Dd})j5AAg4*PMdEpYveVe7Ga)c++PHYu#?W7e+2~0&|M_;tuQMt-u-?q3i^6BM(Pf}LumpC7! z+?lq`ZQ(W3MitfC-2t0cm`;2nC3krLv{`FsvR=*kdsHeq-8Cb+NtRnS>tEXXH){9REnz88_~LH1&YXG5?rG{*j5e?ae#-mJfA_3CYwodw zc}WLT_@40RWQn@Q{m5ZyIG5QUToT%y8gm6EsGt?m!@sr zGvUs`BU#*hs(AuAQx5BNsj#inD&DYq%H(Jx7G4|GdD#yRC~AEwI_92q!Y6>oo_Y7e zS3=pz(QYl9ADv({m+T#x(45iS5iu zWQ@L7V0xtH8%M^biSj{{dM{O;39LF;cAC3<(P`;licJfvRDULF8f-qxWudLUV*7^= zy#-S%%!)2za8e2>mz@9OFk%jcRdHuMM)2;r32-y5^|EAztu>035u7tffgydih> zx~qHbA1>7sc`TEAi?eNiO1+}Ld*zvn(^lP3VcHws6{wpKESGwtxM@~&nR=ooQ<>}a znHnqRL~3rgEt)5?NMV`OqP2O?g#1m!HuGIPR-~AzKmBX}WTB@4GFrEG1k6$6)j6y3 zDI@&41B2*qG1Hvyr3seW68l~DOaGWRCBVCt@1f$cmgvU{9OveGv_+V%)bx0GYND4L z^FpoAfW~mI8wpwke|G&oZhrTAEc=uFcho=J_y5VuenIx;Pc^N`c}uz5rZ~28?ve1$ zd3UGszJ1vY<6N~3Z-kO;mvcv4kXF;+_{Lze<3WO!kK@nd4d*+m8`ETRe56Hm1ZFoC zu^Al5FqkM|X4${{O~M(mpE73-2HG88v0Yr{*vVGKBWarbUUwL{&F0671@=Tc^RSh4 zK6!D8cv|$Pt&0*DyCWveA}!6r zJ4fMbAu~_Km1)k|`5MiEub0lsn%lZ_%UUV^y|bBuSr_uWP}-n#e@ACmPV&672e;jp zSn6qTr941ZT;qrR^99Tolv%GY+7SDj?VUG+&AN$9(cLD;zs*fmy3anVQdL=XQU>$! zEV)h7&vKm2x?yqEyJ_AM;h?%L20xM)thL|_c==SwtL?H*uTNL$??nc`PsH?GaZsKd z?b%y(r;cyq*JabyC*(_vPt}HU3+-Cw_V1@eRC> z7vvrgH@^MtG0Qqb z%>bvJ9R&xXcKcmedh|p5$sZ+b%N9Q5ng216PieB)p2)Sk9J!)4+}OgrqG9Rr-56-ht{356Qs7kD0XI;r^gz{-EzF~_%ppPpA1vh-h9lUs=r~6z@{I6rT!d@ z2#S1E_IyG0{nWkDB`+I3G0#eC_k7c?_S3&Bg=-(nh5b63_q<;>XyrMkO%$wJGGp&t7>Z%CyoVx9;(oxrZ#Wmmcf- zVo=_i*sR98=6Ut&mEo>jTmqX9O)<=>iM4Hb#`5%1MwOuZs_)lUT`_X2***WWO7_WX zxq@=}<)YZ!XFB4B6^<}dgMoKkDBp|d!pR04Q0twGhAbG zU$*4Ma;vPfdb8_UP|hl*_u5MH`h1OUS8>$5X;STLRNKtg&C7GeU{!ZotAxhQgI+G( zFLrk=Yf!!rFSIF_^?z>1K8MxDl{0qCJz8qM-EXE|YRT<9zR$a|RoFhRe>>rHgu$T` z&g#xrLZ^q`bz}=+*SE{9>+j{gcw-_OnUd<*^=Es^wM*3{9Q^$=dA>~ZWn15#k+*jJ?%ogQ zvkfYvAKm|@pK+F>S8EUBCtHaVXIg5?d<-Tx&*FR?qLyd)i>9+oYQzaqoT|9{%VBqo1Q;JkQ!th)WW z$|4DCmGpSFZw((3?WV1htrPURr+47fuJ8IcRu*WTJg1`Gzeh>*azJ)hm{yk+>%AFK zN??p3lpCoy;aHRD$PO-6wR z`o7Z61s`nA?To0aTYcGKU#y*Pde?{ZuRN7ZSIfBe)wi`h-nW%Y_*BqLWqT&e8^wHe zVJ~@ldNh(coE~*pbN_so%(i3a%5;Ah=U>OJTx=H!jeNOwveC&?TBqFhw9d8KVsq`^ zLGcdRw77@LeoO0~T6Bj!-l}^3W3u=ivBfI_lp@WiZk1_%VA{61@B8e-YV)5NnkzjDle;VZY2S=^t^ND?7KzM=XRvqleZKE%TDi&0-=E*~r4{A3 zwv>EZKYwkHp$*I4g(Y))f+y~DpHx&^`&T_-p2!Q=Q%k2Mhe$1~ye-MPJ8)N_(OD^_ zrrZOmhM@-?e=NUPx{h0~<%^irzT|w*xP8pq3!iT(zrugMtlz)t@VBmMyRCQIf4vdC z#pz+D*@e ziFTH49zjRi{v|Gn45@$JFPiq3+%9as zt8u1fmY;ZzllP%hfp*Hx%g;zIopE8GAUE?R?as!(rfjRPbFni=PktG4EN?@Q#1qd= zfpG~OQfyl4fphLZP%&}1Aik`*IeROsG%urirCMa`9F7H3BGe4ro<$rDd39%L?ybF# z@9LVZTot+V>nl;i9CLlWqszmE=bejN>aqLP)GcQ5jOXrpn);f?IkOv1+1I^s;t}Zw ziCw$cj>s_WJzb*=Jo*u1KRxm&C4=H{-23)flLOkld! z!6$doZBfz22fI%GY&;(0a`v8rq1V}2GqO(|7hR=YE4}YR&a+=fcy%jtE6OC=q)eQ@ zC`rXOb};1neA2ky@NvzY#U8U7wN_}yyXuRC_PPixQh(PaY;~aX^GcoO&kNfW+k-k; zC-xm@-1Wv~iOkX27U~Rl^OXIzSavpx+>Nx$-kWDO^8oLT#*-agHt81>K6+0Ki3xQ& zd5fVdV`1v?#S!UkX}fP-{5aoZhHs0&lmw581(J-Lo%gx!Ut3bKb!MZ9@slwtSPd!c87?{3YS z5SJ)iefzM=ThE`?R||t3q;uwE%nQ?1++-|=u zlZ-ww73FQaklL}vcj8Y&hW?}*mOYcEEG!FS)mA8Z#l|l0*XRFx@7`S;_ph#9J?+{m z*A~-ruYx;lt~Es-TD8Pw`z9UR*S?2BH0Fmj-+I4DI@TvP?@r9o?y3t}3oKUK?NsMe zJaL?1&-d*7@5%Mg|0eeP@p%;7o@&v)jAP5%wSBuEZ(VdI|L~%s4eJlhFZpo!`1}(s z?tkyS{MTnv70YLGb5Y)%xXq@Axb9W()UUV|5n*pN(b}y%(oUt=(ZC?=ZR3q^h953V zE}eN!%kJX0l}jdsMm;c#aCJI=PAHqLEWtfw-qOmtR_n!`os0T!%xKb$Jm8t4czK$J<^3)h{Xp=&%n<@tw%=Wh&OD@xV1 z9@Y5qJSy29s^|$W@scA+LY%Esb6~-xeD9Ne+2cg zN`&cc(%R*ERPVfO^Msuj=#)XZcJnR`}*VW4^MtbZ1??8{Qk>dzyA#WZEV)+7HoCDDy~^` zJFcs-uvm0=sha4wI@^Q)W##5DUW+IPotMo$4wPXK==3}O2y_b8o>||KF)?8T`&JJY@J$GamJ$j zl8Gq^dY*lu6XinX1!`W*m6dN*Pk;EXeeV9Rhwk<-7x`DupY-F4uwH}MO6jRT_egwH zZ?dxfSHZPy5kqQce*DSaIN#*=-rLW4uWhM(-rls-H!kE!#*qqvX?r-Av|T+Dci_^B zjUv+)Dosf(wS2zRVnM(*o42>jCM;{q&8)w9y36`~Ajf^($jjhkVc0h1{_xWdr zk|qh$XJ7kK6%ntn`BaRU?mpi)$0RP9w8tm>n*8U)vHBb#7G1A4F71{xyj+(PelWLP z@cz2rgy+pX=DN6buNH85+4M(-a+}TVS3ATvt+VMD!*1PgVe*lAp7r-Sq^q+(w=9UY}*@J`?-5=TNHWH}5mwuE*EkO**8< zcmCJ%1#A=7r@Z0eW)gc-9l&&-JKQm*^0*u8@QOe!krNFMhx6df$7p zW;1arT4XA4{(bpwSz(#nGuyrd%g!s0T>5ThxFppxE$iexxMvQtRc%*z$0fc}>5EMJ zSARaA`ngaj@HDsA+M@F^TMFg9Hrl;hG0k57wfCc))B0XnN0@lEZIiEyzOdExm!v@T zPMb*I>UA3Nk76{tvu^%%5z0tS$=Q4Lj(UJ#}==jyhdH}7fbHMEy{|9G@)e@FfX zQ8}4Dy;C-G!|xqF%r!;g&(t69qV{}~T%#x9r<;|%iX$^ur(4hLYV_$Pq00Y+exJzU zjne7km6B}`<#T;0cT34=fF#o9e| zucFLyp0{n6m!1rf37w!Bn9w6#Gcilg*rjq}j9Nv_&-tI{=oJXPil38u;lS0-<$VRb zS-)L0N&|ydO|4T*R|yqYah(xQD`dq{G#V%8kfEf#BJF4qc zYTayP<6X)XG|s;Wk}7QD`DjmHZuHhj17I@-QGHojU)*BbTqdQJAsm^qe^yj|_OH?P%}F^^%ul=1bP8oU*m^4e!T`X|>^k!0al*{}J`ZIpGWc?HUVl4bo z+c_*?X*$a<@2C}IZ1n6(_#BLi4h;X`%*8kzCYEyIm-1z`9{vT zf9?-nHJy;JnP!}kP{#Q8;u6uykd-;w6Tj@c#<5am{;rr1OO-{t-%YAm!#OwX-gKre zZ<#;Qa)(9tilj|cemmXwt@pAgNy-ZqKdp`S3cSx})?W4g*#AS9=Zh@9d8;aTdisOs z-!Ay*aZG91BCh>*-nr@R`DpbE)sgOFzWzT7CTbvMVbiAMaTe=JxPjzOZTdK6`mr z!LHbYtZw&sEbd#Kd9h4)a%k(()B1XUex2D^lQY?uZXV3g08&R%LBp;U5hWpT;n|3^+bxpPi%2bNci&C z{L`l-b9p9yX;Vb@UaqqXRNZ3(0iE~X3$32b)$ETC~-}CdA+1htMG8YIf zoSMRGp0ihH@5~OHRds2O9a^zgnNHr1TIc)m*WG(*E<4No(dwGFCy$)6RO>%Jsmew? zP}Z8??ChtCvswCL+AB8H+{!vQov)dZ>(-`c2c&-QaQygd?aL?TXP%Z#d_S#l#kbkI zXNw))UOT-jD*J257E_Dw#wQ<5)BB#KdE?!NX_|jcGH;aql-YhO{qK{6xm!g_?X@>g z;xCb?nI`(Jtm#wX--J|qezVf88-De@Q`h?RE6w+Q?zAwDC#&yTSuz>MoRHUZVhM@t z`x?ysEq3s<{;C+8~e%7^Txn90$CF{#~d|tU-{M|blxp|WFK7YD>dVa@s zqq!LyH%KpDVxlc6v(_Q@zLxN!M{+4M#s2oa{V_%HSndCfHDdo4WS2gTU4L(N!ZjY3 zkbUAMbE|K^{53aZ{rA^XmV_?8*qeU6(kX^_$7v{#3Hytrho6E51_l4bTZ{N-? zQ$3jaYR5j=RqIyB-4L6&q5Q>itCHQ@~hV#K_k>>YN`GvXnwr-cG?*81w zzNJW7ddk^}_ROcwZ7yF^JMX2vcZKAt_$K2;m!3cUzV_Ys=dmB94gasoTV3{h&sC{C z_kMi-kotSi-d5go`Ei#HfBy6*=f_|E+;4{~rRN=HkZt+)@NwdQhA$rLb9>bDN;V#o z{`1#HI_dnf+*yzHUH5JK)cE7eT8%G@t=n|hoj&S&;p>zqUs4+8>?#px+g|4I{_VtV z;U{%eEQE}FpD><~`m$`ly#cqB%4(Jcj0bK;6)l|i-|1ED>H@FT;TuZpoo}-#@439{ z=}P_&vkVq(_S3m}SLD{CZ{dq?rcOMczSg%`VQ1L9w)zc5N{_ZX+w%UuoTJe?ZTZ7` zOWxqAHz%6$aPRSDoA_~ap_bv~s9B{GKbUM=lI0z;&wFo2lZQ@SuK#W`zTG@bOQhRo&#|_hUV7l*M&=2>3T54b|NLeC_Cs(&@CNp~ z8P6YE?wvXL*v~ySbD#75xM^IdUp@1Pk!GS#@aMG7hdq5G*-73lL{G60ld zH!0ovk-OvSzlWk4pTgh1XRm+1&uH_R8?hpSv*!lB=U-slARs$S)jO~9&7~_b;cI3E z+N-{_PQGmsXK*;+PRgpRy|K?OT)%kjX4aCY&riG(vtz$&yzk$vSG!+rGPg3^^om_S zZo^#eJ-_(Gxa)J(yRU5Rw3=43G|B0?*o=?2YxP<+eU|^KdiVAJrI`yogN!F^NqW_3 zmtGagH_fq(^L9(a#~``q`=4z8e=O5WZMv|}9^>1`|F*eKSN{E-Pe!v+Hviro-X!xlO=tbx7PlZM_s@$ceDAY%j^sc z3#1qr6tLYp2428Wl30|UT2ic6P`NeYb>3|Yv48KED@lzfqD)r>g&$V*?zWwt0Yc`)e zPj#4bdz@Nqpj6VMSNtZw zGxnWYVc1$#r$U*^r}y@Aq$-4WpEbO1VwV4~bU}S^(7#8!ZM?2?7;ll`StOwQ_UZn7 z+44`Tjepui*GTaT*m%hRqN`K=arM^b>HDxU)XBe>Ed?u;P_^IqwPjf@diCE!xVMp?MEEDh4hPj!uzK@8i z>{!#^QMjsS`S+U=M+F~izg^7!g>kLi6-MJO4i|~8AkG7E$7iNX&6?1APr_N%(rBTn`WA9Jlaf&{tiNz$#PIUc+-x+L2|s&ZCRQDEM5#bNf8 zAFN9s2rRy)C}-dN!M}Ufew()5;)fi;hmExt9)9TXy3;dj+LNH;uH5yH~%oJ&wg2jc#v$zj)FCHevM{vw51@ zSWLG~{rc`;+0B9r&+ln`eXOLguHfXp;_2Uf^_sYkYk&CMY$dl`uut;G)io35nt$+_ zGS~g}w8k>~ov6=4J8D-0mcy#>2PmuBip9%-AXL>EbmRv$H!- z1Q|*EFihjQ>$tUZzUPJ`A`RMsm+}%;b?jbu(nH4UGsn89sS(?}v!~r_(UEJGe6FP0 z!uh&nMZ_bG+M>e}>l-&!#igI*=Kpjrw|L%>McET(KmEg!Ab0c?%X)^%hOSf3#)Mu@ zWi8#gMc(*oefX1e5mUN9Pb>ZmHTPy0y+mPL8VQ`Wfpi}U_u-ZRDb{E}n&%S6|2`1*V4*ZJJ9)4xA_DTCfcQ>$24&)3!>&5=$?%^M*IsBOkvArx$JJOXa?N-m*=2G^R zOMpl3{HuF6^bY05dTU+obre-Mc++b1QEv6N-=!+*a_?CC_cHO_Ty;NW?~79tGpub+ zFw0p#S$nwa$YaMvHeZ8ElD_-0N7&D+dUWB=+R4*5|4h_NJTEp~;%QaoE>1zIYgf0M zHN0PBc_olBKQ}aX|Ku4H>sHU5)42EPmYH|8#G~)7UHs8Uz2njj=e62h{lQO6h21k& zdK^6%v7K?6kS&*Fnq!93!{$s0g^Iwa*z_W=LmAddt{neo&Gu1ol3*-4(J1%u)xA}Q zH(pFK%t&4|MWY}!THDcit+=uJ-%9q-M+>v!7L%@ICzRAf*2%7og(`+Sb&#^&Bu3Ui-g zcY^6x0mt*2Z9m@JyQ7zG-hG*&>>cOw!`Uyj3g4d2=YDs!;)TxS*{^Tkl<9jPb5?Bg z{+cDvY~AEeZCJ)urTxq$tYXBGbDZA<|_9C9{75Xh~_kNyrX*=H;rulx2`t4-@e}dgpuGn+9_dmFoGSyXVO=)>$ z(0R+ipYyK#UHtva6nVaf3;x&{o9tCvvHaZH%`>dJQ_p^{@1Au1t8Diy<~#OwU3{9a zW^Dc}xUkSV;C}hP-_Jv8o5bQfCuZG~W=h_edeDNmc*&kF!@q_d6Il*tJTo?&FnMdQ zoV56DPq&k)f-W}~FKcVIiTeCW&d2yd($T6(wQE#_G+(@twXx@&6`#290na~n)CK_q z0|NsSh+tq~P{h_CNJ%V7)Q^wP%*!l^kJl@xWJbF$P0vyHw+Ax=gCGY3gECG73W`#5 z@)J|^z?Yl$h6d&@wh*X0zh2^^7q`{Qmvi&t%jOp~zFXwo*j!SsJvU|N1D5-YeL0u& zLZ0rwpU^HaDd+nq2ZPUNpU*sRoV>5-eX~xV$E1m_HlLaA&t~vg7JYNay%tl}_=o>p z3~RYsES#LC zYiCbebIV72)yzx5uWj#E-ajCxc1-cblCDLe7fp-zpSz^dW7oL($crk5J-h4XE}g&c&bxbz;TMFzcs^Nl z@y%|wjZUh88Ub%FyLHt^th;*lesA-a<@QV5l|s9=X)O?xnisHy?PTcb2P>~?JQUM% zuXF$ zJLU(f#U-p;bnJLoW|%x*@ImhDs$Gk=tnhug@DuBrmYRi|44MLWhIup_m1!&foMj%d z+xBprO;iFyTk8YPs~$#OUn7FHZ=O)he*N0jcR_pQ7Mijh`SL$~`;YA>J|=KX)0ozC z?_bMziK>~Kt{>f?b@9}kiK6Rgy!vZlEpjz>2gjy5!9%(KXDuldT5{Upgu=ev&Or^+ zg)9Y{`6M4~D?V=`bZ)ms+@S{#-u~w1?dyI2%k<7$nG@48KU_bY!+4INY>%_~ygccz zYGIns_;z$@zdbierK85+;o*$g&EfW4Z#OO5RnnaA$(7j7U;csn&o1_UGXtj|Dqr?H zvVT7JXSYP}&c%iY=4Btb;5*ehM$C-m`g1FXsxW4$fWv{e)sD>YIk!9RgS#}_sn-#c z5+{3W{=c?-Px$dYHz%9AmaLF9K3ZcPnR}m)H(PI#xUu$bOWwD~OqR_}|Hk#uqUri1 zxvk4{na;G|{CU!&^YfIOKfgUb{XlpB<3;klX7&+h}bLoV?1p%Egh1fuWEcvuU57TacNPT2zdjkxM5BX5TgtX}$kfo2B*y zoA1kCMiOrnv!@H3*mcPyK*IUNx2=oaruC?(pWZ(|=jNs-E|u2L?`X&Ve74*1_Vnf7 zf3~F^5Iu9yvcU6_wkE|2%wWx6`qIk)3zcJJYHi|38WDearZlN!8-iLk^!S zQ(rnuc}$)0Xu4XeiSw(NrA?Y49GymiSEn?Fc$mJtGp9yDb-`shi!70+sq0J7Moke%^BWT0;UZy&rn%zLhEd(67~A8+U1*|tlTNBYRyq`PKq%Vf69l<#+S@>5#cxh(R# zVB)OQb%jzhQjacDQ{Q;z&N|hH8*kLSdC{9Iwtq{kQ;CA8cVCO^?v%wPI;WExtu89P z_;ow!m-DsGXi{yn(-FT*O?V~JU*2Ucu# zbDAsn;|=fk{I^?=FDqR)$+A;s`n7TntIWuvO|grFnGc+MakJ#sB+FxBY0GQ*)=CCs ztmSAnli}QA_2j+T&pY}@-`U+cQL6FQGJFD06T^uOM@?I|9e0)Zp~2?qaLZN5I=?Gl zfQ_RqdBy9xhWH6AA6Px>?(!YXF8_?yvvgXU#v#Yaz@TElz#xrQ55SXOVsWlsLFHSi zzy6OczJ32EYWJ2u)71C$Cgm-wwk&_#u+x>>_zsV98UMl)zH_b_cTV0c>&5?Z|NZK| z&vT7hr60IiPZc=1`R~3zcCzh8ot@8HXP#5}Y;)+b$;4R!ibB4o{w-2GIy!+zC&w+1 z(cuVvQe(g&csNDKcxp$-d2Sx}N3%}59PxRvSbF}_j%*(>pX#(_&(#ZkTmy9c&#;89 zsY{QmPtLaH+Z-%s80lxRfx%ktv$URw!NSx{NuP=>-*0IV(LSaU7bqGmS-rvK^cnY{ zc}(Y4#AsNbxpd{dY`)NyJqjgtF`G;tC|b^+^S`j{iR_=Mk`K2(-mX8x#!?p+7PfMk zd-T_tg5vWXUp%Te{9T}%aptcu^V;+I`G+*WPLJ8poO-DCTGBy(mlNV^XC7DbVPj_G z`cUAW^iMvS#qE$T23#?!=E|BpZ$E*^~WiXw@kfPL;PG%Ok8jA0ls|}?{>>B zZ_u%tAg}x6xX`9-MRV0B%lTZcDwa1NJkY-)=!x!!xHm^OR7gDi)xRPlrQ~2kJbP*h z&lL8nyBYsDOp98cWj5EX$BVK0?P(X)g>J@kj2@}gc=BL{sKniCFAq*U&bwqbdx%u5Rqum`3-0b^O@5uM(5ukR8ZFo~T$%UcLS^4Oi!w>yaH7g!v1Zio72dc-31oab z+hFA$(d*v)z8eyj&0#6LdC-ziVSSi^<->z(6!%Nc4nAr#d%BtlM_X!;lvVNjs76Q2 z#ewCq)4PjjZakI5lHB-7WLfzA(~<_qjFsNS_X=spsWb~HMZGp`zm(y6{Zz}8tlYD^ zv_$G=C05+7e!JjDo8y%?EFn9--CL*}>%qy7y1Er2S3c}e*<|@>y|{se zjOkVONC)LWi6SZH19oq8d0NjM{dhb2!P|AS7_MDdBpp!6U$$jR3Ul4_lK&5`mzUn@ z`kKsGHM>A&?w*xx0aqDXdW4&Px1Q5g+Hu7C%X7QEJV{$`M)_qh{?x=9OJf$;% zBf{qWv*)&RURW;PCOhNT;zag|+Sj@Y?DR53kpfx)BQE91P}n4jle<7^Gk%G5KuCb8j;NHqKTxqmkWM|I_04{hD` z`a?(T<_znt-^H`1$Cj++<-cJQeMQot-8n+;r1@o5+iAhlQY+si1b%L0x}`Y3Enrrq z7PoUrotI3~#ZjoTr(U2flQuAXr6&-rQJv?k8q+u-fJE9{x`vUQ<9`Vv_#KVM@XY++Sq{?EqIFzY zO)lG5Z0QXN;xpW{{;5>kxqt1!L0|lzm@OCj<9ctRLgFcb29exZ4Y%#Y-kmsj(|wY? zvq#n&XD-P%j2oAyGR6D|6x;CY+tLvIwZ9G=yAqWtmY>+K(Gq!!=Oe>G3%kN9vtKt9 z*PrQ;3SP0)$5?-<(4pyVS<3#8OV&-&kiT%cE7bbr>uY6qlV1J1Z}T`XVAi>`K*N0> zAFxenc01@IX6$JyZB{8+`bcj7oVQLZSYjLQ-2HJarjAp@VBNFsILG_;jyu(rCK}rD za35ICGO75al|kuF>)leNixPyZFSBgW-?S~#oS7y5@`

#f8^jZi}l4-BK9w_>m)P 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%0Av^yl5rtPN{kiB9+uJIVL+ZlQ)p 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%0Am8q|ZrpwqN=7 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